diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp index 0374b89f39c2d3..8f3305987681e6 100644 --- a/deps/simdjson/simdjson.cpp +++ b/deps/simdjson/simdjson.cpp @@ -1,4 +1,4 @@ -/* auto-generated on 2026-02-20 16:16:37 -0500. version 4.3.1 Do not edit! */ +/* auto-generated on 2026-03-25 17:25:37 -0400. version 4.5.0 Do not edit! */ /* including simdjson.cpp: */ /* begin file simdjson.cpp */ #define SIMDJSON_SRC_SIMDJSON_CPP @@ -146,7 +146,6 @@ #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 */ /* including simdjson/portability.h: #include "simdjson/portability.h" */ @@ -219,6 +218,25 @@ using std::size_t; #define SIMDJSON_IS_LASX 1 // We can always run both #elif defined(__loongarch_sx) #define SIMDJSON_IS_LSX 1 + +// Adjust for runtime dispatching support. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__NVCOMPILER) +#if __GNUC__ > 15 || (__GNUC__ == 15 && __GNUC_MINOR__ >= 0) + // We are ok, we will support runtime dispatch for LASX. +#else + // We disable runtime dispatch for LASX, which means that we will not be able to use LASX + // even if it is supported by the hardware. + // Loongson users should update to GCC 15 or better. + #define SIMDJSON_IMPLEMENTATION_LASX 0 +#endif +#else + // We are not using GCC, so we assume that we can support runtime dispatch for LASX. + // https://godbolt.org/z/jcMnrjYhs + #define SIMDJSON_IMPLEMENTATION_LASX 0 +#endif + + + #endif #elif defined(__PPC64__) || defined(_M_PPC64) #define SIMDJSON_IS_PPC64 1 @@ -7290,6 +7308,12 @@ class dom_parser_implementation { */ size_t _max_depth{0}; +public: + /** Whether to store big integers as strings instead of returning BIGINT_ERROR */ + bool _number_as_string{false}; + +protected: + // Declaring these so that subclasses can use them to implement their constructors. simdjson_inline dom_parser_implementation() noexcept; simdjson_inline dom_parser_implementation(dom_parser_implementation &&other) noexcept; @@ -7865,7 +7889,8 @@ enum class tape_type { DOUBLE = 'd', TRUE_VALUE = 't', FALSE_VALUE = 'f', - NULL_VALUE = 'n' + NULL_VALUE = 'n', + BIGINT = 'Z' // Big integer stored as string in string buffer }; // enum class tape_type } // namespace internal @@ -14160,6 +14185,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -14243,6 +14271,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace arm64 @@ -15180,7 +15220,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -20521,6 +20577,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -20604,6 +20663,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace haswell @@ -21541,7 +21612,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -26877,6 +26964,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -26960,6 +27050,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace icelake @@ -27897,7 +27999,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -33504,6 +33622,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -33587,6 +33708,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace ppc64 @@ -34524,7 +34657,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -40693,6 +40842,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -40776,6 +40928,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace westmere @@ -41713,7 +41877,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -46913,6 +47093,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -46996,6 +47179,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace lasx @@ -47933,7 +48128,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -53037,6 +53248,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -53120,6 +53334,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace lsx @@ -54057,7 +54283,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -59580,6 +59822,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -59663,6 +59908,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace rvv_vls @@ -60600,7 +60857,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { @@ -60938,6 +61211,19 @@ simdjson_inline int leading_zeroes(uint64_t input_num) { #endif// _MSC_VER } +simdjson_inline int trailing_zeroes(uint64_t input_num) { +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + // Search the mask data from least significant bit (LSB) + // to most significant bit (MSB) for a set bit (1). + if (_BitScanForward64(&trailing_zero, input_num)) + return (int)trailing_zero; + else return 64; +#else + return __builtin_ctzll(input_num); +#endif// _MSC_VER +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -63169,6 +63455,19 @@ simdjson_inline int leading_zeroes(uint64_t input_num) { #endif// _MSC_VER } +simdjson_inline int trailing_zeroes(uint64_t input_num) { +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + // Search the mask data from least significant bit (LSB) + // to most significant bit (MSB) for a set bit (1). + if (_BitScanForward64(&trailing_zero, input_num)) + return (int)trailing_zero; + else return 64; +#else + return __builtin_ctzll(input_num); +#endif// _MSC_VER +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -64145,6 +64444,9 @@ struct tape_writer { /** Write a double value to tape. */ simdjson_inline void append_double(double value) noexcept; + /** Write a big integer (as string) to tape. src points to first digit, len is byte count. */ + simdjson_inline void append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept; + /** * Append a tape entry (an 8-bit type,and 56 bits worth of value). */ @@ -64228,6 +64530,18 @@ simdjson_inline void tape_writer::write(uint64_t &tape_loc, uint64_t val, intern tape_loc = val | ((uint64_t(char(t))) << 56); } +simdjson_inline void tape_writer::append_bigint(const uint8_t *src, size_t len, uint8_t *&string_buf) noexcept { + // Write to string buffer: [4-byte LE length][digits][null] + uint32_t str_len = uint32_t(len); + memcpy(string_buf, &str_len, sizeof(uint32_t)); + memcpy(string_buf + sizeof(uint32_t), src, len); + string_buf[sizeof(uint32_t) + len] = 0; + // Tape entry: offset into string buffer + // The caller must set the offset relative to doc.string_buf base + append(0, internal::tape_type::BIGINT); // placeholder offset, caller patches + string_buf += sizeof(uint32_t) + len + 1; +} + } // namespace stage2 } // unnamed namespace } // namespace fallback @@ -64411,7 +64725,23 @@ simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_string( simdjson_warn_unused simdjson_inline error_code tape_builder::visit_number(json_iterator &iter, const uint8_t *value) noexcept { iter.log_value("number"); - return numberparsing::parse_number(value, tape); + error_code err = numberparsing::parse_number(value, tape); + if (simdjson_unlikely(err == BIGINT_ERROR && + iter.dom_parser._number_as_string)) { + // Write big integer to string buffer using the same format as strings. + // Scan digits the same way parse_number does (skip optional '-', then digits). + const uint8_t *p = value; + if (*p == '-') p++; + while (numberparsing::is_digit(*p)) p++; + size_t len = size_t(p - value); + tape.append(current_string_buf_loc - iter.dom_parser.doc->string_buf.get(), internal::tape_type::BIGINT); + uint8_t *dst = current_string_buf_loc + sizeof(uint32_t); + memcpy(dst, value, len); + dst += len; + on_end_string(dst); + return SUCCESS; + } + return err; } simdjson_warn_unused simdjson_inline error_code tape_builder::visit_root_number(json_iterator &iter, const uint8_t *value) noexcept { diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h index cf2658af259b79..3a413a7d1e046e 100644 --- a/deps/simdjson/simdjson.h +++ b/deps/simdjson/simdjson.h @@ -1,4 +1,4 @@ -/* auto-generated on 2026-02-20 16:16:37 -0500. version 4.3.1 Do not edit! */ +/* auto-generated on 2026-03-25 17:25:37 -0400. version 4.5.0 Do not edit! */ /* including simdjson.h: */ /* begin file simdjson.h */ #ifndef SIMDJSON_H @@ -166,7 +166,6 @@ #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 */ /* including simdjson/portability.h: #include "simdjson/portability.h" */ @@ -239,6 +238,25 @@ using std::size_t; #define SIMDJSON_IS_LASX 1 // We can always run both #elif defined(__loongarch_sx) #define SIMDJSON_IS_LSX 1 + +// Adjust for runtime dispatching support. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__NVCOMPILER) +#if __GNUC__ > 15 || (__GNUC__ == 15 && __GNUC_MINOR__ >= 0) + // We are ok, we will support runtime dispatch for LASX. +#else + // We disable runtime dispatch for LASX, which means that we will not be able to use LASX + // even if it is supported by the hardware. + // Loongson users should update to GCC 15 or better. + #define SIMDJSON_IMPLEMENTATION_LASX 0 +#endif +#else + // We are not using GCC, so we assume that we can support runtime dispatch for LASX. + // https://godbolt.org/z/jcMnrjYhs + #define SIMDJSON_IMPLEMENTATION_LASX 0 +#endif + + + #endif #elif defined(__PPC64__) || defined(_M_PPC64) #define SIMDJSON_IS_PPC64 1 @@ -2520,7 +2538,7 @@ namespace std { #define SIMDJSON_SIMDJSON_VERSION_H /** The version of simdjson being used (major.minor.revision) */ -#define SIMDJSON_VERSION "4.3.1" +#define SIMDJSON_VERSION "4.5.0" namespace simdjson { enum { @@ -2531,11 +2549,11 @@ enum { /** * The minor version (major.MINOR.revision) of simdjson being used. */ - SIMDJSON_VERSION_MINOR = 3, + SIMDJSON_VERSION_MINOR = 5, /** * The revision (major.minor.REVISION) of simdjson being used. */ - SIMDJSON_VERSION_REVISION = 1 + SIMDJSON_VERSION_REVISION = 0 }; } // namespace simdjson @@ -3774,6 +3792,12 @@ class dom_parser_implementation { */ size_t _max_depth{0}; +public: + /** Whether to store big integers as strings instead of returning BIGINT_ERROR */ + bool _number_as_string{false}; + +protected: + // Declaring these so that subclasses can use them to implement their constructors. simdjson_inline dom_parser_implementation() noexcept; simdjson_inline dom_parser_implementation(dom_parser_implementation &&other) noexcept; @@ -4326,6 +4350,62 @@ inline std::ostream& operator<<(std::ostream& out, const padded_string& s) { ret inline std::ostream& operator<<(std::ostream& out, simdjson_result &s) noexcept(false) { return out << s.value(); } #endif + +#ifndef _WIN32 +/** + * A class representing a memory-mapped file with padding. + * It is only available on non-Windows platforms, as Windows has different APIs for memory mapping. + */ +class padded_memory_map { +public: + /** + * Create a new padded memory map for the given file. + * After creating the memory map, you can call view() to get a padded_string_view of the file content. + * The memory map will be automatically released when the padded_memory_map instance is destroyed. + * Note that the file content is not copied, so this is efficient for large files. However, + * the file must remain unchanged while the memory map is in use. In case of error (e.g., file not found, + * permission denied, etc.), the memory map will be invalid and view() will return an empty view. + * You can check if the memory map is valid by calling is_valid() before using view(). + * + * @param filename the path to the file to memory-map. + */ + simdjson_inline padded_memory_map(const char *filename) noexcept; + /** + * Destroy the padded memory map and release any resources. + */ + simdjson_inline ~padded_memory_map() noexcept; + + // lifetime of the view is tied to the memory map, so we can return a view + // directly + /** + * Get a view of the memory-mapped file. It always succeeds, but the view may be empty + * if the memory map is invalid (e.g., due to file not found, permission denied, etc.). + * You can check if the memory map is valid by calling is_valid() before using the view. + * + * Lifetime of the view is tied to the memory map, so the view should not be used after the + * padded_memory_map instance is destroyed. + * + * @return a padded_string_view representing the memory-mapped file, or an empty view if the memory map is invalid. + */ + simdjson_inline simdjson::padded_string_view view() const noexcept simdjson_lifetime_bound; + /** + * Check if the memory map is valid. + * + * @return true if the memory map is valid, false otherwise. + */ + simdjson_inline bool is_valid() const noexcept; + +private: + padded_memory_map() = delete; + padded_memory_map(const padded_memory_map &) = delete; + padded_memory_map &operator=(const padded_memory_map &) = delete; + const char *data{nullptr}; + size_t size{0}; +}; +#endif // _WIN32 + + + } // namespace simdjson // This is deliberately outside of simdjson so that people get it without having to use the namespace @@ -4404,7 +4484,7 @@ namespace simdjson { */ class padded_string_view : public std::string_view { private: - size_t _capacity; + size_t _capacity{0}; public: /** Create an empty padded_string_view. */ @@ -4608,6 +4688,14 @@ inline padded_string_view pad_with_reserve(std::string& s) noexcept { #include #include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif + namespace simdjson { namespace internal { @@ -4964,6 +5052,57 @@ inline bool padded_string_builder::reserve(size_t additional) noexcept { return true; } + +#ifndef _WIN32 +simdjson_inline padded_memory_map::padded_memory_map(const char *filename) noexcept { + + int fd = open(filename, O_RDONLY); + if (fd == -1) { + return; // file not found or cannot be opened, data will be nullptr + } + struct stat st; + if (fstat(fd, &st) == -1) { + close(fd); + return; // failed to get file size, data will be nullptr + } + size = static_cast(st.st_size); + size_t total_size = size + simdjson::SIMDJSON_PADDING; + void *anon_map = + mmap(NULL, total_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (anon_map == MAP_FAILED) { + close(fd); + return; // failed to create anonymous mapping, data will be nullptr + } + void *file_map = + mmap(anon_map, size, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0); + if (file_map == MAP_FAILED) { + munmap(anon_map, total_size); + close(fd); + return; // failed to mmap file, data will be nullptr + } + data = static_cast(file_map); + close(fd); // no longer needed after mapping +} + +simdjson_inline padded_memory_map::~padded_memory_map() noexcept { + if (data != nullptr) { + munmap(const_cast(data), size + simdjson::SIMDJSON_PADDING); + } +} + + +simdjson_inline simdjson::padded_string_view padded_memory_map::view() const noexcept simdjson_lifetime_bound { + if(!is_valid()) { + return simdjson::padded_string_view(); // return an empty view if mapping failed + } + return simdjson::padded_string_view(data, size, size + simdjson::SIMDJSON_PADDING); +} + +simdjson_inline bool padded_memory_map::is_valid() const noexcept { + return data != nullptr; +} +#endif // _WIN32 + } // namespace simdjson inline simdjson::padded_string operator ""_padded(const char *str, size_t len) { @@ -4974,6 +5113,7 @@ inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len return simdjson::padded_string(reinterpret_cast(str), len); } #endif + #endif // SIMDJSON_PADDED_STRING_INL_H /* end file simdjson/padded_string-inl.h */ /* skipped duplicate #include "simdjson/padded_string_view.h" */ @@ -6030,6 +6170,13 @@ class parser { inline bool dump_raw_tape(std::ostream &os) const noexcept; + /** + * When enabled, big integers (exceeding uint64 range) are stored as strings + * in the tape instead of returning BIGINT_ERROR. Default: false. + */ + inline void number_as_string(bool enabled) noexcept { _number_as_string = enabled; } + inline bool number_as_string() const noexcept { return _number_as_string; } + private: /** * The maximum document length this parser will automatically support. @@ -6038,6 +6185,9 @@ class parser { */ size_t _max_capacity; + /** Whether to store big integers as strings instead of returning BIGINT_ERROR */ + bool _number_as_string{false}; + /** * The loaded buffer (reused each time load() is called) */ @@ -6431,7 +6581,8 @@ enum class element_type { DOUBLE = 'd', ///< double: Any number with a "." or "e" that fits in double. STRING = '"', ///< std::string_view BOOL = 't', ///< bool - NULL_VALUE = 'n' ///< null + NULL_VALUE = 'n', ///< null + BIGINT = 'Z' ///< std::string_view: big integer stored as raw digit string }; /** @@ -6530,6 +6681,14 @@ class element { */ inline simdjson_result get_bool() const noexcept; + /** + * Read this element as a big integer (raw digit string). + * + * @returns A string_view of the raw digits, or: + * INCORRECT_TYPE if the JSON element is not a big integer. + */ + inline simdjson_result get_bigint() const noexcept; + /** * Whether this element is a json array. * @@ -6585,6 +6744,11 @@ class element { */ inline bool is_null() const noexcept; + /** + * Whether this element is a big integer (number exceeding 64-bit range). + */ + inline bool is_bigint() const noexcept; + /** * Tell whether the value can be cast to provided type (T). * @@ -6943,6 +7107,7 @@ struct simdjson_result : public internal::simdjson_result_base get_uint64() const noexcept; simdjson_inline simdjson_result get_double() const noexcept; simdjson_inline simdjson_result get_bool() const noexcept; + simdjson_inline simdjson_result get_bigint() const noexcept; simdjson_inline bool is_array() const noexcept; simdjson_inline bool is_object() const noexcept; @@ -6953,6 +7118,7 @@ struct simdjson_result : public internal::simdjson_result_base operator[](std::string_view key) const noexcept; simdjson_inline simdjson_result operator[](const char *key) const noexcept; @@ -7943,7 +8109,8 @@ enum class tape_type { DOUBLE = 'd', TRUE_VALUE = 't', FALSE_VALUE = 'f', - NULL_VALUE = 'n' + NULL_VALUE = 'n', + BIGINT = 'Z' // Big integer stored as string in string buffer }; // enum class tape_type } // namespace internal @@ -8817,6 +8984,10 @@ simdjson_inline simdjson_result simdjson_result::get_bool() if (error()) { return error(); } return first.get_bool(); } +simdjson_inline simdjson_result simdjson_result::get_bigint() const noexcept { + if (error()) { return error(); } + return first.get_bigint(); +} simdjson_inline bool simdjson_result::is_array() const noexcept { return !error() && first.is_array(); @@ -8846,6 +9017,9 @@ simdjson_inline bool simdjson_result::is_bool() const noexcept { simdjson_inline bool simdjson_result::is_null() const noexcept { return !error() && first.is_null(); } +simdjson_inline bool simdjson_result::is_bigint() const noexcept { + return !error() && first.is_bigint(); +} simdjson_inline simdjson_result simdjson_result::operator[](std::string_view key) const noexcept { if (error()) { return error(); } @@ -8954,6 +9128,15 @@ inline simdjson_result element::get_bool() const noexcept { } return INCORRECT_TYPE; } +inline simdjson_result element::get_bigint() const noexcept { + SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); + switch (tape.tape_ref_type()) { + case internal::tape_type::BIGINT: + return tape.get_string_view(); + default: + return INCORRECT_TYPE; + } +} inline simdjson_result element::get_c_str() const noexcept { SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 switch (tape.tape_ref_type()) { @@ -9096,6 +9279,10 @@ inline bool element::is_null() const noexcept { return tape.is_null_on_tape(); } +inline bool element::is_bigint() const noexcept { + return tape.tape_ref_type() == internal::tape_type::BIGINT; +} + #if SIMDJSON_EXCEPTIONS inline element::operator bool() const noexcept(false) { return get(); } @@ -9228,6 +9415,8 @@ inline std::ostream& operator<<(std::ostream& out, element_type type) { return out << "bool"; case element_type::NULL_VALUE: return out << "null"; + case element_type::BIGINT: + return out << "bigint"; default: return out << "unexpected content!!!"; // abort() usage is forbidden in the library } @@ -9395,6 +9584,7 @@ inline simdjson_result parser::parse_into_document(document& provided_d buf += 3; len -= 3; } + implementation->_number_as_string = _number_as_string; _error = implementation->parse(buf, len, provided_doc); if (_error) { return _error; } @@ -10073,6 +10263,15 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept { case 'r': // we start and end with the root node // should we be hitting the root node? return false; + case 'Z': // we have a big integer + os << "bigint "; + std::memcpy(&string_length, string_buf.get() + payload, sizeof(uint32_t)); + os << std::string_view( + reinterpret_cast(string_buf.get() + payload + sizeof(uint32_t)), + string_length + ); + os << '\n'; + break; default: return false; } @@ -10558,6 +10757,12 @@ inline void string_builder::append(simdjson::dom::element value) { case tape_type::STRING: format.string(iter.get_string_view()); break; + case tape_type::BIGINT: { + // Big integer stored as string — output raw digits (no quotes) + auto sv = iter.get_string_view(); + format.chars(sv.data(), sv.data() + sv.size()); + break; + } case tape_type::INT64: format.number(iter.next_tape_value()); iter.json_index++; // numbers take up 2 spots, so we need to increment @@ -16498,6 +16703,19 @@ simdjson_inline int leading_zeroes(uint64_t input_num) { #endif// _MSC_VER } +simdjson_inline int trailing_zeroes(uint64_t input_num) { +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + // Search the mask data from least significant bit (LSB) + // to most significant bit (MSB) for a set bit (1). + if (_BitScanForward64(&trailing_zero, input_num)) + return (int)trailing_zero; + else return 64; +#else + return __builtin_ctzll(input_num); +#endif// _MSC_VER +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -39592,6 +39810,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -39604,6 +39838,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace arm64 { @@ -39704,6 +39954,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -39747,28 +40026,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -39806,13 +40069,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -40506,6 +40884,19 @@ simdjson_inline int leading_zeroes(uint64_t input_num) { #endif// _MSC_VER } +simdjson_inline int trailing_zeroes(uint64_t input_num) { +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + // Search the mask data from least significant bit (LSB) + // to most significant bit (MSB) for a set bit (1). + if (_BitScanForward64(&trailing_zero, input_num)) + return (int)trailing_zero; + else return 64; +#else + return __builtin_ctzll(input_num); +#endif// _MSC_VER +} + } // unnamed namespace } // namespace fallback } // namespace simdjson @@ -41503,6 +41894,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -41515,6 +41922,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace fallback { @@ -41615,6 +42038,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -41658,28 +42110,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -41717,13 +42153,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -43914,6 +44465,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -43926,6 +44493,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace haswell { @@ -44026,6 +44609,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -44069,28 +44681,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -44128,13 +44724,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -46325,6 +47036,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -46337,6 +47064,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace icelake { @@ -46437,6 +47180,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -46480,28 +47252,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -46539,13 +47295,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -48851,6 +49722,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -48863,6 +49750,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace ppc64 { @@ -48963,6 +49866,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -49006,28 +49938,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -49065,13 +49981,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -51694,6 +52725,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -51706,6 +52753,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace westmere { @@ -51806,6 +52869,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -51849,28 +52941,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -51908,13 +52984,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -54011,6 +55202,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -54023,6 +55230,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace lsx { @@ -54123,6 +55346,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -54166,28 +55418,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -54225,13 +55461,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -56351,6 +57702,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -56363,6 +57730,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace lasx { @@ -56463,6 +57846,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -56506,28 +57918,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -56565,13 +57961,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -58695,6 +60206,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #define SIMDJSON_EXPERIMENTAL_HAS_NEON 1 #endif #endif +#if defined(__loongarch_sx) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX +#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1 +#endif +#endif +#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \ + defined(__riscv_vector) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV +#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1 +#endif +#endif +#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) +#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1 +#endif +#endif #if SIMDJSON_EXPERIMENTAL_HAS_NEON #include #ifdef _MSC_VER @@ -58707,6 +60234,22 @@ simdjson_warn_unused simdjson_result extract_fractured_json( #include #endif #endif +#if SIMDJSON_EXPERIMENTAL_HAS_LSX +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_RVV +#include +#endif +#if SIMDJSON_EXPERIMENTAL_HAS_PPC64 +#include +#ifdef bool +#undef bool +#endif +#ifdef vector +#undef vector +#endif +#endif + namespace simdjson { namespace rvv_vls { @@ -58807,6 +60350,35 @@ simdjson_inline bool fast_needs_escaping(std::string_view view) { } return _mm_movemask_epi8(running) != 0; } +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline bool fast_needs_escaping(std::string_view view) { + if (view.size() < 16) { + return simple_needs_escaping(view); + } + size_t i = 0; + __vector unsigned char running = vec_splats((unsigned char)0); + __vector unsigned char v34 = vec_splats((unsigned char)34); + __vector unsigned char v92 = vec_splats((unsigned char)92); + __vector unsigned char v32 = vec_splats((unsigned char)32); + + for (; i + 15 < view.size(); i += 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(view.data() + i)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + if (i < view.size()) { + __vector unsigned char word = vec_vsx_ld( + 0, reinterpret_cast(view.data() + view.length() - 16)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v34)); + running = vec_or(running, (__vector unsigned char)vec_cmpeq(word, v92)); + running = vec_or(running, + (__vector unsigned char)vec_cmplt(word, v32)); + } + return !vec_all_eq(running, vec_splats((unsigned char)0)); +} #else simdjson_inline bool fast_needs_escaping(std::string_view view) { return simple_needs_escaping(view); @@ -58850,28 +60422,12 @@ find_next_json_quotable_character(const std::string_view view, needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92)); needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32)); - if (vmaxvq_u32(vreinterpretq_u32_u8(needs_escape)) != 0) { - // Found quotable character - extract exact byte position using ctz - uint64x2_t as64 = vreinterpretq_u64_u8(needs_escape); - uint64_t lo = vgetq_lane_u64(as64, 0); - uint64_t hi = vgetq_lane_u64(as64, 1); + const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4); + const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0); + if(mask != 0) { size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - if (lo != 0) { - _BitScanForward64(&trailing_zero, lo); - return offset + trailing_zero / 8; - } else { - _BitScanForward64(&trailing_zero, hi); - return offset + 8 + trailing_zero / 8; - } -#else - if (lo != 0) { - return offset + __builtin_ctzll(lo) / 8; - } else { - return offset + 8 + __builtin_ctzll(hi) / 8; - } -#endif + auto trailing_zero = trailing_zeroes(mask); + return offset + (trailing_zero >> 2); } ptr += 16; remaining -= 16; @@ -58909,13 +60465,128 @@ find_next_json_quotable_character(const std::string_view view, if (mask != 0) { // Found quotable character - use trailing zero count to find position size_t offset = ptr - reinterpret_cast(view.data()); -#ifdef _MSC_VER - unsigned long trailing_zero = 0; - _BitScanForward(&trailing_zero, mask); - return offset + trailing_zero; + return offset + trailing_zeroes(mask); + } + ptr += 16; + remaining -= 16; + } + + // Scalar fallback for remaining bytes + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_LSX +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + //SIMD constants for characters requiring escape + __m128i v34 = __lsx_vreplgr2vr_b(34); // '"' + __m128i v92 = __lsx_vreplgr2vr_b(92); // '\\' + __m128i v32 = __lsx_vreplgr2vr_b(32); // control char threshold + + while (remaining >= 16){ + __m128i word = __lsx_vld(ptr, 0); + + //Check for the quotable characters: '"', '\\', or control char (<32) + __m128i needs_escape = __lsx_vseq_b(word, v34); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92)); + needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32)); + + if (!__lsx_bz_v(needs_escape)){ + + //Found quotable character - extract exact byte position + uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0); + uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1); + size_t offset = ptr - reinterpret_cast(view.data()); + if ( lo != 0) { + return offset + trailing_zeroes(lo) / 8; + } else { + return offset + 8 + trailing_zeroes(hi) / 8; + } + } + ptr += 16; + remaining -= 16; + } + size_t current = len - remaining; + return find_next_json_quotable_character_scalar(view, current); +} +#elif SIMDJSON_EXPERIMENTAL_HAS_RVV +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + while (remaining > 0) { + size_t vl = __riscv_vsetvl_e8m1(remaining); + vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmseq(word, (uint8_t)92, vl), vl); + needs_escape = __riscv_vmor(needs_escape, + __riscv_vmsltu(word, (uint8_t)32, vl), vl); + + long first = __riscv_vfirst(needs_escape, vl); + if (first >= 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + first; + } + ptr += vl; + remaining -= vl; + } + + return len; +} +#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64 +simdjson_inline size_t +find_next_json_quotable_character(const std::string_view view, + size_t location) noexcept { + const size_t len = view.size(); + const uint8_t *ptr = + reinterpret_cast(view.data()) + location; + size_t remaining = len - location; + + // SIMD constants for characters requiring escape + __vector unsigned char v34 = vec_splats((unsigned char)34); // '"' + __vector unsigned char v92 = vec_splats((unsigned char)92); // '\\' + __vector unsigned char v32 = vec_splats((unsigned char)32); // control char threshold + + // Bitmask for vec_vbpermq to extract one bit per byte + const __vector unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50, + 0x48, 0x40, 0x38, 0x30, 0x28, 0x20, + 0x18, 0x10, 0x08, 0x00}; + + while (remaining >= 16) { + __vector unsigned char word = + vec_vsx_ld(0, reinterpret_cast(ptr)); + + // Check for quotable characters: '"', '\\', or control chars (< 32) + __vector unsigned char needs_escape = + (__vector unsigned char)vec_cmpeq(word, v34); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmpeq(word, v92)); + needs_escape = vec_or(needs_escape, + (__vector unsigned char)vec_cmplt(word, v32)); + + __vector unsigned long long result = + (__vector unsigned long long)vec_vbpermq(needs_escape, perm_mask); +#ifdef __LITTLE_ENDIAN__ + unsigned int mask = static_cast(result[1]); #else - return offset + __builtin_ctz(mask); + unsigned int mask = static_cast(result[0]); #endif + if (mask != 0) { + size_t offset = ptr - reinterpret_cast(view.data()); + return offset + __builtin_ctz(mask); } ptr += 16; remaining -= 16; @@ -73462,6 +75133,19 @@ simdjson_inline int leading_zeroes(uint64_t input_num) { #endif// _MSC_VER } +simdjson_inline int trailing_zeroes(uint64_t input_num) { +#ifdef _MSC_VER + unsigned long trailing_zero = 0; + // Search the mask data from least significant bit (LSB) + // to most significant bit (MSB) for a set bit (1). + if (_BitScanForward64(&trailing_zero, input_num)) + return (int)trailing_zero; + else return 64; +#else + return __builtin_ctzll(input_num); +#endif// _MSC_VER +} + } // unnamed namespace } // namespace fallback } // namespace simdjson