diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp index 819942e828..8a73ef4004 100644 --- a/deps/simdjson/simdjson.cpp +++ b/deps/simdjson/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2025-06-04 00:22:10 -0400. Do not edit! */ +/* auto-generated on 2025-09-29 20:34:35 -0700. version 4.0.7 Do not edit! */ /* including simdjson.cpp: */ /* begin file simdjson.cpp */ #define SIMDJSON_SRC_SIMDJSON_CPP @@ -77,29 +77,70 @@ #endif #endif +#ifndef SIMDJSON_CONSTEXPR_LAMBDA +#if SIMDJSON_CPLUSPLUS17 +#define SIMDJSON_CONSTEXPR_LAMBDA constexpr +#else +#define SIMDJSON_CONSTEXPR_LAMBDA +#endif +#endif + + + #ifdef __has_include #if __has_include() #include #endif #endif +// The current specification is unclear on how we detect +// static reflection, both __cpp_lib_reflection and +// __cpp_impl_reflection are proposed in the draft specification. +// For now, we disable static reflect by default. It must be +// specified at compiler time. +#ifndef SIMDJSON_STATIC_REFLECTION +#define SIMDJSON_STATIC_REFLECTION 0 // disabled by default. +#endif + #if defined(__apple_build_version__) #if __apple_build_version__ < 14000000 #define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to #endif #endif +#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L +#include +#define SIMDJSON_SUPPORTS_RANGES 1 +#else +#define SIMDJSON_SUPPORTS_RANGES 0 +#endif #if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) #if __cpp_concepts >= 201907L #include +#define SIMDJSON_SUPPORTS_CONCEPTS 1 +#else +#define SIMDJSON_SUPPORTS_CONCEPTS 0 +#endif +#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) +#define SIMDJSON_SUPPORTS_CONCEPTS 0 +#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) + +// copy SIMDJSON_SUPPORTS_CONCEPTS to SIMDJSON_SUPPORTS_DESERIALIZATION. +#if SIMDJSON_SUPPORTS_CONCEPTS #define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #else #define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #endif -#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) -#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 -#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) + + +#if !defined(SIMDJSON_CONSTEVAL) +#if defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L +#define SIMDJSON_CONSTEVAL 1 +#else +#define SIMDJSON_CONSTEVAL 0 +#endif // defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L +#endif // !defined(SIMDJSON_CONSTEVAL) #endif // SIMDJSON_COMPILER_CHECK_H /* end file simdjson/compiler_check.h */ @@ -152,6 +193,22 @@ 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 + #endif #elif defined(__loongarch_lp64) #define SIMDJSON_IS_LOONGARCH64 1 #elif defined(__PPC64__) || defined(_M_PPC64) @@ -298,6 +355,7 @@ using std::size_t; #if defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG)) // If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode, // then do away with asserts and use __assume. +// We still recommend that our users set NDEBUG in release mode. #if SIMDJSON_VISUAL_STUDIO #define SIMDJSON_UNREACHABLE() __assume(0) #define SIMDJSON_ASSUME(COND) __assume(COND) @@ -549,17 +607,6 @@ double from_chars(const char *first, const char* end) noexcept; // We assume by default static linkage #define SIMDJSON_DLLIMPORTEXPORT #endif - -/** - * Workaround for the vcpkg package manager. Only vcpkg should - * ever touch the next line. The SIMDJSON_USING_LIBRARY macro is otherwise unused. - */ -#if SIMDJSON_USING_LIBRARY -#define SIMDJSON_DLLIMPORTEXPORT __declspec(dllimport) -#endif -/** - * End of workaround for the vcpkg package manager. - */ #else #define SIMDJSON_DLLIMPORTEXPORT #endif @@ -1022,9 +1069,9 @@ using std::operator<<; #endif #if nssv_HAVE_NODISCARD -# define nssv_nodiscard [[nodiscard]] +# define nssv_nodiscard simdjson_warn_unused #else -# define nssv_nodiscard /*[[nodiscard]]*/ +# define nssv_nodiscard /*simdjson_warn_unused*/ #endif // Additional includes: @@ -2342,16 +2389,25 @@ namespace std { // It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer // sets _DEBUG in a release build under Visual Studio, or if some compiler fails to // set the __OPTIMIZE__ macro). +// We make it so that if NDEBUG is defined, then SIMDJSON_DEVELOPMENT_CHECKS +// is not defined, irrespective of the compiler. +// We recommend that users set NDEBUG in release builds, so that +// SIMDJSON_DEVELOPMENT_CHECKS is not defined in release builds by default, +// irrespective of the compiler. #ifndef SIMDJSON_DEVELOPMENT_CHECKS #ifdef _MSC_VER // Visual Studio seems to set _DEBUG for debug builds. -#ifdef _DEBUG +// We set SIMDJSON_DEVELOPMENT_CHECKS to 1 if _DEBUG is defined +// and NDEBUG is not defined. +#if defined(_DEBUG) && !defined(NDEBUG) #define SIMDJSON_DEVELOPMENT_CHECKS 1 #endif // _DEBUG #else // _MSC_VER // All other compilers appear to set __OPTIMIZE__ to a positive integer // when the compiler is optimizing. -#ifndef __OPTIMIZE__ +// We only set SIMDJSON_DEVELOPMENT_CHECKS if both __OPTIMIZE__ +// and NDEBUG are not defined. +#if !defined(__OPTIMIZE__) && !defined(NDEBUG) #define SIMDJSON_DEVELOPMENT_CHECKS 1 #endif // __OPTIMIZE__ #endif // _MSC_VER @@ -2407,6 +2463,18 @@ namespace std { #define SIMDJSON_AVX512_ALLOWED 1 #endif + +#ifndef __has_cpp_attribute +#define simdjson_lifetime_bound +#elif __has_cpp_attribute(msvc::lifetimebound) +#define simdjson_lifetime_bound [[msvc::lifetimebound]] +#elif __has_cpp_attribute(clang::lifetimebound) +#define simdjson_lifetime_bound [[clang::lifetimebound]] +#elif __has_cpp_attribute(lifetimebound) +#define simdjson_lifetime_bound [[lifetimebound]] +#else +#define simdjson_lifetime_bound +#endif #endif // SIMDJSON_COMMON_DEFS_H /* end file simdjson/common_defs.h */ /* skipped duplicate #include "simdjson/compiler_check.h" */ @@ -2463,7 +2531,8 @@ enum error_code { SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. OUT_OF_BOUNDS, ///< Attempted to access location outside of document. TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input - NUM_ERROR_CODES + OUT_OF_CAPACITY, ///< The capacity was exceeded, we cannot allocate enough memory. + NUM_ERROR_CODES ///< Placeholder for end of error code list. }; /** @@ -2521,6 +2590,10 @@ namespace internal { /** * The result of a simdjson operation that could fail. * + * IMPORTANT: For the ondemand API, we use implementation_simdjson_result_base as a base class + * to avoid some compilation issue. Thus, if you modify this class, please ensure that the ondemand + * implementation_simdjson_result_base is also modified. + * * 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 @@ -2581,8 +2654,27 @@ struct simdjson_result_base : protected std::pair { */ simdjson_inline error_code error() const noexcept; + /** + * Whether there is a value. + */ + simdjson_inline bool has_value() const noexcept; #if SIMDJSON_EXCEPTIONS + /** + * Dereference operator to access the contained 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); + /** * Get the result value. * @@ -2616,12 +2708,42 @@ struct simdjson_result_base : protected std::pair { /** * Get the result value. This function is safe if and only * the error() method returns a value that evaluates to false. + * We discourage the use of value_unsafe(). + * + * The recommended pattern is: + * + * T value; // where T is the type + * auto error = result.get(value); + * if (error) { + * // handle error + * } + * + * Or you may call 'value()' which will raise an exception + * in case of error: + * + * T value = result.value(); */ simdjson_inline const T& value_unsafe() const& noexcept; /** * Take the result value (move it). This function is safe if and only * the error() method returns a value that evaluates to false. + * We discourage the use of value_unsafe(). + * + * The recommended pattern is: + * + * T value; // where T is the type + * auto error = result.get(value); + * if (error) { + * // handle error, return, exit, abort + * } else { + * // use value here. + * } + * + * Or you may call 'value()' which will raise an exception + * in case of error: + * + * T value = result.value(); */ simdjson_inline T&& value_unsafe() && noexcept; @@ -2636,6 +2758,7 @@ struct simdjson_result_base : protected std::pair { */ template struct simdjson_result : public internal::simdjson_result_base { + /** * @private Create a new empty result with error = UNINITIALIZED. */ @@ -2667,24 +2790,33 @@ struct simdjson_result : public internal::simdjson_result_base { * @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; -// + /** * Copy the value to a provided std::string, only enabled for std::string_view. * * @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(std::string &value) && noexcept -#if SIMDJSON_SUPPORTS_DESERIALIZATION - requires (!std::is_same_v) -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - ; + template + simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept { + static_assert(std::is_same::value, "SFINAE"); + std::string_view v; + error_code error = std::forward>(*this).get(v); + if (!error) { + value.assign(v.data(), v.size()); + } + return error; + } + /** * The error. */ simdjson_inline error_code error() const noexcept; -#if SIMDJSON_EXCEPTIONS + +#if SIMDJSON_EXCEPTIONS + using internal::simdjson_result_base::operator*; + using internal::simdjson_result_base::operator->; /** * Get the result value. * @@ -2755,7 +2887,7 @@ inline const std::string error_message(int error) noexcept; /* begin file simdjson/concepts.h */ #ifndef SIMDJSON_CONCEPTS_H #define SIMDJSON_CONCEPTS_H -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #include #include @@ -2787,7 +2919,9 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=) #undef SIMDJSON_IMPL_CONCEPT } // namespace details - +template +concept is_pair = requires { typename T::first_type; typename T::second_type; } && + std::same_as>; template concept string_view_like = std::is_convertible_v && !std::is_convertible_v; @@ -2870,21 +3004,133 @@ concept optional_type = requires(std::remove_cvref_t obj) { { obj.value() } -> std::same_as::value_type&>; requires requires(typename std::remove_cvref_t::value_type &&val) { obj.emplace(std::move(val)); - obj = std::move(val); { obj.value_or(val) } -> std::convertible_to::value_type>; }; { static_cast(obj) } -> std::same_as; // convertible to bool + { obj.reset() } noexcept -> std::same_as; }; +// Types we serialize as JSON strings (not as containers) +template +concept string_like = + std::is_same_v, std::string> || + std::is_same_v, std::string_view> || + std::is_same_v, const char*> || + std::is_same_v, char*>; + +// Concept that checks if a type is a container but not a string (because +// strings handling must be handled differently) +// Now uses iterator-based approach for broader container support +template +concept container_but_not_string = + std::ranges::input_range && !string_like && !concepts::string_view_keyed_map; + + } // namespace concepts + + +/** + * We use tag_invoke as our customization point mechanism. + */ +template +concept tag_invocable = requires(Tag tag, Args... args) { + tag_invoke(std::forward(tag), std::forward(args)...); +}; + +template +concept nothrow_tag_invocable = + tag_invocable && requires(Tag tag, Args... args) { + { + tag_invoke(std::forward(tag), std::forward(args)...) + } noexcept; + }; + } // namespace simdjson -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS #endif // SIMDJSON_CONCEPTS_H /* end file simdjson/concepts.h */ +/* including simdjson/constevalutil.h: #include "simdjson/constevalutil.h" */ +/* begin file simdjson/constevalutil.h */ +#ifndef SIMDJSON_CONSTEVALUTIL_H +#define SIMDJSON_CONSTEVALUTIL_H + +#include +#include +#include + +namespace simdjson { +namespace constevalutil { +#if SIMDJSON_CONSTEVAL + +constexpr static 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}; +constexpr static std::array 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"}; +// unoptimized, meant for compile-time execution +consteval std::string consteval_to_quoted_escaped(std::string_view input) { + std::string out = "\""; + for (char c : input) { + if (json_quotable_character[uint8_t(c)]) { + if (c == '"') { + out.append("\\\""); + } else if (c == '\\') { + out.append("\\\\"); + } else { + std::string_view v = control_chars[uint8_t(c)]; + out.append(v); + } + } else { + out.push_back(c); + } + } + out.push_back('"'); + return out; +} +#endif // SIMDJSON_CONSTEVAL + + +#if SIMDJSON_SUPPORTS_CONCEPTS +template +struct fixed_string { + constexpr fixed_string(const char (&str)[N]) { + for (std::size_t i = 0; i < N; ++i) { + data[i] = str[i]; + } + } + char data[N]; + constexpr std::string_view view() const { return {data, N - 1}; } +}; +template +fixed_string(const char (&)[N]) -> fixed_string; + +template +struct string_constant { + static constexpr std::string_view value = str.view(); +}; +#endif // SIMDJSON_SUPPORTS_CONCEPTS + +} // namespace constevalutil +} // namespace simdjson +#endif // SIMDJSON_CONSTEVALUTIL_H +/* end file simdjson/constevalutil.h */ /** * @brief The top level simdjson namespace, containing everything the library provides. @@ -4612,8 +4858,38 @@ simdjson_inline error_code simdjson_result_base::error() const noexcept { return this->second; } + +template +simdjson_inline bool simdjson_result_base::has_value() const noexcept { + return this->error() == SUCCESS; +} + #if SIMDJSON_EXCEPTIONS + +template +simdjson_inline T& simdjson_result_base::operator*() & noexcept(false) { + return this->value(); +} + +template +simdjson_inline T&& simdjson_result_base::operator*() && noexcept(false) { + return std::forward>(*this).value(); +} + +template +simdjson_inline T* simdjson_result_base::operator->() noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + + +template +simdjson_inline const T* simdjson_result_base::operator->() const noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + template simdjson_inline T& simdjson_result_base::value() & noexcept(false) { if (error()) { throw simdjson_error(error()); } @@ -4638,6 +4914,7 @@ simdjson_inline simdjson_result_base::operator T&&() && noexcept(false) { #endif // SIMDJSON_EXCEPTIONS + template simdjson_inline const T& simdjson_result_base::value_unsafe() const& noexcept { return this->first; @@ -4672,26 +4949,10 @@ simdjson_inline void simdjson_result::tie(T &value, error_code &error) && noe std::forward>(*this).tie(value, error); } -template -simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &value) && noexcept { - return std::forward>(*this).get(value); -} - template simdjson_warn_unused simdjson_inline error_code -simdjson_result::get(std::string &value) && noexcept -#if SIMDJSON_SUPPORTS_DESERIALIZATION -requires (!std::is_same_v) -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION -{ - // SFINAE : n'active que pour T = std::string_view - static_assert(std::is_same::value, "simdjson_result::get(std::string&) n'est disponible que pour T = std::string_view"); - std::string_view v; - error_code error = std::forward>(*this).get(v); - if (!error) { - value.assign(v.data(), v.size()); - } - return error; +simdjson_result::get(T &value) && noexcept { + return std::forward>(*this).get(value); } template @@ -8209,6 +8470,12 @@ namespace { tmp = vpaddq_u8(tmp, tmp); return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); } + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; } }; @@ -8285,7 +8552,7 @@ namespace { // Bit-specific operations simdjson_inline simd8 any_bits_set(simd8 bits) const { return vtstq_u8(*this, bits); } - simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; } + simdjson_inline bool any_bits_set_anywhere() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 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 vshrq_n_u8(*this, N); } @@ -8298,7 +8565,12 @@ namespace { return lookup_table.apply_lookup_16_to(*this); } - + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // Passing a 0 value for mask would be equivalent to writing out every byte to output. // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes @@ -8592,7 +8864,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -8621,6 +8893,32 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask64() + }; +} + + + } // unnamed namespace } // namespace arm64 } // namespace simdjson @@ -9040,12 +9338,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -9054,6 +9357,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -9095,6 +9408,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -9471,7 +9785,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -9499,7 +9813,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -9588,7 +9902,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -9651,13 +9965,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -9683,7 +9997,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -10467,12 +10781,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -10991,6 +11334,12 @@ namespace { tmp = vpaddq_u8(tmp, tmp); return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); } + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; } }; @@ -11067,7 +11416,7 @@ namespace { // Bit-specific operations simdjson_inline simd8 any_bits_set(simd8 bits) const { return vtstq_u8(*this, bits); } - simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; } + simdjson_inline bool any_bits_set_anywhere() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 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 vshrq_n_u8(*this, N); } @@ -11080,7 +11429,12 @@ namespace { return lookup_table.apply_lookup_16_to(*this); } - + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // Passing a 0 value for mask would be equivalent to writing out every byte to output. // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes @@ -11374,7 +11728,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -11403,6 +11757,32 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask64() + }; +} + + + } // unnamed namespace } // namespace arm64 } // namespace simdjson @@ -12110,7 +12490,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -12235,7 +12615,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -12283,7 +12663,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -12437,7 +12817,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -12447,7 +12827,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -12656,7 +13036,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -13508,6 +13888,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for arm64 */ /* including generic/stage2/stringparsing.h for arm64: #include */ /* begin file generic/stage2/stringparsing.h for arm64 */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -13660,7 +14041,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -13705,7 +14087,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -13747,6 +14130,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace arm64 } // namespace simdjson @@ -14974,7 +15358,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -14998,6 +15382,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 32; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace haswell } // namespace simdjson @@ -15415,12 +15824,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -15429,6 +15843,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -15470,6 +15894,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -15846,7 +16271,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -15874,7 +16299,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -15963,7 +16388,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -16026,13 +16451,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -16058,7 +16483,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -16842,12 +17267,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -17627,7 +18081,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -17651,6 +18105,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 32; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace haswell } // namespace simdjson @@ -18356,7 +18835,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -18481,7 +18960,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -18529,7 +19008,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -18683,7 +19162,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -18693,7 +19172,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -18902,7 +19381,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -19754,6 +20233,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for haswell */ /* including generic/stage2/stringparsing.h for haswell: #include */ /* begin file generic/stage2/stringparsing.h for haswell */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -19906,7 +20386,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -19951,7 +20432,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -19993,6 +20475,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace haswell } // namespace simdjson @@ -20834,7 +21317,6 @@ namespace simd { friend simdjson_really_inline uint64_t operator==(const simd8 lhs, const simd8 rhs) { return _mm512_cmpeq_epi8_mask(lhs, rhs); } - static const int SIZE = sizeof(base::value); template @@ -21153,7 +21635,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 64; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -21177,6 +21659,35 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 64; + 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(uint64_t(escape_bits)); } + + __mmask64 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); + __mmask64 is_quote = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('"')); + __mmask64 is_backslash = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('\\')); + __mmask64 is_control = _mm512_cmplt_epi8_mask(v, _mm512_set1_epi8(32)); + return { + (is_backslash | is_quote | is_control) + }; +} + + + + } // unnamed namespace } // namespace icelake } // namespace simdjson @@ -21654,12 +22165,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -21668,6 +22184,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -21709,6 +22235,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -22085,7 +22612,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -22113,7 +22640,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -22202,7 +22729,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -22265,13 +22792,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -22297,7 +22824,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -23081,12 +23608,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -23483,7 +24039,6 @@ namespace simd { friend simdjson_really_inline uint64_t operator==(const simd8 lhs, const simd8 rhs) { return _mm512_cmpeq_epi8_mask(lhs, rhs); } - static const int SIZE = sizeof(base::value); template @@ -23802,7 +24357,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 64; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -23826,6 +24381,35 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 64; + 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(uint64_t(escape_bits)); } + + __mmask64 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); + __mmask64 is_quote = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('"')); + __mmask64 is_backslash = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('\\')); + __mmask64 is_control = _mm512_cmplt_epi8_mask(v, _mm512_set1_epi8(32)); + return { + (is_backslash | is_quote | is_control) + }; +} + + + + } // unnamed namespace } // namespace icelake } // namespace simdjson @@ -24591,7 +25175,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -24716,7 +25300,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -24764,7 +25348,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -24918,7 +25502,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -24928,7 +25512,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -25137,7 +25721,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -25989,6 +26573,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for icelake */ /* including generic/stage2/stringparsing.h for icelake: #include */ /* begin file generic/stage2/stringparsing.h for icelake */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -26141,7 +26726,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -26186,7 +26772,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -26228,6 +26815,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace icelake } // namespace simdjson @@ -27589,7 +28177,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { @@ -27630,6 +28218,32 @@ backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + // We store it as a 64-bit bitmask even though we only need 16 bits. + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace ppc64 } // namespace simdjson @@ -28049,12 +28663,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -28063,6 +28682,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -28104,6 +28733,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -28480,7 +29110,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -28508,7 +29138,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -28597,7 +29227,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -28660,13 +29290,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -28692,7 +29322,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -29476,12 +30106,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -30353,7 +31012,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { @@ -30394,6 +31053,32 @@ backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + // We store it as a 64-bit bitmask even though we only need 16 bits. + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace ppc64 } // namespace simdjson @@ -31101,7 +31786,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -31226,7 +31911,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -31274,7 +31959,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -31428,7 +32113,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -31438,7 +32123,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -31647,7 +32332,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -32499,6 +33184,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for ppc64 */ /* including generic/stage2/stringparsing.h for ppc64: #include */ /* begin file generic/stage2/stringparsing.h for ppc64 */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -32651,7 +33337,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -32696,7 +33383,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -32738,6 +33426,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace ppc64 } // namespace simdjson @@ -34363,7 +35052,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -34389,6 +35078,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace westmere } // namespace simdjson @@ -34806,12 +35520,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -34820,6 +35539,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -34861,6 +35590,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -35237,7 +35967,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -35265,7 +35995,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -35354,7 +36084,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -35417,13 +36147,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -35449,7 +36179,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -36233,12 +36963,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -37442,7 +38201,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -37468,6 +38227,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace westmere } // namespace simdjson @@ -38173,7 +38957,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -38298,7 +39082,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -38346,7 +39130,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -38500,7 +39284,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -38510,7 +39294,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -38719,7 +39503,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -39571,6 +40355,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for westmere */ /* including generic/stage2/stringparsing.h for westmere: #include */ /* begin file generic/stage2/stringparsing.h for westmere */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -39723,7 +40508,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -39768,7 +40554,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -39810,6 +40597,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace westmere } // namespace simdjson @@ -40338,7 +41126,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t * if (error) { return error; } return stage2(_doc); } - } // namespace westmere } // namespace simdjson @@ -40939,7 +41726,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -40968,6 +41755,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + static_cast((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace lsx } // namespace simdjson @@ -41387,12 +42199,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -41401,6 +42218,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -41442,6 +42269,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -41818,7 +42646,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -41846,7 +42674,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -41935,7 +42763,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -41998,13 +42826,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -42030,7 +42858,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -42814,12 +43642,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -43488,7 +44345,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -43517,6 +44374,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + static_cast((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace lsx } // namespace simdjson @@ -44224,7 +45106,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -44349,7 +45231,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -44397,7 +45279,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -44551,7 +45433,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -44561,7 +45443,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -44770,7 +45652,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -45622,6 +46504,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for lsx */ /* including generic/stage2/stringparsing.h for lsx: #include */ /* begin file generic/stage2/stringparsing.h for lsx */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -45774,7 +46657,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -45819,7 +46703,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -45861,6 +46746,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace lsx } // namespace simdjson @@ -46971,7 +47857,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -46994,6 +47880,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask() + }; +} + } // unnamed namespace } // namespace lasx } // namespace simdjson @@ -47413,12 +48324,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -47427,6 +48343,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -47468,6 +48394,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -47844,7 +48771,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -47872,7 +48799,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -47961,7 +48888,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -48024,13 +48951,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -48056,7 +48983,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -48840,12 +49767,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -49536,7 +50492,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -49559,6 +50515,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask() + }; +} + } // unnamed namespace } // namespace lasx } // namespace simdjson @@ -50266,7 +51247,7 @@ using namespace simd; } } // do not forget to call check_eof! - simdjson_inline error_code errors() { + simdjson_warn_unused simdjson_inline error_code errors() { return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; } @@ -50391,7 +51372,7 @@ public: json_scanner() = default; simdjson_inline json_block next(const simd::simd8x64& in); // Returns either UNCLOSED_STRING or SUCCESS - simdjson_inline error_code finish(); + simdjson_warn_unused simdjson_inline error_code finish(); private: // Whether the last character of the previous iteration is part of a scalar token @@ -50439,7 +51420,7 @@ simdjson_inline json_block json_scanner::next(const simd::simd8x64& in) ); } -simdjson_inline error_code json_scanner::finish() { +simdjson_warn_unused simdjson_inline error_code json_scanner::finish() { return string_scanner.finish(); } @@ -50593,7 +51574,7 @@ private: 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_inline error_code finish(uint8_t *dst_start, size_t &dst_len); + simdjson_warn_unused simdjson_inline error_code finish(uint8_t *dst_start, size_t &dst_len); json_scanner scanner{}; uint8_t *dst; }; @@ -50603,7 +51584,7 @@ simdjson_inline void json_minifier::next(const simd::simd8x64& in, cons dst += in.compress(mask, dst); } -simdjson_inline error_code json_minifier::finish(uint8_t *dst_start, size_t &dst_len) { +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; @@ -50812,7 +51793,7 @@ private: 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_inline error_code finish(dom_parser_implementation &parser, size_t idx, size_t len, stage1_mode partial); + 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{}; @@ -51664,6 +52645,7 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::visit_primitive(V /* end file generic/stage2/json_iterator.h for lasx */ /* including generic/stage2/stringparsing.h for lasx: #include */ /* begin file generic/stage2/stringparsing.h for lasx */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -51816,7 +52798,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -51861,7 +52844,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -51903,6 +52887,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace lasx } // namespace simdjson @@ -52516,7 +53501,7 @@ namespace { struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 1; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { return c == '"'; } simdjson_inline bool has_backslash() { return c == '\\'; } @@ -52532,6 +53517,24 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin return { src[0] }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 1; + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits; } + simdjson_inline int escape_index() { return 0; } + + bool escape_bits; +}; // struct escaping + + + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + dst[0] = src[0]; + return { (src[0] == '\\') || (src[0] == '"') || (src[0] < 32) }; +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -53038,12 +54041,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -53052,6 +54060,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -53093,6 +54111,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -53469,7 +54488,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -53497,7 +54516,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -53586,7 +54605,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -53649,13 +54668,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -53681,7 +54700,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -54465,12 +55484,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -54670,7 +55718,7 @@ namespace { struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 1; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { return c == '"'; } simdjson_inline bool has_backslash() { return c == '\\'; } @@ -54686,6 +55734,24 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin return { src[0] }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 1; + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits; } + simdjson_inline int escape_index() { return 0; } + + bool escape_bits; +}; // struct escaping + + + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + dst[0] = src[0]; + return { (src[0] == '\\') || (src[0] == '"') || (src[0] < 32) }; +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -54892,6 +55958,7 @@ simdjson_inline uint32_t find_next_document_index(dom_parser_implementation &par /* end file generic/stage1/find_next_document_index.h for fallback */ /* including generic/stage2/stringparsing.h for fallback: #include */ /* begin file generic/stage2/stringparsing.h for fallback */ +#include #ifndef SIMDJSON_SRC_GENERIC_STAGE2_STRINGPARSING_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -55044,7 +56111,8 @@ simdjson_inline bool handle_unicode_codepoint_wobbly(const uint8_t **src_ptr, 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -55089,7 +56157,8 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t // 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 bs_quote = backslash_and_quote::copy_and_find(src, dst); + 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 @@ -55131,6 +56200,7 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t } } // namespace stringparsing + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -56097,10 +57167,78 @@ simdjson_inline void validate_utf8_character() { idx += 4; } +static const uint8_t CHAR_TYPE_SPACE = 1 << 0; +static const uint8_t CHAR_TYPE_OPERATOR = 1 << 1; +static const uint8_t CHAR_TYPE_ESC_ASCII = 1 << 2; +static const uint8_t CHAR_TYPE_NON_ASCII = 1 << 3; + +const uint8_t char_table[256] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x04, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +simdjson_inline bool char_is_type(uint8_t c, uint8_t type) { + return (char_table[c] & type); +} + +simdjson_inline bool char_is_space(uint8_t c) { + return char_is_type(c, CHAR_TYPE_SPACE); +} + +simdjson_inline bool char_is_operator(uint8_t c) { + return char_is_type(c, CHAR_TYPE_OPERATOR); +} + +simdjson_inline bool char_is_space_or_operator(uint8_t c) { + return char_is_type(c, CHAR_TYPE_SPACE | CHAR_TYPE_OPERATOR); +} + +simdjson_inline bool char_is_ascii_stop(uint8_t c) { + return char_is_type(c, CHAR_TYPE_ESC_ASCII | CHAR_TYPE_NON_ASCII); +} + // Returns true if the string is unclosed. simdjson_inline bool validate_string() { idx++; // skip first quote - while (idx < len && buf[idx] != '"') { + while (idx < len) { + do { + if (char_is_ascii_stop(buf[idx])) { break; } + idx++; + } while (idx < len); + if (idx >= len) { return true; } + if (buf[idx] == '"') { + return false; + } if (buf[idx] == '\\') { idx += 2; } else if (simdjson_unlikely(buf[idx] & 0x80)) { @@ -56114,43 +57252,31 @@ simdjson_inline bool validate_string() { return false; } -simdjson_inline bool is_whitespace_or_operator(uint8_t c) { - switch (c) { - case '{': case '}': case '[': case ']': case ',': case ':': - case ' ': case '\r': case '\n': case '\t': - return true; - default: - return false; - } -} - // // Parse the entire input in STEP_SIZE-byte chunks. // -simdjson_inline error_code scan() { +simdjson_warn_unused simdjson_inline error_code scan() { bool unclosed_string = false; for (;idx= len) { break; } + // String + if (buf[idx] == '"') { + add_structural(); + unclosed_string |= validate_string(); + // Operator + } else if (char_is_operator(buf[idx])) { + add_structural(); + // Primitive or invalid character (invalid characters will be checked in stage 2) + } else { + // Anything else, add the structural and go until we find the next one + add_structural(); + while (idx+1) #include #endif #endif +// The current specification is unclear on how we detect +// static reflection, both __cpp_lib_reflection and +// __cpp_impl_reflection are proposed in the draft specification. +// For now, we disable static reflect by default. It must be +// specified at compiler time. +#ifndef SIMDJSON_STATIC_REFLECTION +#define SIMDJSON_STATIC_REFLECTION 0 // disabled by default. +#endif + #if defined(__apple_build_version__) #if __apple_build_version__ < 14000000 #define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to #endif #endif +#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L +#include +#define SIMDJSON_SUPPORTS_RANGES 1 +#else +#define SIMDJSON_SUPPORTS_RANGES 0 +#endif #if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) #if __cpp_concepts >= 201907L #include +#define SIMDJSON_SUPPORTS_CONCEPTS 1 +#else +#define SIMDJSON_SUPPORTS_CONCEPTS 0 +#endif +#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) +#define SIMDJSON_SUPPORTS_CONCEPTS 0 +#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) + +// copy SIMDJSON_SUPPORTS_CONCEPTS to SIMDJSON_SUPPORTS_DESERIALIZATION. +#if SIMDJSON_SUPPORTS_CONCEPTS #define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #else #define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #endif -#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) -#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 -#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED) + + +#if !defined(SIMDJSON_CONSTEVAL) +#if defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L +#define SIMDJSON_CONSTEVAL 1 +#else +#define SIMDJSON_CONSTEVAL 0 +#endif // defined(__cpp_consteval) && __cpp_consteval >= 201811L && defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L +#endif // !defined(SIMDJSON_CONSTEVAL) #endif // SIMDJSON_COMPILER_CHECK_H /* end file simdjson/compiler_check.h */ @@ -172,6 +213,22 @@ 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 + #endif #elif defined(__loongarch_lp64) #define SIMDJSON_IS_LOONGARCH64 1 #elif defined(__PPC64__) || defined(_M_PPC64) @@ -318,6 +375,7 @@ using std::size_t; #if defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG)) // If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode, // then do away with asserts and use __assume. +// We still recommend that our users set NDEBUG in release mode. #if SIMDJSON_VISUAL_STUDIO #define SIMDJSON_UNREACHABLE() __assume(0) #define SIMDJSON_ASSUME(COND) __assume(COND) @@ -569,17 +627,6 @@ double from_chars(const char *first, const char* end) noexcept; // We assume by default static linkage #define SIMDJSON_DLLIMPORTEXPORT #endif - -/** - * Workaround for the vcpkg package manager. Only vcpkg should - * ever touch the next line. The SIMDJSON_USING_LIBRARY macro is otherwise unused. - */ -#if SIMDJSON_USING_LIBRARY -#define SIMDJSON_DLLIMPORTEXPORT __declspec(dllimport) -#endif -/** - * End of workaround for the vcpkg package manager. - */ #else #define SIMDJSON_DLLIMPORTEXPORT #endif @@ -1042,9 +1089,9 @@ using std::operator<<; #endif #if nssv_HAVE_NODISCARD -# define nssv_nodiscard [[nodiscard]] +# define nssv_nodiscard simdjson_warn_unused #else -# define nssv_nodiscard /*[[nodiscard]]*/ +# define nssv_nodiscard /*simdjson_warn_unused*/ #endif // Additional includes: @@ -2362,16 +2409,25 @@ namespace std { // It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer // sets _DEBUG in a release build under Visual Studio, or if some compiler fails to // set the __OPTIMIZE__ macro). +// We make it so that if NDEBUG is defined, then SIMDJSON_DEVELOPMENT_CHECKS +// is not defined, irrespective of the compiler. +// We recommend that users set NDEBUG in release builds, so that +// SIMDJSON_DEVELOPMENT_CHECKS is not defined in release builds by default, +// irrespective of the compiler. #ifndef SIMDJSON_DEVELOPMENT_CHECKS #ifdef _MSC_VER // Visual Studio seems to set _DEBUG for debug builds. -#ifdef _DEBUG +// We set SIMDJSON_DEVELOPMENT_CHECKS to 1 if _DEBUG is defined +// and NDEBUG is not defined. +#if defined(_DEBUG) && !defined(NDEBUG) #define SIMDJSON_DEVELOPMENT_CHECKS 1 #endif // _DEBUG #else // _MSC_VER // All other compilers appear to set __OPTIMIZE__ to a positive integer // when the compiler is optimizing. -#ifndef __OPTIMIZE__ +// We only set SIMDJSON_DEVELOPMENT_CHECKS if both __OPTIMIZE__ +// and NDEBUG are not defined. +#if !defined(__OPTIMIZE__) && !defined(NDEBUG) #define SIMDJSON_DEVELOPMENT_CHECKS 1 #endif // __OPTIMIZE__ #endif // _MSC_VER @@ -2427,6 +2483,18 @@ namespace std { #define SIMDJSON_AVX512_ALLOWED 1 #endif + +#ifndef __has_cpp_attribute +#define simdjson_lifetime_bound +#elif __has_cpp_attribute(msvc::lifetimebound) +#define simdjson_lifetime_bound [[msvc::lifetimebound]] +#elif __has_cpp_attribute(clang::lifetimebound) +#define simdjson_lifetime_bound [[clang::lifetimebound]] +#elif __has_cpp_attribute(lifetimebound) +#define simdjson_lifetime_bound [[lifetimebound]] +#else +#define simdjson_lifetime_bound +#endif #endif // SIMDJSON_COMMON_DEFS_H /* end file simdjson/common_defs.h */ @@ -2440,22 +2508,22 @@ namespace std { #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "3.13.0" +#define SIMDJSON_VERSION "4.0.7" namespace simdjson { enum { /** * The major version (MAJOR.minor.revision) of simdjson being used. */ - SIMDJSON_VERSION_MAJOR = 3, + SIMDJSON_VERSION_MAJOR = 4, /** * The minor version (major.MINOR.revision) of simdjson being used. */ - SIMDJSON_VERSION_MINOR = 13, + SIMDJSON_VERSION_MINOR = 0, /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 0 + SIMDJSON_VERSION_REVISION = 7 }; } // namespace simdjson @@ -2526,7 +2594,8 @@ enum error_code { SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. OUT_OF_BOUNDS, ///< Attempted to access location outside of document. TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input - NUM_ERROR_CODES + OUT_OF_CAPACITY, ///< The capacity was exceeded, we cannot allocate enough memory. + NUM_ERROR_CODES ///< Placeholder for end of error code list. }; /** @@ -2584,6 +2653,10 @@ namespace internal { /** * The result of a simdjson operation that could fail. * + * IMPORTANT: For the ondemand API, we use implementation_simdjson_result_base as a base class + * to avoid some compilation issue. Thus, if you modify this class, please ensure that the ondemand + * implementation_simdjson_result_base is also modified. + * * 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 @@ -2644,8 +2717,27 @@ struct simdjson_result_base : protected std::pair { */ simdjson_inline error_code error() const noexcept; + /** + * Whether there is a value. + */ + simdjson_inline bool has_value() const noexcept; #if SIMDJSON_EXCEPTIONS + /** + * Dereference operator to access the contained 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); + /** * Get the result value. * @@ -2679,12 +2771,42 @@ struct simdjson_result_base : protected std::pair { /** * Get the result value. This function is safe if and only * the error() method returns a value that evaluates to false. + * We discourage the use of value_unsafe(). + * + * The recommended pattern is: + * + * T value; // where T is the type + * auto error = result.get(value); + * if (error) { + * // handle error + * } + * + * Or you may call 'value()' which will raise an exception + * in case of error: + * + * T value = result.value(); */ simdjson_inline const T& value_unsafe() const& noexcept; /** * Take the result value (move it). This function is safe if and only * the error() method returns a value that evaluates to false. + * We discourage the use of value_unsafe(). + * + * The recommended pattern is: + * + * T value; // where T is the type + * auto error = result.get(value); + * if (error) { + * // handle error, return, exit, abort + * } else { + * // use value here. + * } + * + * Or you may call 'value()' which will raise an exception + * in case of error: + * + * T value = result.value(); */ simdjson_inline T&& value_unsafe() && noexcept; @@ -2699,6 +2821,7 @@ struct simdjson_result_base : protected std::pair { */ template struct simdjson_result : public internal::simdjson_result_base { + /** * @private Create a new empty result with error = UNINITIALIZED. */ @@ -2730,24 +2853,33 @@ struct simdjson_result : public internal::simdjson_result_base { * @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; -// + /** * Copy the value to a provided std::string, only enabled for std::string_view. * * @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(std::string &value) && noexcept -#if SIMDJSON_SUPPORTS_DESERIALIZATION - requires (!std::is_same_v) -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION - ; + template + simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept { + static_assert(std::is_same::value, "SFINAE"); + std::string_view v; + error_code error = std::forward>(*this).get(v); + if (!error) { + value.assign(v.data(), v.size()); + } + return error; + } + /** * The error. */ simdjson_inline error_code error() const noexcept; -#if SIMDJSON_EXCEPTIONS + +#if SIMDJSON_EXCEPTIONS + using internal::simdjson_result_base::operator*; + using internal::simdjson_result_base::operator->; /** * Get the result value. * @@ -2818,7 +2950,7 @@ inline const std::string error_message(int error) noexcept; /* begin file simdjson/concepts.h */ #ifndef SIMDJSON_CONCEPTS_H #define SIMDJSON_CONCEPTS_H -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #include #include @@ -2850,7 +2982,9 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=) #undef SIMDJSON_IMPL_CONCEPT } // namespace details - +template +concept is_pair = requires { typename T::first_type; typename T::second_type; } && + std::same_as>; template concept string_view_like = std::is_convertible_v && !std::is_convertible_v; @@ -2933,21 +3067,133 @@ concept optional_type = requires(std::remove_cvref_t obj) { { obj.value() } -> std::same_as::value_type&>; requires requires(typename std::remove_cvref_t::value_type &&val) { obj.emplace(std::move(val)); - obj = std::move(val); { obj.value_or(val) } -> std::convertible_to::value_type>; }; { static_cast(obj) } -> std::same_as; // convertible to bool + { obj.reset() } noexcept -> std::same_as; }; +// Types we serialize as JSON strings (not as containers) +template +concept string_like = + std::is_same_v, std::string> || + std::is_same_v, std::string_view> || + std::is_same_v, const char*> || + std::is_same_v, char*>; + +// Concept that checks if a type is a container but not a string (because +// strings handling must be handled differently) +// Now uses iterator-based approach for broader container support +template +concept container_but_not_string = + std::ranges::input_range && !string_like && !concepts::string_view_keyed_map; + + } // namespace concepts + + +/** + * We use tag_invoke as our customization point mechanism. + */ +template +concept tag_invocable = requires(Tag tag, Args... args) { + tag_invoke(std::forward(tag), std::forward(args)...); +}; + +template +concept nothrow_tag_invocable = + tag_invocable && requires(Tag tag, Args... args) { + { + tag_invoke(std::forward(tag), std::forward(args)...) + } noexcept; + }; + } // namespace simdjson -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS #endif // SIMDJSON_CONCEPTS_H /* end file simdjson/concepts.h */ +/* including simdjson/constevalutil.h: #include "simdjson/constevalutil.h" */ +/* begin file simdjson/constevalutil.h */ +#ifndef SIMDJSON_CONSTEVALUTIL_H +#define SIMDJSON_CONSTEVALUTIL_H + +#include +#include +#include + +namespace simdjson { +namespace constevalutil { +#if SIMDJSON_CONSTEVAL + +constexpr static 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}; +constexpr static std::array 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"}; +// unoptimized, meant for compile-time execution +consteval std::string consteval_to_quoted_escaped(std::string_view input) { + std::string out = "\""; + for (char c : input) { + if (json_quotable_character[uint8_t(c)]) { + if (c == '"') { + out.append("\\\""); + } else if (c == '\\') { + out.append("\\\\"); + } else { + std::string_view v = control_chars[uint8_t(c)]; + out.append(v); + } + } else { + out.push_back(c); + } + } + out.push_back('"'); + return out; +} +#endif // SIMDJSON_CONSTEVAL + + +#if SIMDJSON_SUPPORTS_CONCEPTS +template +struct fixed_string { + constexpr fixed_string(const char (&str)[N]) { + for (std::size_t i = 0; i < N; ++i) { + data[i] = str[i]; + } + } + char data[N]; + constexpr std::string_view view() const { return {data, N - 1}; } +}; +template +fixed_string(const char (&)[N]) -> fixed_string; + +template +struct string_constant { + static constexpr std::string_view value = str.view(); +}; +#endif // SIMDJSON_SUPPORTS_CONCEPTS + +} // namespace constevalutil +} // namespace simdjson +#endif // SIMDJSON_CONSTEVALUTIL_H +/* end file simdjson/constevalutil.h */ /** * @brief The top level simdjson namespace, containing everything the library provides. @@ -3071,8 +3317,38 @@ simdjson_inline error_code simdjson_result_base::error() const noexcept { return this->second; } + +template +simdjson_inline bool simdjson_result_base::has_value() const noexcept { + return this->error() == SUCCESS; +} + #if SIMDJSON_EXCEPTIONS + +template +simdjson_inline T& simdjson_result_base::operator*() & noexcept(false) { + return this->value(); +} + +template +simdjson_inline T&& simdjson_result_base::operator*() && noexcept(false) { + return std::forward>(*this).value(); +} + +template +simdjson_inline T* simdjson_result_base::operator->() noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + + +template +simdjson_inline const T* simdjson_result_base::operator->() const noexcept(false) { + if (this->error()) { throw simdjson_error(this->error()); } + return &this->first; +} + template simdjson_inline T& simdjson_result_base::value() & noexcept(false) { if (error()) { throw simdjson_error(error()); } @@ -3097,6 +3373,7 @@ simdjson_inline simdjson_result_base::operator T&&() && noexcept(false) { #endif // SIMDJSON_EXCEPTIONS + template simdjson_inline const T& simdjson_result_base::value_unsafe() const& noexcept { return this->first; @@ -3131,26 +3408,10 @@ simdjson_inline void simdjson_result::tie(T &value, error_code &error) && noe std::forward>(*this).tie(value, error); } -template -simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &value) && noexcept { - return std::forward>(*this).get(value); -} - template simdjson_warn_unused simdjson_inline error_code -simdjson_result::get(std::string &value) && noexcept -#if SIMDJSON_SUPPORTS_DESERIALIZATION -requires (!std::is_same_v) -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION -{ - // SFINAE : n'active que pour T = std::string_view - static_assert(std::is_same::value, "simdjson_result::get(std::string&) n'est disponible que pour T = std::string_view"); - std::string_view v; - error_code error = std::forward>(*this).get(v); - if (!error) { - value.assign(v.data(), v.size()); - } - return error; +simdjson_result::get(T &value) && noexcept { + return std::forward>(*this).get(value); } template @@ -4016,6 +4277,9 @@ public: /** The number of allocated bytes. */ inline size_t capacity() const noexcept; + /** check that the view has sufficient padding */ + inline bool has_sufficient_padding() const noexcept; + /** * Remove the UTF-8 Byte Order Mark (BOM) if it exists. * @@ -4042,14 +4306,24 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result= SIMDJSON_PADDING) { + return true; + } + size_t missing_padding = SIMDJSON_PADDING - padding(); + if(length() < missing_padding) { return false; } + + for (size_t i = length() - missing_padding; i < length(); i++) { + char c = data()[i]; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { + return false; + } + } + return true; +} + inline size_t padded_string_view::capacity() const noexcept { return _capacity; } inline size_t padded_string_view::padding() const noexcept { return capacity() - length(); } @@ -4114,10 +4404,33 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result 0; i--) { + char c = s[i - 1]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { + existing_padding++; + } else { + break; + } + } + size_t needed_padding = 0; + if (existing_padding < SIMDJSON_PADDING) { + needed_padding = SIMDJSON_PADDING - existing_padding; + s.append(needed_padding, ' '); + } + + return padded_string_view(s.data(), s.size() - needed_padding, s.size()); } + +inline padded_string_view pad_with_reserve(std::string& s) noexcept { + if (s.capacity() - s.size() < SIMDJSON_PADDING) { + s.reserve(s.size() + SIMDJSON_PADDING ); + } + return padded_string_view(s.data(), s.size(), s.capacity()); +} + + + } // namespace simdjson @@ -4242,9 +4555,9 @@ inline const char *padded_string::data() const noexcept { return data_ptr; } inline char *padded_string::data() noexcept { return data_ptr; } -inline padded_string::operator std::string_view() const { return std::string_view(data(), length()); } +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 { +inline padded_string::operator padded_string_view() const noexcept simdjson_lifetime_bound { return padded_string_view(data(), length(), length() + SIMDJSON_PADDING); } @@ -4384,6 +4697,8 @@ class tape_ref; #ifndef SIMDJSON_DOM_ARRAY_H #define SIMDJSON_DOM_ARRAY_H +#include + /* skipped duplicate #include "simdjson/dom/base.h" */ /* including simdjson/internal/tape_ref.h: #include "simdjson/internal/tape_ref.h" */ /* begin file simdjson/internal/tape_ref.h */ @@ -4491,7 +4806,7 @@ public: iterator& operator=(const iterator&) noexcept = default; private: simdjson_inline iterator(const internal::tape_ref &tape) noexcept; - internal::tape_ref tape; + internal::tape_ref tape{}; friend class array; }; @@ -4542,6 +4857,17 @@ public: */ inline simdjson_result at_pointer(std::string_view json_pointer) const noexcept; + /** + * Recursive function which processes the json path of each child element + */ + inline void process_json_path_of_child_elements(std::vector::iterator& current, std::vector::iterator& end, const std::string_view& path_suffix, std::vector& accumulator) const noexcept; + + + /** + * Adds support for JSONPath expression with wildcards '*' + */ + inline simdjson_result> at_path_with_wildcard(std::string_view json_path) const noexcept; + /** * Get the value associated with the given JSONPath expression. We only support * JSONPath queries that trivially convertible to JSON Pointer queries: key @@ -4575,6 +4901,15 @@ public: */ inline simdjson_result at(size_t index) const noexcept; + /** + * Gets the values of items in an array element + * This function has linear-time complexity: the values are checked one by one. + * + * @return The child elements of an array + */ + + inline std::vector& get_values(std::vector& out) const noexcept; + /** * Implicitly convert object to element */ @@ -4582,7 +4917,7 @@ public: private: simdjson_inline array(const internal::tape_ref &tape) noexcept; - internal::tape_ref tape; + internal::tape_ref tape{}; friend class element; friend struct simdjson_result; template @@ -4601,8 +4936,11 @@ public: simdjson_inline simdjson_result(error_code error) noexcept; ///< @private inline simdjson_result at_pointer(std::string_view json_pointer) const noexcept; + inline void process_json_path_of_child_elements(std::vector::iterator& current, std::vector::iterator& end, const std::string_view& path_suffix, std::vector& accumulator) const noexcept; + inline simdjson_result> at_path_with_wildcard(std::string_view json_path) const noexcept; inline simdjson_result at_path(std::string_view json_path) const noexcept; inline simdjson_result at(size_t index) const noexcept; + inline std::vector& get_values(std::vector& out) const noexcept; #if SIMDJSON_EXCEPTIONS inline dom::array::iterator begin() const noexcept(false); @@ -4615,9 +4953,7 @@ public: } // namespace simdjson -#if defined(__cpp_lib_ranges) -#include - +#if SIMDJSON_SUPPORTS_RANGES namespace std { namespace ranges { template<> @@ -4628,7 +4964,7 @@ inline constexpr bool enable_view load(const std::string &path) & noexcept; - inline simdjson_result load(const std::string &path) && = delete ; + inline simdjson_result load(std::string_view path) & noexcept; + inline simdjson_result load(std::string_view path) && = delete ; /** * Load a JSON document from a file into a provide document instance and return a temporary reference to it. @@ -4883,8 +5219,8 @@ public: * - 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 load_into_document(document& doc, const std::string &path) & noexcept; - inline simdjson_result load_into_document(document& doc, const std::string &path) && =delete; + inline simdjson_result load_into_document(document& doc, std::string_view path) & noexcept; + inline simdjson_result load_into_document(document& doc, std::string_view path) && =delete; /** * Parse a JSON document and return a temporary reference to it. @@ -5121,7 +5457,7 @@ public: * - 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 load_many(const std::string &path, size_t batch_size = dom::DEFAULT_BATCH_SIZE) noexcept; + inline simdjson_result load_many(std::string_view path, size_t batch_size = dom::DEFAULT_BATCH_SIZE) noexcept; /** * Parse a buffer containing many JSON documents. @@ -5392,7 +5728,7 @@ private: inline error_code ensure_capacity(document& doc, size_t desired_capacity) noexcept; /** Read the file into loaded_bytes */ - inline simdjson_result read_file(const std::string &path) noexcept; + inline simdjson_result read_file(std::string_view path) noexcept; friend class parser::Iterator; friend class document_stream; @@ -5729,6 +6065,8 @@ public: #ifndef SIMDJSON_DOM_ELEMENT_H #define SIMDJSON_DOM_ELEMENT_H +#include + /* skipped duplicate #include "simdjson/dom/base.h" */ /* skipped duplicate #include "simdjson/dom/array.h" */ @@ -6127,6 +6465,8 @@ public: */ inline simdjson_result at_pointer(const std::string_view json_pointer) const noexcept; + inline simdjson_result> at_path_with_wildcard(const std::string_view json_path) const noexcept; + /** * Get the value associated with the given JSONPath expression. We only support * JSONPath queries that trivially convertible to JSON Pointer queries: key @@ -6220,7 +6560,7 @@ public: private: simdjson_inline element(const internal::tape_ref &tape) noexcept; - internal::tape_ref tape; + internal::tape_ref tape{}; friend class document; friend class object; friend class array; @@ -6272,6 +6612,7 @@ public: simdjson_inline simdjson_result operator[](const char *key) const noexcept; simdjson_result operator[](int) const noexcept = delete; simdjson_inline simdjson_result at_pointer(const std::string_view json_pointer) const noexcept; + simdjson_inline simdjson_result> at_path_with_wildcard(const std::string_view json_path) const noexcept; simdjson_inline simdjson_result at_path(const std::string_view json_path) const noexcept; [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] simdjson_inline simdjson_result at(const std::string_view json_pointer) const noexcept; @@ -6303,6 +6644,8 @@ public: #ifndef SIMDJSON_DOM_OBJECT_H #define SIMDJSON_DOM_OBJECT_H +#include + /* skipped duplicate #include "simdjson/dom/base.h" */ /* skipped duplicate #include "simdjson/dom/element.h" */ /* skipped duplicate #include "simdjson/internal/tape_ref.h" */ @@ -6391,7 +6734,7 @@ public: private: simdjson_inline iterator(const internal::tape_ref &tape) noexcept; - internal::tape_ref tape; + internal::tape_ref tape{}; friend class object; }; @@ -6474,6 +6817,16 @@ public: */ inline simdjson_result at_pointer(std::string_view json_pointer) const noexcept; + /** + * Recursive function which processes the json path of each child element + */ + inline void process_json_path_of_child_elements(std::vector::iterator& current, std::vector::iterator& end, const std::string_view& path_suffix, std::vector& accumulator) const noexcept; + + /** + * Adds support for JSONPath expression with wildcards '*' + */ + inline simdjson_result> at_path_with_wildcard(std::string_view json_path) const noexcept; + /** * Get the value associated with the given JSONPath expression. We only support * JSONPath queries that trivially convertible to JSON Pointer queries: key @@ -6505,6 +6858,14 @@ public: */ inline simdjson_result at_key(std::string_view key) const noexcept; + /** + * Gets the values associated with keys of an object + * This function has linear-time complexity: the keys are checked one by one. + * + * @return the values associated with each key of an object + */ + inline std::vector& get_values(std::vector& out) const noexcept; + /** * Get the value associated with the given key in a case-insensitive manner. * It is only guaranteed to work over ASCII inputs. @@ -6526,7 +6887,7 @@ public: private: simdjson_inline object(const internal::tape_ref &tape) noexcept; - internal::tape_ref tape; + internal::tape_ref tape{}; friend class element; friend struct simdjson_result; @@ -6563,8 +6924,11 @@ public: inline simdjson_result operator[](const char *key) const noexcept; simdjson_result operator[](int) const noexcept = delete; inline simdjson_result at_pointer(std::string_view json_pointer) const noexcept; + inline void process_json_path_of_child_elements(std::vector::iterator& current, std::vector::iterator& end, const std::string_view& path_suffix, std::vector& accumulator) const noexcept; + inline simdjson_result> at_path_with_wildcard(std::string_view json_path_new) const noexcept; inline simdjson_result at_path(std::string_view json_path) const noexcept; inline simdjson_result at_key(std::string_view key) const noexcept; + inline std::vector& get_values(std::vector& out) const noexcept; inline simdjson_result at_key_case_insensitive(std::string_view key) const noexcept; #if SIMDJSON_EXCEPTIONS @@ -6576,9 +6940,7 @@ public: } // namespace simdjson -#if defined(__cpp_lib_ranges) -#include - +#if SIMDJSON_SUPPORTS_RANGES namespace std { namespace ranges { template<> @@ -6589,7 +6951,7 @@ inline constexpr bool enable_view - namespace simdjson { /** @@ -6614,8 +6974,7 @@ namespace simdjson { */ namespace internal { -template -class base_formatter { +template class base_formatter { public: /** Add a comma **/ simdjson_inline void comma(); @@ -6654,24 +7013,76 @@ public: /** Prints one character **/ simdjson_inline void one_char(char c); + /** Prints characters in [begin, end) verbatim. **/ + simdjson_inline void chars(const char *begin, const char *end); + simdjson_inline void call_print_newline() { - static_cast(this)->print_newline(); + static_cast(this)->print_newline(); } simdjson_inline void call_print_indents(size_t depth) { - static_cast(this)->print_indents(depth); + static_cast(this)->print_indents(depth); } simdjson_inline void call_print_space() { - static_cast(this)->print_space(); + static_cast(this)->print_space(); } protected: // implementation details (subject to change) /** Backing buffer **/ - std::vector buffer{}; // not ideal! -}; + struct vector_with_small_buffer { + vector_with_small_buffer() = default; + ~vector_with_small_buffer() { free_buffer(); } + vector_with_small_buffer(const vector_with_small_buffer &) = delete; + vector_with_small_buffer & + operator=(const vector_with_small_buffer &) = delete; + + void clear() { + size = 0; + capacity = StaticCapacity; + free_buffer(); + buffer = array; + } + + simdjson_inline void push_back(char c) { + if (capacity < size + 1) + grow(capacity * 2); + buffer[size++] = c; + } + + simdjson_inline void append(const char *begin, const char *end) { + const size_t new_size = size + (end - begin); + if (capacity < new_size) + // std::max(new_size, capacity * 2); is broken in tests on Windows + grow(new_size < capacity * 2 ? capacity * 2 : new_size); + std::copy(begin, end, buffer + size); + size = new_size; + } + + std::string_view str() const { return std::string_view(buffer, size); } + + private: + void free_buffer() { + if (buffer != array) + delete[] buffer; + } + void grow(size_t new_capacity) { + auto new_buffer = new char[new_capacity]; + std::copy(buffer, buffer + size, new_buffer); + free_buffer(); + buffer = new_buffer; + capacity = new_capacity; + } + + static const size_t StaticCapacity = 64; + char array[StaticCapacity]; + char *buffer = array; + size_t size = 0; + size_t capacity = StaticCapacity; + } buffer{}; +}; /** * @private This is the class that we expect to use with the string_builder @@ -6705,9 +7116,11 @@ protected: * by a "formatter" which handles the details. Thus * the string_builder template could support both minification * and prettification, and various other tradeoffs. + * + * This is not to be confused with the simdjson::builder::string_builder + * which is a different class. */ -template -class string_builder { +template class string_builder { public: /** Construct an initially empty builder, would print the empty string **/ string_builder() = default; @@ -6729,11 +7142,12 @@ public: simdjson_inline std::string_view str() const; /** Append a key_value_pair to the builder (to be printed) **/ simdjson_inline void append(simdjson::dom::key_value_pair value); + private: formatter format{}; }; -} // internal +} // namespace internal namespace dom { @@ -6742,33 +7156,43 @@ namespace dom { * * @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. + * @throw if there is an error with the underlying output stream. simdjson + * itself will not throw. */ -inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value); +inline std::ostream &operator<<(std::ostream &out, + simdjson::dom::element value); #if SIMDJSON_EXCEPTIONS -inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); +inline std::ostream & +operator<<(std::ostream &out, + simdjson::simdjson_result x); #endif /** * Print JSON to an output stream. * * @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. + * @throw if there is an error with the underlying output stream. simdjson + * itself will not throw. */ -inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value); +inline std::ostream &operator<<(std::ostream &out, simdjson::dom::array value); #if SIMDJSON_EXCEPTIONS -inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); +inline std::ostream & +operator<<(std::ostream &out, + simdjson::simdjson_result x); #endif /** * Print JSON to an output stream. * * @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. + * @throw if there is an error with the underlying output stream. simdjson + * itself will not throw. */ -inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value); +inline std::ostream &operator<<(std::ostream &out, simdjson::dom::object value); #if SIMDJSON_EXCEPTIONS -inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result x); +inline std::ostream & +operator<<(std::ostream &out, + simdjson::simdjson_result x); #endif } // namespace dom @@ -6780,47 +7204,47 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result -std::string to_string(T x) { - // in C++, to_string is standard: http://www.cplusplus.com/reference/string/to_string/ - // Currently minify and to_string are identical but in the future, they may - // differ. - simdjson::internal::string_builder<> sb; - sb.append(x); - std::string_view answer = sb.str(); - return std::string(answer.data(), answer.size()); +template std::string to_string(T x) { + // in C++, to_string is standard: + // http://www.cplusplus.com/reference/string/to_string/ Currently minify and + // to_string are identical but in the future, they may differ. + simdjson::internal::string_builder<> sb; + sb.append(x); + std::string_view answer = sb.str(); + return std::string(answer.data(), answer.size()); } #if SIMDJSON_EXCEPTIONS -template -std::string to_string(simdjson_result x) { - if (x.error()) { throw simdjson_error(x.error()); } - return to_string(x.value()); +template std::string to_string(simdjson_result x) { + if (x.error()) { + throw simdjson_error(x.error()); + } + return to_string(x.value()); } #endif /** - * Minifies a JSON element or document, printing the smallest possible valid JSON. + * Minifies a JSON element or document, printing the smallest possible valid + * JSON. * * dom::parser parser; * element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded); * cout << minify(doc) << endl; // prints [1,2,3] * */ -template -std::string minify(T x) { - return to_string(x); -} +template std::string minify(T x) { return to_string(x); } #if SIMDJSON_EXCEPTIONS -template -std::string minify(simdjson_result x) { - if (x.error()) { throw simdjson_error(x.error()); } - return to_string(x.value()); +template std::string minify(simdjson_result x) { + if (x.error()) { + throw simdjson_error(x.error()); + } + return to_string(x.value()); } #endif /** - * Prettifies a JSON element or document, printing the valid JSON with indentation. + * Prettifies a JSON element or document, printing the valid JSON with + * indentation. * * dom::parser parser; * element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded); @@ -6836,25 +7260,24 @@ std::string minify(simdjson_result x) { * cout << prettify(doc) << endl; * */ -template -std::string prettify(T x) { - simdjson::internal::string_builder sb; - sb.append(x); - std::string_view answer = sb.str(); - return std::string(answer.data(), answer.size()); +template std::string prettify(T x) { + simdjson::internal::string_builder sb; + sb.append(x); + std::string_view answer = sb.str(); + return std::string(answer.data(), answer.size()); } #if SIMDJSON_EXCEPTIONS -template -std::string prettify(simdjson_result x) { - if (x.error()) { throw simdjson_error(x.error()); } - return to_string(x.value()); +template std::string prettify(simdjson_result x) { + if (x.error()) { + throw simdjson_error(x.error()); + } + return to_string(x.value()); } #endif } // namespace simdjson - #endif /* end file simdjson/dom/serialization.h */ @@ -6878,6 +7301,8 @@ std::string prettify(simdjson_result x) { #include /* skipped duplicate #include "simdjson/common_defs.h" */ +#include + namespace simdjson { /** * Converts JSONPath to JSON Pointer. @@ -6886,12 +7311,12 @@ namespace simdjson { */ inline std::string json_path_to_pointer_conversion(std::string_view json_path) { size_t i = 0; - // if JSONPath starts with $, skip it + // json_path.starts_with('$') requires C++20. if (!json_path.empty() && json_path.front() == '$') { i = 1; } - if (json_path.empty() || (json_path[i] != '.' && + if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) { return "-1"; // This is just a sentinel value, the caller should check for this and return an error. } @@ -6934,6 +7359,49 @@ inline std::string json_path_to_pointer_conversion(std::string_view json_path) { return result; } + +inline std::pair get_next_key_and_json_path(std::string_view& json_path) { + std::string_view key; + + if (json_path.empty()) { + return {key, json_path}; + } + size_t i = 0; + + // if JSONPath starts with $, skip it + if (json_path.front() == '$') { + i = 1; + } + + + if (i < json_path.length() && json_path[i] == '.') { + i += 1; + size_t key_start = i; + + while (i < json_path.length() && json_path[i] != '[' && json_path[i] != '.') { + ++i; + } + + key = json_path.substr(key_start, i - key_start); + } else if ((i+1 < json_path.size()) && json_path[i] == '[' && (json_path[i+1] == '\'' || json_path[i+1] == '"')) { + i += 2; + size_t key_start = i; + while (i < json_path.length() && json_path[i] != '\'' && json_path[i] != '"') { + ++i; + } + + key = json_path.substr(key_start, i - key_start); + + i += 2; + } else if ((i+2 < json_path.size()) && json_path[i] == '[' && json_path[i+1] == '*' && json_path[i+2] == ']') { // i.e [*].additional_keys or [*]["additional_keys"] + key = "*"; + i += 3; + } + + + return std::make_pair(key, json_path.substr(i)); +} + } // namespace simdjson #endif // SIMDJSON_JSONPATHUTIL_H /* end file simdjson/jsonpathutil.h */ @@ -7131,11 +7599,22 @@ inline simdjson_result simdjson_result::at_pointer(std return at_pointer(json_pointer); } +inline simdjson_result> simdjson_result::at_path_with_wildcard(std::string_view json_path) const noexcept { + if (error()) { + return error(); + } + return first.at_path_with_wildcard(json_path); +} + inline simdjson_result simdjson_result::at(size_t index) const noexcept { if (error()) { return error(); } return first.at(index); } +inline std::vector& simdjson_result::get_values(std::vector& out) const noexcept { + return first.get_values(out); +} + namespace dom { // @@ -7206,6 +7685,93 @@ inline simdjson_result array::at_path(std::string_view json_path) const return at_pointer(json_pointer); } +inline void array::process_json_path_of_child_elements(std::vector::iterator& current, std::vector::iterator& end, const std::string_view& path_suffix, std::vector& accumulator) const noexcept { + if (current == end) { + return; + } + + simdjson_result> result; + + + for (auto it = current; it != end; ++it) { + std::vector child_result; + auto error = it->at_path_with_wildcard(path_suffix).get(child_result); + if(error) { + continue; + } + accumulator.reserve(accumulator.size() + child_result.size()); + accumulator.insert(accumulator.end(), + std::make_move_iterator(child_result.begin()), + std::make_move_iterator(child_result.end())); + } +} + +inline simdjson_result> array::at_path_with_wildcard(std::string_view json_path) const noexcept { + SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 + + size_t i = 0; + // json_path.starts_with('$') requires C++20. + if (!json_path.empty() && json_path.front() == '$') { + i = 1; + } + + if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) { + return INVALID_JSON_POINTER; + } + + if (json_path.find("*") != std::string::npos) { + std::vector child_values; + + if ( + (json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) || + (json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2) + ) { + get_values(child_values); + return child_values; + } + + std::pair key_and_json_path = get_next_key_and_json_path(json_path); + + std::string_view key = key_and_json_path.first; + json_path = key_and_json_path.second; + + if (key.size() > 0) { + if (key == "*") { + get_values(child_values); + } else { + element pointer_result; + std::string json_pointer = std::string("/") + std::string(key); + auto error = at_pointer(json_pointer).get(pointer_result); + + if (!error) { + child_values.emplace_back(pointer_result); + } + } + + std::vector result = {}; + + if (child_values.size() > 0) { + std::vector::iterator child_values_begin = child_values.begin(); + std::vector::iterator child_values_end = child_values.end(); + + process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result); + } + + return result; + } else { + return INVALID_JSON_POINTER; + } + } else { + element result; + auto error = at_path(json_path).get(result); + if (error) { + return error; + } + + return std::vector{std::move(result)}; + } +} + inline simdjson_result array::at(size_t index) const noexcept { SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 size_t i=0; @@ -7216,6 +7782,15 @@ inline simdjson_result array::at(size_t index) const noexcept { return INDEX_OUT_OF_BOUNDS; } +inline std::vector& array::get_values(std::vector& out) const noexcept { + out.reserve(this->size()); + for (auto element : *this) { + out.emplace_back(element); + } + + return out; +} + inline array::operator element() const noexcept { return element(tape); } @@ -7315,10 +7890,19 @@ inline simdjson_result simdjson_result::at_path(std:: if (json_pointer == "-1") { return INVALID_JSON_POINTER; } return at_pointer(json_pointer); } +inline simdjson_result> simdjson_result::at_path_with_wildcard(std::string_view json_path) const noexcept { + if (error()) { + return error(); + } + return first.at_path_with_wildcard(json_path); +} inline simdjson_result simdjson_result::at_key(std::string_view key) const noexcept { if (error()) { return error(); } return first.at_key(key); } +inline std::vector& simdjson_result::get_values(std::vector& out) const noexcept { + return first.get_values(out); +} inline simdjson_result simdjson_result::at_key_case_insensitive(std::string_view key) const noexcept { if (error()) { return error(); } return first.at_key_case_insensitive(key); @@ -7418,6 +8002,97 @@ inline simdjson_result object::at_path(std::string_view json_path) cons return at_pointer(json_pointer); } +inline void object::process_json_path_of_child_elements(std::vector::iterator& current, std::vector::iterator& end, const std::string_view& path_suffix, std::vector& accumulator) const noexcept { + if (current == end) { + return; + } + + simdjson_result> result; + + for (auto it = current; it != end; ++it) { + std::vector child_result; + auto error = it->at_path_with_wildcard(path_suffix).get(child_result); + if(error) { + continue; + } + accumulator.reserve(accumulator.size() + child_result.size()); + accumulator.insert(accumulator.end(), + std::make_move_iterator(child_result.begin()), + std::make_move_iterator(child_result.end())); + } +} + +inline simdjson_result> object::at_path_with_wildcard(std::string_view json_path) const noexcept { + SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 + + size_t i = 0; + if (json_path.empty()) { + return INVALID_JSON_POINTER; + } + // if JSONPath starts with $, skip it + // json_path.starts_with('$') requires C++20. + if (json_path.front() == '$') { + i = 1; + } + + if (i >= json_path.size() || (json_path[i] != '.' && json_path[i] != '[')) { + // expect json path to always start with $ but this isn't currently + // expected in jsonpathutil.h. + return INVALID_JSON_POINTER; + } + + if (json_path.find("*") != std::string::npos) { + + std::vector child_values; + + if ( + (json_path.compare(i, 3, "[*]") == 0 && json_path.size() == i + 3) || + (json_path.compare(i, 2,".*") == 0 && json_path.size() == i + 2) + ) { + get_values(child_values); + return child_values; + } + + std::pair key_and_json_path = get_next_key_and_json_path(json_path); + + std::string_view key = key_and_json_path.first; + json_path = key_and_json_path.second; + + if (key.size() > 0) { + if (key == "*") { + get_values(child_values); + } else { + element pointer_result; + auto error = at_pointer(std::string("/") + std::string(key)).get(pointer_result); + + if (!error) { + child_values.emplace_back(pointer_result); + } + } + + std::vector result = {}; + if (child_values.size() > 0) { + + std::vector::iterator child_values_begin = child_values.begin(); + std::vector::iterator child_values_end = child_values.end(); + + process_json_path_of_child_elements(child_values_begin, child_values_end, json_path, result); + } + + return result; + } else { + return INVALID_JSON_POINTER; + } + } else { + element result; + auto error = this->at_path(json_path).get(result); + if (error) { + return error; + } + return std::vector{std::move(result)}; + } +} + inline simdjson_result object::at_key(std::string_view key) const noexcept { iterator end_field = end(); for (iterator field = begin(); field != end_field; ++field) { @@ -7427,6 +8102,18 @@ inline simdjson_result object::at_key(std::string_view key) const noexc } return NO_SUCH_FIELD; } + +inline std::vector& object::get_values(std::vector& out) const noexcept { + iterator end_field = end(); + iterator begin_field = begin(); + + out.reserve(std::distance(begin_field, end_field)); + for (iterator field = begin_field; field != end_field; ++field) { + out.emplace_back(field.value()); + } + + return out; +} // In case you wonder why we need this, please see // https://github.com/simdjson/simdjson/issues/323 // People do seek keys in a case-insensitive manner. @@ -7538,14 +8225,14 @@ inline key_value_pair::key_value_pair(std::string_view _key, element _value) noe } // namespace simdjson -#if defined(__cpp_lib_ranges) +#if SIMDJSON_SUPPORTS_RANGES static_assert(std::ranges::view); static_assert(std::ranges::sized_range); #if SIMDJSON_EXCEPTIONS static_assert(std::ranges::view>); static_assert(std::ranges::sized_range>); #endif // SIMDJSON_EXCEPTIONS -#endif // defined(__cpp_lib_ranges) +#endif // SIMDJSON_SUPPORTS_RANGES #endif // SIMDJSON_OBJECT_INL_H /* end file simdjson/dom/object-inl.h */ @@ -7669,6 +8356,12 @@ simdjson_inline simdjson_result simdjson_result::at_ if (json_pointer == "-1") { return INVALID_JSON_POINTER; } return at_pointer(json_pointer); } + +simdjson_inline simdjson_result> simdjson_result::at_path_with_wildcard(const std::string_view json_path) const noexcept { + if (error()) { return error(); } + return first.at_path_with_wildcard(json_path); +} + #ifndef SIMDJSON_DISABLE_DEPRECATED_API [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] simdjson_inline simdjson_result simdjson_result::at(const std::string_view json_pointer) const noexcept { @@ -7959,6 +8652,20 @@ inline simdjson_result element::at_pointer(std::string_view json_pointe } } } + +inline simdjson_result> element::at_path_with_wildcard(std::string_view json_path) const noexcept { + SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 + + switch (tape.tape_ref_type()) { + case internal::tape_type::START_OBJECT: + return object(tape).at_path_with_wildcard(json_path); + case internal::tape_type::START_ARRAY: + return array(tape).at_path_with_wildcard(json_path); + default: + return std::vector{}; + } +} + inline simdjson_result element::at_path(std::string_view json_path) const noexcept { auto json_pointer = json_path_to_pointer_conversion(json_path); if (json_pointer == "-1") { return INVALID_JSON_POINTER; } @@ -8025,14 +8732,14 @@ inline std::ostream& operator<<(std::ostream& out, element_type type) { #endif // SIMDJSON_ELEMENT_INL_H /* end file simdjson/dom/element-inl.h */ -#if defined(__cpp_lib_ranges) +#if SIMDJSON_SUPPORTS_RANGES static_assert(std::ranges::view); static_assert(std::ranges::sized_range); #if SIMDJSON_EXCEPTIONS static_assert(std::ranges::view>); static_assert(std::ranges::sized_range>); #endif // SIMDJSON_EXCEPTIONS -#endif // defined(__cpp_lib_ranges) +#endif // SIMDJSON_SUPPORTS_RANGES #endif // SIMDJSON_ARRAY_INL_H /* end file simdjson/dom/array-inl.h */ @@ -8083,11 +8790,11 @@ inline bool parser::dump_raw_tape(std::ostream &os) const noexcept { return valid ? doc.dump_raw_tape(os) : false; } -inline simdjson_result parser::read_file(const std::string &path) noexcept { +inline simdjson_result parser::read_file(std::string_view path) noexcept { // Open the file SIMDJSON_PUSH_DISABLE_WARNINGS SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe - std::FILE *fp = std::fopen(path.c_str(), "rb"); + std::FILE *fp = std::fopen(path.data(), "rb"); SIMDJSON_POP_DISABLE_WARNINGS if (fp == nullptr) { @@ -8139,18 +8846,18 @@ inline simdjson_result parser::read_file(const std::string &path) noexce return bytes_read; } -inline simdjson_result parser::load(const std::string &path) & noexcept { +inline simdjson_result parser::load(std::string_view path) & noexcept { return load_into_document(doc, path); } -inline simdjson_result parser::load_into_document(document& provided_doc, const std::string &path) & noexcept { +inline simdjson_result parser::load_into_document(document& provided_doc, std::string_view path) & noexcept { size_t len; auto _error = read_file(path).get(len); if (_error) { return _error; } return parse_into_document(provided_doc, loaded_bytes.get(), len, false); } -inline simdjson_result parser::load_many(const std::string &path, size_t batch_size) noexcept { +inline simdjson_result parser::load_many(std::string_view path, size_t batch_size) noexcept { size_t len; auto _error = read_file(path).get(len); if (_error) { return _error; } @@ -8886,8 +9593,8 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept { #define SIMDJSON_SERIALIZATION_INL_H /* skipped duplicate #include "simdjson/dom/base.h" */ -/* skipped duplicate #include "simdjson/dom/serialization.h" */ /* skipped duplicate #include "simdjson/dom/parser.h" */ +/* skipped duplicate #include "simdjson/dom/serialization.h" */ /* skipped duplicate #include "simdjson/internal/tape_type.h" */ /* skipped duplicate #include "simdjson/dom/array-inl.h" */ @@ -8899,7 +9606,9 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept { namespace simdjson { namespace dom { inline bool parser::print_json(std::ostream &os) const noexcept { - if (!valid) { return false; } + if (!valid) { + return false; + } simdjson::internal::string_builder<> sb; sb.append(doc.root()); std::string_view answer = sb.str(); @@ -8907,37 +9616,51 @@ inline bool parser::print_json(std::ostream &os) const noexcept { return true; } -inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) { - simdjson::internal::string_builder<> sb; - sb.append(value); - return (out << sb.str()); +inline std::ostream &operator<<(std::ostream &out, + simdjson::dom::element value) { + simdjson::internal::string_builder<> sb; + sb.append(value); + return (out << sb.str()); } #if SIMDJSON_EXCEPTIONS -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()); } #endif -inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) { - simdjson::internal::string_builder<> sb; - sb.append(value); - return (out << sb.str()); +inline std::ostream &operator<<(std::ostream &out, simdjson::dom::array value) { + simdjson::internal::string_builder<> sb; + sb.append(value); + return (out << sb.str()); } #if SIMDJSON_EXCEPTIONS -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()); } #endif -inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) { - simdjson::internal::string_builder<> sb; - sb.append(value); - return (out << sb.str()); +inline std::ostream &operator<<(std::ostream &out, + simdjson::dom::object value) { + simdjson::internal::string_builder<> sb; + sb.append(value); + return (out << sb.str()); } #if SIMDJSON_EXCEPTIONS -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()); } #endif @@ -8952,8 +9675,9 @@ namespace { * We expect that most compilers will use 8 bytes for this data structure. **/ struct escape_sequence { - uint8_t length; - const char string[7]; // technically, we only ever need 6 characters, we pad to 8 + uint8_t length; + const char + string[7]; // technically, we only ever need 6 characters, we pad to 8 }; /**@private * This converts a signed integer into a character sequence. @@ -8969,7 +9693,7 @@ static char *fast_itoa(char *output, int64_t value) noexcept { char buffer[20]; uint64_t value_positive; // In general, negating a signed integer is unsafe. - if(value < 0) { + if (value < 0) { *output++ = '-'; // Doing value_positive = -value; while avoiding // undefined behavior warnings. @@ -8988,7 +9712,7 @@ static char *fast_itoa(char *output, int64_t value) noexcept { // A faster approach is possible if we expect large integers: // unroll the loop (work in 100s, 1000s) and use some kind of // memoization. - while(value_positive >= 10) { + while (value_positive >= 10) { *write_pointer-- = char('0' + (value_positive % 10)); value_positive /= 10; } @@ -9014,7 +9738,7 @@ static char *fast_itoa(char *output, uint64_t value) noexcept { // A faster approach is possible if we expect large integers: // unroll the loop (work in 100s, 1000s) and use some kind of // memoization. - while(value >= 10) { + while (value >= 10) { *write_pointer-- = char('0' + (value % 10)); value /= 10; }; @@ -9024,7 +9748,6 @@ static char *fast_itoa(char *output, uint64_t value) noexcept { return output + len; } - } // anonymous namespace namespace internal { @@ -9032,193 +9755,208 @@ namespace internal { * Minifier/formatter code. **/ -template +template simdjson_inline void base_formatter::number(uint64_t x) { char number_buffer[24]; char *newp = fast_itoa(number_buffer, x); - buffer.insert(buffer.end(), number_buffer, newp); + chars(number_buffer, newp); } -template +template simdjson_inline void base_formatter::number(int64_t x) { char number_buffer[24]; char *newp = fast_itoa(number_buffer, x); - buffer.insert(buffer.end(), number_buffer, newp); + chars(number_buffer, newp); } -template +template simdjson_inline void base_formatter::number(double x) { char number_buffer[24]; // Currently, passing the nullptr to the second argument is // safe because our implementation does not check the second // argument. char *newp = internal::to_chars(number_buffer, nullptr, x); - buffer.insert(buffer.end(), number_buffer, newp); + chars(number_buffer, newp); } -template -simdjson_inline void base_formatter::start_array() { one_char('['); } +template +simdjson_inline void base_formatter::start_array() { + one_char('['); +} +template +simdjson_inline void base_formatter::end_array() { + one_char(']'); +} -template -simdjson_inline void base_formatter::end_array() { one_char(']'); } +template +simdjson_inline void base_formatter::start_object() { + one_char('{'); +} -template -simdjson_inline void base_formatter::start_object() { one_char('{'); } +template +simdjson_inline void base_formatter::end_object() { + one_char('}'); +} -template -simdjson_inline void base_formatter::end_object() { one_char('}'); } +template +simdjson_inline void base_formatter::comma() { + one_char(','); +} -template -simdjson_inline void base_formatter::comma() { one_char(','); } - -template +template simdjson_inline void base_formatter::true_atom() { - const char * s = "true"; - buffer.insert(buffer.end(), s, s + 4); + const char *s = "true"; + chars(s, s + 4); } -template +template simdjson_inline void base_formatter::false_atom() { - const char * s = "false"; - buffer.insert(buffer.end(), s, s + 5); + const char *s = "false"; + chars(s, s + 5); } -template +template simdjson_inline void base_formatter::null_atom() { - const char * s = "null"; - buffer.insert(buffer.end(), s, s + 4); + const char *s = "null"; + chars(s, s + 4); } -template -simdjson_inline void base_formatter::one_char(char c) { buffer.push_back(c); } +template +simdjson_inline void base_formatter::one_char(char c) { + buffer.push_back(c); +} -template -simdjson_inline void base_formatter::key(std::string_view unescaped) { +template +simdjson_inline void base_formatter::chars(const char *begin, + const char *end) { + buffer.append(begin, end); +} + +template +simdjson_inline void +base_formatter::key(std::string_view unescaped) { string(unescaped); one_char(':'); } -template -simdjson_inline void base_formatter::string(std::string_view unescaped) { +template +simdjson_inline void +base_formatter::string(std::string_view unescaped) { one_char('\"'); size_t i = 0; - // Fast path for the case where we have no control character, no ", and no backslash. - // This should include most keys. + // Fast path for the case where we have no control character, no ", and no + // backslash. This should include most keys. // - // We would like to use 'bool' but some compilers take offense to bitwise operation - // with bool types. - constexpr static char needs_escaping[] = {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}; - for(;i + 8 <= unescaped.length(); i += 8) { + // We would like to use 'bool' but some compilers take offense to bitwise + // operation with bool types. + constexpr static char needs_escaping[] = { + 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}; + for (; i + 8 <= unescaped.length(); i += 8) { // Poor's man vectorization. This could get much faster if we used SIMD. // - // It is not the case that replacing '|' with '||' would be neutral performance-wise. - if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])] - | needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])] - | needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])] - | needs_escaping[uint8_t(unescaped[i+6])] | needs_escaping[uint8_t(unescaped[i+7])] - ) { break; } + // It is not the case that replacing '|' with '||' would be neutral + // performance-wise. + if (needs_escaping[uint8_t(unescaped[i])] | + needs_escaping[uint8_t(unescaped[i + 1])] | + needs_escaping[uint8_t(unescaped[i + 2])] | + needs_escaping[uint8_t(unescaped[i + 3])] | + needs_escaping[uint8_t(unescaped[i + 4])] | + needs_escaping[uint8_t(unescaped[i + 5])] | + needs_escaping[uint8_t(unescaped[i + 6])] | + needs_escaping[uint8_t(unescaped[i + 7])]) { + break; + } } - for(;i < unescaped.length(); i++) { - if(needs_escaping[uint8_t(unescaped[i])]) { break; } + for (; i < unescaped.length(); i++) { + if (needs_escaping[uint8_t(unescaped[i])]) { + break; + } } - // The following is also possible and omits a 256-byte table, but it is slower: - // for (; (i < unescaped.length()) && (uint8_t(unescaped[i]) > 0x1F) + // The following is also possible and omits a 256-byte table, but it is + // slower: for (; (i < unescaped.length()) && (uint8_t(unescaped[i]) > 0x1F) // && (unescaped[i] != '\"') && (unescaped[i] != '\\'); i++) {} // At least for long strings, the following should be fast. We could // do better by integrating the checks and the insertion. - buffer.insert(buffer.end(), unescaped.data(), unescaped.data() + i); + chars(unescaped.data(), unescaped.data() + i); // We caught a control character if we enter this loop (slow). // Note that we are do not restart from the beginning, but rather we continue // from the point where we encountered something that requires escaping. for (; i < unescaped.length(); i++) { switch (unescaped[i]) { - case '\"': - { - const char * s = "\\\""; - buffer.insert(buffer.end(), s, s + 2); - } - break; - case '\\': - { - const char * s = "\\\\"; - buffer.insert(buffer.end(), s, s + 2); - } - break; + case '\"': { + const char *s = "\\\""; + chars(s, s + 2); + } break; + case '\\': { + const char *s = "\\\\"; + chars(s, s + 2); + } break; default: if (uint8_t(unescaped[i]) <= 0x1F) { // If packed, this uses 8 * 32 bytes. // Note that we expect most compilers to embed this code in the data // section. constexpr static escape_sequence escaped[32] = { - {6, "\\u0000"}, {6, "\\u0001"}, {6, "\\u0002"}, {6, "\\u0003"}, - {6, "\\u0004"}, {6, "\\u0005"}, {6, "\\u0006"}, {6, "\\u0007"}, - {2, "\\b"}, {2, "\\t"}, {2, "\\n"}, {6, "\\u000b"}, - {2, "\\f"}, {2, "\\r"}, {6, "\\u000e"}, {6, "\\u000f"}, - {6, "\\u0010"}, {6, "\\u0011"}, {6, "\\u0012"}, {6, "\\u0013"}, - {6, "\\u0014"}, {6, "\\u0015"}, {6, "\\u0016"}, {6, "\\u0017"}, - {6, "\\u0018"}, {6, "\\u0019"}, {6, "\\u001a"}, {6, "\\u001b"}, - {6, "\\u001c"}, {6, "\\u001d"}, {6, "\\u001e"}, {6, "\\u001f"}}; + {6, "\\u0000"}, {6, "\\u0001"}, {6, "\\u0002"}, {6, "\\u0003"}, + {6, "\\u0004"}, {6, "\\u0005"}, {6, "\\u0006"}, {6, "\\u0007"}, + {2, "\\b"}, {2, "\\t"}, {2, "\\n"}, {6, "\\u000b"}, + {2, "\\f"}, {2, "\\r"}, {6, "\\u000e"}, {6, "\\u000f"}, + {6, "\\u0010"}, {6, "\\u0011"}, {6, "\\u0012"}, {6, "\\u0013"}, + {6, "\\u0014"}, {6, "\\u0015"}, {6, "\\u0016"}, {6, "\\u0017"}, + {6, "\\u0018"}, {6, "\\u0019"}, {6, "\\u001a"}, {6, "\\u001b"}, + {6, "\\u001c"}, {6, "\\u001d"}, {6, "\\u001e"}, {6, "\\u001f"}}; auto u = escaped[uint8_t(unescaped[i])]; - buffer.insert(buffer.end(), u.string, u.string + u.length); + chars(u.string, u.string + u.length); } else { one_char(unescaped[i]); } } // switch - } // for + } // for one_char('\"'); } - -template -inline void base_formatter::clear() { +template inline void base_formatter::clear() { buffer.clear(); } -template +template simdjson_inline std::string_view base_formatter::str() const { - return std::string_view(buffer.data(), buffer.size()); + return buffer.str(); } -simdjson_inline void mini_formatter::print_newline() { - return; -} +simdjson_inline void mini_formatter::print_newline() { return; } simdjson_inline void mini_formatter::print_indents(size_t depth) { - (void)depth; - return; + (void)depth; + return; } -simdjson_inline void mini_formatter::print_space() { - return; -} +simdjson_inline void mini_formatter::print_space() { return; } -simdjson_inline void pretty_formatter::print_newline() { - one_char('\n'); -} +simdjson_inline void pretty_formatter::print_newline() { one_char('\n'); } simdjson_inline void pretty_formatter::print_indents(size_t depth) { - if(this->indent_step <= 0) { - return; - } - for(size_t i = 0; i < this->indent_step * depth; i++) { - one_char(' '); - } + if (this->indent_step <= 0) { + return; + } + for (size_t i = 0; i < this->indent_step * depth; i++) { + one_char(' '); + } } -simdjson_inline void pretty_formatter::print_space() { - one_char(' '); -} +simdjson_inline void pretty_formatter::print_space() { one_char(' '); } /*** * String building code. @@ -9397,7 +10135,8 @@ inline void string_builder::append(simdjson::dom::array value) { } template -simdjson_inline void string_builder::append(simdjson::dom::key_value_pair kv) { +simdjson_inline void +string_builder::append(simdjson::dom::key_value_pair kv) { format.key(kv.key); append(kv.value); } @@ -9412,7 +10151,6 @@ simdjson_inline std::string_view string_builder::str() const { return format.str(); } - } // namespace internal } // namespace simdjson @@ -10623,6 +11361,12 @@ namespace { tmp = vpaddq_u8(tmp, tmp); return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); } + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; } }; @@ -10699,7 +11443,7 @@ namespace { // Bit-specific operations simdjson_inline simd8 any_bits_set(simd8 bits) const { return vtstq_u8(*this, bits); } - simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; } + simdjson_inline bool any_bits_set_anywhere() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 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 vshrq_n_u8(*this, N); } @@ -10712,7 +11456,12 @@ namespace { return lookup_table.apply_lookup_16_to(*this); } - + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // Passing a 0 value for mask would be equivalent to writing out every byte to output. // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes @@ -11006,7 +11755,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -11035,6 +11784,32 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask64() + }; +} + + + } // unnamed namespace } // namespace arm64 } // namespace simdjson @@ -11454,12 +12229,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -11468,6 +12248,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -11509,6 +12299,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -11885,7 +12676,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -11913,7 +12704,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -12002,7 +12793,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -12065,13 +12856,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -12097,7 +12888,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -12881,12 +13672,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -13055,7 +13875,7 @@ namespace { struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 1; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { return c == '"'; } simdjson_inline bool has_backslash() { return c == '\\'; } @@ -13071,6 +13891,24 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin return { src[0] }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 1; + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits; } + simdjson_inline int escape_index() { return 0; } + + bool escape_bits; +}; // struct escaping + + + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + dst[0] = src[0]; + return { (src[0] == '\\') || (src[0] == '"') || (src[0] < 32) }; +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -13577,12 +14415,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -13591,6 +14434,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -13632,6 +14485,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -14008,7 +14862,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -14036,7 +14890,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -14125,7 +14979,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -14188,13 +15042,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -14220,7 +15074,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -15004,12 +15858,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -15751,7 +16634,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -15775,6 +16658,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 32; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace haswell } // namespace simdjson @@ -16192,12 +17100,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -16206,6 +17119,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -16247,6 +17170,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -16623,7 +17547,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -16651,7 +17575,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -16740,7 +17664,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -16803,13 +17727,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -16835,7 +17759,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -17619,12 +18543,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -17984,7 +18937,6 @@ namespace simd { friend simdjson_really_inline uint64_t operator==(const simd8 lhs, const simd8 rhs) { return _mm512_cmpeq_epi8_mask(lhs, rhs); } - static const int SIZE = sizeof(base::value); template @@ -18303,7 +19255,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 64; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -18327,6 +19279,35 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 64; + 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(uint64_t(escape_bits)); } + + __mmask64 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); + __mmask64 is_quote = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('"')); + __mmask64 is_backslash = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('\\')); + __mmask64 is_control = _mm512_cmplt_epi8_mask(v, _mm512_set1_epi8(32)); + return { + (is_backslash | is_quote | is_control) + }; +} + + + + } // unnamed namespace } // namespace icelake } // namespace simdjson @@ -18804,12 +19785,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -18818,6 +19804,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -18859,6 +19855,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -19235,7 +20232,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -19263,7 +20260,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -19352,7 +20349,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -19415,13 +20412,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -19447,7 +20444,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -20231,12 +21228,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -21073,7 +22099,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { @@ -21114,6 +22140,32 @@ backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + // We store it as a 64-bit bitmask even though we only need 16 bits. + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace ppc64 } // namespace simdjson @@ -21533,12 +22585,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -21547,6 +22604,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -21588,6 +22655,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -21964,7 +23032,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -21992,7 +23060,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -22081,7 +23149,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -22144,13 +23212,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -22176,7 +23244,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -22960,12 +24028,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -24136,7 +25233,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -24162,6 +25259,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace westmere } // namespace simdjson @@ -24579,12 +25701,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -24593,6 +25720,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -24634,6 +25771,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -25010,7 +26148,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -25038,7 +26176,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -25127,7 +26265,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -25190,13 +26328,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -25222,7 +26360,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -26006,12 +27144,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -26654,7 +27821,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -26683,6 +27850,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + static_cast((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace lsx } // namespace simdjson @@ -27102,12 +28294,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -27116,6 +28313,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -27157,6 +28364,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -27533,7 +28741,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -27561,7 +28769,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -27650,7 +28858,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -27713,13 +28921,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -27745,7 +28953,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -28529,12 +29737,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -29196,7 +30433,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -29219,6 +30456,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask() + }; +} + } // unnamed namespace } // namespace lasx } // namespace simdjson @@ -29638,12 +30900,17 @@ struct implementation_simdjson_result_base { * * @param value The variable to assign the value to. May not be set if there is an error. */ - simdjson_inline error_code get(T &value) && noexcept; + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept; /** * The error. */ - simdjson_inline error_code error() const noexcept; + 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 @@ -29652,6 +30919,16 @@ struct implementation_simdjson_result_base { * * @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); /** @@ -29693,6 +30970,7 @@ struct implementation_simdjson_result_base { * the error() method returns a value that evaluates to false. */ simdjson_inline T&& value_unsafe() && noexcept; + protected: /** users should never directly access first and second. **/ T first{}; /** Users should never directly access 'first'. **/ @@ -30069,7 +31347,7 @@ simdjson_inline bool is_digit(const uint8_t c) { return static_cast(c - '0') <= 9; } -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) { +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 @@ -30097,7 +31375,7 @@ simdjson_inline error_code parse_decimal_after_separator(simdjson_unused const u return SUCCESS; } -simdjson_inline error_code parse_exponent(simdjson_unused const uint8_t *const src, const uint8_t *&p, int64_t &exponent) { +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 @@ -30186,7 +31464,7 @@ static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double /** @private */ template -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) { +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. @@ -30249,13 +31527,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative, // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer); +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_inline error_code parse_number(const uint8_t *const, W &writer) { +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 } @@ -30281,7 +31559,7 @@ simdjson_unused simdjson_inline simdjson_result get_number_type(con // // Our objective is accurate parsing (ULP of 0) at high speed. template -simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { +simdjson_warn_unused simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { // // Check for minus sign // @@ -31065,12 +32343,41 @@ simdjson_warn_unused simdjson_inline error_code implementation_simdjson_result_b } template -simdjson_inline error_code implementation_simdjson_result_base::error() const noexcept { +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()); } @@ -31162,6 +32469,7 @@ simdjson_inline implementation_simdjson_result_base::implementation_simdjson_ // Internal headers needed for ondemand generics. // All includes not under simdjson/generic/ondemand must be here! // Otherwise, amalgamation will fail. +/* skipped duplicate #include "simdjson/concepts.h" */ /* skipped duplicate #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY */ /* skipped duplicate #include "simdjson/implementation.h" */ /* skipped duplicate #include "simdjson/padded_string.h" */ @@ -31596,6 +32904,12 @@ namespace { tmp = vpaddq_u8(tmp, tmp); return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0); } + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; } }; @@ -31672,7 +32986,7 @@ namespace { // Bit-specific operations simdjson_inline simd8 any_bits_set(simd8 bits) const { return vtstq_u8(*this, bits); } - simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; } + simdjson_inline bool any_bits_set_anywhere() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 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 vshrq_n_u8(*this, N); } @@ -31685,7 +32999,12 @@ namespace { return lookup_table.apply_lookup_16_to(*this); } - + // Returns 4-bit out of each byte, alternating between the high 4 bits and low + // bits result it is 64 bit. + simdjson_inline uint64_t to_bitmask64() const { + return vget_lane_u64( + vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0); + } // Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // Passing a 0 value for mask would be equivalent to writing out every byte to output. // Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes @@ -31979,7 +33298,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -32008,6 +33327,32 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask64() + }; +} + + + } // unnamed namespace } // namespace arm64 } // namespace simdjson @@ -32076,7 +33421,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for arm64 */ /* including simdjson/generic/ondemand/deserialize.h for arm64: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for arm64 */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -32085,55 +33430,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -32155,7 +33453,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -32166,28 +33464,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = arm64::ondemand::array; + using object_type = arm64::ondemand::object; using value_type = arm64::ondemand::value; using document_type = arm64::ondemand::document; using document_reference_type = arm64::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -32197,7 +33511,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for arm64 */ /* including simdjson/generic/ondemand/value_iterator.h for arm64: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -32539,7 +33853,7 @@ public: 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_inline error_code error() const 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; @@ -32623,8 +33937,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -32634,8 +33948,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -32672,7 +33986,7 @@ protected: /** @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_inline error_code 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; @@ -32737,13 +34051,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -32760,22 +34075,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -32785,7 +34116,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -32903,7 +34234,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -33424,7 +34755,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -33505,7 +34836,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -33999,14 +35345,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -34026,7 +35372,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -34117,6 +35463,7 @@ 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, ... } ) @@ -34323,6 +35670,12 @@ public: */ 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, @@ -34462,10 +35815,10 @@ public: 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(arm64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(arm64::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -34481,6 +35834,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace arm64 { @@ -34599,7 +35953,9 @@ public: 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 */ + /** @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; @@ -34687,6 +36043,11 @@ public: * 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 @@ -34694,10 +36055,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -34723,14 +36084,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -34832,13 +36195,39 @@ public: 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 @@ -34866,6 +36255,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for arm64 */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for arm64: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for arm64 */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 arm64 { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(arm64::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 arm64 { +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(const 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) + 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::arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::arm64::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for arm64 */ + // All other declarations /* including simdjson/generic/ondemand/array.h for arm64: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for arm64 */ @@ -35002,11 +36700,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -35080,7 +36809,28 @@ public: 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 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 @@ -35125,7 +36875,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -35149,6 +36900,11 @@ public: */ 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: value_iterator iter{}; @@ -35167,7 +36923,6 @@ namespace simdjson { template<> struct simdjson_result : public arm64::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(arm64::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -35180,6 +36935,8 @@ public: 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 @@ -35307,7 +37064,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -35373,7 +37130,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -35396,7 +37153,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -35414,18 +37171,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -35437,7 +37194,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -35447,7 +37204,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -35512,7 +37269,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -35521,7 +37278,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -35671,11 +37428,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -35899,11 +37672,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -35956,7 +37759,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -35965,7 +37768,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -35978,7 +37781,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -36000,14 +37803,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -36019,7 +37822,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -36029,12 +37832,17 @@ public: " 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_DESERIALIZATION +#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 @@ -36103,7 +37911,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -36116,6 +37924,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using arm64::implementation_simdjson_result_base::operator*; + using arm64::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator arm64::ondemand::array() & noexcept(false); @@ -36155,6 +37966,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -36181,7 +37997,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -36232,6 +38048,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -36374,6 +38195,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -36387,6 +38209,7 @@ public: * @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 * @@ -36430,6 +38253,11 @@ public: */ 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. */ @@ -36441,6 +38269,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -36704,6 +38533,9 @@ public: /* 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): #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 { @@ -36901,11 +38733,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -36944,12 +38836,42 @@ public: 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; - 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 @@ -37078,6 +39000,20 @@ inline simdjson_result to_json_string(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 /** @@ -37149,28 +39085,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -37184,7 +39122,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -37193,7 +39130,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -37206,8 +39142,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -37224,7 +39175,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -37233,9 +39183,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - arm64::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, arm64::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)); @@ -37266,7 +39220,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -37292,7 +39245,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, arm64::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)); + + arm64::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, arm64::ondemand::value &val, T &out) noexcept { + arm64::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, arm64::ondemand::document &doc, T &out) noexcept { + arm64::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, arm64::ondemand::document_reference &doc, T &out) noexcept { + arm64::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -37310,7 +39301,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -37335,17 +39325,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -37354,10 +39344,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + arm64::ondemand::object obj; + if constexpr (std::is_same_v, arm64::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for arm64 */ // Inline definitions @@ -37450,7 +39759,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -37641,6 +39950,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace arm64 } // namespace simdjson @@ -37677,7 +39989,9 @@ simdjson_inline simdjson_result &simdjson_resul ++(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 @@ -37734,7 +40048,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -37776,15 +40090,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -38381,7 +40695,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -38407,15 +40721,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -38435,8 +40749,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -38485,7 +40799,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -38587,6 +40901,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 arm64 } // namespace simdjson @@ -38694,7 +41056,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -38730,12 +41092,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -38745,8 +41107,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(arm64::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(arm64::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(arm64::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(arm64::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -38864,6 +41226,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -38898,7 +41269,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -38951,7 +41322,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 arm64 } // namespace simdjson @@ -39048,7 +41425,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -39083,12 +41460,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -39105,13 +41482,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(arm64::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(arm64::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(arm64::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(arm64::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -39199,7 +41576,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -39390,10 +41774,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -39511,7 +41904,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -39757,7 +42153,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -39993,6 +42389,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -40117,7 +42515,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -40161,7 +42559,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -40184,7 +42582,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -40579,6 +42977,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -40636,7 +43038,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -40765,6 +43167,52 @@ 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 arm64 } // namespace simdjson @@ -40841,6 +43289,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -41055,7 +43504,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -41087,10 +43536,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -41112,7 +43558,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -41127,6 +43573,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -41135,16 +43582,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -41179,6 +43634,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 arm64 } // namespace simdjson @@ -41213,8 +43696,13 @@ 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 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}; @@ -41391,6 +43879,10 @@ simdjson_inline simdjson_result 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(arm64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -41416,6 +43908,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -41781,7 +44276,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -42635,7 +45130,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -42797,7 +45292,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -42837,6 +45332,1097 @@ simdjson_inline simdjson_result::simdjson_resul #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for arm64 */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for arm64: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for arm64 */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace arm64 { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 arm64 +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for arm64 */ +/* including simdjson/generic/ondemand/json_builder.h for arm64: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for arm64 */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 arm64 { +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 simdjson_error 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 arm64 +// 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 = arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + arm64::builder::string_builder b(initial_capacity); + arm64::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 simdjson_error 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; + 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 = arm64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + arm64::builder::string_builder b(initial_capacity); + arm64::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/ondemand/json_builder.h for arm64 */ /* end file simdjson/generic/ondemand/amalgamated.h for arm64 */ /* including simdjson/arm64/end.h: #include "simdjson/arm64/end.h" */ @@ -42952,7 +46538,7 @@ namespace { struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 1; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { return c == '"'; } simdjson_inline bool has_backslash() { return c == '\\'; } @@ -42968,6 +46554,24 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin return { src[0] }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 1; + simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst); + + simdjson_inline bool has_escape() { return escape_bits; } + simdjson_inline int escape_index() { return 0; } + + bool escape_bits; +}; // struct escaping + + + +simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) { + dst[0] = src[0]; + return { (src[0] == '\\') || (src[0] == '"') || (src[0] < 32) }; +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -43123,7 +46727,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for fallback */ /* including simdjson/generic/ondemand/deserialize.h for fallback: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for fallback */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -43132,55 +46736,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -43202,7 +46759,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -43213,28 +46770,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = fallback::ondemand::array; + using object_type = fallback::ondemand::object; using value_type = fallback::ondemand::value; using document_type = fallback::ondemand::document; using document_reference_type = fallback::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -43244,7 +46817,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for fallback */ /* including simdjson/generic/ondemand/value_iterator.h for fallback: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -43586,7 +47159,7 @@ public: 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_inline error_code error() const 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; @@ -43670,8 +47243,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -43681,8 +47254,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -43719,7 +47292,7 @@ protected: /** @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_inline error_code 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; @@ -43784,13 +47357,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -43807,22 +47381,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -43832,7 +47422,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -43950,7 +47540,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -44471,7 +48061,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -44552,7 +48142,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -45046,14 +48651,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -45073,7 +48678,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -45164,6 +48769,7 @@ 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, ... } ) @@ -45370,6 +48976,12 @@ public: */ 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, @@ -45509,10 +49121,10 @@ public: 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(fallback::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(fallback::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -45528,6 +49140,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace fallback { @@ -45646,7 +49259,9 @@ public: 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 */ + /** @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; @@ -45734,6 +49349,11 @@ public: * 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 @@ -45741,10 +49361,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -45770,14 +49390,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -45879,13 +49501,39 @@ public: 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 @@ -45913,6 +49561,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for fallback */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for fallback: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for fallback */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 fallback { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(fallback::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 fallback { +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(const 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) + 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::fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::fallback::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for fallback */ + // All other declarations /* including simdjson/generic/ondemand/array.h for fallback: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for fallback */ @@ -46049,11 +50006,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -46127,7 +50115,28 @@ public: 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 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 @@ -46172,7 +50181,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -46196,6 +50206,11 @@ public: */ 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: value_iterator iter{}; @@ -46214,7 +50229,6 @@ namespace simdjson { template<> struct simdjson_result : public fallback::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(fallback::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -46227,6 +50241,8 @@ public: 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 @@ -46354,7 +50370,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -46420,7 +50436,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -46443,7 +50459,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -46461,18 +50477,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -46484,7 +50500,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -46494,7 +50510,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -46559,7 +50575,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -46568,7 +50584,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -46718,11 +50734,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -46946,11 +50978,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -47003,7 +51065,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -47012,7 +51074,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -47025,7 +51087,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -47047,14 +51109,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -47066,7 +51128,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -47076,12 +51138,17 @@ public: " 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_DESERIALIZATION +#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 @@ -47150,7 +51217,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -47163,6 +51230,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using fallback::implementation_simdjson_result_base::operator*; + using fallback::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator fallback::ondemand::array() & noexcept(false); @@ -47202,6 +51272,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -47228,7 +51303,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -47279,6 +51354,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -47421,6 +51501,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -47434,6 +51515,7 @@ public: * @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 * @@ -47477,6 +51559,11 @@ public: */ 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. */ @@ -47488,6 +51575,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -47751,6 +51839,9 @@ public: /* 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): #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 { @@ -47948,11 +52039,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -47991,12 +52142,42 @@ public: 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; - 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 @@ -48125,6 +52306,20 @@ inline simdjson_result to_json_string(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 /** @@ -48196,28 +52391,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -48231,7 +52428,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -48240,7 +52436,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -48253,8 +52448,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -48271,7 +52481,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -48280,9 +52489,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - fallback::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, fallback::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)); @@ -48313,7 +52526,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -48339,7 +52551,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, fallback::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)); + + fallback::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, fallback::ondemand::value &val, T &out) noexcept { + fallback::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, fallback::ondemand::document &doc, T &out) noexcept { + fallback::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, fallback::ondemand::document_reference &doc, T &out) noexcept { + fallback::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -48357,7 +52607,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -48382,17 +52631,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -48401,10 +52650,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + fallback::ondemand::object obj; + if constexpr (std::is_same_v, fallback::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for fallback */ // Inline definitions @@ -48497,7 +53065,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -48688,6 +53256,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace fallback } // namespace simdjson @@ -48724,7 +53295,9 @@ simdjson_inline simdjson_result &simdjson_re ++(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 @@ -48781,7 +53354,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -48823,15 +53396,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -49428,7 +54001,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -49454,15 +54027,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -49482,8 +54055,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -49532,7 +54105,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -49634,6 +54207,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 fallback } // namespace simdjson @@ -49741,7 +54362,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -49777,12 +54398,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -49792,8 +54413,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(fallback::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(fallback::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(fallback::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(fallback::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -49911,6 +54532,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -49945,7 +54575,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -49998,7 +54628,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 fallback } // namespace simdjson @@ -50095,7 +54731,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -50130,12 +54766,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -50152,13 +54788,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(fallback::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(fallback::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(fallback::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(fallback::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -50246,7 +54882,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -50437,10 +55080,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -50558,7 +55210,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -50804,7 +55459,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -51040,6 +55695,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -51164,7 +55821,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -51208,7 +55865,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -51231,7 +55888,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -51626,6 +56283,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -51683,7 +56344,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -51812,6 +56473,52 @@ 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 fallback } // namespace simdjson @@ -51888,6 +56595,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -52102,7 +56810,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -52134,10 +56842,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -52159,7 +56864,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -52174,6 +56879,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -52182,16 +56888,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -52226,6 +56940,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 fallback } // namespace simdjson @@ -52260,8 +57002,13 @@ 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 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}; @@ -52438,6 +57185,10 @@ simdjson_inline simdjson_result 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(fallback::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -52463,6 +57214,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -52828,7 +57582,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -53682,7 +58436,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -53844,7 +58598,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -53884,6 +58638,1097 @@ simdjson_inline simdjson_result::simdjson_re #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for fallback */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for fallback: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for fallback */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace fallback { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 fallback +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for fallback */ +/* including simdjson/generic/ondemand/json_builder.h for fallback: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for fallback */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 fallback { +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 simdjson_error 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 fallback +// 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 = fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + fallback::builder::string_builder b(initial_capacity); + fallback::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 simdjson_error 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; + 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 = fallback::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + fallback::builder::string_builder b(initial_capacity); + fallback::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/ondemand/json_builder.h for fallback */ /* end file simdjson/generic/ondemand/amalgamated.h for fallback */ /* including simdjson/fallback/end.h: #include "simdjson/fallback/end.h" */ @@ -54572,7 +60417,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -54596,6 +60441,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 32; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace haswell } // namespace simdjson @@ -54662,7 +60532,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for haswell */ /* including simdjson/generic/ondemand/deserialize.h for haswell: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for haswell */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -54671,55 +60541,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -54741,7 +60564,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -54752,28 +60575,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = haswell::ondemand::array; + using object_type = haswell::ondemand::object; using value_type = haswell::ondemand::value; using document_type = haswell::ondemand::document; using document_reference_type = haswell::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -54783,7 +60622,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for haswell */ /* including simdjson/generic/ondemand/value_iterator.h for haswell: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -55125,7 +60964,7 @@ public: 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_inline error_code error() const 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; @@ -55209,8 +61048,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -55220,8 +61059,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -55258,7 +61097,7 @@ protected: /** @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_inline error_code 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; @@ -55323,13 +61162,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -55346,22 +61186,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -55371,7 +61227,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -55489,7 +61345,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -56010,7 +61866,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -56091,7 +61947,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -56585,14 +62456,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -56612,7 +62483,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -56703,6 +62574,7 @@ 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, ... } ) @@ -56909,6 +62781,12 @@ public: */ 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, @@ -57048,10 +62926,10 @@ public: 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(haswell::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(haswell::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -57067,6 +62945,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace haswell { @@ -57185,7 +63064,9 @@ public: 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 */ + /** @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; @@ -57273,6 +63154,11 @@ public: * 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 @@ -57280,10 +63166,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -57309,14 +63195,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -57418,13 +63306,39 @@ public: 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 @@ -57452,6 +63366,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for haswell */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for haswell: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for haswell */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 haswell { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(haswell::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 haswell { +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(const 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) + 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::haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::haswell::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for haswell */ + // All other declarations /* including simdjson/generic/ondemand/array.h for haswell: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for haswell */ @@ -57588,11 +63811,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -57666,7 +63920,28 @@ public: 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 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 @@ -57711,7 +63986,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -57735,6 +64011,11 @@ public: */ 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: value_iterator iter{}; @@ -57753,7 +64034,6 @@ namespace simdjson { template<> struct simdjson_result : public haswell::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(haswell::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -57766,6 +64046,8 @@ public: 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 @@ -57893,7 +64175,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -57959,7 +64241,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -57982,7 +64264,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -58000,18 +64282,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -58023,7 +64305,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -58033,7 +64315,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -58098,7 +64380,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -58107,7 +64389,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -58257,11 +64539,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -58485,11 +64783,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -58542,7 +64870,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -58551,7 +64879,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -58564,7 +64892,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -58586,14 +64914,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -58605,7 +64933,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -58615,12 +64943,17 @@ public: " 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_DESERIALIZATION +#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 @@ -58689,7 +65022,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -58702,6 +65035,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using haswell::implementation_simdjson_result_base::operator*; + using haswell::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator haswell::ondemand::array() & noexcept(false); @@ -58741,6 +65077,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -58767,7 +65108,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -58818,6 +65159,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -58960,6 +65306,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -58973,6 +65320,7 @@ public: * @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 * @@ -59016,6 +65364,11 @@ public: */ 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. */ @@ -59027,6 +65380,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -59290,6 +65644,9 @@ public: /* 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): #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 { @@ -59487,11 +65844,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -59530,12 +65947,42 @@ public: 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; - 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 @@ -59664,6 +66111,20 @@ inline simdjson_result to_json_string(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 /** @@ -59735,28 +66196,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -59770,7 +66233,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -59779,7 +66241,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -59792,8 +66253,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -59810,7 +66286,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -59819,9 +66294,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - haswell::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, haswell::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)); @@ -59852,7 +66331,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -59878,7 +66356,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, haswell::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)); + + haswell::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, haswell::ondemand::value &val, T &out) noexcept { + haswell::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, haswell::ondemand::document &doc, T &out) noexcept { + haswell::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, haswell::ondemand::document_reference &doc, T &out) noexcept { + haswell::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -59896,7 +66412,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -59921,17 +66436,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -59940,10 +66455,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + haswell::ondemand::object obj; + if constexpr (std::is_same_v, haswell::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for haswell */ // Inline definitions @@ -60036,7 +66870,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -60227,6 +67061,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace haswell } // namespace simdjson @@ -60263,7 +67100,9 @@ simdjson_inline simdjson_result &simdjson_res ++(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 @@ -60320,7 +67159,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -60362,15 +67201,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -60967,7 +67806,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -60993,15 +67832,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -61021,8 +67860,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -61071,7 +67910,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -61173,6 +68012,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 haswell } // namespace simdjson @@ -61280,7 +68167,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -61316,12 +68203,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -61331,8 +68218,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(haswell::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(haswell::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(haswell::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(haswell::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -61450,6 +68337,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -61484,7 +68380,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -61537,7 +68433,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 haswell } // namespace simdjson @@ -61634,7 +68536,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -61669,12 +68571,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -61691,13 +68593,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(haswell::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(haswell::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(haswell::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(haswell::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -61785,7 +68687,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -61976,10 +68885,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -62097,7 +69015,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -62343,7 +69264,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -62579,6 +69500,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -62703,7 +69626,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -62747,7 +69670,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -62770,7 +69693,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -63165,6 +70088,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -63222,7 +70149,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -63351,6 +70278,52 @@ 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 haswell } // namespace simdjson @@ -63427,6 +70400,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -63641,7 +70615,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -63673,10 +70647,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -63698,7 +70669,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -63713,6 +70684,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -63721,16 +70693,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -63765,6 +70745,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 haswell } // namespace simdjson @@ -63799,8 +70807,13 @@ 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 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}; @@ -63977,6 +70990,10 @@ simdjson_inline simdjson_result 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(haswell::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -64002,6 +71019,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -64367,7 +71387,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -65221,7 +72241,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -65383,7 +72403,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -65423,6 +72443,1097 @@ simdjson_inline simdjson_result::simdjson_res #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for haswell */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for haswell: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for haswell */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace haswell { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 haswell +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for haswell */ +/* including simdjson/generic/ondemand/json_builder.h for haswell: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for haswell */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 haswell { +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 simdjson_error 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 haswell +// 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 = haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + haswell::builder::string_builder b(initial_capacity); + haswell::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 simdjson_error 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; + 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 = haswell::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + haswell::builder::string_builder b(initial_capacity); + haswell::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/ondemand/json_builder.h for haswell */ /* end file simdjson/generic/ondemand/amalgamated.h for haswell */ /* including simdjson/haswell/end.h: #include "simdjson/haswell/end.h" */ @@ -65729,7 +73840,6 @@ namespace simd { friend simdjson_really_inline uint64_t operator==(const simd8 lhs, const simd8 rhs) { return _mm512_cmpeq_epi8_mask(lhs, rhs); } - static const int SIZE = sizeof(base::value); template @@ -66048,7 +74158,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 64; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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; } @@ -66072,6 +74182,35 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 64; + 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(uint64_t(escape_bits)); } + + __mmask64 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); + __mmask64 is_quote = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('"')); + __mmask64 is_backslash = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('\\')); + __mmask64 is_control = _mm512_cmplt_epi8_mask(v, _mm512_set1_epi8(32)); + return { + (is_backslash | is_quote | is_control) + }; +} + + + + } // unnamed namespace } // namespace icelake } // namespace simdjson @@ -66198,7 +74337,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for icelake */ /* including simdjson/generic/ondemand/deserialize.h for icelake: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for icelake */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -66207,55 +74346,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -66277,7 +74369,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -66288,28 +74380,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = icelake::ondemand::array; + using object_type = icelake::ondemand::object; using value_type = icelake::ondemand::value; using document_type = icelake::ondemand::document; using document_reference_type = icelake::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -66319,7 +74427,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for icelake */ /* including simdjson/generic/ondemand/value_iterator.h for icelake: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -66661,7 +74769,7 @@ public: 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_inline error_code error() const 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; @@ -66745,8 +74853,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -66756,8 +74864,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -66794,7 +74902,7 @@ protected: /** @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_inline error_code 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; @@ -66859,13 +74967,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -66882,22 +74991,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -66907,7 +75032,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -67025,7 +75150,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -67546,7 +75671,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -67627,7 +75752,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -68121,14 +76261,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -68148,7 +76288,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -68239,6 +76379,7 @@ 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, ... } ) @@ -68445,6 +76586,12 @@ public: */ 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, @@ -68584,10 +76731,10 @@ public: 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(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(icelake::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -68603,6 +76750,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace icelake { @@ -68721,7 +76869,9 @@ public: 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 */ + /** @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; @@ -68809,6 +76959,11 @@ public: * 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 @@ -68816,10 +76971,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -68845,14 +77000,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -68954,13 +77111,39 @@ public: 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 @@ -68988,6 +77171,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for icelake */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for icelake: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for icelake */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 icelake { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(icelake::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 icelake { +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(const 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) + 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::icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::icelake::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for icelake */ + // All other declarations /* including simdjson/generic/ondemand/array.h for icelake: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for icelake */ @@ -69124,11 +77616,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -69202,7 +77725,28 @@ public: 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 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 @@ -69247,7 +77791,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -69271,6 +77816,11 @@ public: */ 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: value_iterator iter{}; @@ -69289,7 +77839,6 @@ namespace simdjson { template<> struct simdjson_result : public icelake::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(icelake::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -69302,6 +77851,8 @@ public: 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 @@ -69429,7 +77980,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -69495,7 +78046,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -69518,7 +78069,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -69536,18 +78087,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -69559,7 +78110,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -69569,7 +78120,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -69634,7 +78185,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -69643,7 +78194,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -69793,11 +78344,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -70021,11 +78588,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -70078,7 +78675,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -70087,7 +78684,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -70100,7 +78697,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -70122,14 +78719,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -70141,7 +78738,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -70151,12 +78748,17 @@ public: " 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_DESERIALIZATION +#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 @@ -70225,7 +78827,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -70238,6 +78840,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using icelake::implementation_simdjson_result_base::operator*; + using icelake::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator icelake::ondemand::array() & noexcept(false); @@ -70277,6 +78882,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -70303,7 +78913,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -70354,6 +78964,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -70496,6 +79111,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -70509,6 +79125,7 @@ public: * @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 * @@ -70552,6 +79169,11 @@ public: */ 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. */ @@ -70563,6 +79185,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -70826,6 +79449,9 @@ public: /* 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): #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 { @@ -71023,11 +79649,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -71066,12 +79752,42 @@ public: 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; - 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 @@ -71200,6 +79916,20 @@ inline simdjson_result to_json_string(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 /** @@ -71271,28 +80001,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -71306,7 +80038,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -71315,7 +80046,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -71328,8 +80058,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -71346,7 +80091,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -71355,9 +80099,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - icelake::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, icelake::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)); @@ -71388,7 +80136,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -71414,7 +80161,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, icelake::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)); + + icelake::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, icelake::ondemand::value &val, T &out) noexcept { + icelake::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, icelake::ondemand::document &doc, T &out) noexcept { + icelake::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, icelake::ondemand::document_reference &doc, T &out) noexcept { + icelake::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -71432,7 +80217,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -71457,17 +80241,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -71476,10 +80260,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + icelake::ondemand::object obj; + if constexpr (std::is_same_v, icelake::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for icelake */ // Inline definitions @@ -71572,7 +80675,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -71763,6 +80866,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace icelake } // namespace simdjson @@ -71799,7 +80905,9 @@ simdjson_inline simdjson_result &simdjson_res ++(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 @@ -71856,7 +80964,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -71898,15 +81006,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -72503,7 +81611,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -72529,15 +81637,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -72557,8 +81665,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -72607,7 +81715,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -72709,6 +81817,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 icelake } // namespace simdjson @@ -72816,7 +81972,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -72852,12 +82008,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -72867,8 +82023,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(icelake::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(icelake::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(icelake::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(icelake::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -72986,6 +82142,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -73020,7 +82185,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -73073,7 +82238,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 icelake } // namespace simdjson @@ -73170,7 +82341,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -73205,12 +82376,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -73227,13 +82398,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(icelake::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(icelake::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(icelake::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(icelake::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -73321,7 +82492,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -73512,10 +82690,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -73633,7 +82820,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -73879,7 +83069,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -74115,6 +83305,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -74239,7 +83431,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -74283,7 +83475,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -74306,7 +83498,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -74701,6 +83893,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -74758,7 +83954,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -74887,6 +84083,52 @@ 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 icelake } // namespace simdjson @@ -74963,6 +84205,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -75177,7 +84420,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -75209,10 +84452,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -75234,7 +84474,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -75249,6 +84489,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -75257,16 +84498,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -75301,6 +84550,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 icelake } // namespace simdjson @@ -75335,8 +84612,13 @@ 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 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}; @@ -75513,6 +84795,10 @@ simdjson_inline simdjson_result 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(icelake::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -75538,6 +84824,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -75903,7 +85192,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -76757,7 +86046,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -76919,7 +86208,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -76959,6 +86248,1097 @@ simdjson_inline simdjson_result::simdjson_res #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for icelake */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for icelake: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for icelake */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace icelake { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 icelake +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for icelake */ +/* including simdjson/generic/ondemand/json_builder.h for icelake: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for icelake */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 icelake { +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 simdjson_error 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 icelake +// 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 = icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + icelake::builder::string_builder b(initial_capacity); + icelake::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 simdjson_error 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; + 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 = icelake::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + icelake::builder::string_builder b(initial_capacity); + icelake::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/ondemand/json_builder.h for icelake */ /* end file simdjson/generic/ondemand/amalgamated.h for icelake */ /* including simdjson/icelake/end.h: #include "simdjson/icelake/end.h" */ @@ -77742,7 +88122,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote + simdjson_inline backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); simdjson_inline bool has_quote_first() { @@ -77783,6 +88163,32 @@ backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) { }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + // We store it as a 64-bit bitmask even though we only need 16 bits. + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace ppc64 } // namespace simdjson @@ -77851,7 +88257,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for ppc64 */ /* including simdjson/generic/ondemand/deserialize.h for ppc64: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for ppc64 */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -77860,55 +88266,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -77930,7 +88289,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -77941,28 +88300,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = ppc64::ondemand::array; + using object_type = ppc64::ondemand::object; using value_type = ppc64::ondemand::value; using document_type = ppc64::ondemand::document; using document_reference_type = ppc64::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -77972,7 +88347,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for ppc64 */ /* including simdjson/generic/ondemand/value_iterator.h for ppc64: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -78314,7 +88689,7 @@ public: 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_inline error_code error() const 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; @@ -78398,8 +88773,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -78409,8 +88784,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -78447,7 +88822,7 @@ protected: /** @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_inline error_code 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; @@ -78512,13 +88887,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -78535,22 +88911,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -78560,7 +88952,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -78678,7 +89070,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -79199,7 +89591,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -79280,7 +89672,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -79774,14 +90181,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -79801,7 +90208,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -79892,6 +90299,7 @@ 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, ... } ) @@ -80098,6 +90506,12 @@ public: */ 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, @@ -80237,10 +90651,10 @@ public: 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(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(ppc64::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -80256,6 +90670,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace ppc64 { @@ -80374,7 +90789,9 @@ public: 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 */ + /** @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; @@ -80462,6 +90879,11 @@ public: * 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 @@ -80469,10 +90891,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -80498,14 +90920,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -80607,13 +91031,39 @@ public: 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 @@ -80641,6 +91091,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for ppc64 */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for ppc64: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for ppc64 */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 ppc64 { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(ppc64::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 ppc64 { +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(const 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) + 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::ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::ppc64::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for ppc64 */ + // All other declarations /* including simdjson/generic/ondemand/array.h for ppc64: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for ppc64 */ @@ -80777,11 +91536,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -80855,7 +91645,28 @@ public: 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 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 @@ -80900,7 +91711,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -80924,6 +91736,11 @@ public: */ 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: value_iterator iter{}; @@ -80942,7 +91759,6 @@ namespace simdjson { template<> struct simdjson_result : public ppc64::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(ppc64::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -80955,6 +91771,8 @@ public: 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 @@ -81082,7 +91900,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -81148,7 +91966,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -81171,7 +91989,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -81189,18 +92007,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -81212,7 +92030,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -81222,7 +92040,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -81287,7 +92105,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -81296,7 +92114,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -81446,11 +92264,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -81674,11 +92508,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -81731,7 +92595,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -81740,7 +92604,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -81753,7 +92617,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -81775,14 +92639,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -81794,7 +92658,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -81804,12 +92668,17 @@ public: " 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_DESERIALIZATION +#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 @@ -81878,7 +92747,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -81891,6 +92760,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using ppc64::implementation_simdjson_result_base::operator*; + using ppc64::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator ppc64::ondemand::array() & noexcept(false); @@ -81930,6 +92802,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -81956,7 +92833,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -82007,6 +92884,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -82149,6 +93031,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -82162,6 +93045,7 @@ public: * @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 * @@ -82205,6 +93089,11 @@ public: */ 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. */ @@ -82216,6 +93105,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -82479,6 +93369,9 @@ public: /* 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): #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 { @@ -82676,11 +93569,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -82719,12 +93672,42 @@ public: 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; - 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 @@ -82853,6 +93836,20 @@ inline simdjson_result to_json_string(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 /** @@ -82924,28 +93921,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -82959,7 +93958,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -82968,7 +93966,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -82981,8 +93978,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -82999,7 +94011,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -83008,9 +94019,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - ppc64::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, ppc64::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)); @@ -83041,7 +94056,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -83067,7 +94081,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, ppc64::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)); + + ppc64::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, ppc64::ondemand::value &val, T &out) noexcept { + ppc64::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, ppc64::ondemand::document &doc, T &out) noexcept { + ppc64::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, ppc64::ondemand::document_reference &doc, T &out) noexcept { + ppc64::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -83085,7 +94137,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -83110,17 +94161,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -83129,10 +94180,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + ppc64::ondemand::object obj; + if constexpr (std::is_same_v, ppc64::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for ppc64 */ // Inline definitions @@ -83225,7 +94595,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -83416,6 +94786,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace ppc64 } // namespace simdjson @@ -83452,7 +94825,9 @@ simdjson_inline simdjson_result &simdjson_resul ++(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 @@ -83509,7 +94884,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -83551,15 +94926,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -84156,7 +95531,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -84182,15 +95557,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -84210,8 +95585,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -84260,7 +95635,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -84362,6 +95737,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 ppc64 } // namespace simdjson @@ -84469,7 +95892,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -84505,12 +95928,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -84520,8 +95943,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -84639,6 +96062,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -84673,7 +96105,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -84726,7 +96158,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 ppc64 } // namespace simdjson @@ -84823,7 +96261,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -84858,12 +96296,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -84880,13 +96318,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(ppc64::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -84974,7 +96412,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -85165,10 +96610,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -85286,7 +96740,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -85532,7 +96989,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -85768,6 +97225,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -85892,7 +97351,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -85936,7 +97395,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -85959,7 +97418,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -86354,6 +97813,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -86411,7 +97874,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -86540,6 +98003,52 @@ 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 ppc64 } // namespace simdjson @@ -86616,6 +98125,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -86830,7 +98340,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -86862,10 +98372,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -86887,7 +98394,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -86902,6 +98409,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -86910,16 +98418,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -86954,6 +98470,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 ppc64 } // namespace simdjson @@ -86988,8 +98532,13 @@ 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 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}; @@ -87166,6 +98715,10 @@ simdjson_inline simdjson_result 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(ppc64::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -87191,6 +98744,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -87556,7 +99112,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -88410,7 +99966,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -88572,7 +100128,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -88612,6 +100168,1097 @@ simdjson_inline simdjson_result::simdjson_resul #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for ppc64 */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for ppc64: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for ppc64 */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace ppc64 { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 ppc64 +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for ppc64 */ +/* including simdjson/generic/ondemand/json_builder.h for ppc64: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for ppc64 */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 ppc64 { +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 simdjson_error 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 ppc64 +// 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 = ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + ppc64::builder::string_builder b(initial_capacity); + ppc64::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 simdjson_error 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; + 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 = ppc64::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + ppc64::builder::string_builder b(initial_capacity); + ppc64::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/ondemand/json_builder.h for ppc64 */ /* end file simdjson/generic/ondemand/amalgamated.h for ppc64 */ /* including simdjson/ppc64/end.h: #include "simdjson/ppc64/end.h" */ @@ -89729,7 +102376,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -89755,6 +102402,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + uint64_t((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace westmere } // namespace simdjson @@ -89821,7 +102493,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for westmere */ /* including simdjson/generic/ondemand/deserialize.h for westmere: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for westmere */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -89830,55 +102502,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -89900,7 +102525,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -89911,28 +102536,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = westmere::ondemand::array; + using object_type = westmere::ondemand::object; using value_type = westmere::ondemand::value; using document_type = westmere::ondemand::document; using document_reference_type = westmere::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -89942,7 +102583,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for westmere */ /* including simdjson/generic/ondemand/value_iterator.h for westmere: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -90284,7 +102925,7 @@ public: 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_inline error_code error() const 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; @@ -90368,8 +103009,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -90379,8 +103020,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -90417,7 +103058,7 @@ protected: /** @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_inline error_code 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; @@ -90482,13 +103123,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -90505,22 +103147,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -90530,7 +103188,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -90648,7 +103306,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -91169,7 +103827,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -91250,7 +103908,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -91744,14 +104417,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -91771,7 +104444,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -91862,6 +104535,7 @@ 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, ... } ) @@ -92068,6 +104742,12 @@ public: */ 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, @@ -92207,10 +104887,10 @@ public: 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(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(westmere::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -92226,6 +104906,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace westmere { @@ -92344,7 +105025,9 @@ public: 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 */ + /** @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; @@ -92432,6 +105115,11 @@ public: * 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 @@ -92439,10 +105127,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -92468,14 +105156,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -92577,13 +105267,39 @@ public: 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 @@ -92611,6 +105327,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for westmere */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for westmere: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for westmere */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 westmere { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(westmere::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 westmere { +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(const 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) + 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::westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::westmere::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for westmere */ + // All other declarations /* including simdjson/generic/ondemand/array.h for westmere: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for westmere */ @@ -92747,11 +105772,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -92825,7 +105881,28 @@ public: 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 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 @@ -92870,7 +105947,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -92894,6 +105972,11 @@ public: */ 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: value_iterator iter{}; @@ -92912,7 +105995,6 @@ namespace simdjson { template<> struct simdjson_result : public westmere::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(westmere::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -92925,6 +106007,8 @@ public: 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 @@ -93052,7 +106136,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -93118,7 +106202,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -93141,7 +106225,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -93159,18 +106243,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -93182,7 +106266,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -93192,7 +106276,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -93257,7 +106341,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -93266,7 +106350,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -93416,11 +106500,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -93644,11 +106744,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -93701,7 +106831,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -93710,7 +106840,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -93723,7 +106853,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -93745,14 +106875,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -93764,7 +106894,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -93774,12 +106904,17 @@ public: " 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_DESERIALIZATION +#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 @@ -93848,7 +106983,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -93861,6 +106996,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using westmere::implementation_simdjson_result_base::operator*; + using westmere::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator westmere::ondemand::array() & noexcept(false); @@ -93900,6 +107038,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -93926,7 +107069,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -93977,6 +107120,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -94119,6 +107267,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -94132,6 +107281,7 @@ public: * @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 * @@ -94175,6 +107325,11 @@ public: */ 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. */ @@ -94186,6 +107341,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -94449,6 +107605,9 @@ public: /* 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): #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 { @@ -94646,11 +107805,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -94689,12 +107908,42 @@ public: 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; - 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 @@ -94823,6 +108072,20 @@ inline simdjson_result to_json_string(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 /** @@ -94894,28 +108157,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -94929,7 +108194,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -94938,7 +108202,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -94951,8 +108214,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -94969,7 +108247,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -94978,9 +108255,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - westmere::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, westmere::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)); @@ -95011,7 +108292,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -95037,7 +108317,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, westmere::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)); + + westmere::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, westmere::ondemand::value &val, T &out) noexcept { + westmere::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, westmere::ondemand::document &doc, T &out) noexcept { + westmere::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, westmere::ondemand::document_reference &doc, T &out) noexcept { + westmere::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -95055,7 +108373,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -95080,17 +108397,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -95099,10 +108416,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + westmere::ondemand::object obj; + if constexpr (std::is_same_v, westmere::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for westmere */ // Inline definitions @@ -95195,7 +108831,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -95386,6 +109022,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace westmere } // namespace simdjson @@ -95422,7 +109061,9 @@ simdjson_inline simdjson_result &simdjson_re ++(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 @@ -95479,7 +109120,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -95521,15 +109162,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -96126,7 +109767,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -96152,15 +109793,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -96180,8 +109821,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -96230,7 +109871,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -96332,6 +109973,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 westmere } // namespace simdjson @@ -96439,7 +110128,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -96475,12 +110164,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -96490,8 +110179,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(westmere::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(westmere::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(westmere::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(westmere::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -96609,6 +110298,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -96643,7 +110341,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -96696,7 +110394,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 westmere } // namespace simdjson @@ -96793,7 +110497,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -96828,12 +110532,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -96850,13 +110554,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(westmere::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(westmere::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(westmere::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(westmere::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -96944,7 +110648,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -97135,10 +110846,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -97256,7 +110976,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -97502,7 +111225,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -97738,6 +111461,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -97862,7 +111587,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -97906,7 +111631,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -97929,7 +111654,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -98324,6 +112049,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -98381,7 +112110,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -98510,6 +112239,52 @@ 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 westmere } // namespace simdjson @@ -98586,6 +112361,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -98800,7 +112576,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -98832,10 +112608,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -98857,7 +112630,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -98872,6 +112645,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -98880,16 +112654,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -98924,6 +112706,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 westmere } // namespace simdjson @@ -98958,8 +112768,13 @@ 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 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}; @@ -99136,6 +112951,10 @@ simdjson_inline simdjson_result 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(westmere::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -99161,6 +112980,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -99526,7 +113348,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -100380,7 +114202,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -100542,7 +114364,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -100582,6 +114404,1097 @@ simdjson_inline simdjson_result::simdjson_re #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for westmere */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for westmere: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for westmere */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace westmere { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 westmere +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for westmere */ +/* including simdjson/generic/ondemand/json_builder.h for westmere: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for westmere */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 westmere { +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 simdjson_error 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 westmere +// 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 = westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + westmere::builder::string_builder b(initial_capacity); + westmere::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 simdjson_error 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; + 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 = westmere::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + westmere::builder::string_builder b(initial_capacity); + westmere::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/ondemand/json_builder.h for westmere */ /* end file simdjson/generic/ondemand/amalgamated.h for westmere */ /* including simdjson/westmere/end.h: #include "simdjson/westmere/end.h" */ @@ -101171,7 +116084,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -101200,6 +116113,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + static_cast((is_backslash | is_quote | is_control).to_bitmask()) + }; +} + } // unnamed namespace } // namespace lsx } // namespace simdjson @@ -101268,7 +116206,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for lsx */ /* including simdjson/generic/ondemand/deserialize.h for lsx: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for lsx */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -101277,55 +116215,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -101347,7 +116238,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -101358,28 +116249,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = lsx::ondemand::array; + using object_type = lsx::ondemand::object; using value_type = lsx::ondemand::value; using document_type = lsx::ondemand::document; using document_reference_type = lsx::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -101389,7 +116296,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for lsx */ /* including simdjson/generic/ondemand/value_iterator.h for lsx: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -101731,7 +116638,7 @@ public: 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_inline error_code error() const 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; @@ -101815,8 +116722,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -101826,8 +116733,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -101864,7 +116771,7 @@ protected: /** @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_inline error_code 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; @@ -101929,13 +116836,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -101952,22 +116860,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -101977,7 +116901,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -102095,7 +117019,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -102616,7 +117540,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -102697,7 +117621,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -103191,14 +118130,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -103218,7 +118157,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -103309,6 +118248,7 @@ 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, ... } ) @@ -103515,6 +118455,12 @@ public: */ 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, @@ -103654,10 +118600,10 @@ public: 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(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(lsx::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -103673,6 +118619,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace lsx { @@ -103791,7 +118738,9 @@ public: 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 */ + /** @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; @@ -103879,6 +118828,11 @@ public: * 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 @@ -103886,10 +118840,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -103915,14 +118869,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -104024,13 +118980,39 @@ public: 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 @@ -104058,6 +119040,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for lsx */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for lsx: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for lsx */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 lsx { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(lsx::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 lsx { +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(const 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) + 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::lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::lsx::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for lsx */ + // All other declarations /* including simdjson/generic/ondemand/array.h for lsx: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for lsx */ @@ -104194,11 +119485,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -104272,7 +119594,28 @@ public: 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 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 @@ -104317,7 +119660,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -104341,6 +119685,11 @@ public: */ 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: value_iterator iter{}; @@ -104359,7 +119708,6 @@ namespace simdjson { template<> struct simdjson_result : public lsx::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(lsx::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -104372,6 +119720,8 @@ public: 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 @@ -104499,7 +119849,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -104565,7 +119915,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -104588,7 +119938,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -104606,18 +119956,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -104629,7 +119979,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -104639,7 +119989,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -104704,7 +120054,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -104713,7 +120063,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -104863,11 +120213,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -105091,11 +120457,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -105148,7 +120544,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -105157,7 +120553,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -105170,7 +120566,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -105192,14 +120588,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -105211,7 +120607,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -105221,12 +120617,17 @@ public: " 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_DESERIALIZATION +#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 @@ -105295,7 +120696,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -105308,6 +120709,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using lsx::implementation_simdjson_result_base::operator*; + using lsx::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator lsx::ondemand::array() & noexcept(false); @@ -105347,6 +120751,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -105373,7 +120782,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -105424,6 +120833,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -105566,6 +120980,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -105579,6 +120994,7 @@ public: * @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 * @@ -105622,6 +121038,11 @@ public: */ 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. */ @@ -105633,6 +121054,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -105896,6 +121318,9 @@ public: /* 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): #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 { @@ -106093,11 +121518,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -106136,12 +121621,42 @@ public: 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; - 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 @@ -106270,6 +121785,20 @@ inline simdjson_result to_json_string(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 /** @@ -106341,28 +121870,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -106376,7 +121907,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -106385,7 +121915,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -106398,8 +121927,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -106416,7 +121960,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -106425,9 +121968,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - lsx::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, lsx::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)); @@ -106458,7 +122005,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -106484,7 +122030,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, lsx::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)); + + lsx::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, lsx::ondemand::value &val, T &out) noexcept { + lsx::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, lsx::ondemand::document &doc, T &out) noexcept { + lsx::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, lsx::ondemand::document_reference &doc, T &out) noexcept { + lsx::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -106502,7 +122086,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -106527,17 +122110,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -106546,10 +122129,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + lsx::ondemand::object obj; + if constexpr (std::is_same_v, lsx::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for lsx */ // Inline definitions @@ -106642,7 +122544,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -106833,6 +122735,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace lsx } // namespace simdjson @@ -106869,7 +122774,9 @@ simdjson_inline simdjson_result &simdjson_result< ++(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 @@ -106926,7 +122833,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -106968,15 +122875,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -107573,7 +123480,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -107599,15 +123506,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -107627,8 +123534,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -107677,7 +123584,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -107779,6 +123686,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 lsx } // namespace simdjson @@ -107886,7 +123841,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -107922,12 +123877,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -107937,8 +123892,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(lsx::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(lsx::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lsx::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lsx::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -108056,6 +124011,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -108090,7 +124054,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -108143,7 +124107,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 lsx } // namespace simdjson @@ -108240,7 +124210,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -108275,12 +124245,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -108297,13 +124267,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(lsx::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lsx::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(lsx::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lsx::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -108391,7 +124361,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -108582,10 +124559,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -108703,7 +124689,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -108949,7 +124938,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -109185,6 +125174,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -109309,7 +125300,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -109353,7 +125344,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -109376,7 +125367,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -109771,6 +125762,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -109828,7 +125823,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -109957,6 +125952,52 @@ 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 lsx } // namespace simdjson @@ -110033,6 +126074,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -110247,7 +126289,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -110279,10 +126321,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -110304,7 +126343,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -110319,6 +126358,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -110327,16 +126367,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -110371,6 +126419,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 lsx } // namespace simdjson @@ -110405,8 +126481,13 @@ 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 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}; @@ -110583,6 +126664,10 @@ simdjson_inline simdjson_result 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(lsx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -110608,6 +126693,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -110973,7 +127061,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -111827,7 +127915,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -111989,7 +128077,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -112029,6 +128117,1097 @@ simdjson_inline simdjson_result::simdjson_result( #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for lsx */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for lsx: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for lsx */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace lsx { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 lsx +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for lsx */ +/* including simdjson/generic/ondemand/json_builder.h for lsx: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for lsx */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 lsx { +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 simdjson_error 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 lsx +// 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 = lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + lsx::builder::string_builder b(initial_capacity); + lsx::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 simdjson_error 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; + 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 = lsx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + lsx::builder::string_builder b(initial_capacity); + lsx::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/ondemand/json_builder.h for lsx */ /* end file simdjson/generic/ondemand/amalgamated.h for lsx */ /* including simdjson/lsx/end.h: #include "simdjson/lsx/end.h" */ @@ -112637,7 +129816,7 @@ using namespace simd; struct backslash_and_quote { public: static constexpr uint32_t BYTES_PROCESSED = 32; - simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst); + 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 bs_bits != 0; } @@ -112660,6 +129839,31 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin }; } + +struct escaping { + static constexpr uint32_t BYTES_PROCESSED = 16; + 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); } + + 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); + simd8 is_quote = (v == '"'); + simd8 is_backslash = (v == '\\'); + simd8 is_control = (v < 32); + return { + (is_backslash | is_quote | is_control).to_bitmask() + }; +} + } // unnamed namespace } // namespace lasx } // namespace simdjson @@ -112728,7 +129932,7 @@ class value_iterator; /* end file simdjson/generic/ondemand/base.h for lasx */ /* including simdjson/generic/ondemand/deserialize.h for lasx: #include "simdjson/generic/ondemand/deserialize.h" */ /* begin file simdjson/generic/ondemand/deserialize.h for lasx */ -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H /* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */ @@ -112737,55 +129941,8 @@ class value_iterator; /* amalgamation skipped (editor-only): #include "simdjson/generic/ondemand/array.h" */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ -#include namespace simdjson { -namespace tag_invoke_fn_ns { -void tag_invoke(); - -struct tag_invoke_fn { - template - requires requires(Tag tag, Args &&...args) { - tag_invoke(std::forward(tag), std::forward(args)...); - } - constexpr auto operator()(Tag tag, Args &&...args) const - noexcept(noexcept(tag_invoke(std::forward(tag), - std::forward(args)...))) - -> decltype(tag_invoke(std::forward(tag), - std::forward(args)...)) { - return tag_invoke(std::forward(tag), std::forward(args)...); - } -}; -} // namespace tag_invoke_fn_ns - -inline namespace tag_invoke_ns { -inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {}; -} // namespace tag_invoke_ns - -template -concept tag_invocable = requires(Tag tag, Args... args) { - tag_invoke(std::forward(tag), std::forward(args)...); -}; - -template -concept nothrow_tag_invocable = - tag_invocable && requires(Tag tag, Args... args) { - { - tag_invoke(std::forward(tag), std::forward(args)...) - } noexcept; - }; - -template -using tag_invoke_result = - std::invoke_result; - -template -using tag_invoke_result_t = - std::invoke_result_t; - -template using tag_t = std::decay_t; - - struct deserialize_tag; /// These types are deserializable in a built-in way @@ -112807,7 +129964,7 @@ template concept custom_deserializable = tag_invocable; template -concept deserializable = custom_deserializable || is_builtin_deserializable_v; +concept deserializable = custom_deserializable || is_builtin_deserializable_v || concepts::optional_type; template concept nothrow_custom_deserializable = nothrow_tag_invocable; @@ -112818,28 +129975,44 @@ concept nothrow_deserializable = nothrow_custom_deserializable || is_bu /// Deserialize Tag inline constexpr struct deserialize_tag { + using array_type = lasx::ondemand::array; + using object_type = lasx::ondemand::object; using value_type = lasx::ondemand::value; using document_type = lasx::ondemand::document; using document_reference_type = lasx::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 - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_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 - [[nodiscard]] constexpr /* error_code */ auto operator()(document_reference_type &object, T& output) const noexcept(nothrow_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); } @@ -112849,7 +130022,7 @@ inline constexpr struct deserialize_tag { } // namespace simdjson #endif // SIMDJSON_ONDEMAND_DESERIALIZE_H -#endif // SIMDJSON_SUPPORTS_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/deserialize.h for lasx */ /* including simdjson/generic/ondemand/value_iterator.h for lasx: #include "simdjson/generic/ondemand/value_iterator.h" */ @@ -113191,7 +130364,7 @@ public: 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_inline error_code error() const 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; @@ -113275,8 +130448,8 @@ protected: simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept; - simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept; - simdjson_inline error_code end_container() 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). @@ -113286,8 +130459,8 @@ protected: */ simdjson_inline simdjson_result advance_to_value() noexcept; - simdjson_inline error_code incorrect_type_error(const char *message) const noexcept; - simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const 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; /** @@ -113324,7 +130497,7 @@ protected: /** @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_inline error_code 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; @@ -113389,13 +130562,14 @@ public: * * 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -113412,22 +130586,38 @@ public: * 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_inline error_code get(T &out) -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION + #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 " @@ -113437,7 +130627,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -113555,7 +130745,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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. @@ -114076,7 +131266,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -114157,7 +131347,22 @@ public: simdjson_result operator[](int) noexcept = delete; /** - * Get the type of this JSON value. + * 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 @@ -114651,14 +131856,14 @@ public: * @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_inline error_code 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; /** * 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_inline error_code optional_error(error_code error, const char *message) noexcept; + 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 @@ -114678,7 +131883,7 @@ public: simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept; - simdjson_inline error_code consume_character(char c) 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; @@ -114769,6 +131974,7 @@ 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, ... } ) @@ -114975,6 +132181,12 @@ public: */ 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, @@ -115114,10 +132326,10 @@ public: 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(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept; simdjson_inline simdjson_warn_unused simdjson_result unescape_wobbly(lasx::ondemand::json_iterator &iter) const noexcept; }; - } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H @@ -115133,6 +132345,7 @@ public: /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ #include +#include namespace simdjson { namespace lasx { @@ -115251,7 +132464,9 @@ public: 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 */ + /** @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; @@ -115339,6 +132554,11 @@ public: * 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 @@ -115346,10 +132566,10 @@ public: * using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the * SIMDJSON_PADDING bytes to avoid runtime warnings. * - * ### Threads + * This is checked automatically with all iterate_many function calls, except for the two + * that take pointers (const char* or const uint8_t*). * - * When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the - * hood to do some lookahead. + * ### Threads * * ### Parser Capacity * @@ -115375,14 +132595,16 @@ public: */ 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; - inline simdjson_result iterate_many(const std::string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe + /** @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; - inline simdjson_result iterate_many(const padded_string &&s, size_t batch_size, bool allow_comma_separated = false) = delete;// unsafe - /** @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; @@ -115484,13 +132706,39 @@ public: 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 @@ -115518,6 +132766,315 @@ public: #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_H /* end file simdjson/generic/ondemand/parser.h for lasx */ +// JSON builder - needed for extract_into functionality +/* including simdjson/generic/ondemand/json_string_builder.h for lasx: #include "simdjson/generic/ondemand/json_string_builder.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder.h for lasx */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 lasx { +namespace builder { + class string_builder; +}} + +template +struct has_custom_serialization : std::false_type {}; + +inline constexpr struct serialize_tag { + template + requires custom_deserializable + constexpr void operator()(lasx::builder::string_builder& b, T& obj) const{ + return tag_invoke(*this, b, 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 lasx { +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(const 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) + 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::lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + simdjson::lasx::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 simdjson_error 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; + 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/ondemand/json_string_builder.h for lasx */ + // All other declarations /* including simdjson/generic/ondemand/array.h for lasx: #include "simdjson/generic/ondemand/array.h" */ /* begin file simdjson/generic/ondemand/array.h for lasx */ @@ -115654,11 +133211,42 @@ public: * - 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_inline error_code consume() noexcept; + simdjson_warn_unused simdjson_inline error_code consume() noexcept; /** * Begin array iteration. @@ -115732,7 +133320,28 @@ public: 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 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 @@ -115777,7 +133386,8 @@ public: * * Part of the std::iterator interface. */ - simdjson_inline simdjson_result operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. + simdjson_inline simdjson_result + operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION. /** * Check if we are at the end of the JSON. * @@ -115801,6 +133411,11 @@ public: */ 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: value_iterator iter{}; @@ -115819,7 +133434,6 @@ namespace simdjson { template<> struct simdjson_result : public lasx::implementation_simdjson_result_base { -public: simdjson_inline simdjson_result(lasx::ondemand::array_iterator &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; @@ -115832,6 +133446,8 @@ public: 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 @@ -115959,7 +133575,7 @@ public: * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * @@ -116025,7 +133641,7 @@ public: */ template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -116048,7 +133664,7 @@ public: */ template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -116066,18 +133682,18 @@ public: * 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 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_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -116089,7 +133705,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -116099,7 +133715,7 @@ public: " 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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ @@ -116164,7 +133780,7 @@ public: * 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_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * @@ -116173,7 +133789,7 @@ public: * @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_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * @@ -116323,11 +133939,27 @@ public: * 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). * - * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". + * 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; @@ -116551,11 +134183,41 @@ public: * 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -116608,7 +134270,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -116617,7 +134279,7 @@ public: simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -116630,7 +134292,7 @@ public: } template simdjson_inline simdjson_result get() && -#if SIMDJSON_SUPPORTS_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept @@ -116652,14 +134314,14 @@ public: * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template - simdjson_inline error_code get(T &out) & -#if SIMDJSON_SUPPORTS_DESERIALIZATION + 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_DESERIALIZATION +#if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { @@ -116671,7 +134333,7 @@ public: static_cast(out); // to get rid of unused errors return UNINITIALIZED; } -#else // SIMDJSON_SUPPORTS_DESERIALIZATION +#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. " @@ -116681,12 +134343,17 @@ public: " 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_DESERIALIZATION +#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 @@ -116755,7 +134422,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -116768,6 +134435,9 @@ public: template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS + + using lasx::implementation_simdjson_result_base::operator*; + using lasx::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator lasx::ondemand::array() & noexcept(false); @@ -116807,6 +134477,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -116833,7 +134508,7 @@ public: simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template - simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; + 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; @@ -116884,6 +134559,11 @@ public: simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(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 }; @@ -117026,6 +134706,7 @@ public: * Default constructor. */ simdjson_inline iterator() noexcept; + simdjson_inline iterator(const iterator &other) noexcept = default; /** * Get the current document (or error). */ @@ -117039,6 +134720,7 @@ public: * @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 * @@ -117082,6 +134764,11 @@ public: */ 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. */ @@ -117093,6 +134780,7 @@ public: friend class document_stream; friend class json_iterator; }; + using iterator = document_stream::iterator; /** * Start iterating the documents in the stream. @@ -117356,6 +135044,9 @@ public: /* 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): #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 { @@ -117553,11 +135244,71 @@ public: */ 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: + * ```c++ + * 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_inline error_code consume() noexcept; + 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; @@ -117596,12 +135347,42 @@ public: 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; - 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 @@ -117730,6 +135511,20 @@ inline simdjson_result to_json_string(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 /** @@ -117801,28 +135596,30 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result #include +#if SIMDJSON_STATIC_REFLECTION +#include +// #include // for std::define_static_string - header not available yet +#endif namespace simdjson { -template -constexpr bool require_custom_serialization = false; ////////////////////////////// // Number deserialization ////////////////////////////// template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -117836,7 +135633,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { double x; SIMDJSON_TRY(val.get_double().get(x)); @@ -117845,7 +135641,6 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { } template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { using limits = std::numeric_limits; @@ -117858,8 +135653,23 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { 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 - requires(!require_custom_serialization) 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)); @@ -117876,7 +135686,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothr * doc.get>(). */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::value_type; static_assert( @@ -117885,9 +135694,13 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { static_assert( std::is_default_constructible_v, "The specified type inside the container must default constructible."); - lasx::ondemand::array arr; - SIMDJSON_TRY(val.get_array().get(arr)); + if constexpr (std::is_same_v, lasx::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)); @@ -117918,7 +135731,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * string-keyed types. */ template - requires(!require_custom_serialization) error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { using value_type = typename std::remove_cvref_t::mapped_type; static_assert( @@ -117944,7 +135756,45 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { return SUCCESS; } +template +error_code tag_invoke(deserialize_tag, lasx::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)); + + lasx::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, lasx::ondemand::value &val, T &out) noexcept { + lasx::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, lasx::ondemand::document &doc, T &out) noexcept { + lasx::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} + +template +error_code tag_invoke(deserialize_tag, lasx::ondemand::document_reference &doc, T &out) noexcept { + lasx::ondemand::object obj; + SIMDJSON_TRY(doc.get_object().get(obj)); + return simdjson::deserialize(obj, out); +} /** @@ -117962,7 +135812,6 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) { * @return status of the conversion */ template - requires(!require_custom_serialization) 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; @@ -117987,17 +135836,17 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser /** * This CPO (Customization Point Object) will help deserialize into optional types. */ -template - requires(!require_custom_serialization) -error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable::value_type, ValT>) { +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; - 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."); + // 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(); @@ -118006,10 +135855,329 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deser 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 { + lasx::ondemand::object obj; + if constexpr (std::is_same_v, lasx::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_DESERIALIZATION +#endif // SIMDJSON_SUPPORTS_CONCEPTS /* end file simdjson/generic/ondemand/std_deserialize.h for lasx */ // Inline definitions @@ -118102,7 +136270,7 @@ simdjson_inline simdjson_result array::begin() noexcept { simdjson_inline simdjson_result array::end() noexcept { return array_iterator(iter); } -simdjson_inline error_code array::consume() noexcept { +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; @@ -118293,6 +136461,9 @@ simdjson_inline array_iterator &array_iterator::operator++() noexcept { return *this; } +simdjson_inline bool array_iterator::at_end() const noexcept { + return iter.at_end(); +} } // namespace ondemand } // namespace lasx } // namespace simdjson @@ -118329,7 +136500,9 @@ simdjson_inline simdjson_result &simdjson_result ++(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 @@ -118386,7 +136559,7 @@ simdjson_inline simdjson_result value::get_string(bool allow_r return iter.get_string(allow_replacement); } template -simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -118428,15 +136601,15 @@ template<> simdjson_inline simdjson_result value::get() noexcept { retu template<> simdjson_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); } -template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); } -template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); } -template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); } -template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); } +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 @@ -119033,7 +137206,7 @@ simdjson_inline simdjson_result document::get_string(bool allo return get_root_value_iterator().get_root_string(true, allow_replacement); } template -simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept { +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 { @@ -119059,15 +137232,15 @@ template<> simdjson_inline simdjson_result document::get() & noexcept { template<> simdjson_inline simdjson_result document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result document::get() & noexcept { return get_value(); } -template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); } -template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); } -template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); } -template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); } -template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); } -template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); } -template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); } -template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); } -template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); } +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); } @@ -119087,8 +137260,8 @@ simdjson_inline document::operator object() & noexcept(false) { return get_objec 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) { return get_string(false); } -simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); } +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(); } @@ -119137,7 +137310,7 @@ simdjson_inline simdjson_result document::operator[](const char *key) & n return start_or_resume_object()[key]; } -simdjson_inline error_code document::consume() noexcept { +simdjson_warn_unused simdjson_inline error_code document::consume() noexcept { bool scalar = false; auto error = is_scalar().get(scalar); if(error) { return error; } @@ -119239,6 +137412,54 @@ simdjson_inline simdjson_result document::at_path(std::string_view json_p } } + + +#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 lasx } // namespace simdjson @@ -119346,7 +137567,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -119382,12 +137603,12 @@ simdjson_deprecated simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -119397,8 +137618,8 @@ template<> simdjson_deprecated simdjson_inline simdjson_result(first); } -template<> simdjson_inline error_code simdjson_result::get(lasx::ondemand::document &out) & noexcept = delete; -template<> simdjson_inline error_code simdjson_result::get(lasx::ondemand::document &out) && noexcept { +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lasx::ondemand::document &out) & noexcept = delete; +template<> simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lasx::ondemand::document &out) && noexcept { if (error()) { return error(); } out = std::forward(first); return SUCCESS; @@ -119516,6 +137737,15 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -119550,7 +137780,7 @@ simdjson_inline simdjson_result document_reference::get_double() noexcep 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_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_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); } @@ -119603,7 +137833,13 @@ simdjson_inline simdjson_result document_reference::at_pointer(std::strin 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::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 lasx } // namespace simdjson @@ -119700,7 +137936,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get_string(string_type& receiver, bool allow_replacement) noexcept { +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); } @@ -119735,12 +137971,12 @@ simdjson_inline simdjson_result simdjson_result(first).get(); } template -simdjson_inline error_code simdjson_result::get(T &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) & noexcept { if (error()) { return error(); } return first.get(out); } template -simdjson_inline error_code simdjson_result::get(T &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(T &out) && noexcept { if (error()) { return error(); } return std::forward(first).get(out); } @@ -119757,13 +137993,13 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::get(lasx::ondemand::document_reference &out) & noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lasx::ondemand::document_reference &out) & noexcept { if (error()) { return error(); } out = first; return SUCCESS; } template <> -simdjson_inline error_code simdjson_result::get(lasx::ondemand::document_reference &out) && noexcept { +simdjson_warn_unused simdjson_inline error_code simdjson_result::get(lasx::ondemand::document_reference &out) && noexcept { if (error()) { return error(); } out = first; return SUCCESS; @@ -119851,7 +138087,14 @@ simdjson_inline simdjson_result simdjson_result + 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 @@ -120042,10 +138285,19 @@ simdjson_inline document_stream::iterator& document_stream::iterator::operator++ 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. @@ -120163,7 +138415,10 @@ inline void document_stream::next_document() noexcept { // Always set depth=1 at the start of document doc.iter._depth = 1; // consume comma if comma separated is allowed - if (allow_comma_separated) { doc.iter.consume_character(','); } + 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(); @@ -120409,7 +138664,7 @@ simdjson_inline simdjson_result simdjson_result -simdjson_inline error_code simdjson_result::unescaped_key(string_type &receiver, bool allow_replacement) noexcept { +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); } @@ -120645,6 +138900,8 @@ simdjson_inline void json_iterator::assert_valid_position(token_position positio #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] ); +#else + (void)position; // Suppress unused parameter warning #endif } @@ -120769,7 +139026,7 @@ simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept { return _string_buf_loc; } -simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept { +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; @@ -120813,7 +139070,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth _depth = child_depth; } -simdjson_inline error_code json_iterator::consume_character(char c) noexcept { +simdjson_warn_unused simdjson_inline error_code json_iterator::consume_character(char c) noexcept { if (*peek() == c) { return_current_and_advance(); return SUCCESS; @@ -120836,7 +139093,7 @@ simdjson_inline void json_iterator::set_start_position(depth_t depth, token_posi #endif -simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept { +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; @@ -121231,6 +139488,10 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de /* 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): #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 { @@ -121288,7 +139549,7 @@ simdjson_inline simdjson_result object::start_root(value_iterator &iter) SIMDJSON_TRY( iter.start_root_object().error() ); return object(iter); } -simdjson_inline error_code object::consume() noexcept { +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 @@ -121417,6 +139678,52 @@ 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 lasx } // namespace simdjson @@ -121493,6 +139800,7 @@ simdjson_inline simdjson_result simdjson_result parser::iterate(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -121707,7 +140015,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(p #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.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -121739,10 +140047,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(s } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { - if(json.capacity() - json.size() < SIMDJSON_PADDING) { - json.reserve(json.size() + SIMDJSON_PADDING); - } - return iterate(padded_string_view(json)); + return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { @@ -121764,7 +140069,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(c } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { - if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; } + if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); @@ -121779,6 +140084,7 @@ simdjson_warn_unused simdjson_inline simdjson_result parser::iter } 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; @@ -121787,16 +140093,24 @@ inline simdjson_result parser::iterate_many(const uint8_t *buf, 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(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { +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(s.data(), s.length(), batch_size, allow_comma_separated); + 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; } @@ -121831,6 +140145,34 @@ simdjson_inline simdjson_warn_unused simdjson_result parser::u 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 lasx } // namespace simdjson @@ -121865,8 +140207,13 @@ 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 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}; @@ -122043,6 +140390,10 @@ simdjson_inline simdjson_result 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(lasx::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); @@ -122068,6 +140419,9 @@ simdjson_inline simdjson_warn_unused simdjson_result simdjson_ /* 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/ondemand/json_builder.h" */ +/* amalgamation skipped (editor-only): #endif */ /* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */ namespace simdjson { @@ -122433,7 +140787,7 @@ simdjson_warn_unused simdjson_inline simdjson_result value_iterator::start if (*_json_iter->peek() == '}') { logger::log_value(*_json_iter, "empty object"); _json_iter->return_current_and_advance(); - end_container(); + SIMDJSON_TRY(end_container()); return false; } return true; @@ -123287,7 +141641,7 @@ simdjson_inline void value_iterator::advance_scalar(const char *type) noexcept { _json_iter->ascend_to(depth()-1); } -simdjson_inline error_code value_iterator::start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept { +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; @@ -123449,7 +141803,7 @@ simdjson_inline simdjson_result value_iterator::type() const noexcept case '5': case '6': case '7': case '8': case '9': return json_type::number; default: - return TAPE_ERROR; + return json_type::unknown; } } @@ -123489,6 +141843,1097 @@ simdjson_inline simdjson_result::simdjson_result #endif // SIMDJSON_GENERIC_ONDEMAND_VALUE_ITERATOR_INL_H /* end file simdjson/generic/ondemand/value_iterator-inl.h for lasx */ +// JSON builder inline definitions +/* including simdjson/generic/ondemand/json_string_builder-inl.h for lasx: #include "simdjson/generic/ondemand/json_string_builder-inl.h" */ +/* begin file simdjson/generic/ondemand/json_string_builder-inl.h for lasx */ +/** + * This file is part of the builder API. It is temporarily in the ondemand + * directory but we will move it to a builder directory later. + */ +#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 +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 +#include +#endif + +namespace simdjson { +namespace lasx { +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 + +SIMDJSON_CONSTEXPR_LAMBDA inline size_t +find_next_json_quotable_character(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()); +} + +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 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(); + } +} + +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! + 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); + 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) { + 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; + 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) { + 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); + if (negative) { + buffer.get()[position++] = '-'; + } + char *write_pointer = buffer.get() + position + dc - 1; + 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(const T &val) { + serialize(*this, 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) +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 lasx +} // namespace simdjson + +#endif // SIMDJSON_GENERIC_STRING_BUILDER_INL_H +/* end file simdjson/generic/ondemand/json_string_builder-inl.h for lasx */ +/* including simdjson/generic/ondemand/json_builder.h for lasx: #include "simdjson/generic/ondemand/json_builder.h" */ +/* begin file simdjson/generic/ondemand/json_builder.h for lasx */ +/** + * This file is part of the builder API. It is temporarily in the ondemand directory + * but we will move it to a builder directory later. + */ +#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 lasx { +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 simdjson_error 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 lasx +// 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 = lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + lasx::builder::string_builder b(initial_capacity); + lasx::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 simdjson_error 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; + 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 = lasx::builder::string_builder::DEFAULT_INITIAL_CAPACITY) { + lasx::builder::string_builder b(initial_capacity); + lasx::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/ondemand/json_builder.h for lasx */ /* end file simdjson/generic/ondemand/amalgamated.h for lasx */ /* including simdjson/lasx/end.h: #include "simdjson/lasx/end.h" */ @@ -123526,9 +142971,297 @@ namespace simdjson { * @copydoc simdjson::builtin::ondemand */ namespace ondemand = builtin::ondemand; + /** + * @copydoc simdjson::builtin::builder + */ + namespace builder = builtin::builder; + +#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) { + builder::string_builder str_builder; + append(str_builder, obj); + std::string_view view; + if (str_builder.view().get(view) == SUCCESS) { + return std::string(view); + } + return ""; + } +#endif + } // namespace simdjson #endif // SIMDJSON_ONDEMAND_H /* end file simdjson/ondemand.h */ +/* including simdjson/convert.h: #include "simdjson/convert.h" */ +/* begin file simdjson/convert.h */ + +#ifndef SIMDJSON_CONVERT_H +#define SIMDJSON_CONVERT_H + +/* skipped duplicate #include "simdjson/ondemand.h" */ +#include + +#if SIMDJSON_SUPPORTS_CONCEPTS + + +namespace simdjson { +namespace convert { +namespace internal { + +/** + * A utility class for automatically parsing JSON documents. + * This template is NOT part of our public API. + * It is subject to changes. + * @private + */ +template +struct auto_parser { +private: + parser_type m_parser; + ondemand::document m_doc; + error_code m_error{SUCCESS}; + + template + static constexpr bool is_nothrow_gettable = requires(ondemand::document doc) { + { doc.get() } noexcept; + }; +public: + explicit auto_parser(parser_type &&parser, ondemand::document &&doc) noexcept requires(!std::is_pointer_v); + explicit auto_parser(parser_type &&parser, padded_string_view const str) noexcept requires(!std::is_pointer_v); + explicit auto_parser(std::remove_pointer_t &parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v); + explicit auto_parser(std::remove_pointer_t &parser, padded_string_view const str) noexcept requires(std::is_pointer_v); + explicit auto_parser(padded_string_view const str) noexcept requires(std::is_pointer_v); + explicit auto_parser(parser_type parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v); + auto_parser(auto_parser const &) = delete; + auto_parser &operator=(auto_parser const &) = delete; + auto_parser(auto_parser &&) noexcept = default; + auto_parser &operator=(auto_parser &&) noexcept = default; + ~auto_parser() = default; + + simdjson_warn_unused std::remove_pointer_t &parser() noexcept; + + template + simdjson_warn_unused simdjson_inline simdjson_result result() noexcept(is_nothrow_gettable); + template + simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept(is_nothrow_gettable); + + + simdjson_warn_unused simdjson_inline simdjson_result array() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result object() noexcept; + simdjson_warn_unused simdjson_inline simdjson_result number() noexcept; + + +#if SIMDJSON_EXCEPTIONS + template + simdjson_warn_unused simdjson_inline explicit(false) operator T() noexcept(false); +#endif // SIMDJSON_EXCEPTIONS + + template + simdjson_warn_unused simdjson_inline std::optional optional() noexcept(is_nothrow_gettable); +}; + + +/** + * A utility class for adapting values for the `auto_parser`. + * This template is not part of our public API. It is subject to changes. + * @private + */ +template +struct to_adaptor { + T operator()(simdjson_result &val) const noexcept; + auto operator()(padded_string_view const str) const noexcept; + auto operator()(ondemand::parser &parser, padded_string_view const str) const noexcept; + // The std::string is padded with reserve to ensure there is enough space for padding. + // Some sanitizers may not like this, so you can use simdjson::pad instead. + // simdjson::from(simdjson::pad(str)) + auto operator()(std::string str) const noexcept; + auto operator()(ondemand::parser &parser, std::string str) const noexcept; +}; +// deduction guide +auto_parser(padded_string_view const str) -> auto_parser; +} // namespace internal +} // namespace convert + +/** + * The simdjson::from instance is EXPERIMENTAL AND SUBJECT TO CHANGES. + * + * The `from` instance is a utility adaptor for parsing JSON strings into objects. + * It provides a convenient way to convert JSON data into C++ objects using the `auto_parser`. + * + * Example usage: + * + * ```cpp + * std::map obj = + * simdjson::from(R"({"key": "value"})"_padded); + * ``` + * + * This will parse the JSON string and return an object representation. By default, we + * use the simdjson::ondemand::parser::get_parser() instance. A parser instance should + * be used for just one document at a time. + * + * You can also pass you own parser instance: + * ```cpp + * simdjson::ondemand::parser parser; + * std::map obj = + * simdjson::from(parser, R"({"key": "value"})"_padded); + * ``` + * The parser instance can be reused. + * + * This functionality requires C++20 or better. + */ +static constexpr convert::internal::to_adaptor<> from{}; + +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_CONCEPTS +#endif // SIMDJSON_CONVERT_H +/* end file simdjson/convert.h */ +/* including simdjson/convert-inl.h: #include "simdjson/convert-inl.h" */ +/* begin file simdjson/convert-inl.h */ + +#ifndef SIMDJSON_CONVERT_INL_H +#define SIMDJSON_CONVERT_INL_H + +/* skipped duplicate #include "simdjson/convert.h" */ +#if SIMDJSON_SUPPORTS_CONCEPTS +namespace simdjson { +namespace convert { +namespace internal { +// auto_parser method definitions +template +inline auto_parser::auto_parser(parser_type &&parser, ondemand::document &&doc) noexcept requires(!std::is_pointer_v) + : m_parser{std::move(parser)}, m_doc{std::move(doc)} {} + +template +inline auto_parser::auto_parser(parser_type &&parser, padded_string_view const str) noexcept requires(!std::is_pointer_v) + : m_parser{std::move(parser)}, m_doc{}, m_error{SUCCESS} { + m_error = m_parser.iterate(str).get(m_doc); +} + +template +inline auto_parser::auto_parser(std::remove_pointer_t &parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v) + : m_parser{&parser}, m_doc{std::move(doc)} {} + +template +inline auto_parser::auto_parser(std::remove_pointer_t &parser, padded_string_view const str) noexcept requires(std::is_pointer_v) + : m_parser{&parser}, m_doc{}, m_error{SUCCESS} { + m_error = m_parser->iterate(str).get(m_doc); +} + +template +inline auto_parser::auto_parser(padded_string_view const str) noexcept requires(std::is_pointer_v) + : auto_parser{ondemand::parser::get_parser(), str} {} + +template +inline auto_parser::auto_parser(parser_type parser, ondemand::document &&doc) noexcept requires(std::is_pointer_v) + : auto_parser{*parser, std::move(doc)} {} + + + + + +template +inline std::remove_pointer_t &auto_parser::parser() noexcept { + if constexpr (std::is_pointer_v) { + return *m_parser; + } else { + return m_parser; + } +} + +template +template +inline simdjson_result auto_parser::result() noexcept(is_nothrow_gettable) { + if (m_error != SUCCESS) { + return m_error; + } + return m_doc.get(); +} + +template +template +simdjson_warn_unused simdjson_inline error_code auto_parser::get(T &value) && noexcept(is_nothrow_gettable) { + return result().get(value); +} + +template +inline simdjson_result auto_parser::array() noexcept { + return result(); +} + +template +inline simdjson_result auto_parser::object() noexcept { + return result(); +} + +template +inline simdjson_result auto_parser::number() noexcept { + return result(); +} + +#if SIMDJSON_EXCEPTIONS +template +template +inline auto_parser::operator T() noexcept(false) { + if (m_error != SUCCESS) { + throw simdjson_error(m_error); + } + return m_doc.get(); +} +#endif // SIMDJSON_EXCEPTIONS + +template +template +inline std::optional auto_parser::optional() noexcept(is_nothrow_gettable) { + if (m_error != SUCCESS) { + return std::nullopt; + } + T value; + if (m_doc.get().get(value)) [[unlikely]] { + return std::nullopt; + } + return {std::move(value)}; +} + +// to_adaptor method definitions +template +inline T to_adaptor::operator()(simdjson_result &val) const noexcept { + return val.get(); +} + +template +inline auto to_adaptor::operator()(padded_string_view const str) const noexcept { + return auto_parser{str}; +} + +template +inline auto to_adaptor::operator()(ondemand::parser &parser, padded_string_view const str) const noexcept { + return auto_parser{parser, str}; +} + +template +inline auto to_adaptor::operator()(std::string str) const noexcept { + return auto_parser{pad_with_reserve(str)}; +} + +template +inline auto to_adaptor::operator()(ondemand::parser &parser, std::string str) const noexcept { + return auto_parser{parser, pad_with_reserve(str)}; +} +} // namespace internal +} // namespace convert +} // namespace simdjson +#endif // SIMDJSON_SUPPORTS_CONCEPTS +#endif // SIMDJSON_CONVERT_INL_H +/* end file simdjson/convert-inl.h */ #endif // SIMDJSON_H /* end file simdjson.h */