Compare commits

...

14 Commits

Author SHA1 Message Date
Daniel Lemire 969525cd7d moving recursive 2024-10-18 20:09:30 -04:00
Daniel Lemire 36f5dbcb75 documentation for threading... (#2277)
* documentation for threading...

* remove const

* doc
2024-10-11 12:34:11 -04:00
Daniel Lemire 49901fb254 doc 2024-10-10 21:32:51 -04:00
Daniel Lemire c066b5421b Jsonpath (#2272)
* Add support for JSONPath with '$' prefix and integrate into dom::at_path (#2266)

- Updated `json_path_to_pointer_conversion` to support JSONPath starting with the '$' prefix, while maintaining compatibility with the existing implementation.
- Moved `json_path_to_pointer_conversion` to a separate header file for better modularity and to support JSONPath queries in `dom` mode.
- Implemented `at_path` functionality in `dom` mode to enable querying JSON using JSONPath.
- Added unit tests to validate the new JSONPath support in `dom` mode and ensure compatibility with both standard and existing JSONPath formats.

* two minor fixes

* more tests and documentation

* damn compiler warnings

* more documentation fixes

---------

Co-authored-by: Zhengguo Yang <yangzhgg@gmail.com>
2024-10-08 10:37:59 -04:00
Daniel Lemire ec7550a70e fixes issue 2271 (#2273) 2024-10-08 10:36:12 -04:00
Daniel Lemire 3ef3078e51 documentation for issue 2259 (clarifying) (#2260) 2024-09-21 09:10:35 -04:00
tobil4sk fd06782c97 Make document::is_null behavior consistent with documentation (#2258)
* Make null-like value test consistent with docs

According to the docs: `INCORRECT_TYPE If the JSON value begins with 'n'
and is not 'null'.`

* Match document::is_null behavior to documentation

* Test other token beginning with n with is_null
2024-09-20 20:58:41 -04:00
Daniel Lemire 9303efbd0c [no-ci] Update basics.md 2024-09-20 20:56:11 -04:00
Daniel Lemire 6c979f15cc deps: switch to CPM (#2257)
* deps: switch to CPM

* missing file

* setting the dependencies on URL download

* using fixed version of cxxopts
2024-09-20 13:29:47 -04:00
Daniel Lemire 09ccabbe6c enable BMI, but only when LLVM is the compiler (#2255) 2024-09-20 10:59:54 -04:00
Daniel Lemire e00cc8c6dc Update CI (#2254)
* adding missing undef silencer

* Updating CI

* more fixes

* fix

* big endian fix
2024-09-18 09:09:11 -04:00
tobil4sk c10b32d463 Ignore pragma once when amalgamating source files (#2248)
With gcc it causes an error in `simdjson.cpp`:
```
simdjson.cpp:548:9: warning: #pragma once in main file
  548 | #pragma once
      |         ^~~~
```

It had previously been commented out in:
https://github.com/simdjson/simdjson/commit/6ef555e6fb79363fae057a9a46b52cd208d9e305

However, this was lost in an upgrade:
https://github.com/simdjson/simdjson/commit/2a4ff7346813b120f2b5b40e95d69352b593cc9c
2024-09-17 15:41:12 -04:00
Daniel Lemire 025a44348a adding missing undef silencer (#2253) 2024-09-16 21:04:09 -04:00
Daniel Lemire 70a68da941 pedantic viable size 2024-09-06 01:19:47 -04:00
51 changed files with 1211 additions and 188 deletions
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu ppc64le (GCC 11)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
name: Test
id: runcmd
with:
arch: aarch64
distro: ubuntu_latest
githubToken: ${{ github.token }}
install: |
apt-get update -q -y
apt-get install -y cmake make g++
run: |
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
fuzz-seconds: 600 fuzz-seconds: 600
dry-run: false dry-run: false
- name: Upload Crash - name: Upload Crash
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts
@@ -24,7 +24,7 @@ jobs:
echo "no trailing whitespace found, good!" echo "no trailing whitespace found, good!"
fi fi
- name: Archive whitespace patch - name: Archive whitespace patch
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
if: always() if: always()
with: with:
name: whitespace-patch name: whitespace-patch
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
- msystem: "MINGW64" - msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Debug type: Debug
- msystem: "MINGW64" - msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: RelWithDebInfo type: RelWithDebInfo
env: env:
+1 -1
View File
@@ -24,6 +24,6 @@ jobs:
apt-get update -q -y apt-get update -q -y
apt-get install -y cmake make g++ apt-get install -y cmake make g++
run: | run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2 cmake --build build -j=2
ctest --output-on-failure --test-dir build ctest --output-on-failure --test-dir build
+1 -1
View File
@@ -24,6 +24,6 @@ jobs:
apt-get update -q -y apt-get update -q -y
apt-get install -y cmake make g++ apt-get install -y cmake make g++
run: | run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2 cmake --build build -j=2
ctest --output-on-failure --test-dir build ctest --output-on-failure --test-dir build
+1 -1
View File
@@ -24,6 +24,6 @@ jobs:
apt-get update -q -y apt-get update -q -y
apt-get install -y cmake make g++ apt-get install -y cmake make g++
run: | run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build cmake -DCMAKE_BUILD_TYPE=Release -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake --build build -j=2 cmake --build build -j=2
ctest --output-on-failure --test-dir build ctest --output-on-failure --test-dir build
+4 -4
View File
@@ -26,15 +26,15 @@ jobs:
run: | run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
- name: Build Debug - name: Build Debug
run: cmake --build build --config ${{build_type}} --verbose run: cmake --build build --config ${{matrix.build_type}} --verbose
- name: Run tests - name: Run tests
run: | run: |
cd build cd build
ctest -C ${{build_type}} -LE explicitonly --output-on-failure ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
- name: Install - name: Install
run: | run: |
cmake --install build --config ${{build_type}} cmake --install build --config ${{matrix.build_type}}
- name: Test Installation - name: Test Installation
run: | run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
cmake --build build_install_test --config ${{build_type}} cmake --build build_install_test --config ${{matrix.build_type}}
+1
View File
@@ -287,6 +287,7 @@ enable_testing()
add_custom_target(all_tests) add_custom_target(all_tests)
add_subdirectory(windows) add_subdirectory(windows)
include(cmake/CPM.cmake)
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
add_subdirectory(tools) ## This needs to be before tests because of cxxopts add_subdirectory(tools) ## This needs to be before tests because of cxxopts
+6 -5
View File
@@ -50,7 +50,7 @@ private:
uint8_t *p) noexcept; uint8_t *p) noexcept;
simdjson_inline void simdjson_inline void
write_raw_string(simdjson::ondemand::raw_json_string rjs); write_raw_string(simdjson::ondemand::raw_json_string rjs);
inline void recursive_processor(simdjson::ondemand::value element); inline void recursive_processor(simdjson::ondemand::value&& element);
inline void recursive_processor_ref(simdjson::ondemand::value& element); inline void recursive_processor_ref(simdjson::ondemand::value& element);
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
@@ -90,12 +90,13 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
} else { } else {
simdjson::ondemand::value val = doc; simdjson::ondemand::value val = doc;
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER)) #define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
#if SIMDJSON_GCC_COMPILER #if 1
//SIMDJSON_GCC_COMPILER
// the GCC compiler does well with by-value passing. // the GCC compiler does well with by-value passing.
// GCC has superior recursive inlining: // GCC has superior recursive inlining:
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co // https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
// https://godbolt.org/z/TeK4doE51 // https://godbolt.org/z/TeK4doE51
recursive_processor(val); recursive_processor(std::move(val));
#else #else
recursive_processor_ref(val); recursive_processor_ref(val);
#endif #endif
@@ -140,7 +141,7 @@ void simdjson2msgpack::write_raw_string(
write_uint32_at(uint32_t(v.size()), location); write_uint32_at(uint32_t(v.size()), location);
} }
void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) { void simdjson2msgpack::recursive_processor(simdjson::ondemand::value&& element) {
switch (element.type()) { switch (element.type()) {
case simdjson::ondemand::json_type::array: { case simdjson::ondemand::json_type::array: {
uint32_t counter = 0; uint32_t counter = 0;
@@ -148,7 +149,7 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
uint8_t *location = skip_uint32(); uint8_t *location = skip_uint32();
for (auto child : element.get_array()) { for (auto child : element.get_array()) {
counter++; counter++;
recursive_processor(child.value()); recursive_processor(std::move(child.value()));
} }
write_uint32_at(counter, location); write_uint32_at(counter, location);
} break; } break;
+24
View File
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.40.2)
set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})
+76 -37
View File
@@ -1,5 +1,4 @@
include(CMakeDependentOption) include(CMakeDependentOption)
include(import.cmake)
option(SIMDJSON_ALLOW_DOWNLOADS option(SIMDJSON_ALLOW_DOWNLOADS
"Allow dependencies to be downloaded during configure time" "Allow dependencies to be downloaded during configure time"
@@ -11,17 +10,21 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
SIMDJSON_ALLOW_DOWNLOADS OFF) SIMDJSON_ALLOW_DOWNLOADS OFF)
if(SIMDJSON_GOOGLE_BENCHMARKS) if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_TESTING) CPMAddPackage(
set_off(BENCHMARK_ENABLE_INSTALL) NAME google_benchmarks
set_off(BENCHMARK_ENABLE_WERROR) URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.zip
OPTIONS
import_dependency(google_benchmarks google/benchmark v1.7.1) "BENCHMARK_ENABLE_TESTING OFF"
add_dependency(google_benchmarks) "BENCHMARK_ENABLE_INSTALL OFF"
"BENCHMARK_ENABLE_WERROR OFF"
)
endif() endif()
# The bulk of our benchmarking and testing data has been moved simdjson/simdjson-data CPMAddPackage(
import_dependency(simdjson-data simdjson/simdjson-data a5b13babe65c1bba7186b41b43d4cbdc20a5c470) NAME simdjson-data
add_dependency(simdjson-data) URL https://github.com/simdjson/simdjson-data/archive/a5b13babe65c1bba7186b41b43d4cbdc20a5c470.zip
)
option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF) option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF)
# This prevents variables declared with set() from unnecessarily escaping and # This prevents variables declared with set() from unnecessarily escaping and
# should not be called more than once # should not be called more than once
@@ -38,20 +41,30 @@ function(competition_scope_)
int main() {} int main() {}
]] SIMDJSON_FOUND_STRING_VIEW) ]] SIMDJSON_FOUND_STRING_VIEW)
if(SIMDJSON_FOUND_STRING_VIEW AND SIMDJSON_USE_BOOST_JSON) if(SIMDJSON_FOUND_STRING_VIEW AND SIMDJSON_USE_BOOST_JSON)
import_dependency(boostjson boostorg/json ee8d72d) CPMAddPackage(
NAME boostjson
URL https://github.com/boostorg/json/archive/ee8d72d8502b409b5561200299cad30ccdb91415.zip
)
add_library(boostjson STATIC "${boostjson_SOURCE_DIR}/src/src.cpp") add_library(boostjson STATIC "${boostjson_SOURCE_DIR}/src/src.cpp")
target_compile_definitions(boostjson PUBLIC BOOST_JSON_STANDALONE) target_compile_definitions(boostjson PUBLIC BOOST_JSON_STANDALONE)
target_include_directories(boostjson SYSTEM PUBLIC target_include_directories(boostjson SYSTEM PUBLIC
"${boostjson_SOURCE_DIR}/include") "${boostjson_SOURCE_DIR}/include")
target_compile_definitions(boostjson INTERFACE SIMDJSON_COMPETITION_BOOSTJSON) target_compile_definitions(boostjson INTERFACE SIMDJSON_COMPETITION_BOOSTJSON)
endif() endif()
CPMAddPackage(
import_dependency(cjson DaveGamble/cJSON c69134d) NAME cjson
URL https://github.com/DaveGamble/cJSON/archive/c69134d01746dcf551dd7724b4edb12f922eb0d1.zip
DOWNLOAD_ONLY YES
)
add_library(cjson STATIC "${cjson_SOURCE_DIR}/cJSON.c") add_library(cjson STATIC "${cjson_SOURCE_DIR}/cJSON.c")
target_include_directories(cjson SYSTEM PUBLIC "${cjson_SOURCE_DIR}") target_include_directories(cjson SYSTEM PUBLIC "${cjson_SOURCE_DIR}")
target_compile_definitions(cjson INTERFACE SIMDJSON_COMPETITION_CJSON) target_compile_definitions(cjson INTERFACE SIMDJSON_COMPETITION_CJSON)
import_dependency(fastjson mikeando/fastjson 485f994) CPMAddPackage(
NAME fastjson
URL https://github.com/mikeando/fastjson/archive/485f994a61a64ac73fa6a40d4d639b99b463563b.zip
DOWNLOAD_ONLY YES
)
add_library(fastjson STATIC add_library(fastjson STATIC
"${fastjson_SOURCE_DIR}/src/fastjson.cpp" "${fastjson_SOURCE_DIR}/src/fastjson.cpp"
"${fastjson_SOURCE_DIR}/src/fastjson2.cpp" "${fastjson_SOURCE_DIR}/src/fastjson2.cpp"
@@ -60,28 +73,36 @@ int main() {}
"${fastjson_SOURCE_DIR}/include") "${fastjson_SOURCE_DIR}/include")
target_compile_definitions(fastjson INTERFACE SIMDJSON_COMPETITION_FASTJSON) target_compile_definitions(fastjson INTERFACE SIMDJSON_COMPETITION_FASTJSON)
import_dependency(gason vivkin/gason 7aee524) CPMAddPackage(
NAME gason
URL https://github.com/vivkin/gason/archive/7aee524189da1c1ecd19f67981e3d903dae25470.zip
DOWNLOAD_ONLY YES
)
add_library(gason STATIC "${gason_SOURCE_DIR}/src/gason.cpp") add_library(gason STATIC "${gason_SOURCE_DIR}/src/gason.cpp")
target_include_directories(gason SYSTEM PUBLIC "${gason_SOURCE_DIR}/src") target_include_directories(gason SYSTEM PUBLIC "${gason_SOURCE_DIR}/src")
target_compile_definitions(gason INTERFACE SIMDJSON_COMPETITION_GASON) target_compile_definitions(gason INTERFACE SIMDJSON_COMPETITION_GASON)
import_dependency(jsmn zserge/jsmn 18e9fe4) CPMAddPackage(
NAME jsmn
URL https://github.com/zserge/jsmn/archive/18e9fe42cbfe21d65076f5c77ae2be379ad1270f.zip
DOWNLOAD_ONLY YES
)
add_library(jsmn STATIC "${jsmn_SOURCE_DIR}/jsmn.c") add_library(jsmn STATIC "${jsmn_SOURCE_DIR}/jsmn.c")
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}") target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN) target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
message(STATUS "Importing json (nlohmann/json@v3.10.5)") CPMAddPackage(
set(nlohmann_json_SOURCE_DIR "${dep_root}/json") NAME nlohmann_json
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}") URL https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip
file(DOWNLOAD )
"https://github.com/nlohmann/json/releases/download/v3.10.5/json.hpp"
"${nlohmann_json_SOURCE_DIR}/nlohmann/json.hpp")
endif()
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json SYSTEM INTERFACE "${nlohmann_json_SOURCE_DIR}")
target_compile_definitions(nlohmann_json INTERFACE SIMDJSON_COMPETITION_NLOHMANN_JSON)
import_dependency(json11 dropbox/json11 ec4e452) set_property(TARGET nlohmann_json APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS SIMDJSON_COMPETITION_NLOHMANN_JSON)
CPMAddPackage(
NAME json11
URL https://github.com/dropbox/json11/archive/ec4e45219af1d7cde3d58b49ed762376fccf1ace.zip
DOWNLOAD_ONLY YES
)
add_library(json11 STATIC "${json11_SOURCE_DIR}/json11.cpp") add_library(json11 STATIC "${json11_SOURCE_DIR}/json11.cpp")
target_include_directories(json11 SYSTEM PUBLIC "${json11_SOURCE_DIR}") target_include_directories(json11 SYSTEM PUBLIC "${json11_SOURCE_DIR}")
target_compile_definitions(json11 INTERFACE SIMDJSON_COMPETITION_JSON11) target_compile_definitions(json11 INTERFACE SIMDJSON_COMPETITION_JSON11)
@@ -91,7 +112,11 @@ int main() {}
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}") target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP) target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
import_dependency(rapidjson Tencent/rapidjson f54b0e4) CPMAddPackage(
NAME rapidjson
URL https://github.com/Tencent/rapidjson/archive/f54b0e47a08782a6131cc3d60f94d038fa6e0a51.zip
DOWNLOAD_ONLY YES
)
add_library(rapidjson INTERFACE) add_library(rapidjson INTERFACE)
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING) target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
include (TestBigEndian) include (TestBigEndian)
@@ -110,14 +135,22 @@ int main() {}
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON) target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
endif() endif()
import_dependency(sajson chadaustin/sajson 2dcfd35) CPMAddPackage(
NAME sajson
URL https://github.com/chadaustin/sajson/archive/2dcfd350586375f9910f74821d4f07d67ae455ba.zip
DOWNLOAD_ONLY YES
)
add_library(sajson INTERFACE) add_library(sajson INTERFACE)
target_compile_definitions(sajson INTERFACE SAJSON_UNSORTED_OBJECT_KEYS) target_compile_definitions(sajson INTERFACE SAJSON_UNSORTED_OBJECT_KEYS)
target_include_directories(sajson SYSTEM INTERFACE target_include_directories(sajson SYSTEM INTERFACE
"${sajson_SOURCE_DIR}/include") "${sajson_SOURCE_DIR}/include")
target_compile_definitions(sajson INTERFACE SIMDJSON_COMPETITION_SAJSON) target_compile_definitions(sajson INTERFACE SIMDJSON_COMPETITION_SAJSON)
import_dependency(ujson4c esnme/ujson4c e14f3fd) CPMAddPackage(
NAME ujson4c
URL https://github.com/esnme/ujson4c/archive/e14f3fd5207fe30d1bdea723f260609e69d1abfa.zip
DOWNLOAD_ONLY YES
)
add_library(ujson4c STATIC add_library(ujson4c STATIC
"${ujson4c_SOURCE_DIR}/src/ujdecode.c" "${ujson4c_SOURCE_DIR}/src/ujdecode.c"
"${ujson4c_SOURCE_DIR}/3rdparty/ultrajsondec.c") "${ujson4c_SOURCE_DIR}/3rdparty/ultrajsondec.c")
@@ -126,7 +159,11 @@ int main() {}
"${ujson4c_SOURCE_DIR}/3rdparty") "${ujson4c_SOURCE_DIR}/3rdparty")
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C) target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
import_dependency(yyjson ibireme/yyjson c385651) CPMAddPackage(
NAME yyjson
URL https://github.com/ibireme/yyjson/archive/c3856514de0a67d7b66939bf3ed491a2d6e61277.zip
DOWNLOAD_ONLY YES
)
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c") add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src") target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON) target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
@@ -151,10 +188,12 @@ cmake_dependent_option(SIMDJSON_CXXOPTS "Download cxxopts (necessary for tools)"
SIMDJSON_ALLOW_DOWNLOADS OFF) SIMDJSON_ALLOW_DOWNLOADS OFF)
if(SIMDJSON_CXXOPTS) if(SIMDJSON_CXXOPTS)
set_off(CXXOPTS_BUILD_EXAMPLES) CPMAddPackage(
set_off(CXXOPTS_BUILD_TESTS) NAME cxxopts
set_off(CXXOPTS_ENABLE_INSTALL) URL https://github.com/jarro2783/cxxopts/archive/59656709c0c58fcd0ed18b38e02938dbe05284c5.zip
OPTIONS
import_dependency(cxxopts jarro2783/cxxopts 5965670) "CXXOPTS_BUILD_EXAMPLES OFF"
add_dependency(cxxopts) "CXXOPTS_BUILD_TESTS OFF"
"CXXOPTS_ENABLE_INSTALL OFF"
)
endif() endif()
-48
View File
@@ -1,48 +0,0 @@
set(dep_root "${simdjson_SOURCE_DIR}/dependencies/.cache")
if(DEFINED ENV{simdjson_DEPENDENCY_CACHE_DIR})
set(dep_root "$ENV{simdjson_DEPENDENCY_CACHE_DIR}")
endif()
function(import_dependency NAME GITHUB_REPO COMMIT)
message(STATUS "Importing ${NAME} (${GITHUB_REPO}@${COMMIT})")
set(target "${dep_root}/${NAME}")
# If the folder exists in the cache, then we assume that everything is as
# should be and do nothing
if(EXISTS "${target}")
set("${NAME}_SOURCE_DIR" "${target}" PARENT_SCOPE)
return()
endif()
set(zip_url "https://github.com/${GITHUB_REPO}/archive/${COMMIT}.zip")
set(archive "${dep_root}/archive.zip")
set(dest "${dep_root}/_extract")
file(DOWNLOAD "${zip_url}" "${archive}")
file(MAKE_DIRECTORY "${dest}")
execute_process(
WORKING_DIRECTORY "${dest}"
COMMAND "${CMAKE_COMMAND}" -E tar xf "${archive}")
file(REMOVE "${archive}")
# GitHub archives only ever have one folder component at the root, so this
# will always match that single folder
file(GLOB dir LIST_DIRECTORIES YES "${dest}/*")
file(RENAME "${dir}" "${target}")
set("${NAME}_SOURCE_DIR" "${target}" PARENT_SCOPE)
endfunction()
# Delegates to the dependency
macro(add_dependency NAME)
if(NOT DEFINED "${NAME}_SOURCE_DIR")
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
endif()
add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}" EXCLUDE_FROM_ALL)
endmacro()
function(set_off NAME)
set("${NAME}" OFF CACHE INTERNAL "")
endfunction()
+18 -3
View File
@@ -247,7 +247,7 @@ documents.
For code safety, you should keep (1) the `parser` instance, (2) the input string and (3) the document instance alive throughout your parsing. Additionally, you should follow the following rules: For code safety, you should keep (1) the `parser` instance, (2) the input string and (3) the document instance alive throughout your parsing. Additionally, you should follow the following rules:
- A `parser` may have at most one document open at a time, since it holds allocated memory used for the parsing. - A `parser` may have at most one document open at a time, since it holds allocated memory used for the parsing.
- By design, you should only have one `document` instance per JSON document. Thus, if you must pass a document instance to a function, you should avoid passing it by value: choose to pass it by reference instance to avoid the copy. (We also provide a `document_reference` class if you need to pass by value.) - By design, you should only have one `document` instance per JSON document. Thus, if you must pass a document instance to a function, you should avoid passing it by value: choose to pass it by reference instance to avoid the copy. In any case, the `document` class does not have a copy constructor.
During the `iterate` call, the original JSON text is never modified--only read. After you are done During the `iterate` call, the original JSON text is never modified--only read. After you are done
with the document, the source (whether file or string) can be safely discarded. with the document, the source (whether file or string) can be safely discarded.
@@ -1224,9 +1224,11 @@ be represented as `value` instances. You can check that a document is a scalar w
JSONPath JSONPath
------------ ------------
The simdjson library now supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index. The simdjson library supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_path`. This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of
[`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects
and arrays: make sure to consume the values between each call to `at_path`.
Consider the following example: Consider the following example:
@@ -1267,6 +1269,18 @@ doc.at_path(".\\u00E9") == 123; // true
doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD) doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD)
``` ```
We also support the `$` prefix. When you start a JSONPath expression with $, you are indicating that the path starts from the root of the JSON document. E.g.,
```c++
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object obj = doc.get_object();
int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
x = obj.at_path("$.d.foo2.a.2"); // 30
```
Error handling Error handling
-------------- --------------
@@ -2673,6 +2687,7 @@ Performance tips
std::string_view year = data["year"]; std::string_view year = data["year"];
std::string_view rating = data["rating"]; std::string_view rating = data["rating"];
``` ```
- You will get better performance if you seek the keys in the order in which they appear in the document. So if processing `{"a":1, "b":2, "c":3}`, do `value1 = data["a"]; value2 = data["b"]; value3 data["c"];` and not `value2 = data["b"]; value1 = data["a"]; value3 data["c"];`. Of course, it is not always possible to know for sure in which order the keys appear.
+44
View File
@@ -8,6 +8,7 @@ An overview of what you need to know to use simdjson, with examples.
* [Using the Parsed JSON](#using-the-parsed-json) * [Using the Parsed JSON](#using-the-parsed-json)
* [C++17 Support](#c17-support) * [C++17 Support](#c17-support)
* [JSON Pointer](#json-pointer) * [JSON Pointer](#json-pointer)
* [JSONPath](#jsonpath)
* [Error Handling](#error-handling) * [Error Handling](#error-handling)
* [Error Handling Example](#error-handling-example) * [Error Handling Example](#error-handling-example)
* [Exceptions](#exceptions) * [Exceptions](#exceptions)
@@ -257,6 +258,49 @@ for (dom::element car_element : cars) {
} }
``` ```
JSONPath
------------
The simdjson library supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
Consider the following example:
```c++
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(cars_json).get(doc);
if(error) { /*won't happen*/ }
double p;
error = doc.at_path("[0].tire_pressure[1]").get(p);
if(error) { /*won't happen*/ }
cout << p << endl; // Prints 39.9
```
We also support the `$` prefix. When you start a JSONPath expression with $, you are indicating that the path starts from the root of the JSON document. E.g.,
```c++
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(json).get(doc);
if(error) { /*won't happen*/ }
dom::object obj;
error = doc.get_object().get(obj);
if(error) { /*won't happen*/ }
int64_t x;
error = obj.at_path("$[3].foo.a[1]").get(x);
if(error) { /*won't happen*/ }
if(x != 20) { /*won't happen*/ }
x = obj.at_path("$.d.foo2.a.2");
if(error) { /*won't happen*/ }
```
Error Handling Error Handling
+6 -1
View File
@@ -102,7 +102,12 @@ remove almost entirely its cost and replaces it by the overhead of a thread, whi
cheaper. Ain't that awesome! cheaper. Ain't that awesome!
Thread support is only active if thread supported is detected in which case the macro Thread support is only active if thread supported is detected in which case the macro
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode. SIMDJSON_THREADS_ENABLED is set. You can also manually pass `SIMDJSON_THREADS_ENABLED=1` flag
to the library. Otherwise the library runs in single-thread mode.
You should be consistent. If you link against the simdjson library built for multithreading
(i.e., with `SIMDJSON_THREADS_ENABLED`), then you should build your application with multithreading
system (setting `SIMDJSON_THREADS_ENABLED=1` and linking against a thread library).
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread. A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
+6 -1
View File
@@ -103,7 +103,12 @@ cases, remove almost entirely its cost and replaces it by the overhead of a thre
of magnitude cheaper. Ain't that awesome! of magnitude cheaper. Ain't that awesome!
Thread support is only active if thread supported is detected in which case the macro Thread support is only active if thread supported is detected in which case the macro
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode. SIMDJSON_THREADS_ENABLED is set. You can also manually pass `SIMDJSON_THREADS_ENABLED=1` flag
to the library. Otherwise the library runs in single-thread mode.
You should be consistent. If you link against the simdjson library built for multithreading
(i.e., with `SIMDJSON_THREADS_ENABLED`), then you should build your application with multithreading
system (setting `SIMDJSON_THREADS_ENABLED=1` and linking against a thread library).
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread. A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
You should expect the main thread to be fully occupied while the worker thread is partially busy You should expect the main thread to be fully occupied while the worker thread is partially busy
+2 -2
View File
@@ -241,8 +241,8 @@ long page_size() {
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the // Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
// page boundary. // page boundary.
bool need_allocation(const char *buf, size_t len) { bool need_allocation(const char *buf, size_t len) {
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) < return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
simdjson::SIMDJSON_PADDING); + simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
} }
simdjson::padded_string_view simdjson::padded_string_view
+6
View File
@@ -35,6 +35,12 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1); return input_num & (input_num-1);
} }
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
@@ -51,6 +51,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64 } // namespace arm64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
+14
View File
@@ -7,6 +7,7 @@
#include "simdjson/dom/array.h" #include "simdjson/dom/array.h"
#include "simdjson/dom/element.h" #include "simdjson/dom/element.h"
#include "simdjson/error-inl.h" #include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include "simdjson/internal/tape_ref-inl.h" #include "simdjson/internal/tape_ref-inl.h"
#include <limits> #include <limits>
@@ -44,6 +45,13 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
if (error()) { return error(); } if (error()) { return error(); }
return first.at_pointer(json_pointer); return first.at_pointer(json_pointer);
} }
inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept { inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.at(index); return first.at(index);
@@ -113,6 +121,12 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
return child; return child;
} }
inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<element> array::at(size_t index) const noexcept { inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0; size_t i=0;
+16
View File
@@ -108,6 +108,21 @@ public:
*/ */
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
/** /**
* Get the value at the given index. This function has linear-time complexity and * Get the value at the given index. This function has linear-time complexity and
* is equivalent to the following: * is equivalent to the following:
@@ -152,6 +167,7 @@ public:
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at(size_t index) const noexcept; inline simdjson_result<dom::element> at(size_t index) const noexcept;
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
+11
View File
@@ -9,6 +9,7 @@
#include "simdjson/dom/object-inl.h" #include "simdjson/dom/object-inl.h"
#include "simdjson/error-inl.h" #include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include <ostream> #include <ostream>
#include <limits> #include <limits>
@@ -122,6 +123,11 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
if (error()) { return error(); } if (error()) { return error(); }
return first.at_pointer(json_pointer); return first.at_pointer(json_pointer);
} }
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_path(const std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API #ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept { simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
@@ -412,6 +418,11 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
} }
} }
} }
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API #ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
inline simdjson_result<element> element::at(std::string_view json_pointer) const noexcept { inline simdjson_result<element> element::at(std::string_view json_pointer) const noexcept {
+16
View File
@@ -397,6 +397,21 @@ public:
*/ */
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept; inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
#ifndef SIMDJSON_DISABLE_DEPRECATED_API #ifndef SIMDJSON_DISABLE_DEPRECATED_API
/** /**
* *
@@ -526,6 +541,7 @@ public:
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept; simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept; simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept; simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]] [[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept; simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept; simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept;
+12
View File
@@ -7,6 +7,7 @@
#include "simdjson/dom/element-inl.h" #include "simdjson/dom/element-inl.h"
#include "simdjson/error-inl.h" #include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include <cstring> #include <cstring>
@@ -34,6 +35,11 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_pointer(st
if (error()) { return error(); } if (error()) { return error(); }
return first.at_pointer(json_pointer); return first.at_pointer(json_pointer);
} }
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept { inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
if (error()) { return error(); } if (error()) { return error(); }
return first.at_key(key); return first.at_key(key);
@@ -131,6 +137,12 @@ inline simdjson_result<element> object::at_pointer(std::string_view json_pointer
return child; return child;
} }
inline simdjson_result<element> object::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept { inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
iterator end_field = end(); iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) { for (iterator field = begin(); field != end_field; ++field) {
+16
View File
@@ -171,6 +171,21 @@ public:
*/ */
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
/** /**
* Get the value associated with the given key. * Get the value associated with the given key.
* *
@@ -244,6 +259,7 @@ public:
inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept; inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
inline simdjson_result<dom::element> operator[](const char *key) const noexcept; inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept; inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept; inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept; inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
+6 -1
View File
@@ -549,9 +549,14 @@ public:
/** /**
* The parser instance can use threads when they are available to speed up some * The parser instance can use threads when they are available to speed up some
* operations. It is enabled by default. Changing this attribute will change the * operations. It is enabled by default. Changing this attribute will change the
* behavior of the parser for future operations. * behavior of the parser for future operations. Set to true by default.
*/ */
bool threaded{true}; bool threaded{true};
#else
/**
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
*/
bool threaded{false};
#endif #endif
/** @private Use the new DOM API instead */ /** @private Use the new DOM API instead */
class Iterator; class Iterator;
@@ -75,6 +75,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback } // namespace fallback
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
-1
View File
@@ -574,7 +574,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
+1 -47
View File
@@ -2,6 +2,7 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE #ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H #define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
#include "simdjson/jsonpathutil.h"
#include "simdjson/generic/ondemand/base.h" #include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/array.h" #include "simdjson/generic/ondemand/array.h"
#include "simdjson/generic/ondemand/array_iterator-inl.h" #include "simdjson/generic/ondemand/array_iterator-inl.h"
@@ -163,53 +164,6 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
return child; return child;
} }
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"; // This is just a sentinel value, the caller should check for this and return an error.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
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"; // Using 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 result;
}
inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept { inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path); auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; } if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
@@ -13,5 +13,6 @@
#include "simdjson/padded_string.h" #include "simdjson/padded_string.h"
#include "simdjson/padded_string_view.h" #include "simdjson/padded_string_view.h"
#include "simdjson/internal/dom_parser_implementation.h" #include "simdjson/internal/dom_parser_implementation.h"
#include "simdjson/jsonpathutil.h"
#endif // SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H #endif // SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H
@@ -691,6 +691,11 @@ protected:
/** /**
* A document_reference is a thin wrapper around a document reference instance. * A document_reference is a thin wrapper around a document reference instance.
* The document_reference instances are used primarily/solely for streams of JSON
* documents. They differ from document instances when parsing a scalar value
* (a document that is not an array or an object). In the case of a document,
* we expect the document to be fully consumed. In the case of a document_reference,
* we allow trailing content.
*/ */
class document_reference { class document_reference {
public: public:
+5 -1
View File
@@ -278,8 +278,12 @@ public:
* behavior of the parser for future operations. * behavior of the parser for future operations.
*/ */
bool threaded{true}; bool threaded{true};
#else
/**
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
*/
bool threaded{false};
#endif #endif
/** /**
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer. * Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
* The result must be valid UTF-8. * The result must be valid UTF-8.
@@ -799,6 +799,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
if(result) { // we have something that looks like a null. if(result) { // we have something that looks like a null.
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; } if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("null"); advance_root_scalar("null");
} else if (json[0] == 'n') {
return incorrect_type_error("Not a null but starts with n");
} }
return result; return result;
} }
+6
View File
@@ -4,8 +4,14 @@
#include "simdjson/haswell/intrinsics.h" #include "simdjson/haswell/intrinsics.h"
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL #if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt") SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif #endif
#endif
#include "simdjson/haswell/bitmanipulation.h" #include "simdjson/haswell/bitmanipulation.h"
#include "simdjson/haswell/bitmask.h" #include "simdjson/haswell/bitmask.h"
+64
View File
@@ -0,0 +1,64 @@
#ifndef SIMDJSON_JSONPATHUTIL_H
#define SIMDJSON_JSONPATHUTIL_H
#include <string>
#include <string_view>
namespace simdjson {
/**
* Converts JSONPath to JSON Pointer.
* @param json_path The JSONPath string to be converted.
* @return A string containing the equivalent JSON Pointer.
*/
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
size_t i = 0;
// if JSONPath starts with $, skip it
if (!json_path.empty() && json_path.front() == '$') {
i = 1;
}
if (json_path.empty() || (json_path[i] != '.' &&
json_path[i] != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
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"; // Using 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 result;
}
} // namespace simdjson
#endif // SIMDJSON_JSONPATHUTIL_H
@@ -36,6 +36,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx } // namespace lasx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
@@ -36,6 +36,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx } // namespace lsx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+9 -1
View File
@@ -53,6 +53,9 @@ inline padded_string::padded_string(const char *data, size_t length) noexcept
if ((data != nullptr) && (data_ptr != nullptr)) { if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, data, length); std::memcpy(data_ptr, data, length);
} }
if (data_ptr == nullptr) {
viable_size = 0;
}
} }
#ifdef __cpp_char8_t #ifdef __cpp_char8_t
inline padded_string::padded_string(const char8_t *data, size_t length) noexcept inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
@@ -60,12 +63,17 @@ inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
if ((data != nullptr) && (data_ptr != nullptr)) { if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length); std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length);
} }
if (data_ptr == nullptr) {
viable_size = 0;
}
} }
#endif #endif
// note: do not pass std::string arguments by value // note: do not pass std::string arguments by value
inline padded_string::padded_string(const std::string & str_ ) noexcept inline padded_string::padded_string(const std::string & str_ ) noexcept
: viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) { : viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) {
if (data_ptr != nullptr) { if (data_ptr == nullptr) {
viable_size = 0;
} else {
std::memcpy(data_ptr, str_.data(), str_.size()); std::memcpy(data_ptr, str_.data(), str_.size());
} }
} }
+39
View File
@@ -201,4 +201,43 @@ using std::size_t;
#endif #endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H #endif // SIMDJSON_PORTABILITY_H
@@ -60,6 +60,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64 } // namespace ppc64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
+4
View File
@@ -323,6 +323,10 @@ class Amalgamator:
for line in fid2: for line in fid2:
line = line.rstrip('\n') line = line.rstrip('\n')
# Ignore #pragma once, it causes warnings if it ends up in a .cpp file
if re.search(r'^#pragma once$', line):
continue
# Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE # Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE
if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line): if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file!" assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file!"
+112 -10
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-08-26 09:37:03 -0400. Do not edit! */ /* auto-generated on 2024-09-17 15:48:50 -0400. Do not edit! */
/* including simdjson.cpp: */ /* including simdjson.cpp: */
/* begin file simdjson.cpp */ /* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP #define SIMDJSON_SRC_SIMDJSON_CPP
@@ -284,6 +284,45 @@ using std::size_t;
#endif #endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H #endif // SIMDJSON_PORTABILITY_H
/* end file simdjson/portability.h */ /* end file simdjson/portability.h */
@@ -549,7 +588,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#ifndef NONSTD_SV_LITE_H_INCLUDED #ifndef NONSTD_SV_LITE_H_INCLUDED
#define NONSTD_SV_LITE_H_INCLUDED #define NONSTD_SV_LITE_H_INCLUDED
@@ -7639,6 +7677,12 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1); return input_num & (input_num-1);
} }
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
@@ -7811,7 +7855,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64 } // namespace arm64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */ /* end file simdjson/arm64/numberparsing_defs.h */
@@ -9428,7 +9478,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -10395,6 +10444,12 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1); return input_num & (input_num-1);
} }
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
@@ -10567,7 +10622,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64 } // namespace arm64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */ /* end file simdjson/arm64/numberparsing_defs.h */
@@ -15770,7 +15831,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -21984,7 +22044,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -26750,7 +26809,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64 } // namespace ppc64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */ /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -28354,7 +28419,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -29494,7 +29558,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64 } // namespace ppc64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */ /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -35090,7 +35160,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -40176,7 +40245,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx } // namespace lsx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */ /* end file simdjson/lsx/numberparsing_defs.h */
@@ -41650,7 +41725,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -42705,7 +42779,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx } // namespace lsx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */ /* end file simdjson/lsx/numberparsing_defs.h */
@@ -46159,7 +46239,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx } // namespace lasx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */ /* end file simdjson/lasx/numberparsing_defs.h */
@@ -47649,7 +47735,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -48704,7 +48789,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx } // namespace lasx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */ /* end file simdjson/lasx/numberparsing_defs.h */
@@ -52188,7 +52279,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback } // namespace fallback
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */ /* end file simdjson/fallback/numberparsing_defs.h */
@@ -53247,7 +53344,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -54322,7 +54418,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback } // namespace fallback
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */ /* end file simdjson/fallback/numberparsing_defs.h */
+129 -15
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-08-26 09:37:03 -0400. Do not edit! */ /* auto-generated on 2024-09-17 15:48:50 -0400. Do not edit! */
/* including simdjson.h: */ /* including simdjson.h: */
/* begin file simdjson.h */ /* begin file simdjson.h */
#ifndef SIMDJSON_H #ifndef SIMDJSON_H
@@ -304,6 +304,45 @@ using std::size_t;
#endif #endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H #endif // SIMDJSON_PORTABILITY_H
/* end file simdjson/portability.h */ /* end file simdjson/portability.h */
@@ -569,7 +608,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#ifndef NONSTD_SV_LITE_H_INCLUDED #ifndef NONSTD_SV_LITE_H_INCLUDED
#define NONSTD_SV_LITE_H_INCLUDED #define NONSTD_SV_LITE_H_INCLUDED
@@ -3911,6 +3949,9 @@ inline padded_string::padded_string(const char *data, size_t length) noexcept
if ((data != nullptr) && (data_ptr != nullptr)) { if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, data, length); std::memcpy(data_ptr, data, length);
} }
if (data_ptr == nullptr) {
viable_size = 0;
}
} }
#ifdef __cpp_char8_t #ifdef __cpp_char8_t
inline padded_string::padded_string(const char8_t *data, size_t length) noexcept inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
@@ -3918,12 +3959,17 @@ inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
if ((data != nullptr) && (data_ptr != nullptr)) { if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length); std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length);
} }
if (data_ptr == nullptr) {
viable_size = 0;
}
} }
#endif #endif
// note: do not pass std::string arguments by value // note: do not pass std::string arguments by value
inline padded_string::padded_string(const std::string & str_ ) noexcept inline padded_string::padded_string(const std::string & str_ ) noexcept
: viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) { : viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) {
if (data_ptr != nullptr) { if (data_ptr == nullptr) {
viable_size = 0;
} else {
std::memcpy(data_ptr, str_.data(), str_.size()); std::memcpy(data_ptr, str_.data(), str_.size());
} }
} }
@@ -9854,6 +9900,12 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1); return input_num & (input_num-1);
} }
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
@@ -10026,7 +10078,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64 } // namespace arm64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */ /* end file simdjson/arm64/numberparsing_defs.h */
@@ -11643,7 +11701,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -12687,7 +12744,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback } // namespace fallback
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */ /* end file simdjson/fallback/numberparsing_defs.h */
@@ -13746,7 +13809,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -16341,7 +16403,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -18935,7 +18996,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -20040,7 +20100,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64 } // namespace ppc64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */ /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -21644,7 +21710,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -24676,7 +24741,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -25705,7 +25769,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx } // namespace lsx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */ /* end file simdjson/lsx/numberparsing_defs.h */
@@ -27179,7 +27249,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -28205,7 +28274,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx } // namespace lasx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */ /* end file simdjson/lasx/numberparsing_defs.h */
@@ -29695,7 +29770,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed. // Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W> template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) { simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// //
// Check for minus sign // Check for minus sign
// //
@@ -30668,6 +30742,12 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1); return input_num & (input_num-1);
} }
// We sometimes call leading_zeroes on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */ /* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) { simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
@@ -30840,7 +30920,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64 } // namespace arm64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */ /* end file simdjson/arm64/numberparsing_defs.h */
@@ -36362,8 +36448,14 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
} }
inline std::string json_path_to_pointer_conversion(std::string_view json_path) { inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
if (json_path.empty() || (json_path.front() != '.' && size_t i = 0;
json_path.front() != '[')) {
// if JSONPath starts with $, skip it
if (!json_path.empty() && json_path.front() == '$') {
i = 1;
}
if (json_path.empty() || (json_path[i] != '.' &&
json_path[i] != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error. return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
} }
@@ -36372,8 +36464,6 @@ inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
// to escaping. // to escaping.
result.reserve(json_path.size() * 2); result.reserve(json_path.size() * 2);
size_t i = 0;
while (i < json_path.length()) { while (i < json_path.length()) {
if (json_path[i] == '.') { if (json_path[i] == '.') {
result += '/'; result += '/';
@@ -41865,7 +41955,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback } // namespace fallback
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H #endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */ /* end file simdjson/fallback/numberparsing_defs.h */
@@ -74310,7 +74406,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64 } // namespace ppc64
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H #endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */ /* end file simdjson/ppc64/numberparsing_defs.h */
@@ -96703,7 +96805,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx } // namespace lsx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */ /* end file simdjson/lsx/numberparsing_defs.h */
@@ -107567,7 +107675,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx } // namespace lasx
} // namespace simdjson } // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1 #define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H #endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */ /* end file simdjson/lasx/numberparsing_defs.h */
+1
View File
@@ -12,6 +12,7 @@ add_cpp_test(errortests LABELS dom acceptance per_implementation
add_cpp_test(extracting_values_example LABELS dom acceptance per_implementation) add_cpp_test(extracting_values_example LABELS dom acceptance per_implementation)
add_cpp_test(integer_tests LABELS dom acceptance per_implementation) add_cpp_test(integer_tests LABELS dom acceptance per_implementation)
add_cpp_test(jsoncheck LABELS dom acceptance per_implementation) add_cpp_test(jsoncheck LABELS dom acceptance per_implementation)
add_cpp_test(json_path_tests LABELS dom acceptance per_implementation)
add_cpp_test(minefieldcheck LABELS dom acceptance per_implementation) add_cpp_test(minefieldcheck LABELS dom acceptance per_implementation)
add_cpp_test(numberparsingcheck LABELS dom acceptance per_implementation) # https://tools.ietf.org/html/rfc6901 add_cpp_test(numberparsingcheck LABELS dom acceptance per_implementation) # https://tools.ietf.org/html/rfc6901
add_cpp_test(parse_many_test LABELS dom acceptance per_implementation) add_cpp_test(parse_many_test LABELS dom acceptance per_implementation)
+350
View File
@@ -0,0 +1,350 @@
/**
* refer to pathcheck.cpp
*/
#include <iostream>
#include <string>
using namespace std::string_literals;
#include "simdjson.h"
#include "test_macros.h"
// we define our own asserts to get around NDEBUG
#ifndef ASSERT
#define ASSERT(x) \
{ \
if (!(x)) { \
std::cerr << "Failed assertion " << #x << std::endl; \
return false; \
} \
}
#endif
using namespace simdjson;
bool demo() {
#if SIMDJSON_EXCEPTIONS
std::cout << "demo test" << std::endl;
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars = parser.parse(cars_json);
double x = cars.at_path("$[0].tire_pressure[1]");
if (x != 39.9)
return false;
// Iterating through an array of objects
std::vector<double> measured;
for (dom::element car_element : cars) {
dom::object car;
simdjson::error_code error;
if ((error = car_element.get(car))) {
std::cerr << error << std::endl;
return false;
}
double x3 = car.at_path("$.tire_pressure[1]");
measured.push_back(x3);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
#endif
return true;
}
const padded_string TEST_JSON = R"(
{
"/~01abc": [
0,
{
"\\\" 0": [
"value0",
"value1"
]
}
],
"0": "0 ok",
"01": "01 ok",
"": "empty ok",
"arr": []
}
)"_padded;
const padded_string TEST_RFC_JSON = R"(
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
)"_padded;
bool run_success_test(const padded_string &source, const char *json_path,
std::string_view expected_value) {
std::cout << "Running successful JSONPath test '" << json_path << "' ..."
<< std::endl;
dom::parser parser;
dom::element doc;
auto error = parser.parse(source).get(doc);
if (error) {
std::cerr << "cannot parse: " << error << std::endl;
return false;
}
dom::element answer;
error = doc.at_path(json_path).get(answer);
if (error) {
std::cerr << "cannot access pointer: " << error << std::endl;
return false;
}
std::string str_answer = simdjson::minify(answer);
if (str_answer != expected_value) {
std::cerr << "They differ!!!" << std::endl;
std::cerr << " found '" << str_answer << "'" << std::endl;
std::cerr << " expected '" << expected_value << "'" << std::endl;
}
ASSERT_EQUAL(str_answer, expected_value);
return true;
}
bool run_failure_test(const padded_string &source, const char *json_path,
error_code expected_error) {
std::cout << "Running invalid JSONPath test '" << json_path << "' ..."
<< std::endl;
dom::parser parser;
ASSERT_ERROR(parser.parse(source).at_path(json_path).error(), expected_error);
return true;
}
bool demo_relative_path() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
auto error = parser.parse(cars_json).get(cars);
if (error) {
std::cerr << "cannot parse: " << error << std::endl;
return false;
}
dom::array cars_array;
error = cars.get(cars_array);
if (error) {
std::cerr << "cannot get array: " << error << std::endl;
return false;
}
for (auto car_element : cars_array) {
double x;
ASSERT_SUCCESS(car_element.at_path(".tire_pressure[1]").get(x));
measured.push_back(x);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
TEST_SUCCEED();
}
bool many_json_paths() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
ASSERT_SUCCESS(parser.parse(cars_json).get(cars));
for (int i = 0; i < 3; i++) {
double x;
std::string json_path = std::string("$[") + std::to_string(i) +
std::string("].tire_pressure[1]");
ASSERT_SUCCESS(cars.at_path(json_path).get(x));
measured.push_back(x);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
TEST_SUCCEED();
}
bool many_json_paths_object_array() {
TEST_START();
auto dogcatpotato =
R"( { "dog" : [1,2,3], "cat" : [5, 6, 7], "potato" : [1234]})"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(dogcatpotato).get(doc));
dom::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.dog[1]").get(x));
ASSERT_EQUAL(x, 2);
ASSERT_SUCCESS(obj.at_path("$.potato[0]").get(x));
ASSERT_EQUAL(x, 1234);
TEST_SUCCEED();
}
bool many_json_paths_object() {
TEST_START();
auto cfoofoo2 =
R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(cfoofoo2).get(doc));
dom::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.c.foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
ASSERT_SUCCESS(obj.at_path("$.d.foo2.a.2").get(x));
ASSERT_EQUAL(x, 30);
ASSERT_SUCCESS(obj.at_path("$.e").get(x));
ASSERT_EQUAL(x, 120);
TEST_SUCCEED();
}
bool many_json_paths_array() {
TEST_START();
auto cfoofoo2 =
R"( [ 111, 2, 3, { "foo": { "a": [ 10, 20, 33 ] }}, { "foo2": { "a": [ 10, 20, 30 ] }}, 1001 ])"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(cfoofoo2).get(doc));
dom::array arr;
ASSERT_SUCCESS(doc.get_array().get(arr));
int64_t x;
ASSERT_SUCCESS(arr.at_path("$[3].foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
TEST_SUCCEED();
}
struct car_type {
std::string make;
std::string model;
uint64_t year;
std::vector<double> tire_pressure;
car_type(std::string_view _make, std::string_view _model, uint64_t _year,
std::vector<double> &&_tire_pressure)
: make{_make}, model{_model}, year(_year), tire_pressure(_tire_pressure) {
}
};
bool json_path_invalidation() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
ASSERT_SUCCESS(parser.parse(cars_json).get(cars));
std::vector<car_type> content;
for (int i = 0; i < 3; i++) {
dom::object obj;
std::string json_path =
std::string("$[") + std::to_string(i) + std::string("]");
// Each successive at_path call invalidates
// previously parsed values, strings, objects and array.
ASSERT_SUCCESS(cars.at_path(json_path).get(obj));
// We materialize the object.
std::string_view make;
ASSERT_SUCCESS(obj["make"].get(make));
std::string_view model;
ASSERT_SUCCESS(obj["model"].get(model));
uint64_t year;
ASSERT_SUCCESS(obj["year"].get(year));
// We materialize the array.
dom::array arr;
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
std::vector<double> values;
for (auto x : arr) {
double value_double;
ASSERT_SUCCESS(x.get(value_double));
values.push_back(value_double);
}
content.emplace_back(make, model, year, std::move(values));
}
std::string expected[] = {"Toyota", "Kia", "Toyota"};
int i = 0;
for (car_type c : content) {
std::cout << c.make << " " << c.model << " " << c.year << "\n";
ASSERT_EQUAL(expected[i++], c.make);
}
TEST_SUCCEED();
}
// for 0.5 version and following (standard compliant)
bool modern_support() {
#if SIMDJSON_EXCEPTIONS
std::cout << "modern test" << std::endl;
auto example_json = R"({"key": "value", "array": [0, 1, 2]})"_padded;
dom::parser parser;
dom::element example = parser.parse(example_json);
std::string_view value_str = example.at_path("$.key");
ASSERT_EQUAL(value_str, "value");
int64_t array0 = example.at_path("$.array[0]");
ASSERT_EQUAL(array0, 0);
array0 = example.at_path("$.array").at_path("$[0]");
ASSERT_EQUAL(array0, 0);
ASSERT_ERROR(example.at_path("$.no_such_key").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_path("$.array[9]").error(), INDEX_OUT_OF_BOUNDS);
ASSERT_ERROR(example.at_path("$.array.not_a_num").error(), INCORRECT_TYPE);
ASSERT_ERROR(example.at_path("$.array.").error(), INVALID_JSON_POINTER);
#endif
return true;
}
int main() {
if (true && demo() && modern_support() &&
run_success_test(TEST_RFC_JSON, "$.foo", "[\"bar\",\"baz\"]") &&
run_success_test(TEST_RFC_JSON, "$.foo[0]", "\"bar\"") &&
run_success_test(TEST_RFC_JSON, "$.", "0") &&
run_success_test(TEST_RFC_JSON, "$.a/b", "1") &&
run_success_test(TEST_RFC_JSON, "$.c%d", "2") &&
run_success_test(TEST_RFC_JSON, "$.e^f", "3") &&
run_success_test(TEST_RFC_JSON, "$.g|h", "4") &&
run_success_test(TEST_RFC_JSON, "$.i\\j", "5") &&
run_success_test(TEST_RFC_JSON, "$.k\"l", "6") &&
run_success_test(TEST_RFC_JSON, "$. ", "7") &&
run_success_test(TEST_RFC_JSON, "$.m~n", "8") &&
run_success_test(TEST_JSON, "$./~01abc",
R"([0,{"\\\" 0":["value0","value1"]}])") &&
run_success_test(TEST_JSON, "$./~01abc[1]",
R"({"\\\" 0":["value0","value1"]})") &&
run_success_test(TEST_JSON, "$./~01abc[1].\\\" 0",
R"(["value0","value1"])") &&
run_success_test(TEST_JSON, "$.arr", R"([])") // get array
&&
run_failure_test(TEST_JSON, R"($./~01abc[1].\\\" 0[2])", NO_SUCH_FIELD) &&
run_failure_test(TEST_JSON, "$.arr[0]", INDEX_OUT_OF_BOUNDS) &&
run_failure_test(TEST_JSON, "/~01abc", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, ".~1abc", NO_SUCH_FIELD) &&
run_failure_test(TEST_JSON, "./~01abc.01", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, "./~01abc.", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, "./~01abc.-", INDEX_OUT_OF_BOUNDS)) {
std::cout << "Success!" << std::endl;
return 0;
} else {
std::cerr << "Failed!" << std::endl;
return 1;
}
}
+37
View File
@@ -461,7 +461,44 @@ void parse_documentation_lowlevel() {
(void)element; (void)element;
} }
void jsondollar() {
dom::parser parser;
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::element doc;
auto error = parser.parse(json).get(doc);
if(error) { exit(-1); }
dom::object obj;
error = doc.get_object().get(obj);
if(error) { exit(-1); }
int64_t x = 0; // initialization to silence unwarranted compiler warning
error = obj.at_path("$[3].foo.a[1]").get(x);
if(error) { exit(-1); }
if(x != 20) { exit(-1); }
x = obj.at_path("$.d.foo2.a.2");
if(x != 30) { exit(-1); }
if(error) { exit(-1); }
}
void jsonpath() {
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(cars_json).get(doc);
if(error) { exit(-1); }
double p = 0.0; // initialization to silence unwarranted compiler warning
error = doc.at_path("[0].tire_pressure[1]").get(p);
if(error) { exit(-1); }
if(p != 39.9) { exit(-1); }
}
int main() { int main() {
jsonpath();
jsondollar();
basics_dom_1(); basics_dom_1();
basics_dom_2(); basics_dom_2();
basics_dom_3(); basics_dom_3();
+22 -2
View File
@@ -21,8 +21,24 @@ long page_size() {
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the // Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
// page boundary. // page boundary.
bool need_allocation(const char *buf, size_t len) { bool need_allocation(const char *buf, size_t len) {
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) < return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
simdjson::SIMDJSON_PADDING); + simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
}
bool check_need_allocation() {
long ps = page_size();
std::vector<std::tuple<uintptr_t,size_t,bool>> test_cases = {
{2*ps, 5, false}, {2*ps, ps, true}, {2*ps, 100, false},
};
for(auto t : test_cases) {
uintptr_t buf = std::get<0>(t);
size_t len = std::get<1>(t);
bool expected = std::get<2>(t);
if(need_allocation(reinterpret_cast<const char *>(buf), len) != expected) {
return false;
}
}
return true;
} }
simdjson::padded_string_view simdjson::padded_string_view
@@ -39,6 +55,10 @@ get_padded_string_view(const char *buf, size_t len,
int main() { int main() {
printf("page_size: %ld\n", page_size()); printf("page_size: %ld\n", page_size());
if(!check_need_allocation()) {
printf("Bug in the need_allocation function.\n");
return EXIT_FAILURE;
}
const char *jsonpoiner = R"( const char *jsonpoiner = R"(
{ {
"key": "value" "key": "value"
@@ -346,6 +346,54 @@ namespace json_path_tests {
TEST_SUCCEED(); TEST_SUCCEED();
} }
bool many_json_paths_with_prefix() {
TEST_START();
// object
{
auto cfoofoo2 = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(cfoofoo2).get(doc));
ondemand::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.c.foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
ASSERT_SUCCESS(obj.at_path("$.d.foo2.a.2").get(x));
ASSERT_EQUAL(x, 30);
ASSERT_SUCCESS(obj.at_path("$.e").get(x));
ASSERT_EQUAL(x, 120);
}
// array
{
auto cfoofoo2 = R"( [ 111, 2, 3, { "foo": { "a": [ 10, 20, 33 ] }}, { "foo2": { "a": [ 10, 20, 30 ] }}, 1001 ])"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(cfoofoo2).get(doc));
ondemand::array arr;
ASSERT_SUCCESS(doc.get_array().get(arr));
int64_t x;
ASSERT_SUCCESS(arr.at_path("$[3].foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
}
// onject array
{
auto dogcatpotato = R"( { "dog" : [1,2,3], "cat" : [5, 6, 7], "potato" : [1234]})"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(dogcatpotato).get(doc));
ondemand::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.dog[1]").get(x));
ASSERT_EQUAL(x, 2);
ASSERT_SUCCESS(obj.at_path("$.potato[0]").get(x));
ASSERT_EQUAL(x, 1234);
}
TEST_SUCCEED();
}
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
bool json_path_invalidation_exceptions() { bool json_path_invalidation_exceptions() {
TEST_START(); TEST_START();
@@ -392,6 +440,7 @@ namespace json_path_tests {
many_json_paths_array() && many_json_paths_array() &&
many_json_paths_object() && many_json_paths_object() &&
many_json_paths_object_array() && many_json_paths_object_array() &&
many_json_paths_with_prefix() &&
run_broken_tests() && run_broken_tests() &&
json_path_invalidation() && json_path_invalidation() &&
demo_test() && demo_test() &&
@@ -236,6 +236,19 @@ bool gen_raw2() {
TEST_SUCCEED(); TEST_SUCCEED();
} }
bool jsondollar() {
TEST_START();
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object obj = doc.get_object();
int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
ASSERT_EQUAL(x, 20);
x = obj.at_path("$.d.foo2.a.2"); // 30
ASSERT_EQUAL(x, 30);
TEST_SUCCEED();
}
bool gen_raw3() { bool gen_raw3() {
TEST_START(); TEST_START();
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
@@ -1891,6 +1904,7 @@ bool run() {
#if SIMDJSON_CPLUSPLUS17 #if SIMDJSON_CPLUSPLUS17
&& big_int_array() && big_int_array()
#endif // SIMDJSON_CPLUSPLUS17 #endif // SIMDJSON_CPLUSPLUS17
&& jsondollar()
&& big_int_array_as_double() && big_int_array_as_double()
&& key_raw_json_token() && key_raw_json_token()
&& to_optional() && to_optional()
+12 -3
View File
@@ -369,15 +369,24 @@ namespace scalar_tests {
ondemand::parser parser; ondemand::parser parser;
ondemand::document doc; ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc)); ASSERT_SUCCESS(parser.iterate(json).get(doc));
bool x; ASSERT_ERROR(doc.is_null(), INCORRECT_TYPE);
ASSERT_SUCCESS(doc.is_null().get(x)); TEST_SUCCEED();
ASSERT_TRUE(!x); }
bool nul() {
TEST_START();
auto json = R"( nul )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.is_null(), INCORRECT_TYPE);
TEST_SUCCEED(); TEST_SUCCEED();
} }
bool run() { bool run() {
return return
nully() && nully() &&
nul() &&
string_with_trailing() && string_with_trailing() &&
uint64_with_trailing() && uint64_with_trailing() &&
int64_with_trailing() && int64_with_trailing() &&