mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db91f62bd7 | |||
| 20cd6e30ee | |||
| e45d8edbd6 | |||
| 6efb8d81bd | |||
| f562878afc | |||
| 60aa25a0c2 | |||
| d01662560d | |||
| a63c77a977 | |||
| bbb3cb80a6 | |||
| 43219e50e0 | |||
| 49b9860899 | |||
| 0388d79770 | |||
| c0fa1aec66 | |||
| 6e61b7f6ef | |||
| a76e778804 |
@@ -25,7 +25,6 @@ CompileFlags:
|
||||
Diagnostics:
|
||||
Suppress:
|
||||
- pp_including_mainfile_in_preamble
|
||||
- unused-includes
|
||||
---
|
||||
# Amalgamated files that require or partly define an implementation
|
||||
If:
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Ubuntu 24.04 CI (CXX 20)
|
||||
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
cxx: [g++-13, clang++-16]
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Prepare
|
||||
run: cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_DEVELOPER_MODE=ON -B build
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
- name: Build
|
||||
run: cmake --build build -j=2
|
||||
- name: Test
|
||||
run: ctest --output-on-failure --test-dir build
|
||||
@@ -0,0 +1,37 @@
|
||||
name: VS17-CLANG-CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
name: windows-vs17
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: Debug}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: Release}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, build_type: RelWithDebInfo}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
- name: Build
|
||||
run: cmake --build build --config ${{matrix.build_type}} --verbose
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config ${{matrix.build_type}}
|
||||
- name: Test Installation
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||
cmake --build build_install_test --config ${{matrix.build_type}}
|
||||
Vendored
+18
-6
@@ -109,11 +109,23 @@
|
||||
"numbers": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"cfenv": "cpp"
|
||||
},
|
||||
"cmake.configureSettings": {
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "YES",
|
||||
"SIMDJSON_DEVELOPER_MODE": "ON",
|
||||
"SIMDJSON_SINGLEHEADER": "OFF"
|
||||
"cfenv": "cpp",
|
||||
"format": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xutility": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocale": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp"
|
||||
}
|
||||
}
|
||||
+8
-18
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.10.1
|
||||
VERSION 3.10.0
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -23,11 +23,7 @@ string(
|
||||
set(SIMDJSON_LIB_VERSION "23.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "23" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
|
||||
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
|
||||
message(WARNING "SIMDJSON_BUILD_STATIC_LIB only makes sense if BUILD_SHARED_LIBS is set to ON")
|
||||
message(WARNING "You might be building and installing a two identical static libraries.")
|
||||
endif()
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
@@ -55,7 +51,6 @@ endif()
|
||||
if(is_top_project)
|
||||
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
|
||||
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
|
||||
option(SIMDJSON_SINGLEHEADER "Disable singleheader generation" ON)
|
||||
endif()
|
||||
|
||||
include(cmake/handle-deprecations.cmake)
|
||||
@@ -160,13 +155,11 @@ endif()
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(SIMDJSON_SINGLEHEADER)
|
||||
install(
|
||||
FILES singleheader/simdjson.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
endif()
|
||||
install(
|
||||
FILES singleheader/simdjson.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS simdjson
|
||||
@@ -210,7 +203,6 @@ if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
TARGETS simdjson_static
|
||||
EXPORT simdjson_staticTargets
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
install(
|
||||
EXPORT simdjson_staticTargets
|
||||
@@ -287,7 +279,6 @@ enable_testing()
|
||||
add_custom_target(all_tests)
|
||||
|
||||
add_subdirectory(windows)
|
||||
include(cmake/CPM.cmake)
|
||||
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
|
||||
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
|
||||
|
||||
@@ -295,9 +286,8 @@ add_subdirectory(tools) ## This needs to be before tests because of cxxopts
|
||||
# most of the data has been moved to https://github.com/simdjson/simdjson-data
|
||||
add_subdirectory(jsonexamples)
|
||||
|
||||
if(SIMDJSON_SINGLEHEADER)
|
||||
|
||||
add_subdirectory(singleheader)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "3.10.1"
|
||||
PROJECT_NUMBER = "3.10.0"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -201,8 +201,8 @@ For the video inclined, <br />
|
||||
Funding
|
||||
-------
|
||||
|
||||
The work is supported by the Natural Sciences and Engineering Research Council of Canada under grants
|
||||
RGPIN-2017-03910 and RGPIN-2024-03787.
|
||||
The work is supported by the Natural Sciences and Engineering Research Council of Canada under grant
|
||||
number RGPIN-2017-03910.
|
||||
|
||||
[license]: LICENSE
|
||||
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg
|
||||
|
||||
@@ -13,7 +13,7 @@ struct nlohmann_json {
|
||||
auto root = nlohmann::json::parse(json.data(), json.data() + json.size());
|
||||
for (auto tweet : root["statuses"]) {
|
||||
if (tweet["id"] == find_id) {
|
||||
result = tweet["text"];
|
||||
result = to_string(tweet["text"]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ private:
|
||||
uint8_t *p) noexcept;
|
||||
simdjson_inline void
|
||||
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);
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
@@ -90,13 +90,12 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
} else {
|
||||
simdjson::ondemand::value val = doc;
|
||||
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
|
||||
#if 1
|
||||
//SIMDJSON_GCC_COMPILER
|
||||
#if SIMDJSON_GCC_COMPILER
|
||||
// the GCC compiler does well with by-value passing.
|
||||
// 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://godbolt.org/z/TeK4doE51
|
||||
recursive_processor(std::move(val));
|
||||
recursive_processor(val);
|
||||
#else
|
||||
recursive_processor_ref(val);
|
||||
#endif
|
||||
@@ -141,7 +140,7 @@ void simdjson2msgpack::write_raw_string(
|
||||
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()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
@@ -149,7 +148,7 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value&& element)
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto child : element.get_array()) {
|
||||
counter++;
|
||||
recursive_processor(std::move(child.value()));
|
||||
recursive_processor(child.value());
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
|
||||
@@ -26,8 +26,8 @@ struct nlohmann_json {
|
||||
}
|
||||
}
|
||||
|
||||
result.text = top_tweet["text"];
|
||||
result.screen_name = top_tweet["user"]["screen_name"];
|
||||
result.text = to_string(top_tweet["text"]);
|
||||
result.screen_name = to_string(top_tweet["user"]["screen_name"]);
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# 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})
|
||||
Vendored
+37
-76
@@ -1,4 +1,5 @@
|
||||
include(CMakeDependentOption)
|
||||
include(import.cmake)
|
||||
|
||||
option(SIMDJSON_ALLOW_DOWNLOADS
|
||||
"Allow dependencies to be downloaded during configure time"
|
||||
@@ -10,21 +11,17 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
|
||||
SIMDJSON_ALLOW_DOWNLOADS OFF)
|
||||
|
||||
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||
CPMAddPackage(
|
||||
NAME google_benchmarks
|
||||
URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.zip
|
||||
OPTIONS
|
||||
"BENCHMARK_ENABLE_TESTING OFF"
|
||||
"BENCHMARK_ENABLE_INSTALL OFF"
|
||||
"BENCHMARK_ENABLE_WERROR OFF"
|
||||
)
|
||||
set_off(BENCHMARK_ENABLE_TESTING)
|
||||
set_off(BENCHMARK_ENABLE_INSTALL)
|
||||
set_off(BENCHMARK_ENABLE_WERROR)
|
||||
|
||||
import_dependency(google_benchmarks google/benchmark v1.7.1)
|
||||
add_dependency(google_benchmarks)
|
||||
endif()
|
||||
|
||||
CPMAddPackage(
|
||||
NAME simdjson-data
|
||||
URL https://github.com/simdjson/simdjson-data/archive/a5b13babe65c1bba7186b41b43d4cbdc20a5c470.zip
|
||||
)
|
||||
|
||||
# The bulk of our benchmarking and testing data has been moved simdjson/simdjson-data
|
||||
import_dependency(simdjson-data simdjson/simdjson-data a5b13babe65c1bba7186b41b43d4cbdc20a5c470)
|
||||
add_dependency(simdjson-data)
|
||||
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
|
||||
# should not be called more than once
|
||||
@@ -41,30 +38,20 @@ function(competition_scope_)
|
||||
int main() {}
|
||||
]] SIMDJSON_FOUND_STRING_VIEW)
|
||||
if(SIMDJSON_FOUND_STRING_VIEW AND SIMDJSON_USE_BOOST_JSON)
|
||||
CPMAddPackage(
|
||||
NAME boostjson
|
||||
URL https://github.com/boostorg/json/archive/ee8d72d8502b409b5561200299cad30ccdb91415.zip
|
||||
)
|
||||
import_dependency(boostjson boostorg/json ee8d72d)
|
||||
add_library(boostjson STATIC "${boostjson_SOURCE_DIR}/src/src.cpp")
|
||||
target_compile_definitions(boostjson PUBLIC BOOST_JSON_STANDALONE)
|
||||
target_include_directories(boostjson SYSTEM PUBLIC
|
||||
"${boostjson_SOURCE_DIR}/include")
|
||||
target_compile_definitions(boostjson INTERFACE SIMDJSON_COMPETITION_BOOSTJSON)
|
||||
endif()
|
||||
CPMAddPackage(
|
||||
NAME cjson
|
||||
URL https://github.com/DaveGamble/cJSON/archive/c69134d01746dcf551dd7724b4edb12f922eb0d1.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
import_dependency(cjson DaveGamble/cJSON c69134d)
|
||||
add_library(cjson STATIC "${cjson_SOURCE_DIR}/cJSON.c")
|
||||
target_include_directories(cjson SYSTEM PUBLIC "${cjson_SOURCE_DIR}")
|
||||
target_compile_definitions(cjson INTERFACE SIMDJSON_COMPETITION_CJSON)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME fastjson
|
||||
URL https://github.com/mikeando/fastjson/archive/485f994a61a64ac73fa6a40d4d639b99b463563b.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(fastjson mikeando/fastjson 485f994)
|
||||
add_library(fastjson STATIC
|
||||
"${fastjson_SOURCE_DIR}/src/fastjson.cpp"
|
||||
"${fastjson_SOURCE_DIR}/src/fastjson2.cpp"
|
||||
@@ -73,36 +60,28 @@ int main() {}
|
||||
"${fastjson_SOURCE_DIR}/include")
|
||||
target_compile_definitions(fastjson INTERFACE SIMDJSON_COMPETITION_FASTJSON)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME gason
|
||||
URL https://github.com/vivkin/gason/archive/7aee524189da1c1ecd19f67981e3d903dae25470.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(gason vivkin/gason 7aee524)
|
||||
add_library(gason STATIC "${gason_SOURCE_DIR}/src/gason.cpp")
|
||||
target_include_directories(gason SYSTEM PUBLIC "${gason_SOURCE_DIR}/src")
|
||||
target_compile_definitions(gason INTERFACE SIMDJSON_COMPETITION_GASON)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jsmn
|
||||
URL https://github.com/zserge/jsmn/archive/18e9fe42cbfe21d65076f5c77ae2be379ad1270f.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(jsmn zserge/jsmn 18e9fe4)
|
||||
add_library(jsmn STATIC "${jsmn_SOURCE_DIR}/jsmn.c")
|
||||
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
|
||||
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME nlohmann_json
|
||||
URL https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip
|
||||
)
|
||||
message(STATUS "Importing json (nlohmann/json@v3.10.5)")
|
||||
set(nlohmann_json_SOURCE_DIR "${dep_root}/json")
|
||||
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}")
|
||||
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)
|
||||
|
||||
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
|
||||
)
|
||||
import_dependency(json11 dropbox/json11 ec4e452)
|
||||
add_library(json11 STATIC "${json11_SOURCE_DIR}/json11.cpp")
|
||||
target_include_directories(json11 SYSTEM PUBLIC "${json11_SOURCE_DIR}")
|
||||
target_compile_definitions(json11 INTERFACE SIMDJSON_COMPETITION_JSON11)
|
||||
@@ -112,11 +91,7 @@ int main() {}
|
||||
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
|
||||
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME rapidjson
|
||||
URL https://github.com/Tencent/rapidjson/archive/f54b0e47a08782a6131cc3d60f94d038fa6e0a51.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(rapidjson Tencent/rapidjson f54b0e4)
|
||||
add_library(rapidjson INTERFACE)
|
||||
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
|
||||
include (TestBigEndian)
|
||||
@@ -135,22 +110,14 @@ int main() {}
|
||||
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
|
||||
endif()
|
||||
|
||||
CPMAddPackage(
|
||||
NAME sajson
|
||||
URL https://github.com/chadaustin/sajson/archive/2dcfd350586375f9910f74821d4f07d67ae455ba.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(sajson chadaustin/sajson 2dcfd35)
|
||||
add_library(sajson INTERFACE)
|
||||
target_compile_definitions(sajson INTERFACE SAJSON_UNSORTED_OBJECT_KEYS)
|
||||
target_include_directories(sajson SYSTEM INTERFACE
|
||||
"${sajson_SOURCE_DIR}/include")
|
||||
target_compile_definitions(sajson INTERFACE SIMDJSON_COMPETITION_SAJSON)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ujson4c
|
||||
URL https://github.com/esnme/ujson4c/archive/e14f3fd5207fe30d1bdea723f260609e69d1abfa.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(ujson4c esnme/ujson4c e14f3fd)
|
||||
add_library(ujson4c STATIC
|
||||
"${ujson4c_SOURCE_DIR}/src/ujdecode.c"
|
||||
"${ujson4c_SOURCE_DIR}/3rdparty/ultrajsondec.c")
|
||||
@@ -159,11 +126,7 @@ int main() {}
|
||||
"${ujson4c_SOURCE_DIR}/3rdparty")
|
||||
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME yyjson
|
||||
URL https://github.com/ibireme/yyjson/archive/c3856514de0a67d7b66939bf3ed491a2d6e61277.zip
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
import_dependency(yyjson ibireme/yyjson c385651)
|
||||
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
|
||||
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
|
||||
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
|
||||
@@ -188,12 +151,10 @@ cmake_dependent_option(SIMDJSON_CXXOPTS "Download cxxopts (necessary for tools)"
|
||||
SIMDJSON_ALLOW_DOWNLOADS OFF)
|
||||
|
||||
if(SIMDJSON_CXXOPTS)
|
||||
CPMAddPackage(
|
||||
NAME cxxopts
|
||||
URL https://github.com/jarro2783/cxxopts/archive/59656709c0c58fcd0ed18b38e02938dbe05284c5.zip
|
||||
OPTIONS
|
||||
"CXXOPTS_BUILD_EXAMPLES OFF"
|
||||
"CXXOPTS_BUILD_TESTS OFF"
|
||||
"CXXOPTS_ENABLE_INSTALL OFF"
|
||||
)
|
||||
set_off(CXXOPTS_BUILD_EXAMPLES)
|
||||
set_off(CXXOPTS_BUILD_TESTS)
|
||||
set_off(CXXOPTS_ENABLE_INSTALL)
|
||||
|
||||
import_dependency(cxxopts jarro2783/cxxopts 5965670)
|
||||
add_dependency(cxxopts)
|
||||
endif()
|
||||
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
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()
|
||||
+213
-25
@@ -17,6 +17,8 @@ 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: additional examples](#using-the-parsed-json-additional-examples)
|
||||
- [Adding support for custom types](#adding-support-for-custom-types)
|
||||
- [1. Specialize `simdjson::ondemand::value::get` to get custom types](#1-specialize-simdjsonondemandvalueget-to-get-custom-types)
|
||||
- [2. Use `tag_invoke` for custom types (C++20)](#2-use-tag_invoke-for-custom-types-c20)
|
||||
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||
- [JSON Pointer](#json-pointer)
|
||||
@@ -247,7 +249,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:
|
||||
|
||||
- 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. In any case, the `document` class does not have a copy constructor.
|
||||
- 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.)
|
||||
|
||||
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.
|
||||
@@ -788,6 +790,25 @@ for (ondemand::object points : parser.iterate(points_json)) {
|
||||
Adding support for custom types
|
||||
----------------------
|
||||
|
||||
There are 2 main ways provided by simdjson to deserialize a value into a custom type:
|
||||
|
||||
1. Provide a [**template specialization** for member functions](https://en.cppreference.com/w/cpp/language/template_specialization#Members_of_specializations)
|
||||
1. Specialize `simdjson::ondemand::document::get` for the whole document
|
||||
2. Specialize `simdjson::ondemand::value::get` for each value
|
||||
2. Using `tag_invoke` *(the recommended way if your system supports C++20 or better)*
|
||||
|
||||
The differences between the two approaches are as follows:
|
||||
|
||||
1. Your compiler needs to support C++20 for `tag_invoke`.
|
||||
2. The first way limits you to know your type fully, but in the `tag_invoke` way, you can use C++20 concepts and template meta programming as well.
|
||||
3. Another difference between the two ways is that in `tag_invoke` way you may or may not mark your deserialization function (`tag_invoke` itself) as `noexcept`, but in the
|
||||
*template specialization* way (the first way) you HAVE TO mark your specialization as `noexcept` which means that you may need to catch exceptions so
|
||||
that your function does not throw any exception all the while it potentially can (for example any type like `std::string`, `std::vector`, etc. that has an allocator can potentially throw exceptions).
|
||||
4. Another difference is that the `tag_invoke` way can work on both `document` and `value` but in the first way you have to provide 2 distinct specializations.
|
||||
5. If you by mistake use both way with each other, the *specialization way* will be used silently due to backward-compatibility.
|
||||
|
||||
### 1. Specialize `simdjson::ondemand::value::get` to get custom types
|
||||
|
||||
Suppose you have your own types, such as a `Car` struct:
|
||||
|
||||
```C++
|
||||
@@ -821,9 +842,14 @@ type:
|
||||
```
|
||||
|
||||
We may do so by providing additional template definitions to the `ondemand::value` type.
|
||||
We may start by providing a definition for `std::vector<double>` as follows:
|
||||
We may start by providing a definition for `std::vector<double>` as follows. Observe
|
||||
how we guard the code with `#ifndef __cpp_concepts`: that is because the necessary code
|
||||
is automatically provided by simdjson if C++20 (and concepts) are available.
|
||||
See [Use `tag_invoke` for custom types](#2-use-tag_invoke-for-custom-types-c20) if you have
|
||||
C++20 support.
|
||||
|
||||
```c++
|
||||
#ifndef __cpp_concepts // because the code is unnecessary with C++20
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
@@ -835,10 +861,11 @@ simdjson::ondemand::value::get() noexcept {
|
||||
double val;
|
||||
error = v.get_double().get(val);
|
||||
if (error) { return error; }
|
||||
vec.push_back(val);
|
||||
try { vec.push_back(val); } catch (...) { return simdjson::UNEXPECTED_ERROR; }
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
We may then provide support for our `Car` struct:
|
||||
@@ -856,6 +883,7 @@ simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
|
||||
raw_json_string key;
|
||||
error = field.key().get(key);
|
||||
if (error) { return error; }
|
||||
|
||||
if (key == "make") {
|
||||
error = field.value().get_string(car.make);
|
||||
if (error) { return error; }
|
||||
@@ -867,7 +895,7 @@ simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
|
||||
if (error) { return error; }
|
||||
} else if (key == "tire_pressure") {
|
||||
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
|
||||
if (auto error) { return error; }
|
||||
if (error) { return error; }
|
||||
}
|
||||
}
|
||||
return car;
|
||||
@@ -893,6 +921,7 @@ struct Car {
|
||||
std::vector<double> tire_pressure;
|
||||
};
|
||||
|
||||
#ifndef __cpp_concepts // because the code is unnecessary with C++20
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
@@ -908,6 +937,7 @@ simdjson::ondemand::value::get() noexcept {
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template <>
|
||||
@@ -950,7 +980,7 @@ int main(void) {
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val);
|
||||
Car c(val); // an exception may be thrown
|
||||
std::cout << c.make << std::endl;
|
||||
}
|
||||
direct();
|
||||
@@ -958,7 +988,7 @@ int main(void) {
|
||||
}
|
||||
```
|
||||
|
||||
Observe that we require an explicit cast (`Car c(val)` instead of `for (Car c : doc) {`): it is by design.
|
||||
Observe that we require an explicit cast (`Car c(val)` instead of `for (Car c : doc) {`): it is by design. We require explicit casting.
|
||||
|
||||
If you prefer to avoid exceptions, you may modify the `main` function as follows:
|
||||
|
||||
@@ -1009,6 +1039,7 @@ struct Car {
|
||||
std::vector<double> tire_pressure;
|
||||
};
|
||||
|
||||
#ifndef __cpp_concepts // because the code is unnecessary with C++20
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
@@ -1022,7 +1053,7 @@ simdjson::ondemand::value::get() noexcept {
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <>
|
||||
simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() & noexcept {
|
||||
@@ -1066,6 +1097,178 @@ int main(void) {
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Use `tag_invoke` for custom types (C++20)
|
||||
|
||||
A standard approach to provide support for deserialization is to add a `tag_invoke` function
|
||||
in your own class:
|
||||
|
||||
```C++
|
||||
/**
|
||||
* A custom type that we want to parse.
|
||||
*/
|
||||
|
||||
struct Car {
|
||||
std::string make;
|
||||
std::string model;
|
||||
int year = 0;
|
||||
std::vector<double> tire_pressure;
|
||||
|
||||
friend simdjson_result<Car>
|
||||
tag_invoke(simdjson::deserialize_tag, std::type_identity<Car>, auto &val) {
|
||||
simdjson::ondemand::object obj;
|
||||
auto error = val.get_object().get(obj);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
Car car{};
|
||||
// Instead of repeatedly obj["something"], we iterate through the object
|
||||
// which we expect to be faster.
|
||||
for (auto field : obj) {
|
||||
simdjson::ondemand::raw_json_string key;
|
||||
error = field.key().get(key);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (key == "make") {
|
||||
error = field.value().get_string(car.make);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "model") {
|
||||
error = field.value().get_string(car.model);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "year") {
|
||||
error = field.value().get(car.year);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "tire_pressure") {
|
||||
error = field.value().get(car.tire_pressure);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return car;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Let us explain each argument of `tag_invoke`:
|
||||
|
||||
- `simdjson::deserialize_tag`: it is the tag for Customization Point Object (CPO)
|
||||
- `std::type_identity<T>`: We specify the custom type we want here
|
||||
- `simdjson::ondemand::value&` or `simdjson::ondemand::document&`: the value or document that we want to deserialize from; you may want to just specify `auto&` to capture both of them.
|
||||
|
||||
You can use it like so:
|
||||
|
||||
```cpp
|
||||
simdjson::padded_string json =
|
||||
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
Car c(doc);
|
||||
std::cout << c.make << std::endl;
|
||||
```
|
||||
|
||||
Observe how we first get an instance of `document` and then we cast.
|
||||
|
||||
You can also handle errors explicitly:
|
||||
|
||||
```cpp
|
||||
simdjson::padded_string json =
|
||||
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
Car c;
|
||||
auto error = doc.get(c);
|
||||
if(error) { std::cerr << simdjson::error_message(error); return false; }
|
||||
std::cout << c.make << std::endl;
|
||||
```
|
||||
|
||||
You can also read instances of `Car` from an array or an object:
|
||||
```cpp
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val); // an exception may be thrown
|
||||
std::cout << c.year << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
Observe how we first get a generic (`val`) which we cast to `Car`. It is by design: we require
|
||||
explicit casting. The cast may throw an exception.
|
||||
|
||||
Once more, you can handle errors explicitly:
|
||||
|
||||
```cpp
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c;
|
||||
auto error = val.get(c);
|
||||
if(error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
|
||||
}
|
||||
```
|
||||
|
||||
You can also use the custom `Car` type as part of a template such as `std::vector`:
|
||||
|
||||
```cpp
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
std::vector<Car> cars(doc);
|
||||
// visual studio users need an explicit call:
|
||||
// std::vector<Car> cars = doc.get<std::vector<Car>>();
|
||||
// because the compiler does not know whether to convert
|
||||
// doc to an unsigned int or to a vector.
|
||||
for(Car& c : cars) {
|
||||
std::cout << c.year << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
You can also extend support to arbitrary templates.
|
||||
Suppose your custom types are `std::unique_ptr<any type>`,
|
||||
you could add the following `tag_invoke`:
|
||||
|
||||
```C++
|
||||
namespace simdjson {
|
||||
|
||||
// This tag_invoke MUST be inside simdjson namespace since we can't make it a friend of unique_ptr
|
||||
template <typename T>
|
||||
auto tag_invoke(deserialize_tag, std::type_identity<std::unique_ptr<T>>, auto &val) {
|
||||
return simdjson_result{std::make_unique<T>(val.template get<T>())};
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
```
|
||||
|
||||
You can also mark your `tag_invoke` function as `noexcept` and we will obey that, unlike the *template specialization* way.
|
||||
|
||||
You would use it like this:
|
||||
```C++
|
||||
int main() {
|
||||
auto const json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
std::unique_ptr<Car> c(doc);
|
||||
std::cout << c->make << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
Minifying JSON strings without parsing
|
||||
----------------------
|
||||
@@ -1224,11 +1427,9 @@ be represented as `value` instances. You can check that a document is a scalar w
|
||||
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.
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
@@ -1269,18 +1470,6 @@ doc.at_path(".\\u00E9") == 123; // true
|
||||
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
|
||||
--------------
|
||||
|
||||
@@ -1357,7 +1546,7 @@ Notice how we can retrieve the exact error condition (in this instance `simdjson
|
||||
from the exception.
|
||||
|
||||
We can write a "quick start" example where we attempt to parse the following JSON file and access some data, without triggering exceptions:
|
||||
```JavaScript
|
||||
```JSON
|
||||
{
|
||||
"statuses": [
|
||||
{
|
||||
@@ -2687,7 +2876,6 @@ Performance tips
|
||||
std::string_view year = data["year"];
|
||||
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
@@ -8,7 +8,6 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
* [Using the Parsed JSON](#using-the-parsed-json)
|
||||
* [C++17 Support](#c17-support)
|
||||
* [JSON Pointer](#json-pointer)
|
||||
* [JSONPath](#jsonpath)
|
||||
* [Error Handling](#error-handling)
|
||||
* [Error Handling Example](#error-handling-example)
|
||||
* [Exceptions](#exceptions)
|
||||
@@ -258,49 +257,6 @@ 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
|
||||
|
||||
+1
-6
@@ -102,12 +102,7 @@ remove almost entirely its cost and replaces it by the overhead of a thread, whi
|
||||
cheaper. Ain't that awesome!
|
||||
|
||||
Thread support is only active if thread supported is detected in which case the macro
|
||||
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).
|
||||
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
|
||||
|
||||
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
|
||||
|
||||
|
||||
+2
-7
@@ -103,12 +103,7 @@ cases, remove almost entirely its cost and replaces it by the overhead of a thre
|
||||
of magnitude cheaper. Ain't that awesome!
|
||||
|
||||
Thread support is only active if thread supported is detected in which case the macro
|
||||
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).
|
||||
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
|
||||
|
||||
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
|
||||
@@ -130,7 +125,7 @@ Whitespace Characters:
|
||||
- **Nothing**
|
||||
|
||||
Some official formats **(non-exhaustive list)**:
|
||||
- [Newline-Delimited JSON (NDJSON)](https://github.com/ndjson/ndjson-spec)
|
||||
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
||||
- [JSON lines (JSONL)](http://jsonlines.org/)
|
||||
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream!
|
||||
- [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
|
||||
|
||||
+2
-2
@@ -241,8 +241,8 @@ long page_size() {
|
||||
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
||||
// page boundary.
|
||||
bool need_allocation(const char *buf, size_t len) {
|
||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
|
||||
+ simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
|
||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
|
||||
simdjson::SIMDJSON_PADDING);
|
||||
}
|
||||
|
||||
simdjson::padded_string_view
|
||||
|
||||
@@ -35,12 +35,6 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
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 */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
|
||||
@@ -51,12 +51,6 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace arm64
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
|
||||
|
||||
@@ -50,8 +50,6 @@ double from_chars(const char *first, const char* end) noexcept;
|
||||
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
|
||||
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
// We could use [[deprecated]] but it requires C++14
|
||||
#define simdjson_deprecated __declspec(deprecated)
|
||||
|
||||
#define simdjson_really_inline __forceinline
|
||||
#define simdjson_never_inline __declspec(noinline)
|
||||
@@ -90,8 +88,6 @@ double from_chars(const char *first, const char* end) noexcept;
|
||||
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
|
||||
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
// We could use [[deprecated]] but it requires C++14
|
||||
#define simdjson_deprecated __attribute__((deprecated))
|
||||
|
||||
#define simdjson_really_inline inline __attribute__((always_inline))
|
||||
#define simdjson_never_inline inline __attribute__((noinline))
|
||||
|
||||
@@ -50,4 +50,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
#include <utility>
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
||||
#else // __cpp_concepts
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif
|
||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "simdjson/dom/array.h"
|
||||
#include "simdjson/dom/element.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/jsonpathutil.h"
|
||||
#include "simdjson/internal/tape_ref-inl.h"
|
||||
|
||||
#include <limits>
|
||||
@@ -45,13 +44,6 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
|
||||
if (error()) { return error(); }
|
||||
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 {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
@@ -121,12 +113,6 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
|
||||
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 {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
size_t i=0;
|
||||
|
||||
@@ -108,21 +108,6 @@ public:
|
||||
*/
|
||||
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
|
||||
* is equivalent to the following:
|
||||
@@ -167,7 +152,6 @@ public:
|
||||
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_path(std::string_view json_path) const noexcept;
|
||||
inline simdjson_result<dom::element> at(size_t index) const noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "simdjson/dom/object-inl.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/jsonpathutil.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <limits>
|
||||
@@ -123,11 +122,6 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
|
||||
if (error()) { return error(); }
|
||||
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
|
||||
[[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 {
|
||||
@@ -418,11 +412,6 @@ 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
|
||||
[[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 {
|
||||
|
||||
@@ -397,21 +397,6 @@ public:
|
||||
*/
|
||||
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
|
||||
/**
|
||||
*
|
||||
@@ -541,7 +526,6 @@ public:
|
||||
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> 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 ")]]
|
||||
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;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "simdjson/dom/element-inl.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
#include "simdjson/jsonpathutil.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -35,11 +34,6 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_pointer(st
|
||||
if (error()) { return error(); }
|
||||
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 {
|
||||
if (error()) { return error(); }
|
||||
return first.at_key(key);
|
||||
@@ -137,12 +131,6 @@ inline simdjson_result<element> object::at_pointer(std::string_view json_pointer
|
||||
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 {
|
||||
iterator end_field = end();
|
||||
for (iterator field = begin(); field != end_field; ++field) {
|
||||
|
||||
@@ -171,21 +171,6 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -259,7 +244,6 @@ public:
|
||||
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> 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_case_insensitive(std::string_view key) const noexcept;
|
||||
|
||||
|
||||
@@ -549,14 +549,9 @@ public:
|
||||
/**
|
||||
* The parser instance can use threads when they are available to speed up some
|
||||
* operations. It is enabled by default. Changing this attribute will change the
|
||||
* behavior of the parser for future operations. Set to true by default.
|
||||
* behavior of the parser for future operations.
|
||||
*/
|
||||
bool threaded{true};
|
||||
#else
|
||||
/**
|
||||
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
|
||||
*/
|
||||
bool threaded{false};
|
||||
#endif
|
||||
/** @private Use the new DOM API instead */
|
||||
class Iterator;
|
||||
|
||||
@@ -75,12 +75,6 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace fallback
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
|
||||
|
||||
@@ -574,6 +574,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// Stuff other things depend on
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator.h"
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#include "simdjson/generic/ondemand/logger.h"
|
||||
@@ -23,9 +24,13 @@
|
||||
#include "simdjson/generic/ondemand/object_iterator.h"
|
||||
#include "simdjson/generic/ondemand/serialization.h"
|
||||
|
||||
// Deserialization for standard types
|
||||
#include "simdjson/generic/ondemand/std_deserialize.h"
|
||||
|
||||
// Inline definitions
|
||||
#include "simdjson/generic/ondemand/array-inl.h"
|
||||
#include "simdjson/generic/ondemand/array_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/document-inl.h"
|
||||
#include "simdjson/generic/ondemand/document_stream-inl.h"
|
||||
#include "simdjson/generic/ondemand/field-inl.h"
|
||||
@@ -38,5 +43,6 @@
|
||||
#include "simdjson/generic/ondemand/raw_json_string-inl.h"
|
||||
#include "simdjson/generic/ondemand/serialization-inl.h"
|
||||
#include "simdjson/generic/ondemand/token_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
|
||||
#include "simdjson/jsonpathutil.h"
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/array.h"
|
||||
#include "simdjson/generic/ondemand/array_iterator-inl.h"
|
||||
@@ -164,6 +163,53 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
|
||||
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 {
|
||||
auto json_pointer = json_path_to_pointer_conversion(json_path);
|
||||
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
|
||||
|
||||
@@ -13,6 +13,5 @@
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/padded_string_view.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#include "simdjson/jsonpathutil.h"
|
||||
|
||||
#endif // SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H
|
||||
@@ -0,0 +1,114 @@
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/array.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <concepts>
|
||||
namespace simdjson {
|
||||
|
||||
namespace tag_invoke_fn_ns {
|
||||
void tag_invoke();
|
||||
|
||||
struct tag_invoke_fn {
|
||||
template <typename Tag, typename... Args>
|
||||
requires requires(Tag tag, Args &&...args) {
|
||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||
}
|
||||
constexpr auto operator()(Tag tag, Args &&...args) const
|
||||
noexcept(noexcept(tag_invoke(std::forward<Tag>(tag),
|
||||
std::forward<Args>(args)...)))
|
||||
-> decltype(tag_invoke(std::forward<Tag>(tag),
|
||||
std::forward<Args>(args)...)) {
|
||||
return tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // namespace tag_invoke_fn_ns
|
||||
|
||||
inline namespace tag_invoke_ns {
|
||||
inline constexpr tag_invoke_fn_ns::tag_invoke_fn tag_invoke = {};
|
||||
} // namespace tag_invoke_ns
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
concept tag_invocable = requires(Tag tag, Args... args) {
|
||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
concept nothrow_tag_invocable =
|
||||
tag_invocable<Tag, Args...> && requires(Tag tag, Args... args) {
|
||||
{
|
||||
tag_invoke(std::forward<Tag>(tag), std::forward<Args>(args)...)
|
||||
} noexcept;
|
||||
};
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
using tag_invoke_result =
|
||||
std::invoke_result<decltype(tag_invoke), Tag, Args...>;
|
||||
|
||||
template <typename Tag, typename... Args>
|
||||
using tag_invoke_result_t =
|
||||
std::invoke_result_t<decltype(tag_invoke), Tag, Args...>;
|
||||
|
||||
template <auto &Tag> using tag_t = std::decay_t<decltype(Tag)>;
|
||||
|
||||
|
||||
struct deserialize_tag;
|
||||
|
||||
/// These types are deserializable in a built-in way
|
||||
template <typename> struct is_builtin_deserializable : std::false_type {};
|
||||
template <> struct is_builtin_deserializable<int64_t> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<uint64_t> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<double> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<bool> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::array> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::object> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::value> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> : std::true_type {};
|
||||
template <> struct is_builtin_deserializable<std::string_view> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
concept is_builtin_deserializable_v = is_builtin_deserializable<T>::value;
|
||||
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept custom_deserializable = tag_invocable<deserialize_tag, ValT&, T&>;
|
||||
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept deserializable = custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
|
||||
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept nothrow_custom_deserializable = nothrow_tag_invocable<deserialize_tag, ValT&, T&>;
|
||||
|
||||
// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned.
|
||||
template <typename T, typename ValT = SIMDJSON_IMPLEMENTATION::ondemand::value>
|
||||
concept nothrow_deserializable = nothrow_custom_deserializable<T, ValT> || is_builtin_deserializable_v<T>;
|
||||
|
||||
/// Deserialize Tag
|
||||
inline constexpr struct deserialize_tag {
|
||||
using value_type = SIMDJSON_IMPLEMENTATION::ondemand::value;
|
||||
using document_type = SIMDJSON_IMPLEMENTATION::ondemand::document;
|
||||
|
||||
// Customization Point for value
|
||||
template <typename T>
|
||||
requires custom_deserializable<T, value_type>
|
||||
[[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, value_type>) {
|
||||
return tag_invoke(*this, object, output);
|
||||
}
|
||||
|
||||
// Customization Point for document
|
||||
template <typename T>
|
||||
requires custom_deserializable<T, document_type>
|
||||
[[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable<T, document_type>) {
|
||||
return tag_invoke(*this, object, output);
|
||||
}
|
||||
|
||||
} deserialize{};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
@@ -3,15 +3,19 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/array-inl.h"
|
||||
#include "simdjson/generic/ondemand/array_iterator.h"
|
||||
#include "simdjson/generic/ondemand/document.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
|
||||
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion-inl.h"
|
||||
#include "simdjson/generic/ondemand/json_type.h"
|
||||
#include "simdjson/generic/ondemand/object-inl.h"
|
||||
#include "simdjson/generic/ondemand/raw_json_string.h"
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#include "simdjson/generic/ondemand/array-inl.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/object-inl.h"
|
||||
#include "simdjson/generic/ondemand/value-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
@@ -165,26 +169,20 @@ template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept {
|
||||
template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
||||
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
|
||||
template<> simdjson_inline error_code document::get(array& out) & noexcept { return get_array().get(out); }
|
||||
template<> simdjson_inline error_code document::get(object& out) & noexcept { return get_object().get(out); }
|
||||
template<> simdjson_inline error_code document::get(raw_json_string& out) & noexcept { return get_raw_json_string().get(out); }
|
||||
template<> simdjson_inline error_code document::get(std::string_view& out) & noexcept { return get_string(false).get(out); }
|
||||
template<> simdjson_inline error_code document::get(double& out) & noexcept { return get_double().get(out); }
|
||||
template<> simdjson_inline error_code document::get(uint64_t& out) & noexcept { return get_uint64().get(out); }
|
||||
template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { return get_int64().get(out); }
|
||||
template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
|
||||
template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
|
||||
|
||||
template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
|
||||
return get<T>().get(out);
|
||||
}
|
||||
template<typename T> simdjson_deprecated simdjson_inline error_code document::get(T &out) && noexcept {
|
||||
return std::forward<document>(*this).get<T>().get(out);
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
|
||||
template <class T>
|
||||
simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
|
||||
simdjson_inline document::operator T() noexcept(false) { return get<T>(); }
|
||||
simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
|
||||
simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
|
||||
simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
|
||||
@@ -471,7 +469,7 @@ simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::onde
|
||||
return first.get<T>();
|
||||
}
|
||||
template<typename T>
|
||||
simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get() && noexcept {
|
||||
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get() && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first).get<T>();
|
||||
}
|
||||
@@ -487,7 +485,7 @@ simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::do
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() & noexcept = delete;
|
||||
template<> simdjson_deprecated simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() && noexcept {
|
||||
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
#define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#include "simdjson/generic/ondemand/value.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
@@ -178,24 +181,39 @@ public:
|
||||
* @returns A value of the given type, parsed from the JSON.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||
*/
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
template <typename T>
|
||||
simdjson_inline simdjson_result<T> get() &
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
static_assert(std::is_default_constructible<T>::value, "Cannot initialize the specified type.");
|
||||
T out{};
|
||||
SIMDJSON_TRY(get<T>(out));
|
||||
return out;
|
||||
}
|
||||
/** @overload template<typename T> simdjson_result<T> get() & noexcept */
|
||||
template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept {
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
/**
|
||||
* @overload template<typename T> simdjson_result<T> get() & noexcept
|
||||
*
|
||||
* We disallow the use tag_invoke CPO on a moved document; it may create UB
|
||||
* if user uses `ondemand::array` or `ondemand::object` in their custom type.
|
||||
*
|
||||
* The member function is still remains specialize-able for compatibility
|
||||
* reasons, but we completely disallow its use when a tag_invoke customization
|
||||
* is provided.
|
||||
*/
|
||||
template<typename T>
|
||||
simdjson_inline simdjson_result<T> get() &&
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
static_assert(!std::is_same<T, array>::value && !std::is_same<T, object>::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour.");
|
||||
return static_cast<document&>(*this).get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,9 +227,34 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
|
||||
*/
|
||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||
template<typename T>
|
||||
simdjson_inline error_code get(T &out) &
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, document> ? nothrow_custom_deserializable<T, document> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, document>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
@@ -224,10 +267,7 @@ public:
|
||||
* @returns An instance of type T
|
||||
*/
|
||||
template <class T>
|
||||
explicit simdjson_inline operator T() & noexcept(false);
|
||||
template <class T>
|
||||
explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
|
||||
|
||||
explicit simdjson_inline operator T() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
*
|
||||
@@ -691,11 +731,6 @@ protected:
|
||||
|
||||
/**
|
||||
* A document_reference is a thin wrapper around a document reference instance.
|
||||
* The document_reference instances are used primarily/solely for streams of JSON
|
||||
* documents. They differ from document instances when parsing a scalar value
|
||||
* (a document that is not an array or an object). In the case of a document,
|
||||
* we expect the document to be fully consumed. In the case of a document_reference,
|
||||
* we allow trailing content.
|
||||
*/
|
||||
class document_reference {
|
||||
public:
|
||||
@@ -798,7 +833,7 @@ public:
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
|
||||
template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
|
||||
|
||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
@@ -316,7 +316,7 @@ private:
|
||||
friend class document;
|
||||
friend class json_iterator;
|
||||
friend struct simdjson_result<ondemand::document_stream>;
|
||||
friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
|
||||
friend struct internal::simdjson_result_base<ondemand::document_stream>;
|
||||
}; // document_stream
|
||||
|
||||
} // namespace ondemand
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
|
||||
#define SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_ONDEMAND_JSON_PATH_TO_POINTER_CONVERSION_INL_H
|
||||
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {}
|
||||
namespace ondemand {
|
||||
|
||||
simdjson_inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
|
||||
if (json_path.empty() || (json_path.front() != '.' && json_path.front() != '[') {
|
||||
return "-1"; // Sentinel value to be handled as an error by the caller.
|
||||
}
|
||||
|
||||
std::string result;
|
||||
// Reserve space to reduce allocations, adjusting for potential increases due
|
||||
// to escaping.
|
||||
result.reserve(json_path.size() * 2);
|
||||
|
||||
// Skip the initial '.' as it's assumed every path starts with it.
|
||||
size_t i = 0;
|
||||
|
||||
while (i < json_path.length()) {
|
||||
if (json_path[i] == '.') {
|
||||
result += '/';
|
||||
} else if (json_path[i] == '[') {
|
||||
result += '/';
|
||||
++i; // Move past the '['
|
||||
while (i < json_path.length() && json_path[i] != ']') {
|
||||
if (json_path[i] == '~') {
|
||||
result += "~0";
|
||||
} else if (json_path[i] == '/') {
|
||||
result += "~1";
|
||||
} else {
|
||||
result += json_path[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (i == json_path.length() || json_path[i] != ']') {
|
||||
return "-1"; // Returning sentinel value that will be handled as an error by the caller
|
||||
}
|
||||
} else {
|
||||
if (json_path[i] == '~') {
|
||||
result += "~0";
|
||||
} else if (json_path[i] == '/') {
|
||||
result += "~1";
|
||||
} else {
|
||||
result += json_path[i];
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return simdjson_result<std::string>(result);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_H
|
||||
#define SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_H
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace internal {
|
||||
|
||||
/**
|
||||
* Converts JSONPath to JSON Pointer.
|
||||
* @param json_path The JSONPath string to be converted.
|
||||
* @return A string containing the equivalent JSON Pointer.
|
||||
* @throws simdjson_error If the conversion fails.
|
||||
*/
|
||||
simdjson_inline std::string json_path_to_pointer_conversion(std::string_view json_path);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_JSON_PATH_TO_POINTER_CONVERSION_H
|
||||
@@ -278,12 +278,8 @@ public:
|
||||
* behavior of the parser for future operations.
|
||||
*/
|
||||
bool threaded{true};
|
||||
#else
|
||||
/**
|
||||
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
|
||||
*/
|
||||
bool threaded{false};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||
* The result must be valid UTF-8.
|
||||
@@ -344,7 +340,7 @@ public:
|
||||
|
||||
private:
|
||||
/** @private [for benchmarking access] The implementation to use */
|
||||
std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
|
||||
std::unique_ptr<internal::dom_parser_implementation> implementation{};
|
||||
size_t _capacity{0};
|
||||
size_t _max_capacity;
|
||||
size_t _max_depth{DEFAULT_MAX_DEPTH};
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/ondemand/array.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
//////////////////////////////
|
||||
// Number deserialization
|
||||
//////////////////////////////
|
||||
|
||||
template <std::unsigned_integral T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
using limits = std::numeric_limits<T>;
|
||||
|
||||
uint64_t x;
|
||||
SIMDJSON_TRY(val.get_uint64().get(x));
|
||||
if (x > (limits::max)()) {
|
||||
return NUMBER_OUT_OF_RANGE;
|
||||
}
|
||||
out = static_cast<T>(x);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template <std::floating_point T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
double x;
|
||||
SIMDJSON_TRY(val.get_double().get(x));
|
||||
out = static_cast<T>(x);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template <std::signed_integral T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
using limits = std::numeric_limits<T>;
|
||||
|
||||
int64_t x;
|
||||
SIMDJSON_TRY(val.get_int64().get(x));
|
||||
if (x > (limits::max)() || x < (limits::min)()) {
|
||||
return NUMBER_OUT_OF_RANGE;
|
||||
}
|
||||
out = static_cast<T>(x);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// STL list deserialization
|
||||
//////////////////////////////
|
||||
|
||||
template <typename T, typename AllocT, typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val,
|
||||
std::list<T, AllocT> &out) noexcept(false) {
|
||||
|
||||
// For better error messages, don't use these as constraints on
|
||||
// the tag_invoke CPO.
|
||||
static_assert(
|
||||
deserializable<T, ValT>,
|
||||
"The specified type inside the list must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<T>,
|
||||
"The specified type inside the list must default constructible.");
|
||||
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
|
||||
SIMDJSON_TRY(val.get_array().get(arr));
|
||||
for (auto v : arr) {
|
||||
if (auto const err = v.get<T>().get(out.emplace_back()); err) {
|
||||
// If an error occurs, the empty element that we just inserted gets
|
||||
// removed. We're not using a temp variable because if T is a heavy type,
|
||||
// we want the valid path to be the fast path and the slow path be the
|
||||
// path that has errors in it.
|
||||
static_cast<void>(out.pop_back());
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// std::string deserialization
|
||||
//////////////////////////////
|
||||
|
||||
template <typename CharT,
|
||||
typename TraitsT,
|
||||
typename AllocT,
|
||||
typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val, std::basic_string<CharT, TraitsT, AllocT> &out) noexcept(false) {
|
||||
using string_type = std::basic_string<CharT, TraitsT, AllocT>;
|
||||
|
||||
if constexpr (std::same_as<string_type, string_type>) {
|
||||
SIMDJSON_TRY(val.get_string(out));
|
||||
} else {
|
||||
// todo: optimize performance
|
||||
std::string tmp;
|
||||
SIMDJSON_TRY(val.get_string(tmp));
|
||||
for (auto const ch : tmp) {
|
||||
out.push_back(ch);
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// STL Vector deserialization
|
||||
//////////////////////////////
|
||||
|
||||
/**
|
||||
* STL containers have several constructors including one that takes a single
|
||||
* size argument. Thus, some compilers (Visual Studio) will not be able to
|
||||
* disambiguate between the size and container constructor. Users should
|
||||
* explicitly specify the type of the container as needed: e.g.,
|
||||
* doc.get<std::vector<int>>().
|
||||
*/
|
||||
template <typename T, typename AllocT, typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val,
|
||||
std::vector<T, AllocT> &out) noexcept(false) {
|
||||
|
||||
// For better error messages, don't use these as constraints on
|
||||
// the tag_invoke CPO.
|
||||
static_assert(
|
||||
deserializable<T, ValT>,
|
||||
"The specified type inside the vector must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<T>,
|
||||
"The specified type inside the vector must default constructible.");
|
||||
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::array arr;
|
||||
SIMDJSON_TRY(val.get_array().get(arr));
|
||||
for (auto v : arr) {
|
||||
if (auto const err = v.get<T>().get(out.emplace_back()); err) {
|
||||
// If an error occurs, the empty element that we just inserted gets
|
||||
// removed. We're not using a temp variable because if T is a heavy type,
|
||||
// we want the valid path to be the fast path and the slow path be the
|
||||
// path that has errors in it.
|
||||
static_cast<void>(out.pop_back());
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// std::unique_ptr deserialization
|
||||
//////////////////////////////
|
||||
|
||||
/**
|
||||
* This CPO (Customization Point Object) will help deserialize into
|
||||
* `unique_ptr`s.
|
||||
*
|
||||
* If constructing T is nothrow, this conversion should be nothrow as well since
|
||||
* we return MEMALLOC if we're not able to allocate memory instead of throwing
|
||||
* the the error message.
|
||||
*
|
||||
* @tparam T The type inside the unique_ptr
|
||||
* @tparam Deleter The Deleter of the unique_ptr
|
||||
* @tparam ValT document/value type
|
||||
* @param val document/value
|
||||
* @param out output unique_ptr
|
||||
* @return status of the conversion
|
||||
*/
|
||||
template <typename T, typename Deleter, typename ValT>
|
||||
error_code tag_invoke(deserialize_tag, ValT &val,
|
||||
std::unique_ptr<T, Deleter>
|
||||
&out) noexcept(nothrow_deserializable<T, ValT>) {
|
||||
|
||||
// For better error messages, don't use these as constraints on
|
||||
// the tag_invoke CPO.
|
||||
static_assert(
|
||||
deserializable<T, ValT>,
|
||||
"The specified type inside the unique_ptr must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<T>,
|
||||
"The specified type inside the unique_ptr must default constructible.");
|
||||
|
||||
auto ptr = new (std::nothrow) T();
|
||||
if (ptr == nullptr) {
|
||||
return MEMALLOC;
|
||||
}
|
||||
SIMDJSON_TRY(val.template get<T>(*ptr));
|
||||
out.reset(ptr);
|
||||
return SUCCESS;
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "simdjson/generic/ondemand/array.h"
|
||||
#include "simdjson/generic/ondemand/array_iterator.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator.h"
|
||||
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
|
||||
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion-inl.h"
|
||||
#include "simdjson/generic/ondemand/json_type.h"
|
||||
#include "simdjson/generic/ondemand/object.h"
|
||||
#include "simdjson/generic/ondemand/raw_json_string.h"
|
||||
@@ -78,6 +80,7 @@ simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||
simdjson_inline simdjson_result<bool> value::is_null() noexcept {
|
||||
return iter.is_null();
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
|
||||
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
||||
@@ -88,9 +91,16 @@ template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { ret
|
||||
template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
|
||||
|
||||
template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
|
||||
return get<T>().get(out);
|
||||
}
|
||||
|
||||
template<> simdjson_inline error_code value::get(array& out) noexcept { return get_array().get(out); }
|
||||
template<> simdjson_inline error_code value::get(object& out) noexcept { return get_object().get(out); }
|
||||
template<> simdjson_inline error_code value::get(raw_json_string& out) noexcept { return get_raw_json_string().get(out); }
|
||||
template<> simdjson_inline error_code value::get(std::string_view& out) noexcept { return get_string(false).get(out); }
|
||||
template<> simdjson_inline error_code value::get(number& out) noexcept { return get_number().get(out); }
|
||||
template<> simdjson_inline error_code value::get(double& out) noexcept { return get_double().get(out); }
|
||||
template<> simdjson_inline error_code value::get(uint64_t& out) noexcept { return get_uint64().get(out); }
|
||||
template<> simdjson_inline error_code value::get(int64_t& out) noexcept { return get_int64().get(out); }
|
||||
template<> simdjson_inline error_code value::get(bool& out) noexcept { return get_bool().get(out); }
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
template <class T>
|
||||
@@ -414,6 +424,12 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
|
||||
return first.is_null();
|
||||
}
|
||||
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
|
||||
if (error()) { return error(); }
|
||||
out = first;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get<T>();
|
||||
@@ -427,11 +443,6 @@ template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::va
|
||||
if (error()) { return error(); }
|
||||
return std::move(first);
|
||||
}
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
|
||||
if (error()) { return error(); }
|
||||
out = first;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
@@ -465,7 +476,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> simdj
|
||||
template <class T>
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator T() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return static_cast<T>(first);
|
||||
return first.get<T>();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#include "simdjson/generic/ondemand/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator.h"
|
||||
#include "simdjson/generic/ondemand/deserialize.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace ondemand {
|
||||
|
||||
/**
|
||||
* An ephemeral JSON value returned during iteration. It is only valid for as long as you do
|
||||
* not access more data in the JSON document.
|
||||
@@ -35,16 +38,21 @@ public:
|
||||
* @returns A value of the given type, parsed from the JSON.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||
*/
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
template <typename T>
|
||||
simdjson_inline simdjson_result<T> get()
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
static_assert(std::is_default_constructible<T>::value, "The specified type is not default constructible.");
|
||||
T out{};
|
||||
SIMDJSON_TRY(get<T>(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
@@ -54,7 +62,32 @@ public:
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
|
||||
*/
|
||||
template<typename T> simdjson_inline error_code get(T &out) noexcept;
|
||||
template <typename T>
|
||||
simdjson_inline error_code get(T &out)
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
noexcept(custom_deserializable<T, value> ? nothrow_custom_deserializable<T, value> : true)
|
||||
#else
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, value>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#include "simdjson/generic/atomparsing.h"
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
#include "simdjson/generic/ondemand/json_iterator.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator.h"
|
||||
#include "simdjson/generic/ondemand/json_type-inl.h"
|
||||
#include "simdjson/generic/ondemand/raw_json_string-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
@@ -799,8 +799,6 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
|
||||
if(result) { // we have something that looks like a null.
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
advance_root_scalar("null");
|
||||
} else if (json[0] == 'n') {
|
||||
return incorrect_type_error("Not a null but starts with n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,8 @@
|
||||
#include "simdjson/haswell/intrinsics.h"
|
||||
|
||||
#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")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "simdjson/haswell/bitmanipulation.h"
|
||||
#include "simdjson/haswell/bitmask.h"
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#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,12 +36,6 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace lasx
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
|
||||
|
||||
@@ -36,12 +36,6 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace lsx
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
|
||||
|
||||
@@ -53,9 +53,6 @@ inline padded_string::padded_string(const char *data, size_t length) noexcept
|
||||
if ((data != nullptr) && (data_ptr != nullptr)) {
|
||||
std::memcpy(data_ptr, data, length);
|
||||
}
|
||||
if (data_ptr == nullptr) {
|
||||
viable_size = 0;
|
||||
}
|
||||
}
|
||||
#ifdef __cpp_char8_t
|
||||
inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
|
||||
@@ -63,17 +60,12 @@ inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
|
||||
if ((data != nullptr) && (data_ptr != nullptr)) {
|
||||
std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length);
|
||||
}
|
||||
if (data_ptr == nullptr) {
|
||||
viable_size = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// note: do not pass std::string arguments by value
|
||||
inline padded_string::padded_string(const std::string & str_ ) noexcept
|
||||
: viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) {
|
||||
if (data_ptr == nullptr) {
|
||||
viable_size = 0;
|
||||
} else {
|
||||
if (data_ptr != nullptr) {
|
||||
std::memcpy(data_ptr, str_.data(), str_.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,43 +201,4 @@ using std::size_t;
|
||||
|
||||
#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
|
||||
|
||||
@@ -60,12 +60,6 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace ppc64
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION "3.10.1"
|
||||
#define SIMDJSON_VERSION "3.10.0"
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -19,7 +19,7 @@ enum {
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
SIMDJSON_VERSION_REVISION = 0
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -323,10 +323,6 @@ class Amalgamator:
|
||||
for line in fid2:
|
||||
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
|
||||
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!"
|
||||
|
||||
+22
-116
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2024-09-17 15:48:50 -0400. Do not edit! */
|
||||
/* auto-generated on 2024-07-15 08:51:57 -0400. Do not edit! */
|
||||
/* including simdjson.cpp: */
|
||||
/* begin file simdjson.cpp */
|
||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||
@@ -77,6 +77,18 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
#include <utility>
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
||||
#else // __cpp_concepts
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif
|
||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||
/* end file simdjson/compiler_check.h */
|
||||
/* including simdjson/portability.h: #include "simdjson/portability.h" */
|
||||
@@ -284,45 +296,6 @@ using std::size_t;
|
||||
|
||||
#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
|
||||
/* end file simdjson/portability.h */
|
||||
|
||||
@@ -371,8 +344,6 @@ double from_chars(const char *first, const char* end) noexcept;
|
||||
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
|
||||
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
// We could use [[deprecated]] but it requires C++14
|
||||
#define simdjson_deprecated __declspec(deprecated)
|
||||
|
||||
#define simdjson_really_inline __forceinline
|
||||
#define simdjson_never_inline __declspec(noinline)
|
||||
@@ -411,8 +382,6 @@ double from_chars(const char *first, const char* end) noexcept;
|
||||
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
|
||||
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
// We could use [[deprecated]] but it requires C++14
|
||||
#define simdjson_deprecated __attribute__((deprecated))
|
||||
|
||||
#define simdjson_really_inline inline __attribute__((always_inline))
|
||||
#define simdjson_never_inline inline __attribute__((noinline))
|
||||
@@ -588,6 +557,7 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
// 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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NONSTD_SV_LITE_H_INCLUDED
|
||||
#define NONSTD_SV_LITE_H_INCLUDED
|
||||
@@ -7677,12 +7647,6 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
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 */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
@@ -7855,13 +7819,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace arm64
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/arm64/numberparsing_defs.h */
|
||||
@@ -9478,6 +9436,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -10444,12 +10403,6 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
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 */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
@@ -10622,13 +10575,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace arm64
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/arm64/numberparsing_defs.h */
|
||||
@@ -15831,6 +15778,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -22044,6 +21992,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -26809,13 +26758,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace ppc64
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/ppc64/numberparsing_defs.h */
|
||||
@@ -28419,6 +28362,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -29558,13 +29502,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace ppc64
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/ppc64/numberparsing_defs.h */
|
||||
@@ -35160,6 +35098,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -40245,13 +40184,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace lsx
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/lsx/numberparsing_defs.h */
|
||||
@@ -41725,6 +41658,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -42779,13 +42713,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace lsx
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/lsx/numberparsing_defs.h */
|
||||
@@ -46239,13 +46167,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace lasx
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/lasx/numberparsing_defs.h */
|
||||
@@ -47735,6 +47657,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -48789,13 +48712,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace lasx
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/lasx/numberparsing_defs.h */
|
||||
@@ -52279,13 +52196,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace fallback
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/fallback/numberparsing_defs.h */
|
||||
@@ -53344,6 +53255,7 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
||||
// Our objective is accurate parsing (ULP of 0) at high speed.
|
||||
template<typename W>
|
||||
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
||||
|
||||
//
|
||||
// Check for minus sign
|
||||
//
|
||||
@@ -54418,13 +54330,7 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
|
||||
} // namespace fallback
|
||||
} // 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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
|
||||
/* end file simdjson/fallback/numberparsing_defs.h */
|
||||
|
||||
+8069
-4959
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,6 @@ add_cpp_test(errortests 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(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(numberparsingcheck LABELS dom acceptance per_implementation) # https://tools.ietf.org/html/rfc6901
|
||||
add_cpp_test(parse_many_test LABELS dom acceptance per_implementation)
|
||||
|
||||
@@ -1,350 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -461,44 +461,7 @@ void parse_documentation_lowlevel() {
|
||||
(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() {
|
||||
jsonpath();
|
||||
jsondollar();
|
||||
basics_dom_1();
|
||||
basics_dom_2();
|
||||
basics_dom_3();
|
||||
|
||||
@@ -2,32 +2,35 @@
|
||||
link_libraries(simdjson)
|
||||
include_directories(..)
|
||||
add_subdirectory(compilation_failure_tests)
|
||||
add_cpp_test(ondemand_log_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_log_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_tostring_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_active_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_array_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_array_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_compilation_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_document_stream_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_error_location_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_json_pointer_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_json_path_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_key_string_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_misc_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_number_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_number_in_string_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_object_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_object_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_ordering_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_parse_api_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_readme_examples LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_scalar_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_to_string LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_twitter_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_wrong_type_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_iterate_many_csv LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_log_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_log_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_tostring_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_active_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_array_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_array_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_compilation_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_document_stream_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_error_location_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_json_pointer_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_json_path_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_key_string_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_misc_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_number_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_number_in_string_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_object_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_object_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_ordering_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_parse_api_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_readme_examples LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_scalar_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_to_string LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_twitter_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_wrong_type_error_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_iterate_many_csv LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_custom_types_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_custom_types_document_tests LABELS ondemand acceptance per_implementation)
|
||||
add_cpp_test(ondemand_stl_types_tests LABELS ondemand acceptance per_implementation)
|
||||
if(NOT SIMDJSON_SANITIZE)
|
||||
add_cpp_test(ondemand_cacheline LABELS ondemand acceptance per_implementation)
|
||||
endif()
|
||||
|
||||
@@ -13,8 +13,7 @@ function(add_dual_compile_test TEST_NAME)
|
||||
target_compile_definitions(${TEST_NAME}_should_not_compile PRIVATE COMPILATION_TEST_USE_FAILING_CODE=1)
|
||||
endfunction(add_dual_compile_test)
|
||||
|
||||
add_dual_compile_test(iterate_object)
|
||||
add_dual_compile_test(iterate_array)
|
||||
|
||||
add_dual_compile_test(iterate_char_star)
|
||||
add_dual_compile_test(iterate_string_view)
|
||||
add_dual_compile_test(iterate_temporary_buffer)
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
int main() {
|
||||
auto json = "[1]"_padded;
|
||||
ondemand::parser parser;
|
||||
auto f = [](ondemand::parser& p, simdjson::padded_string& jsons) -> ondemand::document {
|
||||
ondemand::document doc;
|
||||
auto error = p.iterate(jsons).get(doc);
|
||||
if(error) { std::abort(); }
|
||||
return doc;
|
||||
};
|
||||
ondemand::array arrayv;
|
||||
#if COMPILATION_TEST_USE_FAILING_CODE
|
||||
// Not allowed as this would be unsafe, the document must remain alive.
|
||||
auto error = f(parser).get_array().get(arrayv);
|
||||
#else
|
||||
ondemand::document doc = f(parser, json);
|
||||
auto error = doc.get_array().get(arrayv);
|
||||
#endif
|
||||
if(error) {
|
||||
std::cout << "Failure" << std::endl;
|
||||
}
|
||||
int64_t a = 0;
|
||||
error = arrayv.at(0).get_int64().get(a);
|
||||
if(error) {
|
||||
std::cout << "failure" << std::endl;
|
||||
}
|
||||
printf("a = %d\n", (int)a);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
int main() {
|
||||
auto json = "{\"a\":1}"_padded;
|
||||
ondemand::parser parser;
|
||||
auto f = [](ondemand::parser& p, simdjson::padded_string& jsons) -> ondemand::document {
|
||||
ondemand::document doc;
|
||||
auto error = p.iterate(jsons).get(doc);
|
||||
if(error) { std::abort(); }
|
||||
return doc;
|
||||
};
|
||||
ondemand::object objv;
|
||||
#if COMPILATION_TEST_USE_FAILING_CODE
|
||||
// Not allowed as this would be unsafe, the document must remain alive.
|
||||
auto error = f(parser).get_object().get(objv);
|
||||
#else
|
||||
ondemand::document doc = f(parser, json);
|
||||
auto error = doc.get_object().get(objv);
|
||||
#endif
|
||||
if(error) {
|
||||
std::cout << "Failure" << std::endl;
|
||||
}
|
||||
int64_t a = 0;
|
||||
error = objv["a"].get_int64().get(a);
|
||||
if(error) {
|
||||
std::cout << "failure" << std::endl;
|
||||
}
|
||||
printf("a = %d\n", (int)a);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -21,24 +21,8 @@ long page_size() {
|
||||
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
|
||||
// page boundary.
|
||||
bool need_allocation(const char *buf, size_t len) {
|
||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
|
||||
+ 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;
|
||||
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
|
||||
simdjson::SIMDJSON_PADDING);
|
||||
}
|
||||
|
||||
simdjson::padded_string_view
|
||||
@@ -55,10 +39,6 @@ get_padded_string_view(const char *buf, size_t len,
|
||||
|
||||
int main() {
|
||||
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"(
|
||||
{
|
||||
"key": "value"
|
||||
|
||||
@@ -59,22 +59,6 @@ void compilation_test_3() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not run this, it is only meant to compile
|
||||
void compilation_test_4() {
|
||||
const padded_string bogus = ""_padded;
|
||||
ondemand::parser parser;
|
||||
int64_t x1 = (int64_t)parser.iterate(bogus);
|
||||
double x2 = (double)parser.iterate(bogus);
|
||||
std::string_view x = (std::string_view)parser.iterate(bogus);
|
||||
uint64_t x3 = (uint64_t)parser.iterate(bogus);
|
||||
bool x4 = (bool)parser.iterate(bogus);
|
||||
(void) x1;
|
||||
(void) x2;
|
||||
(void) x3;
|
||||
(void) x4;
|
||||
(void) x;
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_ondemand.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
// unique_ptr<T>
|
||||
template <typename T>
|
||||
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<T>& out) {
|
||||
out = std::make_unique<T>(val.template get<T>());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
namespace doc_custom_types_tests {
|
||||
#if SIMDJSON_EXCEPTIONS && defined(__cpp_concepts)
|
||||
struct Car {
|
||||
std::string make{};
|
||||
std::string model{};
|
||||
int64_t year{};
|
||||
std::vector<double> tire_pressure{};
|
||||
|
||||
friend error_code tag_invoke(simdjson::deserialize_tag,
|
||||
auto &val, Car& car) {
|
||||
simdjson::ondemand::object obj;
|
||||
if (auto const error = val.get_object().get(obj)) {
|
||||
return error;
|
||||
}
|
||||
// Instead of repeatedly obj["something"], we iterate through the object
|
||||
// which we expect to be faster.
|
||||
for (auto field : obj) {
|
||||
simdjson::ondemand::raw_json_string key;
|
||||
if (auto const error = field.key().get(key)) {
|
||||
return error;
|
||||
}
|
||||
if (key == "make") {
|
||||
if (auto const error = field.value().get_string(car.make)) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "model") {
|
||||
if (auto const error = field.value().get_string(car.model)) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "year") {
|
||||
if (auto const error = field.value().get_int64().get(car.year)) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "tire_pressure") {
|
||||
if (auto const error = field.value().get<std::vector<double>>().get(
|
||||
car.tire_pressure)) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return error_code::SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(simdjson::custom_deserializable<std::unique_ptr<Car>, simdjson::ondemand::value>, "It should be invocable");
|
||||
static_assert(simdjson::custom_deserializable<std::unique_ptr<Car>, simdjson::ondemand::document>, "Tag_invoke should work with document as well.");
|
||||
static_assert(simdjson::custom_deserializable<std::vector<Car>, simdjson::ondemand::value>, "It should be invocable");
|
||||
static_assert(simdjson::custom_deserializable<std::vector<Car>, simdjson::ondemand::document>, "Tag_invoke should work with document as well.");
|
||||
|
||||
bool custom_test() {
|
||||
TEST_START();
|
||||
auto const json = R"( {
|
||||
"make": "Toyota",
|
||||
"model": "Camry",
|
||||
"year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ]
|
||||
} )"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
|
||||
// creating car directly from "doc":
|
||||
const std::unique_ptr<Car> car(doc);
|
||||
if (car->make != "Toyota") {
|
||||
return false;
|
||||
}
|
||||
if (car->model != "Camry") {
|
||||
return false;
|
||||
}
|
||||
if (car->year != 2018) {
|
||||
return false;
|
||||
}
|
||||
if (car->tire_pressure.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool readme_test() {
|
||||
TEST_START();
|
||||
auto const json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
std::unique_ptr<Car> c(doc);
|
||||
std::cout << c->make << std::endl;
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool simple_document_test() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
Car c(doc);
|
||||
std::cout << c.make << std::endl;
|
||||
ASSERT_EQUAL(c.make, "Toyota");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool custom_test_crazier() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
std::vector<Car> cars = doc.get<std::vector<Car>>();
|
||||
#else
|
||||
std::vector<Car> cars(doc);
|
||||
#endif
|
||||
for(Car& c : cars) {
|
||||
std::cout << c.year << std::endl;
|
||||
if (c.make != "Toyota" && c.make != "Kia") {
|
||||
return false;
|
||||
}
|
||||
if (c.model != "Camry" && c.model != "Soul" && c.model != "Tercel") {
|
||||
return false;
|
||||
}
|
||||
if (c.year != 2018 && c.year != 2012 && c.year != 1999) {
|
||||
return false;
|
||||
}
|
||||
if (c.tire_pressure.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simple_document_test_no_except() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] })"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
Car c;
|
||||
auto error = doc.get(c);
|
||||
if(error) { std::cerr << simdjson::error_message(error); return false; }
|
||||
std::cout << c.make << std::endl;
|
||||
ASSERT_EQUAL(c.make, "Toyota");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS && defined(__cpp_concepts)
|
||||
readme_test() &&
|
||||
custom_test() &&
|
||||
simple_document_test() &&
|
||||
simple_document_test_no_except() &&
|
||||
custom_test_crazier() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace doc_custom_types_tests
|
||||
|
||||
int main(const int argc, char *argv[]) {
|
||||
return test_main(argc, argv, doc_custom_types_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_ondemand.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
template <typename T>
|
||||
struct is_unique_ptr : std::false_type {
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct is_unique_ptr<std::unique_ptr<T>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept is_unique_ptr_v = is_unique_ptr<T>::value;
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
// this is to demonstrate that we can use concept; otherwise a simple
|
||||
// type_identity<unique_ptr<T>> as the second argument would have done the job.
|
||||
//
|
||||
// This tag_invoke MUST be inside simdjson namespace
|
||||
template <typename T>
|
||||
requires is_unique_ptr_v<T>
|
||||
auto tag_invoke(deserialize_tag, auto &val, T& out) {
|
||||
using type = typename T::element_type;
|
||||
out = std::make_unique<type>(val.template get<type>());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
|
||||
namespace custom_types_tests {
|
||||
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
struct Car {
|
||||
std::string make{};
|
||||
std::string model{};
|
||||
int year{};
|
||||
std::vector<double> tire_pressure{};
|
||||
|
||||
friend simdjson::error_code tag_invoke(simdjson::deserialize_tag, auto &val, Car& car) {
|
||||
simdjson::ondemand::object obj;
|
||||
auto error = val.get_object().get(obj);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
// Instead of repeatedly obj["something"], we iterate through the object
|
||||
// which we expect to be faster.
|
||||
for (auto field : obj) {
|
||||
simdjson::ondemand::raw_json_string key;
|
||||
error = field.key().get(key);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (key == "make") {
|
||||
error = field.value().get_string(car.make);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "model") {
|
||||
error = field.value().get_string(car.model);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "year") {
|
||||
error = field.value().get(car.year);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
} else if (key == "tire_pressure") {
|
||||
error = field.value().get(car.tire_pressure);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return simdjson::SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(simdjson::custom_deserializable<std::unique_ptr<Car>>, "It should be deserializable");
|
||||
|
||||
bool custom_uniqueptr_test() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
std::unique_ptr<Car> c(val);
|
||||
if (c->make != "Toyota" && c->make != "Kia") {
|
||||
return false;
|
||||
}
|
||||
if (c->model != "Camry" && c->model != "Soul" && c->model != "Tercel") {
|
||||
return false;
|
||||
}
|
||||
if (c->year != 2018 && c->year != 2012 && c->year != 1999) {
|
||||
return false;
|
||||
}
|
||||
if (c->tire_pressure.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool custom_test() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val);
|
||||
if (c.make != "Toyota" && c.make != "Kia") {
|
||||
return false;
|
||||
}
|
||||
if (c.model != "Camry" && c.model != "Soul" && c.model != "Tercel") {
|
||||
return false;
|
||||
}
|
||||
if (c.year != 2018 && c.year != 2012 && c.year != 1999) {
|
||||
return false;
|
||||
}
|
||||
if (c.tire_pressure.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool custom_test_crazy() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val);
|
||||
std::cout << c.year << std::endl;
|
||||
if (c.make != "Toyota" && c.make != "Kia") {
|
||||
return false;
|
||||
}
|
||||
if (c.model != "Camry" && c.model != "Soul" && c.model != "Tercel") {
|
||||
return false;
|
||||
}
|
||||
if (c.year != 2018 && c.year != 2012 && c.year != 1999) {
|
||||
return false;
|
||||
}
|
||||
if (c.tire_pressure.size() != 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool custom_no_except() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012,
|
||||
"tire_pressure": [ 30.1, 31.0 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999,
|
||||
"tire_pressure": [ 29.8, 30.0 ] }
|
||||
])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c;
|
||||
auto error = val.get(c);
|
||||
if(error) { std::cerr << simdjson::error_message(error) << std::endl; return false; }
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
custom_test() &&
|
||||
custom_uniqueptr_test() &&
|
||||
custom_no_except() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace custom_types_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, custom_types_tests::run);
|
||||
}
|
||||
@@ -346,54 +346,6 @@ namespace json_path_tests {
|
||||
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
|
||||
bool json_path_invalidation_exceptions() {
|
||||
TEST_START();
|
||||
@@ -440,7 +392,6 @@ namespace json_path_tests {
|
||||
many_json_paths_array() &&
|
||||
many_json_paths_object() &&
|
||||
many_json_paths_object_array() &&
|
||||
many_json_paths_with_prefix() &&
|
||||
run_broken_tests() &&
|
||||
json_path_invalidation() &&
|
||||
demo_test() &&
|
||||
|
||||
@@ -164,7 +164,8 @@ namespace json_pointer_tests {
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking true"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(true_json).is_scalar().get(is_scalar));
|
||||
ASSERT_SUCCESS(parser.iterate(true_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking object"<< std::endl;
|
||||
|
||||
@@ -49,6 +49,7 @@ struct Car {
|
||||
std::vector<double> tire_pressure;
|
||||
};
|
||||
|
||||
#ifndef __cpp_concepts
|
||||
template <>
|
||||
simdjson_inline simdjson_result<std::vector<double>>
|
||||
simdjson::ondemand::value::get() noexcept {
|
||||
@@ -66,7 +67,7 @@ simdjson::ondemand::value::get() noexcept {
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
template <>
|
||||
@@ -193,8 +194,8 @@ int custom_type_with_exceptions() {
|
||||
])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
Car c(val);
|
||||
for (auto value : doc) {
|
||||
Car c(value);
|
||||
std::cout << c.make << std::endl;
|
||||
}
|
||||
return 0;
|
||||
@@ -236,19 +237,6 @@ bool gen_raw2() {
|
||||
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() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
@@ -1904,7 +1892,6 @@ bool run() {
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
&& big_int_array()
|
||||
#endif // SIMDJSON_CPLUSPLUS17
|
||||
&& jsondollar()
|
||||
&& big_int_array_as_double()
|
||||
&& key_raw_json_token()
|
||||
&& to_optional()
|
||||
|
||||
@@ -369,24 +369,15 @@ namespace scalar_tests {
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.is_null(), INCORRECT_TYPE);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
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);
|
||||
bool x;
|
||||
ASSERT_SUCCESS(doc.is_null().get(x));
|
||||
ASSERT_TRUE(!x);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
nully() &&
|
||||
nul() &&
|
||||
string_with_trailing() &&
|
||||
uint64_with_trailing() &&
|
||||
int64_with_trailing() &&
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_ondemand.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace stl_types {
|
||||
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
bool basic_general_madness() {
|
||||
TEST_START();
|
||||
simdjson::padded_string json =
|
||||
R"( [ { "codes": [1.2, 3.4, 5.6, 7.8, 9.0] },
|
||||
{ "codes": [2.2, 4.4, 6.6, 8.8, 10.0] } ])"_padded;
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc = parser.iterate(json);
|
||||
std::vector<std::unique_ptr<float>> codes;
|
||||
for (auto val : doc) {
|
||||
simdjson::ondemand::object obj;
|
||||
SIMDJSON_TRY(val.get_object().get(obj));
|
||||
obj["codes"].get(codes); // append to it
|
||||
}
|
||||
|
||||
if (codes.size() != 10) {
|
||||
return false;
|
||||
}
|
||||
if (*codes[5] != 2.2f || *codes[7] != 6.6f || *codes[9] != 10.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
basic_general_madness() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace stl_types
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, stl_types::run);
|
||||
}
|
||||
Reference in New Issue
Block a user