Compare commits

...

8 Commits

Author SHA1 Message Date
John Keiser f56226470c Add ability to handle 8 UTF-8 SIMD blocks at a time 2024-08-18 14:31:12 -07:00
John Keiser 3225226ddc Make UTF-8 validation step by step 2024-08-18 14:31:12 -07:00
John Keiser 2726f4543e Create simd bitmask builder 2024-08-18 14:29:52 -07:00
John Keiser 4c1b0a41d8 Enable SIMDJSON_SINGLEHEADER=OFF in VS Code
With singleheader on, clangd can't find the right
include files.
2024-08-18 14:21:00 -07:00
John Keiser ef563a4b09 Make simdjson compile again 2024-08-18 11:21:26 -07:00
Daniel Lemire 7a9ff93388 [no-ci] Update README.md 2024-08-15 12:52:47 -04:00
Sasha Lopoukhine fc61d7c7ba Fix ndjson spec link (#2234)
* fix ndjson spec link

The link in the readme of parse_many links to a casino spam site

* fix link
2024-08-10 10:11:05 -04:00
Daniel Lemire d506af0a79 fix: add tests related to issue 2227 (#2229)
* fix: add tests related to issue 2227

* avoiding name clash

* pedantic fix

* deprecate rvalue get on document

* selectively deprecating
2024-08-07 20:15:06 -04:00
31 changed files with 639 additions and 237 deletions
+9
View File
@@ -25,6 +25,7 @@ CompileFlags:
Diagnostics: Diagnostics:
Suppress: Suppress:
- pp_including_mainfile_in_preamble - pp_including_mainfile_in_preamble
- unused-includes
--- ---
# Amalgamated files that require or partly define an implementation # Amalgamated files that require or partly define an implementation
If: If:
@@ -44,3 +45,11 @@ Diagnostics:
Suppress: Suppress:
- pragma_attribute_no_pop_eof - pragma_attribute_no_pop_eof
- pragma_attribute_stack_mismatch - pragma_attribute_stack_mismatch
---
# clang 18
If:
PathMatch:
- dependencies/.cache/json11/json11.cpp
CompileFlags:
Add:
- -Wno-unqualified-std-cast-call
+5
View File
@@ -110,5 +110,10 @@
"semaphore": "cpp", "semaphore": "cpp",
"stop_token": "cpp", "stop_token": "cpp",
"cfenv": "cpp" "cfenv": "cpp"
},
"cmake.configureSettings": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "YES",
"SIMDJSON_DEVELOPER_MODE": "ON",
"SIMDJSON_SINGLEHEADER": "OFF"
} }
} }
+10 -6
View File
@@ -51,6 +51,7 @@ endif()
if(is_top_project) if(is_top_project)
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF) option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF) option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
option(SIMDJSON_SINGLEHEADER "Disable singleheader generation" ON)
endif() endif()
include(cmake/handle-deprecations.cmake) include(cmake/handle-deprecations.cmake)
@@ -155,11 +156,13 @@ endif()
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
include(GNUInstallDirs) include(GNUInstallDirs)
install( if(SIMDJSON_SINGLEHEADER)
FILES singleheader/simdjson.h install(
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" FILES singleheader/simdjson.h
COMPONENT simdjson_Development DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
) COMPONENT simdjson_Development
)
endif()
install( install(
TARGETS simdjson TARGETS simdjson
@@ -286,8 +289,9 @@ add_subdirectory(tools) ## This needs to be before tests because of cxxopts
# most of the data has been moved to https://github.com/simdjson/simdjson-data # most of the data has been moved to https://github.com/simdjson/simdjson-data
add_subdirectory(jsonexamples) add_subdirectory(jsonexamples)
if(SIMDJSON_SINGLEHEADER)
add_subdirectory(singleheader) add_subdirectory(singleheader)
endif()
+2 -2
View File
@@ -201,8 +201,8 @@ For the video inclined, <br />
Funding Funding
------- -------
The work is supported by the Natural Sciences and Engineering Research Council of Canada under grant The work is supported by the Natural Sciences and Engineering Research Council of Canada under grants
number RGPIN-2017-03910. RGPIN-2017-03910 and RGPIN-2024-03787.
[license]: LICENSE [license]: LICENSE
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg [license img]: https://img.shields.io/badge/License-Apache%202-blue.svg
+1 -1
View File
@@ -125,7 +125,7 @@ Whitespace Characters:
- **Nothing** - **Nothing**
Some official formats **(non-exhaustive list)**: Some official formats **(non-exhaustive list)**:
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/) - [Newline-Delimited JSON (NDJSON)](https://github.com/ndjson/ndjson-spec)
- [JSON lines (JSONL)](http://jsonlines.org/) - [JSON lines (JSONL)](http://jsonlines.org/)
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream! - [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream!
- [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming) - [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
+66 -17
View File
@@ -210,6 +210,7 @@ namespace {
// Bit-specific operations // Bit-specific operations
simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return vtstq_u8(*this, bits); } simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return vtstq_u8(*this, bits); }
simdjson_inline bool is_ascii() const { return this->max_val() < 0x80u; }
simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; } simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; }
simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return (*this & bits).any_bits_set_anywhere(); } simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return (*this & bits).any_bits_set_anywhere(); }
template<int N> template<int N>
@@ -412,6 +413,66 @@ namespace {
} }
}; };
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
static const uint8x16_t BITMASK64_BUILDER_MASK = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
);
#else
static const uint8x16_t BITMASK64_BUILDER_MASK = {
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
};
#endif
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<4> {
const uint64_t mask;
operator uint64_t() && { return mask; }
}; // struct simd_bitmask64_builder<4>
template<>
struct simd_bitmask64_builder<3> {
const uint8x16_t sum01;
const simd8<bool> val2;
simdjson_inline simd_bitmask64_builder<4> next(simd8<bool> val3) {
// Add each of the elements next to each other, successively, to stuff each 8 byte mask into one.
uint8x16_t sum23 = vpaddq_u8(val2 & BITMASK64_BUILDER_MASK, val3 & BITMASK64_BUILDER_MASK);
uint8x16_t sum0123 = vpaddq_u8(sum01, sum23);
// This algorithm is actually designed to create a 128-bit mask from 8 16-byte simd masks,
// but since we only want 64 bits, we add the mask to itself (creating the final mask twice).
uint8x16_t sum01230123 = vpaddq_u8(sum0123, sum0123);
return { vgetq_lane_u64(vreinterpretq_u64_u8(sum01230123), 0) };
}
}; // struct simd_bitmask64_builder<3>
template<>
struct simd_bitmask64_builder<2> {
const uint8x16_t sum01;
simdjson_inline simd_bitmask64_builder<3> next(simd8<bool> val2) {
return { sum01, val2 };
}
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<1> {
const simd8<bool> val0;
simdjson_inline simd_bitmask64_builder<2> next(simd8<bool> val1) {
return { vpaddq_u8(val0 & BITMASK64_BUILDER_MASK, val1 & BITMASK64_BUILDER_MASK) };
}
}; // struct simd_bitmask64_builder<1>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val) {
return { val };
}
}; // struct simd_bitmask64_builder<0>
template<typename T> template<typename T>
struct simd8x64 { struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
@@ -449,23 +510,11 @@ namespace {
} }
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO return simd_bitmask64_builder<0>()
const uint8x16_t bit_mask = simdjson_make_uint8x16_t( .next(this->chunks[0])
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, .next(this->chunks[1])
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 .next(this->chunks[2])
); .next(this->chunks[3]);
#else
const uint8x16_t bit_mask = {
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
};
#endif
// Add each of the elements next to each other, successively, to stuff each 8 byte mask into one.
uint8x16_t sum0 = vpaddq_u8(this->chunks[0] & bit_mask, this->chunks[1] & bit_mask);
uint8x16_t sum1 = vpaddq_u8(this->chunks[2] & bit_mask, this->chunks[3] & bit_mask);
sum0 = vpaddq_u8(sum0, sum1);
sum0 = vpaddq_u8(sum0, sum0);
return vgetq_lane_u64(vreinterpretq_u64_u8(sum0), 0);
} }
simdjson_inline uint64_t eq(const T m) const { simdjson_inline uint64_t eq(const T m) const {
+4
View File
@@ -50,6 +50,8 @@ double from_chars(const char *first, const char* end) noexcept;
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0) #define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
#if SIMDJSON_REGULAR_VISUAL_STUDIO #if SIMDJSON_REGULAR_VISUAL_STUDIO
// We could use [[deprecated]] but it requires C++14
#define simdjson_deprecated __declspec(deprecated)
#define simdjson_really_inline __forceinline #define simdjson_really_inline __forceinline
#define simdjson_never_inline __declspec(noinline) #define simdjson_never_inline __declspec(noinline)
@@ -88,6 +90,8 @@ double from_chars(const char *first, const char* end) noexcept;
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS #define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
#else // SIMDJSON_REGULAR_VISUAL_STUDIO #else // SIMDJSON_REGULAR_VISUAL_STUDIO
// We could use [[deprecated]] but it requires C++14
#define simdjson_deprecated __attribute__((deprecated))
#define simdjson_really_inline inline __attribute__((always_inline)) #define simdjson_really_inline inline __attribute__((always_inline))
#define simdjson_never_inline inline __attribute__((noinline)) #define simdjson_never_inline inline __attribute__((noinline))
@@ -3,16 +3,14 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE #ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
#include "simdjson/generic/ondemand/base.h" #include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/array-inl.h"
#include "simdjson/generic/ondemand/array_iterator.h" #include "simdjson/generic/ondemand/array_iterator.h"
#include "simdjson/generic/ondemand/document.h" #include "simdjson/generic/ondemand/document.h"
#include "simdjson/generic/ondemand/json_iterator-inl.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion-inl.h"
#include "simdjson/generic/ondemand/json_type.h" #include "simdjson/generic/ondemand/json_type.h"
#include "simdjson/generic/ondemand/object-inl.h"
#include "simdjson/generic/ondemand/raw_json_string.h" #include "simdjson/generic/ondemand/raw_json_string.h"
#include "simdjson/generic/ondemand/value.h" #include "simdjson/generic/ondemand/value.h"
#include "simdjson/generic/ondemand/array-inl.h"
#include "simdjson/generic/ondemand/json_iterator-inl.h"
#include "simdjson/generic/ondemand/object-inl.h"
#include "simdjson/generic/ondemand/value_iterator-inl.h" #include "simdjson/generic/ondemand/value_iterator-inl.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE #endif // SIMDJSON_CONDITIONAL_INCLUDE
@@ -167,24 +165,26 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); } template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); } template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
template<> simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); } template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
template<> simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); } template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
template<> simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); } template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
template<> simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); } template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
template<> simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); } template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
template<> simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); } template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
template<> simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); } template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
template<typename T> simdjson_inline error_code document::get(T &out) & noexcept { template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
return get<T>().get(out); return get<T>().get(out);
} }
template<typename T> simdjson_inline error_code document::get(T &out) && noexcept { template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
return std::forward<document>(*this).get<T>().get(out); return std::forward<document>(*this).get<T>().get(out);
} }
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
template <class T> template <class T>
simdjson_inline document::operator T() noexcept(false) { return get<T>(); } simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
template <class T>
simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
simdjson_inline document::operator array() & noexcept(false) { return get_array(); } simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
simdjson_inline document::operator object() & noexcept(false) { return get_object(); } simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); } simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
@@ -471,7 +471,7 @@ simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::onde
return first.get<T>(); return first.get<T>();
} }
template<typename T> template<typename T>
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get() && noexcept { simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get() && noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first).get<T>(); return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first).get<T>();
} }
@@ -487,7 +487,7 @@ simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::do
} }
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() & noexcept = delete; template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() & noexcept = delete;
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() && noexcept { template<> simdjson_deprecated simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() && noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first); return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first);
} }
+7 -4
View File
@@ -188,7 +188,7 @@ public:
" You may also add support for custom types, see our documentation."); " You may also add support for custom types, see our documentation.");
} }
/** @overload template<typename T> simdjson_result<T> get() & noexcept */ /** @overload template<typename T> simdjson_result<T> get() & noexcept */
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept { template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
// Unless the simdjson library or the user provides an inline implementation, calling this method should // Unless the simdjson library or the user provides an inline implementation, calling this method should
// immediately fail. // immediately fail.
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
@@ -211,7 +211,7 @@ public:
*/ */
template<typename T> simdjson_inline error_code get(T &out) & noexcept; template<typename T> simdjson_inline error_code get(T &out) & noexcept;
/** @overload template<typename T> error_code get(T &out) & noexcept */ /** @overload template<typename T> error_code get(T &out) & noexcept */
template<typename T> simdjson_inline error_code get(T &out) && noexcept; template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
/** /**
@@ -224,7 +224,10 @@ public:
* @returns An instance of type T * @returns An instance of type T
*/ */
template <class T> template <class T>
explicit simdjson_inline operator T() noexcept(false); explicit simdjson_inline operator T() & noexcept(false);
template <class T>
explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
/** /**
* Cast this JSON value to an array. * Cast this JSON value to an array.
* *
@@ -790,7 +793,7 @@ public:
simdjson_inline simdjson_result<bool> is_null() noexcept; simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept; template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept; template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
template<typename T> simdjson_inline error_code get(T &out) & noexcept; template<typename T> simdjson_inline error_code get(T &out) & noexcept;
template<typename T> simdjson_inline error_code get(T &out) && noexcept; template<typename T> simdjson_inline error_code get(T &out) && noexcept;
@@ -316,7 +316,7 @@ private:
friend class document; friend class document;
friend class json_iterator; friend class json_iterator;
friend struct simdjson_result<ondemand::document_stream>; friend struct simdjson_result<ondemand::document_stream>;
friend struct internal::simdjson_result_base<ondemand::document_stream>; friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
}; // document_stream }; // document_stream
} // namespace ondemand } // namespace ondemand
@@ -1,67 +0,0 @@
#pragma once
#ifndef SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
#define SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_JSON_PATH_TO_POINTER_CONVERSION_INL_H
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {}
namespace ondemand {
simdjson_inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
if (json_path.empty() || (json_path.front() != '.' && json_path.front() != '[') {
return "-1"; // Sentinel value to be handled as an error by the caller.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
// Skip the initial '.' as it's assumed every path starts with it.
size_t i = 0;
while (i < json_path.length()) {
if (json_path[i] == '.') {
result += '/';
} else if (json_path[i] == '[') {
result += '/';
++i; // Move past the '['
while (i < json_path.length() && json_path[i] != ']') {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
++i;
}
if (i == json_path.length() || json_path[i] != ']') {
return "-1"; // Returning sentinel value that will be handled as an error by the caller
}
} else {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
}
++i;
}
return simdjson_result<std::string>(result);
}
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
@@ -1,22 +0,0 @@
#pragma once
#ifndef SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_H
#define SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_H
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace internal {
/**
* Converts JSONPath to JSON Pointer.
* @param json_path The JSONPath string to be converted.
* @return A string containing the equivalent JSON Pointer.
* @throws simdjson_error If the conversion fails.
*/
simdjson_inline std::string json_path_to_pointer_conversion(std::string_view json_path);
} // namespace internal
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_JSON_PATH_TO_POINTER_CONVERSION_H
+1 -1
View File
@@ -340,7 +340,7 @@ public:
private: private:
/** @private [for benchmarking access] The implementation to use */ /** @private [for benchmarking access] The implementation to use */
std::unique_ptr<internal::dom_parser_implementation> implementation{}; std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
size_t _capacity{0}; size_t _capacity{0};
size_t _max_capacity; size_t _max_capacity;
size_t _max_depth{DEFAULT_MAX_DEPTH}; size_t _max_depth{DEFAULT_MAX_DEPTH};
@@ -6,8 +6,6 @@
#include "simdjson/generic/ondemand/array.h" #include "simdjson/generic/ondemand/array.h"
#include "simdjson/generic/ondemand/array_iterator.h" #include "simdjson/generic/ondemand/array_iterator.h"
#include "simdjson/generic/ondemand/json_iterator.h" #include "simdjson/generic/ondemand/json_iterator.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion-inl.h"
#include "simdjson/generic/ondemand/json_type.h" #include "simdjson/generic/ondemand/json_type.h"
#include "simdjson/generic/ondemand/object.h" #include "simdjson/generic/ondemand/object.h"
#include "simdjson/generic/ondemand/raw_json_string.h" #include "simdjson/generic/ondemand/raw_json_string.h"
@@ -6,9 +6,9 @@
#include "simdjson/generic/atomparsing.h" #include "simdjson/generic/atomparsing.h"
#include "simdjson/generic/numberparsing.h" #include "simdjson/generic/numberparsing.h"
#include "simdjson/generic/ondemand/json_iterator.h" #include "simdjson/generic/ondemand/json_iterator.h"
#include "simdjson/generic/ondemand/value_iterator.h"
#include "simdjson/generic/ondemand/json_type-inl.h" #include "simdjson/generic/ondemand/json_type-inl.h"
#include "simdjson/generic/ondemand/raw_json_string-inl.h" #include "simdjson/generic/ondemand/raw_json_string-inl.h"
#include "simdjson/generic/ondemand/value_iterator.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE #endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
+27 -3
View File
@@ -295,6 +295,30 @@ namespace simd {
simdjson_inline int get_bit() const { return _mm256_movemask_epi8(_mm256_slli_epi16(*this, 7-N)); } simdjson_inline int get_bit() const { return _mm256_movemask_epi8(_mm256_slli_epi16(*this, 7-N)); }
}; };
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<2> {
const uint64_t bitmask;
operator uint64_t() && { return bitmask; }
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<1> {
const int bitmask;
simdjson_inline simd_bitmask64_builder<2> next(simd8<bool> val) {
uint64_t r_lo = uint32_t(bitmask);
uint64_t r_hi = val.to_bitmask();
return { r_lo | (r_hi << 32) };
}
}; // struct simd_bitmask64_builder<1>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val) { return { val.to_bitmask() }; }
}; // struct simd_bitmask64_builder<0>
template<typename T> template<typename T>
struct simd8x64 { struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
@@ -322,9 +346,9 @@ namespace simd {
} }
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
uint64_t r_lo = uint32_t(this->chunks[0].to_bitmask()); return simd_bitmask64_builder<0>()
uint64_t r_hi = this->chunks[1].to_bitmask(); .next(this->chunks[0])
return r_lo | (r_hi << 32); .next(this->chunks[1]);
} }
simdjson_inline simd8<T> reduce_or() const { simdjson_inline simd8<T> reduce_or() const {
+14
View File
@@ -314,6 +314,20 @@ namespace simd {
simdjson_inline uint64_t get_bit() const { return _mm512_movepi8_mask(_mm512_slli_epi16(*this, 7-N)); } simdjson_inline uint64_t get_bit() const { return _mm512_movepi8_mask(_mm512_slli_epi16(*this, 7-N)); }
}; };
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<1> {
const __mmask64 bitmask;
operator __mmask64() && { return bitmask; }
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val) { return { _mm512_movepi8_mask(val) }; }
}; // struct simd_bitmask64_builder<0>
template<typename T> template<typename T>
struct simd8x64 { struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
+32 -7
View File
@@ -298,6 +298,35 @@ namespace simd {
simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lasx_xvslli_b(*this, N)); } simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lasx_xvslli_b(*this, N)); }
}; };
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<2> {
const unsigned long int mask01;
operator uint64_t() { return mask01; }
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<1> {
const __m256i mask0;
simdjson_inline simd_bitmask64_builder<2> next(simd8<bool> val1) {
__m256i mask1 = __lasx_xvmskltz_b(val1);
__m256i mask_tmp = __lasx_xvpickve_w(mask0, 4);
__m256i tmp = __lasx_xvpickve_w(mask1, 4);
__m256i mask01 = __lasx_xvinsve0_w(mask0, mask1, 1);
__m256i mask01_tmp = __lasx_xvinsve0_w(mask_tmp, tmp, 1);
return { __lasx_xvpickve2gr_du(__lasx_xvpackev_h(mask01_tmp, mask01), 0) };
}
}; // struct simd_bitmask64_builder<1>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val) {
return { __lasx_xvmskltz_b(val0) };
}
}; // struct simd_bitmask64_builder<0>
template<typename T> template<typename T>
struct simd8x64 { struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
@@ -331,13 +360,9 @@ namespace simd {
} }
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
__m256i mask0 = __lasx_xvmskltz_b(this->chunks[0]); return simd_bitmask64_builder<0>()
__m256i mask1 = __lasx_xvmskltz_b(this->chunks[1]); .next(this->chunks[0])
__m256i mask_tmp = __lasx_xvpickve_w(mask0, 4); .next(this->chunks[1]);
__m256i tmp = __lasx_xvpickve_w(mask1, 4);
mask0 = __lasx_xvinsve0_w(mask0, mask1, 1);
mask_tmp = __lasx_xvinsve0_w(mask_tmp, tmp, 1);
return __lasx_xvpickve2gr_du(__lasx_xvpackev_h(mask_tmp, mask0), 0);
} }
simdjson_inline simd8<T> reduce_or() const { simdjson_inline simd8<T> reduce_or() const {
+49 -7
View File
@@ -255,6 +255,50 @@ namespace simd {
simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lsx_vslli_b(*this, N)); } simdjson_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(__lsx_vslli_b(*this, N)); }
}; };
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<4> {
const unsigned long int result;
operator uint64_t() { return result; }
}; // struct simd_bitmask64_builder<4>
template<>
struct simd_bitmask64_builder<3> {
const __m128i mask01;
const __m128i mask2;
simdjson_inline simd_bitmask64_builder<4> next(simd8<bool> val3) {
__m128i mask3 = __lsx_vmskltz_b(val3);
__m128i mask23 = __lsx_vilvl_h(mask3, mask2);
return { __lsx_vpickve2gr_du(__lsx_vilvl_w(mask23, mask01), 0) };
}
}; // struct simd_bitmask64_builder<3>
template<>
struct simd_bitmask64_builder<2> {
const __m128i mask01;
simdjson_inline simd_bitmask64_builder<3> next(simd8<bool> val2) {
return { mask01, __lsx_vmskltz_b(val2) };
}
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<1> {
const __m128i mask0;
simdjson_inline simd_bitmask64_builder<2> next(simd8<bool> val1) {
__m128i mask1 = __lsx_vmskltz_b(val1);
return { __lsx_vilvl_h(mask1, mask0) };
}
}; // struct simd_bitmask64_builder<1>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val0) {
return { __lsx_vmskltz_b(val0) };
}
}; // struct simd_bitmask64_builder<0>
template<typename T> template<typename T>
struct simd8x64 { struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
@@ -303,13 +347,11 @@ namespace simd {
} }
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
__m128i mask1 = __lsx_vmskltz_b(this->chunks[0]); return simd_bitmask64_builder<0>()
__m128i mask2 = __lsx_vmskltz_b(this->chunks[1]); .next(this->chunks[0])
__m128i mask3 = __lsx_vmskltz_b(this->chunks[2]); .next(this->chunks[1])
__m128i mask4 = __lsx_vmskltz_b(this->chunks[3]); .next(this->chunks[2])
mask1 = __lsx_vilvl_h(mask2, mask1); .next(this->chunks[3]);
mask2 = __lsx_vilvl_h(mask4, mask3);
return __lsx_vpickve2gr_du(__lsx_vilvl_w(mask2, mask1), 0);
} }
simdjson_inline simd8<T> reduce_or() const { simdjson_inline simd8<T> reduce_or() const {
+50 -5
View File
@@ -392,6 +392,51 @@ template <> struct simd8<uint8_t> : base8_numeric<uint8_t> {
} }
}; };
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<4> {
const uint64_t bitmask;
simdjson_inline operator uint64_t() && { return bitmask; }
}; // struct simd_bitmask64_builder<4>
template<>
struct simd_bitmask64_builder<3> {
const int bitmask01;
const int bitmask2;
simdjson_inline simd_bitmask64_builder<4> next(simd8<bool> val) {
return {
uint64_t(this->bitmask01) |
(uint64_t(this->bitmask2) << 32) |
(uint64_t(val.to_bitmask()) << 48)
};
}
}; // struct simd_bitmask64_builder<3>
template<>
struct simd_bitmask64_builder<2> {
const int bitmask01;
simdjson_inline simd_bitmask64_builder<3> next(simd8<bool> val) {
return { bitmask01, val.to_bitmask() };
}
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<1> {
const int bitmask0;
simdjson_inline simd_bitmask64_builder<2> next(simd8<bool> val) {
return { bitmask0 | (val.to_bitmask() << 16) };
}
}; // struct simd_bitmask64_builder<1>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val) {
return { val.to_bitmask() };
}
}; // struct simd_bitmask64_builder<0>
template <typename T> struct simd8x64 { template <typename T> struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
static_assert(NUM_CHUNKS == 4, static_assert(NUM_CHUNKS == 4,
@@ -434,11 +479,11 @@ template <typename T> struct simd8x64 {
} }
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
uint64_t r0 = uint32_t(this->chunks[0].to_bitmask()); return simd_bitmask64_builder<0>()
uint64_t r1 = this->chunks[1].to_bitmask(); .next(this->chunks[0])
uint64_t r2 = this->chunks[2].to_bitmask(); .next(this->chunks[1])
uint64_t r3 = this->chunks[3].to_bitmask(); .next(this->chunks[2])
return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48); .next(this->chunks[3]);
} }
simdjson_inline uint64_t eq(const T m) const { simdjson_inline uint64_t eq(const T m) const {
+50 -5
View File
@@ -260,6 +260,51 @@ namespace simd {
simdjson_inline int get_bit() const { return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N)); } simdjson_inline int get_bit() const { return _mm_movemask_epi8(_mm_slli_epi16(*this, 7-N)); }
}; };
template <int N = 0>
struct simd_bitmask64_builder;
template<>
struct simd_bitmask64_builder<4> {
const uint64_t bitmask;
operator uint64_t() && { return bitmask; }
}; // struct simd_bitmask64_builder<4>
template<>
struct simd_bitmask64_builder<3> {
uint32_t bitmask01;
const int bitmask2;
simdjson_inline simd_bitmask64_builder<4> next(simd8<bool> val3) {
return {
uint64_t(this->bitmask01) |
(uint64_t(this->bitmask2) << 32) |
(uint64_t(val3.to_bitmask()) << 48)
};
}
}; // struct simd_bitmask64_builder<3>
template<>
struct simd_bitmask64_builder<2> {
uint32_t bitmask01;
simdjson_inline simd_bitmask64_builder<3> next(simd8<bool> val2) {
return { bitmask01, val2.to_bitmask() };
}
}; // struct simd_bitmask64_builder<2>
template<>
struct simd_bitmask64_builder<1> {
const int bitmask0;
simdjson_inline simd_bitmask64_builder<2> next(simd8<bool> val1) {
return { uint32_t(bitmask0) | (uint32_t(val1.to_bitmask()) << 16) };
}
}; // struct simd_bitmask64_builder<1>
template<>
struct simd_bitmask64_builder<0> {
simdjson_inline simd_bitmask64_builder<1> next(simd8<bool> val0) {
return { val0.to_bitmask() };
}
}; // struct simd_bitmask64_builder<0>
template<typename T> template<typename T>
struct simd8x64 { struct simd8x64 {
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>); static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
@@ -293,11 +338,11 @@ namespace simd {
} }
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
uint64_t r0 = uint32_t(this->chunks[0].to_bitmask() ); return simd_bitmask64_builder<0>()
uint64_t r1 = this->chunks[1].to_bitmask() ; .next(this->chunks[0])
uint64_t r2 = this->chunks[2].to_bitmask() ; .next(this->chunks[1])
uint64_t r3 = this->chunks[3].to_bitmask() ; .next(this->chunks[2])
return r0 | (r1 << 16) | (r2 << 32) | (r3 << 48); .next(this->chunks[3]);
} }
simdjson_inline uint64_t eq(const T m) const { simdjson_inline uint64_t eq(const T m) const {
+1
View File
@@ -1,6 +1,7 @@
// Stuff other things depend on // Stuff other things depend on
#include <generic/stage1/base.h> #include <generic/stage1/base.h>
#include <generic/stage1/buf_block_reader.h> #include <generic/stage1/buf_block_reader.h>
#include <generic/stage1/simd_reducer.h>
#include <generic/stage1/json_escape_scanner.h> #include <generic/stage1/json_escape_scanner.h>
#include <generic/stage1/json_string_scanner.h> #include <generic/stage1/json_string_scanner.h>
#include <generic/stage1/utf8_lookup4_algorithm.h> #include <generic/stage1/utf8_lookup4_algorithm.h>
+2 -3
View File
@@ -239,7 +239,7 @@ simdjson_inline void json_structural_indexer::step<64>(const uint8_t *block, buf
simdjson_inline void json_structural_indexer::next(const simd::simd8x64<uint8_t>& in, const json_block& block, size_t idx) { simdjson_inline void json_structural_indexer::next(const simd::simd8x64<uint8_t>& in, const json_block& block, size_t idx) {
uint64_t unescaped = in.lteq(0x1F); uint64_t unescaped = in.lteq(0x1F);
#if SIMDJSON_UTF8VALIDATION #if SIMDJSON_UTF8VALIDATION
checker.check_next_input(in); checker.next(in);
#endif #endif
indexer.write(uint32_t(idx-64), prev_structurals); // Output *last* iteration's structurals to the parser indexer.write(uint32_t(idx-64), prev_structurals); // Output *last* iteration's structurals to the parser
prev_structurals = block.structural_start(); prev_structurals = block.structural_start();
@@ -343,8 +343,7 @@ simdjson_inline error_code json_structural_indexer::finish(dom_parser_implementa
return EMPTY; return EMPTY;
} }
} }
checker.check_eof(); return std::move(checker).eof();
return checker.errors();
} }
} // namespace stage1 } // namespace stage1
+80
View File
@@ -0,0 +1,80 @@
#ifndef SIMDJSON_SRC_GENERIC_STAGE1_SIMD_REDUCER_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_SRC_GENERIC_STAGE1_SIMD_REDUCER_H
#include <generic/stage1/base.h>
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
namespace simd {
/** Incrementally performs a reduce OR operation to accumulate an error. */
template <int N>
struct simd_or_reducer;
template<> struct simd_or_reducer<8> {
simd8<uint8_t> error01234567;
operator simd8<uint8_t>() && { return error01234567; }
};
template<> struct simd_or_reducer<7> {
simd8<uint8_t> error0123;
simd8<uint8_t> error45;
simd8<uint8_t> error6;
simd_or_reducer<8> next(simd8<uint8_t> error7) && { return { error0123 | error45 | error6 | error7 }; }
operator simd8<uint8_t>() && { return error0123 | error45 | error6; }
};
template<> struct simd_or_reducer<6> {
simd8<uint8_t> error0123;
simd8<uint8_t> error45;
// simd8<uint8_t> error_;
simd_or_reducer<7> next(simd8<uint8_t> error6) && { return { error0123, error45, error6 }; }
operator simd8<uint8_t>() && { return error0123 | error45; }
};
template<> struct simd_or_reducer<5> {
simd8<uint8_t> error0123;
// simd8<uint8_t> error__;
simd8<uint8_t> error4;
simd_or_reducer<6> next(simd8<uint8_t> error5) && { return { error0123, error4 | error5 }; }
operator simd8<uint8_t>() && { return error0123 | error4; }
};
template<> struct simd_or_reducer<4> {
simd8<uint8_t> error0123;
// simd8<uint8_t> error__;
// simd8<uint8_t> error_;
operator simd8<uint8_t>() && { return error0123; }
};
template<> struct simd_or_reducer<3> {
// simd8<uint8_t> error____;
simd8<uint8_t> error01;
simd8<uint8_t> error2;
simd_or_reducer<4> next(simd8<uint8_t> error3) && { return { error01 | error2 | error3 }; }
operator simd8<uint8_t>() && { return error01 | error2; }
};
template<> struct simd_or_reducer<2> {
// simd8<uint8_t> error____;
simd8<uint8_t> error01;
// simd8<uint8_t> error_;
simd_or_reducer<3> next(simd8<uint8_t> error2) && { return { error01, error2 }; }
operator simd8<uint8_t>() && { return error01; }
};
template<> struct simd_or_reducer<1> {
// simd8<uint8_t> error____;
// simd8<uint8_t> error__;
simd8<uint8_t> error0;
simd_or_reducer<2> next(simd8<uint8_t> error1) && { return { error0 | error1 }; }
operator simd8<uint8_t>() && { return error0; }
};
template<> struct simd_or_reducer<0> {
simd8<uint8_t> prev_error{};
simd_or_reducer<1> next(simd8<uint8_t> error0) && { return { prev_error | error0 }; }
operator simd8<uint8_t>() && { return prev_error; }
};
} // namespace simd
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_SRC_GENERIC_STAGE1_SIMD_REDUCER_H
+120 -60
View File
@@ -4,6 +4,7 @@
#define SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H #define SIMDJSON_SRC_GENERIC_STAGE1_UTF8_LOOKUP4_ALGORITHM_H
#include <generic/stage1/base.h> #include <generic/stage1/base.h>
#include <generic/dom_parser_implementation.h> #include <generic/dom_parser_implementation.h>
#include <generic/stage1/simd_reducer.h>
#endif // SIMDJSON_CONDITIONAL_INCLUDE #endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
@@ -11,15 +12,84 @@ namespace SIMDJSON_IMPLEMENTATION {
namespace { namespace {
namespace utf8_validation { namespace utf8_validation {
using namespace simd; using namespace simd;
simdjson_inline simd8<uint8_t> check_special_cases(const simd8<uint8_t> input, const simd8<uint8_t> prev1) { // At its height, this will keep 5 registers around.
// Bit 0 = Too Short (lead byte/ASCII followed by lead byte/ASCII) template <int N>
// Bit 1 = Too Long (ASCII followed by continuation) struct simd_utf8_checker {
// Bit 2 = Overlong 3-byte /**
// Bit 4 = Surrogate * The current error.
// Bit 5 = Overlong 2-byte */
// Bit 7 = Two Continuations simd_or_reducer<N> error;
/**
* Whether the previous input had incomplete UTF-8 characters at the end.
*/
simd8<uint8_t> prev_incomplete;
/**
* Check the next simd input block.
*/
simdjson_inline simd_utf8_checker<N+1> next(simd8<uint8_t> input, simd8<uint8_t> prev_input) &&;
/**
* Used to wrap back around to the beginning, starting with error and prev_incomplete
* from the end of this block
*/
simdjson_inline simd_utf8_checker<0> next_cycle() && {
return { std::move(error), std::move(prev_incomplete) };
}
/**
* Extracts the validation error from the block.
*/
simdjson_inline error_code eof() && {
if ((prev_incomplete | std::move(error)).any_bits_set_anywhere()) {
return error_code::UTF8_ERROR;
} else {
return error_code::SUCCESS;
}
}
private:
simdjson_inline simd8<uint8_t> check_utf8_bytes(simd8<uint8_t> input, simd8<uint8_t> prev_input) const;
simdjson_inline simd8<uint8_t> is_incomplete(simd8<uint8_t> input) const;
simdjson_inline simd8<uint8_t> check_special_cases(simd8<uint8_t> input, simd8<uint8_t> prev1) const;
simdjson_inline simd8<uint8_t> check_multibyte_lengths(simd8<uint8_t> input, simd8<uint8_t> prev_input, simd8<uint8_t> sc) const;
};
template <int N>
simdjson_inline simd_utf8_checker<N+1> simd_utf8_checker<N>::next(simd8<uint8_t> input, simd8<uint8_t> prev_input) && {
if (simdjson_likely(input.is_ascii())) {
return {
std::move(this->error).next(this->prev_incomplete),
simd8<uint8_t>::zero()
};
} else {
return {
std::move(this->error).next(check_utf8_bytes(input, prev_input)),
is_incomplete(input)
};
}
}
template <int N>
simdjson_inline simd8<uint8_t> simd_utf8_checker<N>::check_utf8_bytes(simd8<uint8_t> input, simd8<uint8_t> prev_input) const {
// Flip prev1...prev3 so we can easily determine if they are 2+, 3+ or 4+ lead bytes
// (2, 3, 4-byte leads become large positive numbers instead of small negative numbers)
simd8<uint8_t> prev1 = input.prev<1>(prev_input);
simd8<uint8_t> sc = check_special_cases(input, prev1);
return check_multibyte_lengths(input, prev_input, sc);
}
template <int N>
simdjson_inline simd8<uint8_t> simd_utf8_checker<N>::check_special_cases(simd8<uint8_t> input, simd8<uint8_t> prev1) const {
// Bit 0 = Too Short (lead byte/ASCII followed by lead byte/ASCII)
// Bit 1 = Too Long (ASCII followed by continuation)
// Bit 2 = Overlong 3-byte
// Bit 4 = Surrogate
// Bit 5 = Overlong 2-byte
// Bit 7 = Two Continuations
constexpr const uint8_t TOO_SHORT = 1<<0; // 11______ 0_______ constexpr const uint8_t TOO_SHORT = 1<<0; // 11______ 0_______
// 11______ 11______ // 11______ 11______
constexpr const uint8_t TOO_LONG = 1<<1; // 0_______ 10______ constexpr const uint8_t TOO_LONG = 1<<1; // 0_______ 10______
@@ -103,8 +173,13 @@ using namespace simd;
); );
return (byte_1_high & byte_1_low & byte_2_high); return (byte_1_high & byte_1_low & byte_2_high);
} }
simdjson_inline simd8<uint8_t> check_multibyte_lengths(const simd8<uint8_t> input,
const simd8<uint8_t> prev_input, const simd8<uint8_t> sc) { template <int N>
simdjson_inline simd8<uint8_t> simd_utf8_checker<N>::check_multibyte_lengths(
simd8<uint8_t> input,
simd8<uint8_t> prev_input,
simd8<uint8_t> sc
) const {
simd8<uint8_t> prev2 = input.prev<2>(prev_input); simd8<uint8_t> prev2 = input.prev<2>(prev_input);
simd8<uint8_t> prev3 = input.prev<3>(prev_input); simd8<uint8_t> prev3 = input.prev<3>(prev_input);
simd8<uint8_t> must23 = must_be_2_3_continuation(prev2, prev3); simd8<uint8_t> must23 = must_be_2_3_continuation(prev2, prev3);
@@ -116,7 +191,8 @@ using namespace simd;
// Return nonzero if there are incomplete multibyte characters at the end of the block: // Return nonzero if there are incomplete multibyte characters at the end of the block:
// e.g. if there is a 4-byte character, but it's 3 bytes from the end. // e.g. if there is a 4-byte character, but it's 3 bytes from the end.
// //
simdjson_inline simd8<uint8_t> is_incomplete(const simd8<uint8_t> input) { template <int N>
simdjson_inline simd8<uint8_t> simd_utf8_checker<N>::is_incomplete(simd8<uint8_t> input) const {
// If the previous input's last 3 bytes match this, they're too short (they ended at EOF): // If the previous input's last 3 bytes match this, they're too short (they ended at EOF):
// ... 1111____ 111_____ 11______ // ... 1111____ 111_____ 11______
#if SIMDJSON_IMPLEMENTATION_ICELAKE #if SIMDJSON_IMPLEMENTATION_ICELAKE
@@ -144,59 +220,43 @@ using namespace simd;
struct utf8_checker { struct utf8_checker {
// If this is nonzero, there has been a UTF-8 error. // If this is nonzero, there has been a UTF-8 error.
simd8<uint8_t> error; simd_utf8_checker<0> checker;
// The last input we received simd8<uint8_t> prev_input;
simd8<uint8_t> prev_input_block;
// Whether the last input we received was incomplete (used for ASCII fast path)
simd8<uint8_t> prev_incomplete;
// simdjson_inline void next(const simd8x64<uint8_t>& input) & {
// Check whether the current bytes are valid UTF-8. // you might think that a for-loop would work, but under Visual Studio, it is not good enough.
// static_assert(
simdjson_inline void check_utf8_bytes(const simd8<uint8_t> input, const simd8<uint8_t> prev_input) { (simd8x64<uint8_t>::NUM_CHUNKS == 1) ||
// Flip prev1...prev3 so we can easily determine if they are 2+, 3+ or 4+ lead bytes (simd8x64<uint8_t>::NUM_CHUNKS == 2) ||
// (2, 3, 4-byte leads become large positive numbers instead of small negative numbers) (simd8x64<uint8_t>::NUM_CHUNKS == 4),
simd8<uint8_t> prev1 = input.prev<1>(prev_input); "We support one, two or four chunks per 64-byte block."
simd8<uint8_t> sc = check_special_cases(input, prev1); );
this->error |= check_multibyte_lengths(input, prev_input, sc);
}
// The only problem that can happen at EOF is that a multibyte character is too short SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
// or a byte value too large in the last bytes: check_special_cases only checks for bytes this->checker = std::move(this->checker)
// too large in the first of two bytes. .next(input.chunks[0], this->prev_input)
simdjson_inline void check_eof() { .next_cycle();
// If the previous block had incomplete UTF-8 characters at the end, an ASCII block can't } else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
// possibly finish them. this->checker = std::move(this->checker)
this->error |= this->prev_incomplete; .next(input.chunks[0], this->prev_input)
} .next(input.chunks[1], input.chunks[0])
.next_cycle();
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) { } else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
if(simdjson_likely(is_ascii(input))) { this->checker = std::move(this->checker)
this->error |= this->prev_incomplete; .next(input.chunks[0], this->prev_input)
} else { .next(input.chunks[1], input.chunks[0])
// you might think that a for-loop would work, but under Visual Studio, it is not good enough. .next(input.chunks[2], input.chunks[1])
static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 1) .next(input.chunks[3], input.chunks[2])
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) .next_cycle();
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
this->check_utf8_bytes(input.chunks[3], input.chunks[2]);
}
this->prev_incomplete = is_incomplete(input.chunks[simd8x64<uint8_t>::NUM_CHUNKS-1]);
this->prev_input_block = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS-1];
} }
this->prev_input = input.chunks[simd8x64<uint8_t>::NUM_CHUNKS-1];
} }
// do not forget to call check_eof!
simdjson_inline error_code errors() { simdjson_inline error_code eof() && {
return this->error.any_bits_set_anywhere() ? error_code::UTF8_ERROR : error_code::SUCCESS; // The only problem that can happen at EOF is that a multibyte character is too short
// or a byte value too large in the last bytes: check_special_cases only checks for bytes
// too large in the first of two bytes.
return std::move(this->checker).eof() ? error_code::UTF8_ERROR : error_code::SUCCESS;
} }
}; // struct utf8_checker }; // struct utf8_checker
+4 -4
View File
@@ -21,16 +21,16 @@ bool generic_validate_utf8(const uint8_t * input, size_t length) {
buf_block_reader<64> reader(input, length); buf_block_reader<64> reader(input, length);
while (reader.has_full_block()) { while (reader.has_full_block()) {
simd::simd8x64<uint8_t> in(reader.full_block()); simd::simd8x64<uint8_t> in(reader.full_block());
c.check_next_input(in); c.next(in);
reader.advance(); reader.advance();
} }
// TODO parse the remainder in sub-blocks (16/32 bytes at a time depending on arch)
uint8_t block[64]{}; uint8_t block[64]{};
reader.get_remainder(block); reader.get_remainder(block);
simd::simd8x64<uint8_t> in(block); simd::simd8x64<uint8_t> in(block);
c.check_next_input(in); c.next(in);
reader.advance(); reader.advance();
c.check_eof(); return std::move(c).eof() == error_code::SUCCESS;
return c.errors() == error_code::SUCCESS;
} }
bool generic_validate_utf8(const char * input, size_t length) { bool generic_validate_utf8(const char * input, size_t length) {
@@ -13,7 +13,8 @@ function(add_dual_compile_test TEST_NAME)
target_compile_definitions(${TEST_NAME}_should_not_compile PRIVATE COMPILATION_TEST_USE_FAILING_CODE=1) target_compile_definitions(${TEST_NAME}_should_not_compile PRIVATE COMPILATION_TEST_USE_FAILING_CODE=1)
endfunction(add_dual_compile_test) endfunction(add_dual_compile_test)
add_dual_compile_test(iterate_object)
add_dual_compile_test(iterate_array)
add_dual_compile_test(iterate_char_star) add_dual_compile_test(iterate_char_star)
add_dual_compile_test(iterate_string_view) add_dual_compile_test(iterate_string_view)
add_dual_compile_test(iterate_temporary_buffer) add_dual_compile_test(iterate_temporary_buffer)
@@ -0,0 +1,34 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main() {
auto json = "[1]"_padded;
ondemand::parser parser;
auto f = [](ondemand::parser& p, simdjson::padded_string& jsons) -> ondemand::document {
ondemand::document doc;
auto error = p.iterate(jsons).get(doc);
if(error) { std::abort(); }
return doc;
};
ondemand::array arrayv;
#if COMPILATION_TEST_USE_FAILING_CODE
// Not allowed as this would be unsafe, the document must remain alive.
auto error = f(parser).get_array().get(arrayv);
#else
ondemand::document doc = f(parser, json);
auto error = doc.get_array().get(arrayv);
#endif
if(error) {
std::cout << "Failure" << std::endl;
}
int64_t a = 0;
error = arrayv.at(0).get_int64().get(a);
if(error) {
std::cout << "failure" << std::endl;
}
printf("a = %d\n", (int)a);
return EXIT_SUCCESS;
}
@@ -0,0 +1,34 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main() {
auto json = "{\"a\":1}"_padded;
ondemand::parser parser;
auto f = [](ondemand::parser& p, simdjson::padded_string& jsons) -> ondemand::document {
ondemand::document doc;
auto error = p.iterate(jsons).get(doc);
if(error) { std::abort(); }
return doc;
};
ondemand::object objv;
#if COMPILATION_TEST_USE_FAILING_CODE
// Not allowed as this would be unsafe, the document must remain alive.
auto error = f(parser).get_object().get(objv);
#else
ondemand::document doc = f(parser, json);
auto error = doc.get_object().get(objv);
#endif
if(error) {
std::cout << "Failure" << std::endl;
}
int64_t a = 0;
error = objv["a"].get_int64().get(a);
if(error) {
std::cout << "failure" << std::endl;
}
printf("a = %d\n", (int)a);
return EXIT_SUCCESS;
}
@@ -59,6 +59,22 @@ void compilation_test_3() {
} }
} }
} }
// Do not run this, it is only meant to compile
void compilation_test_4() {
const padded_string bogus = ""_padded;
ondemand::parser parser;
int64_t x1 = (int64_t)parser.iterate(bogus);
double x2 = (double)parser.iterate(bogus);
std::string_view x = (std::string_view)parser.iterate(bogus);
uint64_t x3 = (uint64_t)parser.iterate(bogus);
bool x4 = (bool)parser.iterate(bogus);
(void) x1;
(void) x2;
(void) x3;
(void) x4;
(void) x;
}
#endif // SIMDJSON_EXCEPTIONS #endif // SIMDJSON_EXCEPTIONS
int main(void) { int main(void) {
@@ -164,8 +164,7 @@ namespace json_pointer_tests {
ASSERT_TRUE(is_scalar); ASSERT_TRUE(is_scalar);
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE); ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
std::cout << " checking true"<< std::endl; std::cout << " checking true"<< std::endl;
ASSERT_SUCCESS(parser.iterate(true_json).get(doc)); ASSERT_SUCCESS(parser.iterate(true_json).is_scalar().get(is_scalar));
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
ASSERT_TRUE(is_scalar); ASSERT_TRUE(is_scalar);
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE); ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
std::cout << " checking object"<< std::endl; std::cout << " checking object"<< std::endl;