mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ad452459c | |||
| d987f1871c | |||
| 4acaf2ea1c | |||
| 86adda06d0 | |||
| 8df5f96eba | |||
| 937667796c | |||
| 7d86b04247 | |||
| 265022ad8f | |||
| 0c0ce1bd48 | |||
| f64c004cb7 | |||
| d7d19db6ae | |||
| a260c967ed | |||
| 16e390d81a | |||
| 8d34e14000 | |||
| b717136fd9 | |||
| f3ac74caf8 | |||
| 2369927661 | |||
| 818c0491a1 | |||
| 9f14f90a64 | |||
| 00843d2711 | |||
| 2887a17bab | |||
| d84c934768 | |||
| 7cec7c7ae4 | |||
| c52b010a57 | |||
| ee301599b1 | |||
| 7382dc2be8 | |||
| 8c14e0c56f | |||
| a9a62feb75 | |||
| b9228b4d3c | |||
| 726c3eb611 | |||
| 4cdc4f18ef |
@@ -0,0 +1,17 @@
|
|||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
|
- uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
|
||||||
|
- name: Verify
|
||||||
|
run: emcc -v
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v3.6.0
|
||||||
|
- name: Configure
|
||||||
|
run: emcmake cmake -B build
|
||||||
|
- name: Build # We build but do not test
|
||||||
|
run: cmake --build build
|
||||||
@@ -4,7 +4,7 @@ on: [push, pull_request]
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
whitespace:
|
whitespace:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Remove whitespace and check the diff
|
- name: Remove whitespace and check the diff
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
name: Ubuntu 20.04 CI (GCC 8)
|
|
||||||
|
|
||||||
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-20.04
|
|
||||||
env:
|
|
||||||
CXX: g++-8
|
|
||||||
CC: gcc-8
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: Install GCC 8
|
|
||||||
run: sudo apt-get install -y g++-8
|
|
||||||
- name: Use cmake
|
|
||||||
run: |
|
|
||||||
mkdir builddebug &&
|
|
||||||
cd builddebug &&
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest --output-on-failure -LE explicitonly -j &&
|
|
||||||
cd .. &&
|
|
||||||
mkdir build &&
|
|
||||||
cd build &&
|
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest --output-on-failure -LE explicitonly -j &&
|
|
||||||
cmake --install . &&
|
|
||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
|
||||||
cd ../tests/installation_tests/find &&
|
|
||||||
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
name: Ubuntu 20.04 CI (GCC 9)
|
|
||||||
|
|
||||||
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-20.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: Use cmake to build just the library
|
|
||||||
run: |
|
|
||||||
mkdir buildjustlib &&
|
|
||||||
cd buildjustlib &&
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
cmake --install . &&
|
|
||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
|
|
||||||
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
|
|
||||||
cd ../tests/installation_tests/find &&
|
|
||||||
mkdir buildjustlib &&
|
|
||||||
cd buildjustlib &&
|
|
||||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
|
|
||||||
cmake --build .
|
|
||||||
- name: Use cmake
|
|
||||||
run: |
|
|
||||||
mkdir builddebug &&
|
|
||||||
cd builddebug &&
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest --output-on-failure -LE explicitonly -j &&
|
|
||||||
cd .. &&
|
|
||||||
mkdir build &&
|
|
||||||
cd build &&
|
|
||||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
|
||||||
cmake --build . &&
|
|
||||||
ctest --output-on-failure -LE explicitonly -j &&
|
|
||||||
cmake --install . &&
|
|
||||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
|
||||||
cd ../tests/installation_tests/find &&
|
|
||||||
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
|
||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
if: >-
|
if: >-
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
+12
-4
@@ -1,9 +1,11 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
cmake_policy(VERSION 3.5) # For doctest
|
||||||
|
|
||||||
|
|
||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 3.12.2
|
VERSION 3.13.0
|
||||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||||
HOMEPAGE_URL "https://simdjson.org/"
|
HOMEPAGE_URL "https://simdjson.org/"
|
||||||
LANGUAGES CXX C
|
LANGUAGES CXX C
|
||||||
@@ -20,8 +22,8 @@ string(
|
|||||||
# ---- Options, variables ----
|
# ---- Options, variables ----
|
||||||
|
|
||||||
# These version numbers are modified by tools/release.py
|
# These version numbers are modified by tools/release.py
|
||||||
set(SIMDJSON_LIB_VERSION "25.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "26.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "25" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "26" 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)
|
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)
|
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
|
||||||
@@ -84,7 +86,7 @@ set_target_properties(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# FIXME: Use proper CMake integration for exports
|
# FIXME: Use proper CMake integration for exports
|
||||||
if(MSVC AND BUILD_SHARED_LIBS)
|
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
simdjson
|
simdjson
|
||||||
PRIVATE SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY=1
|
PRIVATE SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY=1
|
||||||
@@ -111,6 +113,12 @@ if(
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(SIMDJSON_MINUS_ZERO_AS_FLOAT "Treat -0 as a floating-point value" OFF)
|
||||||
|
|
||||||
|
if(SIMDJSON_MINUS_ZERO_AS_FLOAT)
|
||||||
|
simdjson_add_props(target_compile_definitions PRIVATE SIMDJSON_MINUS_ZERO_AS_FLOAT=1)
|
||||||
|
endif(SIMDJSON_MINUS_ZERO_AS_FLOAT)
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(loongarch64)$")
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(loongarch64)$")
|
||||||
option(SIMDJSON_PREFER_LSX "Prefer LoongArch SX" ON)
|
option(SIMDJSON_PREFER_LSX "Prefer LoongArch SX" ON)
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
|||||||
+1
-1
@@ -92,7 +92,7 @@ We welcome contributions from women and less represented groups. If you need hel
|
|||||||
|
|
||||||
Consider the following points when engaging with the project:
|
Consider the following points when engaging with the project:
|
||||||
|
|
||||||
- We discourage arguments from authority: ideas are discusssed on their own merits and not based on who stated it.
|
- We discourage arguments from authority: ideas are discussed on their own merits and not based on who stated it.
|
||||||
- Be mindful that what you may view as an aggression is maybe merely a difference of opinion or a misunderstanding.
|
- Be mindful that what you may view as an aggression is maybe merely a difference of opinion or a misunderstanding.
|
||||||
- Be mindful that a collection of small aggressions, even if mild in isolation, can become harmful.
|
- Be mindful that a collection of small aggressions, even if mild in isolation, can become harmful.
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "3.12.2"
|
PROJECT_NUMBER = "3.13.0"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# 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
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ Real-world usage
|
|||||||
- [fastgron](https://github.com/adamritter/fastgron)
|
- [fastgron](https://github.com/adamritter/fastgron)
|
||||||
- [WasmEdge](https://wasmedge.org)
|
- [WasmEdge](https://wasmedge.org)
|
||||||
- [RonDB](https://github.com/logicalclocks/rondb)
|
- [RonDB](https://github.com/logicalclocks/rondb)
|
||||||
|
- [GreptimeDB](https://github.com/GreptimeTeam/greptimedb)
|
||||||
|
|
||||||
|
|
||||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||||
@@ -173,7 +174,8 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
|||||||
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
|
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
|
||||||
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
||||||
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
||||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
- [zimdjson](https://github.com/EzequielRamis/zimdjson): Zig port.
|
||||||
|
- [simdjzon](https://github.com/travisstaloch/simdjzon): Zig port.
|
||||||
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||||
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||||
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
|
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
# Flags used by exes and by the simdjson library (project-wide flags)
|
# Flags used by exes and by the simdjson library (project-wide flags)
|
||||||
#
|
#
|
||||||
add_library(simdjson-internal-flags INTERFACE)
|
add_library(simdjson-internal-flags INTERFACE)
|
||||||
|
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||||
|
# We default to ON for all targets, so that we can use the library in shared libraries.
|
||||||
|
set_target_properties(simdjson-internal-flags PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
endif(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||||
|
|
||||||
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer. The setting is unnecessary since we require padding of the inputs. You should expect tests to fail with this option turned on." OFF)
|
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer. The setting is unnecessary since we require padding of the inputs. You should expect tests to fail with this option turned on." OFF)
|
||||||
if(SIMDJSON_CHECK_EOF)
|
if(SIMDJSON_CHECK_EOF)
|
||||||
@@ -52,7 +55,6 @@ endif()
|
|||||||
|
|
||||||
option(SIMDJSON_SANITIZE_MEMORY "Sanitize memory" OFF)
|
option(SIMDJSON_SANITIZE_MEMORY "Sanitize memory" OFF)
|
||||||
|
|
||||||
|
|
||||||
if(SIMDJSON_SANITIZE_MEMORY)
|
if(SIMDJSON_SANITIZE_MEMORY)
|
||||||
message(STATUS "Setting the memory sanitizer.")
|
message(STATUS "Setting the memory sanitizer.")
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
@@ -158,9 +160,6 @@ We recommend Visual Studio 2019 or better on a 64-bit system.")
|
|||||||
add_compile_options(/Zi)
|
add_compile_options(/Zi)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
if(NOT WIN32)
|
|
||||||
target_compile_options(simdjson-internal-flags INTERFACE -fPIC)
|
|
||||||
endif()
|
|
||||||
target_compile_options(
|
target_compile_options(
|
||||||
simdjson-internal-flags INTERFACE
|
simdjson-internal-flags INTERFACE
|
||||||
-Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings
|
-Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings
|
||||||
|
|||||||
Vendored
+5
-13
@@ -7,12 +7,12 @@ option(SIMDJSON_ALLOW_DOWNLOADS
|
|||||||
cmake_dependent_option(SIMDJSON_COMPETITION "Compile competitive benchmarks" ON
|
cmake_dependent_option(SIMDJSON_COMPETITION "Compile competitive benchmarks" ON
|
||||||
SIMDJSON_ALLOW_DOWNLOADS OFF)
|
SIMDJSON_ALLOW_DOWNLOADS OFF)
|
||||||
cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark benchmarks" ON
|
cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark benchmarks" ON
|
||||||
SIMDJSON_ALLOW_DOWNLOADS OFF)
|
"SIMDJSON_ALLOW_DOWNLOADS OR MINGW" OFF)
|
||||||
|
|
||||||
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
if(SIMDJSON_GOOGLE_BENCHMARKS)
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME google_benchmarks
|
NAME google_benchmarks
|
||||||
URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.zip
|
URL https://github.com/google/benchmark/archive/refs/tags/v1.9.4.zip
|
||||||
OPTIONS
|
OPTIONS
|
||||||
"BENCHMARK_ENABLE_TESTING OFF"
|
"BENCHMARK_ENABLE_TESTING OFF"
|
||||||
"BENCHMARK_ENABLE_INSTALL OFF"
|
"BENCHMARK_ENABLE_INSTALL OFF"
|
||||||
@@ -22,7 +22,7 @@ endif()
|
|||||||
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME simdjson-data
|
NAME simdjson-data
|
||||||
URL https://github.com/simdjson/simdjson-data/archive/a5b13babe65c1bba7186b41b43d4cbdc20a5c470.zip
|
URL https://github.com/simdjson/simdjson-data/archive/351949906abde446f0314bf79606fb5d884f5be7.zip
|
||||||
)
|
)
|
||||||
|
|
||||||
option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF)
|
option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF)
|
||||||
@@ -93,19 +93,11 @@ int main() {}
|
|||||||
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
NAME nlohmann_json
|
NAME nlohmann_json
|
||||||
URL https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip
|
URL https://github.com/nlohmann/json/archive/refs/tags/v3.12.0.zip
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET nlohmann_json APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS 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
|
|
||||||
)
|
|
||||||
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)
|
|
||||||
|
|
||||||
set(jsoncpp_SOURCE_DIR "${simdjson_SOURCE_DIR}/dependencies/jsoncppdist")
|
set(jsoncpp_SOURCE_DIR "${simdjson_SOURCE_DIR}/dependencies/jsoncppdist")
|
||||||
add_library(jsoncpp STATIC "${jsoncpp_SOURCE_DIR}/jsoncpp.cpp")
|
add_library(jsoncpp STATIC "${jsoncpp_SOURCE_DIR}/jsoncpp.cpp")
|
||||||
@@ -177,7 +169,7 @@ int main() {}
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(competition-all INTERFACE)
|
add_library(competition-all INTERFACE)
|
||||||
target_link_libraries(competition-all INTERFACE competition-core jsoncpp json11 fastjson gason ujson4c)
|
target_link_libraries(competition-all INTERFACE competition-core jsoncpp fastjson gason ujson4c)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
if(SIMDJSON_COMPETITION)
|
if(SIMDJSON_COMPETITION)
|
||||||
|
|||||||
+111
-13
@@ -47,13 +47,15 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
Requirements
|
Requirements
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
The simdjson library is widely deployed in popular systems such as the Node.js runtime
|
||||||
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64 or ARM64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clang-cl) as well as as the regular Visual Studio compiler. For better release performance (both compile time and execution time), we recommend Visual Studio users adopt LLVM (clang-cl). We also support MinGW 64-bit under Windows.
|
environment.
|
||||||
|
|
||||||
|
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on POSIX systems such as macOS, FreeBSD or Linux. We require that the compiler supports the C++11 standard or better. We test the library on a big-endian system (IBM s390x with Linux).
|
||||||
|
- Visual Studio 2017 or better. We support the LLVM clang compiler under Visual Studio (clang-cl) as well as as the regular Visual Studio compiler. For better release performance (both compile time and execution time), we recommend Visual Studio users adopt LLVM (clang-cl). We also support MinGW 64-bit under Windows.
|
||||||
|
|
||||||
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better, AMD Zen 4 or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler.
|
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better, AMD Zen 4 or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler.
|
||||||
|
|
||||||
We test the library on a big-endian system (IBM s390x with Linux).
|
|
||||||
|
|
||||||
Including simdjson
|
Including simdjson
|
||||||
------------------
|
------------------
|
||||||
@@ -320,13 +322,15 @@ transcode the UTF-8 strings produced by the simdjson library to other formats. S
|
|||||||
Avoiding pitfalls: enable development checks
|
Avoiding pitfalls: enable development checks
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
We recommend that you first compile and run your code in Debug mode:
|
We recommend that you first compile and run your code in debug mode:
|
||||||
|
|
||||||
- under Visual Studio, it means having the `_DEBUG` macro defined,
|
- under Visual Studio, it means having the `_DEBUG` macro defined,
|
||||||
- for other compilers, it means leaving the `__OPTIMIZE__` macro undefined.
|
- for many other compilers, it means leaving the `__OPTIMIZE__` macro undefined.
|
||||||
|
|
||||||
The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1` in debug mode.
|
The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1` in debug mode. Because
|
||||||
Alternatively, you can set the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
|
the C++ standard does not provide a direct way of checking for a debug build, and
|
||||||
|
because you may want the checks while building with otimizations, you can set
|
||||||
|
the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
|
||||||
the `simdjson.h` header to enable these additional checks: just make sure you remove the
|
the `simdjson.h` header to enable these additional checks: just make sure you remove the
|
||||||
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
|
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
|
||||||
simdjson library runs additional (expensive) tests on your code to help ensure that you are
|
simdjson library runs additional (expensive) tests on your code to help ensure that you are
|
||||||
@@ -335,9 +339,12 @@ using the library in a safe manner.
|
|||||||
Once your code has been tested, you can then run it in
|
Once your code has been tested, you can then run it in
|
||||||
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
|
||||||
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
|
||||||
disable these checks by setting `SIMDJSON_DEVELOPMENT_CHECKS` to 0. Once your code is tested, we
|
disable these checks by setting `SIMDJSON_DEVELOPMENT_CHECKS` to 0.
|
||||||
further encourage you to define `NDEBUG` in your Release builds to disable additional runtime
|
|
||||||
testing and get the best performance.
|
Once your code is tested, we further encourage you to define `NDEBUG` in your release
|
||||||
|
builds to disable additional runtime testing and get the best performance. We
|
||||||
|
disable these checks on a best-effort basis but the C++ standard does not provide
|
||||||
|
a direct way to check for a release build.
|
||||||
|
|
||||||
Using the parsed JSON
|
Using the parsed JSON
|
||||||
---------------------
|
---------------------
|
||||||
@@ -1081,6 +1088,32 @@ int main(void) {
|
|||||||
|
|
||||||
### 2. Use `tag_invoke` for custom types (C++20)
|
### 2. Use `tag_invoke` for custom types (C++20)
|
||||||
|
|
||||||
|
The simdjson library takes advantage of C++20. An immediate benefit
|
||||||
|
is that you can deserialize JSON data directly in standard containers
|
||||||
|
and other standard value types:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
simdjson::padded_string json = R"({"data" : [1,2,3,4]})"_padded;
|
||||||
|
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document d = parser.iterate(json);
|
||||||
|
std::vector<uint8_t> array = d["data"].get<std::vector<uint8_t>>();
|
||||||
|
```
|
||||||
|
|
||||||
|
Appending to an existing container is just as easy:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
std::vector<uint32_t> array = {0, 0};
|
||||||
|
|
||||||
|
simdjson::padded_string json = R"({"data" : [1,2,3,4]})"_padded;
|
||||||
|
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document d = parser.iterate(json);
|
||||||
|
|
||||||
|
d["data"].get<std::vector<uint32_t>>(array);
|
||||||
|
// array is now {0,0,1,2,3,4}
|
||||||
|
```
|
||||||
|
|
||||||
In C++20, the standard introduced the notion of *customization point*.
|
In C++20, the standard introduced the notion of *customization point*.
|
||||||
A customization point is a function or function object that can be customized for different types. It allows library authors to provide default behavior while giving users the ability to override this behavior for specific types.
|
A customization point is a function or function object that can be customized for different types. It allows library authors to provide default behavior while giving users the ability to override this behavior for specific types.
|
||||||
|
|
||||||
@@ -1243,7 +1276,6 @@ int main() {
|
|||||||
You may also conditionally fill in `std::optional` values.
|
You may also conditionally fill in `std::optional` values.
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
|
|
||||||
padded_string json =
|
padded_string json =
|
||||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
"tire_pressure": [ 40.1, 39.9 ] }
|
"tire_pressure": [ 40.1, 39.9 ] }
|
||||||
@@ -1258,6 +1290,23 @@ You may also conditionally fill in `std::optional` values.
|
|||||||
// error is simdjson::SUCCESS
|
// error is simdjson::SUCCESS
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also deserialize to map-like types with keys that can be constructed
|
||||||
|
from `std::string_view` instances:
|
||||||
|
|
||||||
|
|
||||||
|
```C++
|
||||||
|
padded_string json =
|
||||||
|
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
|
"tire_pressure": [ 40.1, 39.9 ] }
|
||||||
|
})"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
std:map<std::string,Car> cars;
|
||||||
|
error = doc.get<std:map<std::string,Car>>().get(cars);
|
||||||
|
// car has value car1->Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}}
|
||||||
|
// error is simdjson::SUCCESS
|
||||||
|
```
|
||||||
|
|
||||||
And so forth.
|
And so forth.
|
||||||
|
|
||||||
Advanced users may want to overwrite the defaults provided by the simdjson library.
|
Advanced users may want to overwrite the defaults provided by the simdjson library.
|
||||||
@@ -1531,7 +1580,20 @@ Some errors are recoverable:
|
|||||||
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
|
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
|
||||||
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
|
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
|
||||||
|
|
||||||
Other errors (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`) may indicate a fatal error and often follow from the fact that the document is not valid JSON. In which case, it is no longer possible to continue accessing the document: calling the method `is_alive()` on the document instance returns false. All following accesses will keep returning the same fatal error (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`).
|
Other errors (`simdjson::INCOMPLETE_ARRAY_OR_OBJECT` and `simdjson::TAPE_ERROR`) indicate a fatal error and follow from the fact that the document is not valid JSON. These errors are not recoverable: you cannot continue. In which case, it is no longer safe to continue accessing the document: calling the method `is_alive()` on the document instance returns false. It is your responsibility as a user to stop using the simdjson
|
||||||
|
document after encountering these fatal errors. Consider the following example, after
|
||||||
|
the fatal error, the document instance cannot be used. Observe how the JSON input is invalid.
|
||||||
|
```cpp
|
||||||
|
simdjson::padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto errordoc = parser.iterate(badjson).get(doc);
|
||||||
|
// errordoc == simdjson::SUCCESS
|
||||||
|
simdjson::ondemand::value v;
|
||||||
|
auto error = doc.get_object()["year"].get(v);
|
||||||
|
// simdjson::is_fatal(error)) is true!
|
||||||
|
// doc.is_alive() is false
|
||||||
|
```
|
||||||
|
|
||||||
When you use the code without exceptions, it is your responsibility to check for error before using the
|
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||||
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
||||||
@@ -1920,6 +1982,8 @@ conclude that you have trailing content and that your document is not valid JSON
|
|||||||
You may then use `doc.current_location()` to obtain a pointer to the start of the trailing
|
You may then use `doc.current_location()` to obtain a pointer to the start of the trailing
|
||||||
content.
|
content.
|
||||||
|
|
||||||
|
Example 1.
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
auto json = R"([1, 2] foo ])"_padded;
|
auto json = R"([1, 2] foo ])"_padded;
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -1934,6 +1998,21 @@ content.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Example 2.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto json = R"(["extra close"]])"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::array array = doc.get_array();
|
||||||
|
for (std::string_view values : array) {
|
||||||
|
std::cout << values << std::endl;
|
||||||
|
}
|
||||||
|
if(!doc.at_end()) {
|
||||||
|
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The `at_end()` method is equivalent to `doc.current_location().error() == simdjson::SUCCESS` but
|
The `at_end()` method is equivalent to `doc.current_location().error() == simdjson::SUCCESS` but
|
||||||
more convenient.
|
more convenient.
|
||||||
|
|
||||||
@@ -2200,6 +2279,11 @@ Thus it is a dynamically typed number. Before accessing the value, you must dete
|
|||||||
such a number of `get_number()`, you get the error `BIGINT_ERROR`. You can access the underlying string of digits with the function `raw_json_token()` which returns a `std::string_view` instance starting at the beginning of the digit. You can also call `get_double()` to get a floating-point approximation.
|
such a number of `get_number()`, you get the error `BIGINT_ERROR`. You can access the underlying string of digits with the function `raw_json_token()` which returns a `std::string_view` instance starting at the beginning of the digit. You can also call `get_double()` to get a floating-point approximation.
|
||||||
|
|
||||||
|
|
||||||
|
By default, the string `-0` is parsed as the integer 0 as in Python or C++. If you set the macro
|
||||||
|
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to `1` when building simdjson, you can get that `-0` is mapped to `-0.0`
|
||||||
|
as in JavaScript. You can get the desired effect by building simdjson with cmake setting the
|
||||||
|
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to on: `cmake -B build -D SIMDJSON_MINUS_ZERO_AS_FLOAT=ON`.
|
||||||
|
|
||||||
You must check the type before accessing the value: it is an error to call `get_int64()` when `number.get_number_type()` is not `number_type::signed_integer` and when `number.is_int64()` is false. You are responsible for this check as the user of the library.
|
You must check the type before accessing the value: it is an error to call `get_int64()` when `number.get_number_type()` is not `number_type::signed_integer` and when `number.is_int64()` is false. You are responsible for this check as the user of the library.
|
||||||
|
|
||||||
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
|
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
|
||||||
@@ -2527,6 +2611,20 @@ can use it with features such as `std::optional`:
|
|||||||
// value was populated with "3.1416"
|
// value was populated with "3.1416"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can generally convert any answer that would return an `std::string_view`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto json = R"({"\u0062\u0065\u0062\u0065": 2} })"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::object object = doc.get_object();
|
||||||
|
for (auto field : object) {
|
||||||
|
std::string key;
|
||||||
|
error = field.unescaped_key().get(key);
|
||||||
|
if(error) { /* */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You should be mindful of the trade-off: allocating multiple
|
You should be mindful of the trade-off: allocating multiple
|
||||||
`std::string` instances can become expensive.
|
`std::string` instances can become expensive.
|
||||||
|
|
||||||
@@ -2545,7 +2643,7 @@ The CPU detection, which runs the first time parsing is attempted and switches t
|
|||||||
parser for your CPU, is transparent and thread-safe.
|
parser for your CPU, is transparent and thread-safe.
|
||||||
Our runtime dispatching is based on global objects that are instantiated at the beginning of the
|
Our runtime dispatching is based on global objects that are instantiated at the beginning of the
|
||||||
main thread and may be discarded at the end of the main thread. If you have multiple threads running
|
main thread and may be discarded at the end of the main thread. If you have multiple threads running
|
||||||
and some threads use the library while the main thread is cleaning up ressources, you may encounter
|
and some threads use the library while the main thread is cleaning up resources, you may encounter
|
||||||
issues. If you expect such problems, you may consider using [std::quick_exit](https://en.cppreference.com/w/cpp/utility/program/quick_exit).
|
issues. If you expect such problems, you may consider using [std::quick_exit](https://en.cppreference.com/w/cpp/utility/program/quick_exit).
|
||||||
|
|
||||||
In a threaded environment, stack space is often limited. Running code like simdjson in debug mode may require hundreds of kilobytes of stack memory. Thus stack overflows are a possibility. We recommend you turn on optimization when working in an environment where stack space is limited. If you must run your code in debug mode, we recommend you configure your system to have more stack space. We discourage you from running production code based on a debug build.
|
In a threaded environment, stack space is often limited. Running code like simdjson in debug mode may require hundreds of kilobytes of stack memory. Thus stack overflows are a possibility. We recommend you turn on optimization when working in an environment where stack space is limited. If you must run your code in debug mode, we recommend you configure your system to have more stack space. We discourage you from running production code based on a debug build.
|
||||||
|
|||||||
+26
-2
@@ -7,6 +7,7 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents-using-the-dom-front-end)
|
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents-using-the-dom-front-end)
|
||||||
* [Using the Parsed JSON](#using-the-parsed-json)
|
* [Using the Parsed JSON](#using-the-parsed-json)
|
||||||
* [C++17 Support](#c17-support)
|
* [C++17 Support](#c17-support)
|
||||||
|
* [C++20 Support](#c20-support)
|
||||||
* [JSON Pointer](#json-pointer)
|
* [JSON Pointer](#json-pointer)
|
||||||
* [JSONPath](#jsonpath)
|
* [JSONPath](#jsonpath)
|
||||||
* [Error Handling](#error-handling)
|
* [Error Handling](#error-handling)
|
||||||
@@ -90,7 +91,7 @@ During the`load` or `parse` calls, neither the input file nor the input string a
|
|||||||
For best performance, a `parser` instance should be reused over several files: otherwise you will needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
|
For best performance, a `parser` instance should be reused over several files: otherwise you will needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
|
||||||
|
|
||||||
If you need a lower-level interface, you may call the function `parser.parse(const char * p, size_t l)` on a pointer `p` while specifying the
|
If you need a lower-level interface, you may call the function `parser.parse(const char * p, size_t l)` on a pointer `p` while specifying the
|
||||||
length of your input `l` in bytes. To see how to get the very best performance from a low-level approach, you way want to read our [performance notes](https://github.com/simdjson/simdjson/blob/master/doc/performance.md#padding-and-temporary-copies) on this topic (see the Padding and Temporary Copies section).
|
length of your input `l` in bytes.
|
||||||
|
|
||||||
*Windows-specific*: Windows users who need to read files with
|
*Windows-specific*: Windows users who need to read files with
|
||||||
non-ANSI characters in the name should set their code page to
|
non-ANSI characters in the name should set their code page to
|
||||||
@@ -119,6 +120,12 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
|||||||
std::cout << "I parsed " << value << " from " << numberstring.data() << std::endl;
|
std::cout << "I parsed " << value << " from " << numberstring.data() << std::endl;
|
||||||
```
|
```
|
||||||
The strings contain unescaped valid UTF-8 strings: no unmatched surrogate is allowed.
|
The strings contain unescaped valid UTF-8 strings: no unmatched surrogate is allowed.
|
||||||
|
Internally, numbers are stored as either 64-bit integers or 64-bit floating-point numbers.
|
||||||
|
Thus it is possible to get the full 64-bit integer range (either signed or unsigned).
|
||||||
|
By default, the string `-0` is parsed as the integer 0 as in Pytho or C++. If you set the macro
|
||||||
|
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to `1` when building simdjson, you can get that `-0` is mapped to `-0.0`
|
||||||
|
as in JavaScript. You can get the desired effect by building simdjson with cmake setting the
|
||||||
|
`SIMDJSON_MINUS_ZERO_AS_FLOAT` to on: `cmake -B build -D SIMDJSON_MINUS_ZERO_AS_FLOAT=ON`.
|
||||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`.
|
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`.
|
||||||
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
|
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
|
||||||
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
|
||||||
@@ -232,6 +239,23 @@ for (dom::key_value_pair field : object) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C++20 Support
|
||||||
|
------------
|
||||||
|
|
||||||
|
simdjson library also supports some C++20 feature including `std::ranges`:
|
||||||
|
|
||||||
|
```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;
|
||||||
|
auto justmodel = [](auto car) { return car["model"]; };
|
||||||
|
for (auto car : parser.parse(cars_json).get_array() | std::views::transform(justmodel)) {
|
||||||
|
std::cout << car << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
JSON Pointer
|
JSON Pointer
|
||||||
------------
|
------------
|
||||||
@@ -733,5 +757,5 @@ Setting the `realloc_if_needed` parameter `false` in this manner may lead to bet
|
|||||||
Performance Tips
|
Performance Tips
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directrive, you must set it manually (e.g., `-DNDEBUG`).
|
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`).
|
||||||
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
|
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
|
||||||
|
|||||||
+1
-1
@@ -367,7 +367,7 @@ Please see our main documentation (`basics.md`) under
|
|||||||
"Use `tag_invoke` for custom types (C++20)" for details about
|
"Use `tag_invoke` for custom types (C++20)" for details about
|
||||||
tag_invoke functions.
|
tag_invoke functions.
|
||||||
|
|
||||||
Given a stream of JSON documents, you can add them to a data struture
|
Given a stream of JSON documents, you can add them to a data structure
|
||||||
such as a `std::vector<Car>` like so if you support exceptions:
|
such as a `std::vector<Car>` like so if you support exceptions:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
|
|||||||
+20
-9
@@ -4,9 +4,9 @@ Performance Notes
|
|||||||
simdjson strives to be at its fastest *without tuning*, and generally achieves this. However, there
|
simdjson strives to be at its fastest *without tuning*, and generally achieves this. However, there
|
||||||
are still some scenarios where tuning can enhance performance.
|
are still some scenarios where tuning can enhance performance.
|
||||||
Once your code is tested, we
|
Once your code is tested, we
|
||||||
further encourage you to define `NDEBUG` in your Release builds to disable additional runtime
|
further encourage you to define `NDEBUG` in your release builds to disable additional runtime
|
||||||
testing and get the best performance.
|
testing and get the best performance.
|
||||||
* [NDEBUG directive](#ndebug-directive)
|
* [NDEBUG macro](#ndebug-macro)
|
||||||
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
|
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
|
||||||
* [Reusing string buffers](#reusing-string-buffers)
|
* [Reusing string buffers](#reusing-string-buffers)
|
||||||
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
|
||||||
@@ -17,16 +17,27 @@ testing and get the best performance.
|
|||||||
* [Free Padding](#free-padding)
|
* [Free Padding](#free-padding)
|
||||||
|
|
||||||
|
|
||||||
NDEBUG directive
|
NDEBUG macro
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
In C/C++, the `NDEBUG` pre-processor directive is not set by default. When it is not set, the simdjson library does
|
We recommend that you set `NDEBUG` macro in your release builds.
|
||||||
many additional checks that may impact negatively the performance. We recommend that, once your code
|
|
||||||
is well tested, you define `NDEBUG` directive in your Release builds. The `NDEBUG` directive should be defined
|
|
||||||
prior to including the `simdjson.h` header.
|
|
||||||
|
|
||||||
The `NDEBUG` directive is generally independent from optimization flags. For example, setting `-O3` under
|
In C/C++, the `NDEBUG` macro is not set by default.
|
||||||
GCC does not set the `NDEBUG` directive.
|
When it is not set, the software may do many additional checks that may impact
|
||||||
|
negatively the performance. We recommend that, once your code
|
||||||
|
is well tested, you define `NDEBUG` directive in your release builds.
|
||||||
|
|
||||||
|
The `NDEBUG` directive is generally independent from optimization flags.
|
||||||
|
For example, setting `-O3` under GCC does not set the `NDEBUG` directive.
|
||||||
|
However, tools like `CMake` automatically
|
||||||
|
set `NDEBUG` for release builds.
|
||||||
|
|
||||||
|
In the simdjson library, we check the `NDEBUG` macro as well as other
|
||||||
|
macros to make performant release builds. However, the C++ standard
|
||||||
|
does not provide a definitive approach to determine whether you are
|
||||||
|
compiling for a release build. Thus we recommend that you follow
|
||||||
|
the practice of setting the `NDEBUG` macro in release mode to make sure
|
||||||
|
that you do not get undesirable expensive checks.
|
||||||
|
|
||||||
Reusing the parser for maximum efficiency
|
Reusing the parser for maximum efficiency
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SIMDJSON_EXCEPTIONS
|
#ifndef SIMDJSON_EXCEPTIONS
|
||||||
#if __cpp_exceptions
|
#if defined(__cpp_exceptions) || defined(_CPPUNWIND)
|
||||||
#define SIMDJSON_EXCEPTIONS 1
|
#define SIMDJSON_EXCEPTIONS 1
|
||||||
#else
|
#else
|
||||||
#define SIMDJSON_EXCEPTIONS 0
|
#define SIMDJSON_EXCEPTIONS 0
|
||||||
@@ -226,12 +226,14 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
// even if we do not have C++17 support.
|
// even if we do not have C++17 support.
|
||||||
#ifdef __cpp_lib_string_view
|
#ifdef __cpp_lib_string_view
|
||||||
#define SIMDJSON_HAS_STRING_VIEW
|
#define SIMDJSON_HAS_STRING_VIEW
|
||||||
|
#include <string_view>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Some systems have string_view even if we do not have C++17 support,
|
// Some systems have string_view even if we do not have C++17 support,
|
||||||
// and even if __cpp_lib_string_view is undefined, it is the case
|
// and even if __cpp_lib_string_view is undefined, it is the case
|
||||||
// with Apple clang version 11.
|
// with Apple clang version 11.
|
||||||
// We must handle it. *This is important.*
|
// We must handle it. *This is important.*
|
||||||
|
#ifndef _MSC_VER
|
||||||
#ifndef SIMDJSON_HAS_STRING_VIEW
|
#ifndef SIMDJSON_HAS_STRING_VIEW
|
||||||
#if defined __has_include
|
#if defined __has_include
|
||||||
// do not combine the next #if with the previous one (unsafe)
|
// do not combine the next #if with the previous one (unsafe)
|
||||||
@@ -247,6 +249,7 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
#endif // __has_include (<string_view>)
|
#endif // __has_include (<string_view>)
|
||||||
#endif // defined __has_include
|
#endif // defined __has_include
|
||||||
#endif // def SIMDJSON_HAS_STRING_VIEW
|
#endif // def SIMDJSON_HAS_STRING_VIEW
|
||||||
|
#endif // def _MSC_VER
|
||||||
// end of complicated but important routine to try to detect string_view.
|
// end of complicated but important routine to try to detect string_view.
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -279,16 +282,25 @@ namespace std {
|
|||||||
// It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer
|
// It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer
|
||||||
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails to
|
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails to
|
||||||
// set the __OPTIMIZE__ macro).
|
// set the __OPTIMIZE__ macro).
|
||||||
|
// We make it so that if NDEBUG is defined, then SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
// is not defined, irrespective of the compiler.
|
||||||
|
// We recommend that users set NDEBUG in release builds, so that
|
||||||
|
// SIMDJSON_DEVELOPMENT_CHECKS is not defined in release builds by default,
|
||||||
|
// irrespective of the compiler.
|
||||||
#ifndef SIMDJSON_DEVELOPMENT_CHECKS
|
#ifndef SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// Visual Studio seems to set _DEBUG for debug builds.
|
// Visual Studio seems to set _DEBUG for debug builds.
|
||||||
#ifdef _DEBUG
|
// We set SIMDJSON_DEVELOPMENT_CHECKS to 1 if _DEBUG is defined
|
||||||
|
// and NDEBUG is not defined.
|
||||||
|
#if defined(_DEBUG) && !defined(NDEBUG)
|
||||||
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
// All other compilers appear to set __OPTIMIZE__ to a positive integer
|
// All other compilers appear to set __OPTIMIZE__ to a positive integer
|
||||||
// when the compiler is optimizing.
|
// when the compiler is optimizing.
|
||||||
#ifndef __OPTIMIZE__
|
// We only set SIMDJSON_DEVELOPMENT_CHECKS if both __OPTIMIZE__
|
||||||
|
// and NDEBUG are not defined.
|
||||||
|
#if !defined(__OPTIMIZE__) && !defined(NDEBUG)
|
||||||
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
||||||
#endif // __OPTIMIZE__
|
#endif // __OPTIMIZE__
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|||||||
@@ -32,14 +32,30 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
|||||||
#undef SIMDJSON_IMPL_CONCEPT
|
#undef SIMDJSON_IMPL_CONCEPT
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||||
|
!std::is_convertible_v<T, const char*>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
|
||||||
|
&& !std::is_same_v<T, std::string_view>
|
||||||
|
&& std::is_default_constructible_v<T>;
|
||||||
|
|
||||||
|
template<typename M>
|
||||||
|
concept string_view_keyed_map = string_view_like<typename M::key_type>
|
||||||
|
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
|
||||||
|
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
|
||||||
|
};
|
||||||
|
|
||||||
/// Check if T is a container that we can append to, including:
|
/// Check if T is a container that we can append to, including:
|
||||||
/// std::vector, std::deque, std::list, std::string, ...
|
/// std::vector, std::deque, std::list, std::string, ...
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept appendable_containers =
|
concept appendable_containers =
|
||||||
details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||||
details::supports_push_back<T> || details::supports_push<T> ||
|
details::supports_push_back<T> || details::supports_push<T> ||
|
||||||
details::supports_add<T> || details::supports_append<T> ||
|
details::supports_add<T> || details::supports_append<T> ||
|
||||||
details::supports_insert<T>;
|
details::supports_insert<T>) && !string_view_keyed_map<T>;
|
||||||
|
|
||||||
/// Insert into the container however possible
|
/// Insert into the container however possible
|
||||||
template <appendable_containers T, typename... Args>
|
template <appendable_containers T, typename... Args>
|
||||||
@@ -107,6 +123,8 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
|||||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace concepts
|
} // namespace concepts
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
iterator& operator=(const iterator&) noexcept = default;
|
iterator& operator=(const iterator&) noexcept = default;
|
||||||
private:
|
private:
|
||||||
simdjson_inline iterator(const internal::tape_ref &tape) noexcept;
|
simdjson_inline iterator(const internal::tape_ref &tape) noexcept;
|
||||||
internal::tape_ref tape;
|
internal::tape_ref tape{};
|
||||||
friend class array;
|
friend class array;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
simdjson_inline array(const internal::tape_ref &tape) noexcept;
|
simdjson_inline array(const internal::tape_ref &tape) noexcept;
|
||||||
internal::tape_ref tape;
|
internal::tape_ref tape{};
|
||||||
friend class element;
|
friend class element;
|
||||||
friend struct simdjson_result<element>;
|
friend struct simdjson_result<element>;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public:
|
|||||||
* The memory allocation is strict: you
|
* The memory allocation is strict: you
|
||||||
* can you use this function to increase
|
* can you use this function to increase
|
||||||
* or lower the amount of allocated memory.
|
* or lower the amount of allocated memory.
|
||||||
* Passsing zero clears the memory.
|
* Passing zero clears the memory.
|
||||||
*/
|
*/
|
||||||
error_code allocate(size_t len) noexcept;
|
error_code allocate(size_t len) noexcept;
|
||||||
/** @private Capacity in bytes, in terms
|
/** @private Capacity in bytes, in terms
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
simdjson_inline element(const internal::tape_ref &tape) noexcept;
|
simdjson_inline element(const internal::tape_ref &tape) noexcept;
|
||||||
internal::tape_ref tape;
|
internal::tape_ref tape{};
|
||||||
friend class document;
|
friend class document;
|
||||||
friend class object;
|
friend class object;
|
||||||
friend class array;
|
friend class array;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
simdjson_inline iterator(const internal::tape_ref &tape) noexcept;
|
simdjson_inline iterator(const internal::tape_ref &tape) noexcept;
|
||||||
|
|
||||||
internal::tape_ref tape;
|
internal::tape_ref tape{};
|
||||||
|
|
||||||
friend class object;
|
friend class object;
|
||||||
};
|
};
|
||||||
@@ -224,7 +224,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
simdjson_inline object(const internal::tape_ref &tape) noexcept;
|
simdjson_inline object(const internal::tape_ref &tape) noexcept;
|
||||||
|
|
||||||
internal::tape_ref tape;
|
internal::tape_ref tape{};
|
||||||
|
|
||||||
friend class element;
|
friend class element;
|
||||||
friend struct simdjson_result<element>;
|
friend struct simdjson_result<element>;
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ public:
|
|||||||
* arrays or objects) MUST be separated with whitespace.
|
* arrays or objects) MUST be separated with whitespace.
|
||||||
*
|
*
|
||||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||||
* performance.
|
* performance.
|
||||||
*
|
*
|
||||||
* ### Error Handling
|
* ### Error Handling
|
||||||
@@ -434,7 +434,7 @@ public:
|
|||||||
* arrays or objects) MUST be separated with whitespace.
|
* arrays or objects) MUST be separated with whitespace.
|
||||||
*
|
*
|
||||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||||
* performance.
|
* performance.
|
||||||
*
|
*
|
||||||
* ### Error Handling
|
* ### Error Handling
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
|
inline bool is_fatal(error_code error) noexcept {
|
||||||
|
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
// We store the error code so we can validate the error message is associated with the right code
|
// We store the error code so we can validate the error message is associated with the right code
|
||||||
struct error_code_info {
|
struct error_code_info {
|
||||||
@@ -127,6 +132,23 @@ simdjson_warn_unused simdjson_inline error_code simdjson_result<T>::get(T &value
|
|||||||
return std::forward<internal::simdjson_result_base<T>>(*this).get(value);
|
return std::forward<internal::simdjson_result_base<T>>(*this).get(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline error_code
|
||||||
|
simdjson_result<T>::get(std::string &value) && noexcept
|
||||||
|
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
requires (!std::is_same_v<T, std::string>)
|
||||||
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
{
|
||||||
|
// SFINAE : n'active que pour T = std::string_view
|
||||||
|
static_assert(std::is_same<T, std::string_view>::value, "simdjson_result<T>::get(std::string&) n'est disponible que pour T = std::string_view");
|
||||||
|
std::string_view v;
|
||||||
|
error_code error = std::forward<simdjson_result<T>>(*this).get(v);
|
||||||
|
if (!error) {
|
||||||
|
value.assign(v.data(), v.size());
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline error_code simdjson_result<T>::error() const noexcept {
|
simdjson_inline error_code simdjson_result<T>::error() const noexcept {
|
||||||
return internal::simdjson_result_base<T>::error();
|
return internal::simdjson_result_base<T>::error();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ enum error_code {
|
|||||||
SUCCESS = 0, ///< No error
|
SUCCESS = 0, ///< No error
|
||||||
CAPACITY, ///< This parser can't support a document that big
|
CAPACITY, ///< This parser can't support a document that big
|
||||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||||
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
|
||||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||||
STRING_ERROR, ///< Problem while parsing a string
|
STRING_ERROR, ///< Problem while parsing a string
|
||||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||||
@@ -45,13 +45,21 @@ enum error_code {
|
|||||||
PARSER_IN_USE, ///< parser is already in use.
|
PARSER_IN_USE, ///< parser is already in use.
|
||||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
|
||||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||||
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||||
NUM_ERROR_CODES
|
NUM_ERROR_CODES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some errors are fatal and invalidate the document. This function returns true if the
|
||||||
|
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
|
||||||
|
* Once a fatal error is encountered, the on-demand document is no longer valid and
|
||||||
|
* processing should stop.
|
||||||
|
*/
|
||||||
|
inline bool is_fatal(error_code error) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||||
@@ -188,6 +196,7 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
|||||||
* @throw simdjson_error if there was an error.
|
* @throw simdjson_error if there was an error.
|
||||||
*/
|
*/
|
||||||
simdjson_inline operator T&&() && noexcept(false);
|
simdjson_inline operator T&&() && noexcept(false);
|
||||||
|
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -244,7 +253,17 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
|||||||
* @param value The variable to assign the value to. May not be set if there is an error.
|
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
|
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
|
||||||
|
//
|
||||||
|
/**
|
||||||
|
* Copy the value to a provided std::string, only enabled for std::string_view.
|
||||||
|
*
|
||||||
|
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept
|
||||||
|
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
requires (!std::is_same_v<T, std::string>)
|
||||||
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
;
|
||||||
/**
|
/**
|
||||||
* The error.
|
* The error.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -647,7 +647,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -1108,6 +1117,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
|
|||||||
@@ -45,4 +45,8 @@
|
|||||||
#include "simdjson/generic/ondemand/token_iterator-inl.h"
|
#include "simdjson/generic/ondemand/token_iterator-inl.h"
|
||||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||||
|
|
||||||
|
// JSON builder, ideally they should not be part of the ondemand directory
|
||||||
|
// but it is convenient for now to have them here.
|
||||||
|
#include "simdjson/generic/ondemand/json_string_builder.h"
|
||||||
|
#include "simdjson/generic/ondemand/json_string_builder-inl.h"
|
||||||
|
|
||||||
|
|||||||
@@ -239,20 +239,27 @@ public:
|
|||||||
if constexpr (custom_deserializable<T, document>) {
|
if constexpr (custom_deserializable<T, document>) {
|
||||||
return deserialize(*this, out);
|
return deserialize(*this, out);
|
||||||
} else {
|
} else {
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
"And you do not seem to have added support for it. Indeed, we have that "
|
||||||
// immediately fail.
|
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
"int64_t, double, or bool.");
|
||||||
"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
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
|
||||||
}
|
}
|
||||||
#endif
|
#else // 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;
|
||||||
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
/** @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_deprecated simdjson_inline error_code get(T &out) && noexcept;
|
||||||
|
|
||||||
@@ -814,20 +821,27 @@ public:
|
|||||||
if constexpr (custom_deserializable<T, document_reference>) {
|
if constexpr (custom_deserializable<T, document_reference>) {
|
||||||
return deserialize(*this, out);
|
return deserialize(*this, out);
|
||||||
} else {
|
} else {
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
"And you do not seem to have added support for it. Indeed, we have that "
|
||||||
// immediately fail.
|
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
"int64_t, double, or bool.");
|
||||||
"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
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
|
||||||
}
|
}
|
||||||
#endif
|
#else // 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;
|
||||||
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the builder API. It is temporarily in the ondemand directory
|
||||||
|
* but we will move it to a builder directory later.
|
||||||
|
*/
|
||||||
|
#ifndef SIMDJSON_GENERIC_BUILDER_INL_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#define SIMDJSON_GENERIC_BUILDER_INL_H
|
||||||
|
#include "simdjson/generic/builder/json_string_builder.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace builder {
|
||||||
|
simdjson_inline string_builder::string_builder(size_t initial_capacity) :
|
||||||
|
buffer(new (std::nothrow) char[initial_capacity]),
|
||||||
|
position(0), capacity(buffer.get() != nullptr ? initial_capacity : 0),
|
||||||
|
is_valid(buffer.get() != nullptr) {}
|
||||||
|
/***
|
||||||
|
char *padded_buffer = new (std::nothrow) char[totalpaddedlength];
|
||||||
|
if (padded_buffer == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
simdjson_inline bool string_builder::capacity_check(size_t upcoming_bytes) {
|
||||||
|
if (upcoming_bytes <= capacity - position) { return true; }
|
||||||
|
// check for overflow:
|
||||||
|
if (position + upcoming_bytes < position) { return false; }
|
||||||
|
grow_buffer(std::max(capacity * 2, position + upcoming_bytes));
|
||||||
|
return is_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline void string_builder::grow_buffer(size_t desired_capacity) {
|
||||||
|
if (!is_valid) { return; }
|
||||||
|
std::unique_ptr<char[]> new_buffer(new (std::nothrow) char[desired_capacity]);
|
||||||
|
if (new_buffer.get() == nullptr) {
|
||||||
|
is_valid = false;
|
||||||
|
capacity = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(new_buffer.get(), buffer.get(), position);
|
||||||
|
buffer.swap(new_buffer);
|
||||||
|
capacity = desired_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_inline size_t string_builder::size() const {
|
||||||
|
return is_valid ? position : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace builder
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_GENERIC_BUILDER_INL_H
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of the builder API. It is temporarily in the ondemand directory
|
||||||
|
* but we will move it to a builder directory later.
|
||||||
|
*/
|
||||||
|
#ifndef SIMDJSON_GENERIC_BUILDER_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
#define SIMDJSON_GENERIC_BUILDER_H
|
||||||
|
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||||
|
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace builder {
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// TODO: at the end of the processing, possibly as an optional step, we should
|
||||||
|
// validate the UTF-8 of the string.
|
||||||
|
/////////////////////////
|
||||||
|
/**
|
||||||
|
* A builder for JSON strings representing documents. This is a low-level
|
||||||
|
* builder that is not meant to be used directly by end-users. Though it
|
||||||
|
* supports atomic types (Booleans, strings), it does not support composed
|
||||||
|
* types (arrays and objects).
|
||||||
|
*
|
||||||
|
* Ultimately, this class should support kernel-specific optimizations. E.g.,
|
||||||
|
* it may make use of SIMD instructions to escape strings faster.
|
||||||
|
*/
|
||||||
|
class string_builder {
|
||||||
|
public:
|
||||||
|
simdjson_inline string_builder(size_t initial_capacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append number (includes Booleans). Booleans are mapped to the strings
|
||||||
|
* false and true. Numbers are converted to strings abiding by the JSON standard.
|
||||||
|
* Floating-point numbers are converted to the shortest string that 'correctly'
|
||||||
|
* represents the number.
|
||||||
|
*/
|
||||||
|
template<typename number_type,
|
||||||
|
typename = typename std::enable_if<std::is_arithmetic<number_type>::value>::type>
|
||||||
|
simdjson_inline void append(number_type v) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append character c.
|
||||||
|
*/
|
||||||
|
simdjson_inline void append(char c) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the string 'null'.
|
||||||
|
*/
|
||||||
|
simdjson_inline void append_null() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the content.
|
||||||
|
*/
|
||||||
|
simdjson_inline void clear() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the std::string_view, after escaping it.
|
||||||
|
* There is no UTF-8 validation.
|
||||||
|
*/
|
||||||
|
simdjson_inline void escape_and_append(std::string_view input) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the std::string_view surrounded by double quotes, after escaping it.
|
||||||
|
* There is no UTF-8 validation.
|
||||||
|
*/
|
||||||
|
simdjson_inline void escape_and_append_with_quotes(std::string_view input) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the C string directly, without escaping.
|
||||||
|
* There is no UTF-8 validation.
|
||||||
|
*/
|
||||||
|
simdjson_inline void append_raw(const char *c) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the std::string_view directly, without escaping.
|
||||||
|
* There is no UTF-8 validation.
|
||||||
|
*/
|
||||||
|
simdjson_inline void append_raw(std::string_view str) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append len characters from str.
|
||||||
|
* There is no UTF-8 validation.
|
||||||
|
*/
|
||||||
|
simdjson_inline void append_raw(const char *str, size_t len) noexcept;
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
/**
|
||||||
|
* Creates an std::string from the written JSON buffer.
|
||||||
|
* Throws if memory allocation failed
|
||||||
|
*/
|
||||||
|
simdjson_inline operator std::string() const noexcept(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an std::string_view from the written JSON buffer.
|
||||||
|
* Throws if memory allocation failed
|
||||||
|
*/
|
||||||
|
simdjson_inline operator std::string_view() const noexcept(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view on the written JSON buffer. Returns an error
|
||||||
|
* if memory allocation failed.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_result<std::string_view> view() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the null character to the buffer and returns
|
||||||
|
* a pointer to the beginning of the written JSON buffer.
|
||||||
|
* Returns an error if memory allocation failed.
|
||||||
|
*/
|
||||||
|
simdjson_inline simdjson_result<const char *> c_str();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current size of the written JSON buffer.
|
||||||
|
* If an error occurred, returns 0.
|
||||||
|
*/
|
||||||
|
simdjson_inline size_t size() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Returns true if we can write at least upcoming_bytes bytes.
|
||||||
|
* The underlying buffer is reallocated if needed. It is designed
|
||||||
|
* to be called before writing to the buffer. It should be fast.
|
||||||
|
*/
|
||||||
|
simdjson_inline bool capacity_check(size_t upcoming_bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grow the buffer to at least desired_capacity bytes.
|
||||||
|
* If the allocation fails, is_valid is set to false. We expect
|
||||||
|
* that this function would not be repeatedly called.
|
||||||
|
*/
|
||||||
|
simdjson_inline void grow_buffer(size_t desired_capacity);
|
||||||
|
std::unique_ptr<char[]> buffer;
|
||||||
|
size_t position;
|
||||||
|
size_t capacity;
|
||||||
|
bool is_valid{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_GENERIC_BUILDER_H
|
||||||
@@ -55,6 +55,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <concepts::constructible_from_string_view T, typename ValT>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v<T, std::string_view>) {
|
||||||
|
std::string_view str;
|
||||||
|
SIMDJSON_TRY(val.get_string().get(str));
|
||||||
|
out = T{str};
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* STL containers have several constructors including one that takes a single
|
* STL containers have several constructors including one that takes a single
|
||||||
* size argument. Thus, some compilers (Visual Studio) will not be able to
|
* size argument. Thus, some compilers (Visual Studio) will not be able to
|
||||||
@@ -100,6 +110,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We want to support std::map and std::unordered_map but only for
|
||||||
|
* string-keyed types.
|
||||||
|
*/
|
||||||
|
template <concepts::string_view_keyed_map T, typename ValT>
|
||||||
|
requires(!require_custom_serialization<T>)
|
||||||
|
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||||
|
using value_type = typename std::remove_cvref_t<T>::mapped_type;
|
||||||
|
static_assert(
|
||||||
|
deserializable<value_type, ValT>,
|
||||||
|
"The specified value type inside the container must itself be deserializable");
|
||||||
|
static_assert(
|
||||||
|
std::is_default_constructible_v<value_type>,
|
||||||
|
"The specified value type inside the container must default constructible.");
|
||||||
|
SIMDJSON_IMPLEMENTATION::ondemand::object obj;
|
||||||
|
SIMDJSON_TRY(val.get_object().get(obj));
|
||||||
|
for (auto field : obj) {
|
||||||
|
std::string_view key;
|
||||||
|
SIMDJSON_TRY(field.unescaped_key().get(key));
|
||||||
|
value_type this_value;
|
||||||
|
SIMDJSON_TRY(field.value().get<value_type>().get(this_value));
|
||||||
|
[[maybe_unused]] std::pair<typename T::iterator, bool> result = out.emplace(key, this_value);
|
||||||
|
// unclear what to do if the key already exists
|
||||||
|
// if (result.second == false) {
|
||||||
|
// // key already exists
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
(void)out;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This CPO (Customization Point Object) will help deserialize into
|
* This CPO (Customization Point Object) will help deserialize into
|
||||||
|
|||||||
@@ -70,22 +70,28 @@ public:
|
|||||||
noexcept
|
noexcept
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
if constexpr (custom_deserializable<T, value>) {
|
if constexpr (custom_deserializable<T, value>) {
|
||||||
return deserialize(*this, out);
|
return deserialize(*this, out);
|
||||||
} else {
|
} else {
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
"And you do not seem to have added support for it. Indeed, we have that "
|
||||||
// immediately fail.
|
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
"int64_t, double, or bool.");
|
||||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
static_cast<void>(out); // to get rid of unused errors
|
||||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
return UNINITIALIZED;
|
||||||
" You may also add support for custom types, see our documentation.");
|
}
|
||||||
static_cast<void>(out); // to get rid of unused errors
|
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
return UNINITIALIZED;
|
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
// 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;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -778,19 +778,23 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_root_length();
|
auto max_len = peek_root_length();
|
||||||
auto json = peek_root_scalar("bool");
|
auto json = peek_root_scalar("bool");
|
||||||
uint8_t tmpbuf[5+1+1]; // +1 for null termination
|
// We have a boolean if we have either "true" or "false" and the next character is either
|
||||||
tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
|
// a structural character or whitespace. We also check that the length is correct:
|
||||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
|
// "true" and "false" are 4 and 5 characters long, respectively.
|
||||||
auto result = parse_bool(tmpbuf);
|
bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") &&
|
||||||
if(result.error() == SUCCESS) {
|
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
|
||||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") &&
|
||||||
advance_root_scalar("bool");
|
(max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5])));
|
||||||
}
|
if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); }
|
||||||
return result;
|
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||||
|
advance_root_scalar("bool");
|
||||||
|
return value_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
|
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
|
||||||
auto max_len = peek_root_length();
|
auto max_len = peek_root_length();
|
||||||
auto json = peek_root_scalar("null");
|
auto json = peek_root_scalar("null");
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @returns Whether the object had any fields (returns false for empty).
|
* @returns Whether the object had any fields (returns false for empty).
|
||||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||||
* array or object is incomplete).
|
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||||
|
* invalidates the document.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -135,7 +136,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @returns Whether the object had any fields (returns false for empty).
|
* @returns Whether the object had any fields (returns false for empty).
|
||||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||||
* array or object is incomplete).
|
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||||
|
* invalidates the document.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
|
||||||
|
|
||||||
@@ -257,7 +259,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @returns Whether the array had any elements (returns false for empty).
|
* @returns Whether the array had any elements (returns false for empty).
|
||||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||||
* array or object is incomplete).
|
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||||
|
* invalidates the document.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -267,7 +270,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @returns Whether the array had any elements (returns false for empty).
|
* @returns Whether the array had any elements (returns false for empty).
|
||||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||||
* array or object is incomplete).
|
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||||
|
* invalidates the document.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
|
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define SIMDJSON_JSONPATHUTIL_H
|
#define SIMDJSON_JSONPATHUTIL_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include "simdjson/common_defs.h"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ using std::size_t;
|
|||||||
#if defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG))
|
#if defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG))
|
||||||
// If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode,
|
// If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode,
|
||||||
// then do away with asserts and use __assume.
|
// then do away with asserts and use __assume.
|
||||||
|
// We still recommend that our users set NDEBUG in release mode.
|
||||||
#if SIMDJSON_VISUAL_STUDIO
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
#define SIMDJSON_UNREACHABLE() __assume(0)
|
#define SIMDJSON_UNREACHABLE() __assume(0)
|
||||||
#define SIMDJSON_ASSUME(COND) __assume(COND)
|
#define SIMDJSON_ASSUME(COND) __assume(COND)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||||
|
|
||||||
/** The version of simdjson being used (major.minor.revision) */
|
/** The version of simdjson being used (major.minor.revision) */
|
||||||
#define SIMDJSON_VERSION "3.12.2"
|
#define SIMDJSON_VERSION "3.13.0"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
@@ -15,11 +15,11 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_MINOR = 12,
|
SIMDJSON_VERSION_MINOR = 13,
|
||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 2
|
SIMDJSON_VERSION_REVISION = 0
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ if (Python3_Interpreter_FOUND AND (NOT WIN32))
|
|||||||
# file regeneration in the source directory without the user's knowledge.
|
# file regeneration in the source directory without the user's knowledge.
|
||||||
# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/simdjson.cpp ${CMAKE_CURRENT_SOURCE_DIR}/simdjson.h ${CMAKE_CURRENT_SOURCE_DIR}/amalgamate_demo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/README.md
|
# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/simdjson.cpp ${CMAKE_CURRENT_SOURCE_DIR}/simdjson.h ${CMAKE_CURRENT_SOURCE_DIR}/amalgamate_demo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/README.md
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${SINGLEHEADER_FILES} ${CMAKE_CURRENT_SOURCE_DIR}
|
COMMAND ${CMAKE_COMMAND} -E copy ${SINGLEHEADER_FILES} ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
DEPENDS ${SINGLEHEADER_FILES}
|
POST_BUILD ${SINGLEHEADER_FILES}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
+63
-16
@@ -10,12 +10,41 @@ import os
|
|||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import datetime
|
import datetime
|
||||||
|
import json
|
||||||
from typing import Dict, List, Optional, Set, TextIO, Union, cast
|
from typing import Dict, List, Optional, Set, TextIO, Union, cast
|
||||||
|
|
||||||
|
# Check for Python 3, this does not actually work.
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
sys.stdout.write("Sorry, requires Python 3.x or better\n")
|
sys.stdout.write("Sorry, requires Python 3.x or better\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
rules = """
|
||||||
|
|
||||||
|
We refer your to the HACKING.md file for more information on how the project is organized.
|
||||||
|
|
||||||
|
To help understand the error, here are the rules for including files in simdjson:
|
||||||
|
|
||||||
|
All implementation-specific files, including arm64.h, arm64/implementation.h and
|
||||||
|
arm64/ondemand.h, must be within SIMDJSON_CONDITIONAL_INCLUDE blocks.
|
||||||
|
|
||||||
|
Top-level headers must not be included in any SIMDJSON_CONDITIONAL_INCLUDE block.
|
||||||
|
|
||||||
|
Generic files must be included only in amalgamator files (arm64.h,
|
||||||
|
arm64/implementation.h, arm64/ondemand.h, generic/amalgamated.h).
|
||||||
|
|
||||||
|
We fail if an implementation-specific file is included more than once in the same block.
|
||||||
|
We fail if a generic file is included more than once per implementation in the same block.
|
||||||
|
|
||||||
|
|
||||||
|
Tip: generally, "file" will search the including file's source directory first, then
|
||||||
|
the search paths while <file> does it the other way around.
|
||||||
|
We prefer to use <> in simdjson headers to avoid accidentally including a file from the
|
||||||
|
wrong directory.
|
||||||
|
|
||||||
|
The amalgamate.py script checks that all files are included.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
SCRIPTPATH = os.path.dirname(os.path.abspath(sys.argv[0]))
|
SCRIPTPATH = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||||
PROJECTPATH = os.path.dirname(SCRIPTPATH)
|
PROJECTPATH = os.path.dirname(SCRIPTPATH)
|
||||||
print(f"SCRIPTPATH={SCRIPTPATH} PROJECTPATH={PROJECTPATH}")
|
print(f"SCRIPTPATH={SCRIPTPATH} PROJECTPATH={PROJECTPATH}")
|
||||||
@@ -62,6 +91,22 @@ class SimdjsonFile:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.include_path
|
return self.include_path
|
||||||
|
|
||||||
|
def dump(self):
|
||||||
|
return {
|
||||||
|
'root': self.root,
|
||||||
|
'include_path': self.include_path,
|
||||||
|
'includes': [include.include_path for include in self.includes],
|
||||||
|
'included_from': [included_from.include_path for included_from in self.included_from],
|
||||||
|
'editor_only_includes': [editor_only_include.include_path for editor_only_include in self.editor_only_includes],
|
||||||
|
'editor_only_included_from': [editor_only_included_from.include_path for editor_only_included_from in self.editor_only_included_from],
|
||||||
|
'processed': self.processed,
|
||||||
|
'dependency_file': self.dependency_file.include_path if self.dependency_file else None,
|
||||||
|
'is_amalgamator': self.is_amalgamator,
|
||||||
|
'implementation': self.implementation,
|
||||||
|
}
|
||||||
|
def json(self):
|
||||||
|
return json.dumps(self.dump(), indent=4, sort_keys=True, ensure_ascii=False)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.include_path
|
return self.include_path
|
||||||
|
|
||||||
@@ -162,20 +207,21 @@ class SimdjsonFile:
|
|||||||
|
|
||||||
def add_include(self, include: 'SimdjsonFile'):
|
def add_include(self, include: 'SimdjsonFile'):
|
||||||
if self.is_conditional_include:
|
if self.is_conditional_include:
|
||||||
assert include.is_conditional_include, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE."
|
# If I have a dependency file, I can only include something that has a dependency file.
|
||||||
|
assert include.is_conditional_include, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE. {rules}"
|
||||||
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
||||||
# if include.amalgamator_file:
|
# if include.amalgamator_file:
|
||||||
# assert include.amalgamator_file == self, f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
# assert include.amalgamator_file == self, f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
||||||
else:
|
else:
|
||||||
assert include.is_amalgamator or not include.is_conditional_include, f"{self} cannot include {include} because it is an amalgamated file."
|
assert include.is_amalgamator or not include.is_conditional_include, f"{self} cannot include {include} because it is an amalgamated file. {rules}"
|
||||||
|
|
||||||
self.includes.append(include)
|
self.includes.append(include)
|
||||||
include.included_from.add(self)
|
include.included_from.add(self)
|
||||||
|
|
||||||
def add_editor_only_include(self, include: 'SimdjsonFile'):
|
def add_editor_only_include(self, include: 'SimdjsonFile'):
|
||||||
assert self.is_conditional_include, f"Cannot use #ifndef SIMDJSON_CONDITIONAL_INCLUDE in {self} because it is not an amalgamated file."
|
assert self.is_conditional_include, f"Cannot use #ifndef SIMDJSON_CONDITIONAL_INCLUDE in {self} because it is not an amalgamated file. {rules}"
|
||||||
if not include.is_conditional_include:
|
if not include.is_conditional_include:
|
||||||
assert self.dependency_file, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE."
|
assert self.dependency_file, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE. {rules}"
|
||||||
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
||||||
# elif include.amalgamator_file:
|
# elif include.amalgamator_file:
|
||||||
# assert self.is_amalgamated_before(self.amalgamator_file), f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
# assert self.is_amalgamated_before(self.amalgamator_file), f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
||||||
@@ -190,11 +236,11 @@ class SimdjsonFile:
|
|||||||
if file.dependency_file == self:
|
if file.dependency_file == self:
|
||||||
for editor_only_include in file.editor_only_includes:
|
for editor_only_include in file.editor_only_includes:
|
||||||
if not editor_only_include.is_conditional_include:
|
if not editor_only_include.is_conditional_include:
|
||||||
assert editor_only_include in self.includes, f"{file} includes {editor_only_include}, but it is not included from {self}. It must be added to {self}."
|
assert editor_only_include in self.includes, f"{file} includes {editor_only_include}, but it is not included from {self}. It must be added to {self}. {rules}"
|
||||||
if editor_only_include in extra_include_set:
|
if editor_only_include in extra_include_set:
|
||||||
extra_include_set.remove(editor_only_include)
|
extra_include_set.remove(editor_only_include)
|
||||||
|
|
||||||
assert len(extra_include_set) == 0, f"{self} unnecessarily includes {extra_include_set}. They are not included in the corresponding amalgamated files."
|
assert len(extra_include_set) == 0, f"{self} unnecessarily includes {extra_include_set}. They are not included in the corresponding amalgamated files. {rules}"
|
||||||
|
|
||||||
class SimdjsonRepository:
|
class SimdjsonRepository:
|
||||||
def __init__(self, project_path: str, relative_roots: List[RelativeRoot]):
|
def __init__(self, project_path: str, relative_roots: List[RelativeRoot]):
|
||||||
@@ -320,6 +366,7 @@ class Amalgamator:
|
|||||||
|
|
||||||
assert not self.editor_only_region
|
assert not self.editor_only_region
|
||||||
with open(file.absolute_path, 'r') as fid2:
|
with open(file.absolute_path, 'r') as fid2:
|
||||||
|
print(f"including: {file}")
|
||||||
for line in fid2:
|
for line in fid2:
|
||||||
line = line.rstrip('\n')
|
line = line.rstrip('\n')
|
||||||
|
|
||||||
@@ -329,9 +376,9 @@ class Amalgamator:
|
|||||||
|
|
||||||
# Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
# Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
|
if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
|
||||||
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file!"
|
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file! {rules}"
|
||||||
assert self.in_conditional_include_block, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE without a prior #define SIMDJSON_CONDITIONAL_INCLUDE: {self.include_stack}"
|
assert self.in_conditional_include_block, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE without a prior #define SIMDJSON_CONDITIONAL_INCLUDE: {self.include_stack} {rules}"
|
||||||
assert not self.editor_only_region, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE twice in a row"
|
assert not self.editor_only_region, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE twice in a row {rules}"
|
||||||
self.editor_only_region = True
|
self.editor_only_region = True
|
||||||
|
|
||||||
# Handle ignored lines (and ending ignore blocks)
|
# Handle ignored lines (and ending ignore blocks)
|
||||||
@@ -349,7 +396,7 @@ class Amalgamator:
|
|||||||
self.editor_only_region = False
|
self.editor_only_region = False
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert not end_ignore, f"{file} has #endif // SIMDJSON_CONDITIONAL_INCLUDE without #ifndef SIMDJSON_CONDITIONAL_INCLUDE"
|
assert not end_ignore, f"{file} has #endif // SIMDJSON_CONDITIONAL_INCLUDE without #ifndef SIMDJSON_CONDITIONAL_INCLUDE {rules}"
|
||||||
|
|
||||||
# Handle #include lines
|
# Handle #include lines
|
||||||
included = re.search(r'^#include\s+["<]([^">]*)[">]', line)
|
included = re.search(r'^#include\s+["<]([^">]*)[">]', line)
|
||||||
@@ -376,26 +423,26 @@ class Amalgamator:
|
|||||||
self.implementation = None
|
self.implementation = None
|
||||||
elif re.search(r'\bSIMDJSON_IMPLEMENTATION\b', line) and file.include_path != IMPLEMENTATION_DETECTION_H:
|
elif re.search(r'\bSIMDJSON_IMPLEMENTATION\b', line) and file.include_path != IMPLEMENTATION_DETECTION_H:
|
||||||
# copy the line, with SIMDJSON_IMPLEMENTATION replace to what it is currently defined to
|
# copy the line, with SIMDJSON_IMPLEMENTATION replace to what it is currently defined to
|
||||||
assert self.implementation, f"Use of SIMDJSON_IMPLEMENTATION while not defined in {file}: {line}"
|
assert self.implementation, f"Use of SIMDJSON_IMPLEMENTATION while not defined in {file}: {line}\n{rules}"
|
||||||
line = re.sub(r'\bSIMDJSON_IMPLEMENTATION\b',self.implementation,line)
|
line = re.sub(r'\bSIMDJSON_IMPLEMENTATION\b',self.implementation,line)
|
||||||
|
|
||||||
# Handle defining and undefining SIMDJSON_CONDITIONAL_INCLUDE
|
# Handle defining and undefining SIMDJSON_CONDITIONAL_INCLUDE
|
||||||
defined = re.search(r'^#define\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line)
|
defined = re.search(r'^#define\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line)
|
||||||
if defined:
|
if defined:
|
||||||
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE defined in amalgamated file {file}! Not allowed."
|
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE defined in amalgamated file {file}! Not allowed. {rules}"
|
||||||
assert not self.in_conditional_include_block, f"{file} redefines SIMDJSON_CONDITIONAL_INCLUDE"
|
assert not self.in_conditional_include_block, f"{file} redefines SIMDJSON_CONDITIONAL_INCLUDE {rules}"
|
||||||
self.in_conditional_include_block = True
|
self.in_conditional_include_block = True
|
||||||
self.found_includes_per_conditional_block.clear()
|
self.found_includes_per_conditional_block.clear()
|
||||||
self.write(f'/* defining SIMDJSON_CONDITIONAL_INCLUDE */')
|
self.write(f'/* defining SIMDJSON_CONDITIONAL_INCLUDE */')
|
||||||
elif re.search(r'^#undef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
|
elif re.search(r'^#undef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
|
||||||
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE undefined in amalgamated file {file}! Not allowed."
|
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE undefined in amalgamated file {file}! Not allowed. {rules}"
|
||||||
assert self.in_conditional_include_block, f"{file} undefines SIMDJSON_CONDITIONAL_INCLUDE without defining it"
|
assert self.in_conditional_include_block, f"{file} undefines SIMDJSON_CONDITIONAL_INCLUDE without defining it {rules}"
|
||||||
self.write(f'/* undefining SIMDJSON_CONDITIONAL_INCLUDE */')
|
self.write(f'/* undefining SIMDJSON_CONDITIONAL_INCLUDE */')
|
||||||
self.in_conditional_include_block = False
|
self.in_conditional_include_block = False
|
||||||
|
|
||||||
self.write(line)
|
self.write(line)
|
||||||
|
|
||||||
assert not self.editor_only_region, f"{file} ended without #endif // SIMDJSON_CONDITIONAL_INCLUDE"
|
assert not self.editor_only_region, f"{file} ended without #endif // SIMDJSON_CONDITIONAL_INCLUDE {rules}"
|
||||||
|
|
||||||
self.write(f"/* end file {self.file_to_str(file)} */")
|
self.write(f"/* end file {self.file_to_str(file)} */")
|
||||||
|
|
||||||
|
|||||||
+220
-28
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
|
/* auto-generated on 2025-07-14 11:45:25 -0400. Do not edit! */
|
||||||
/* including simdjson.cpp: */
|
/* including simdjson.cpp: */
|
||||||
/* begin file simdjson.cpp */
|
/* begin file simdjson.cpp */
|
||||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||||
@@ -298,6 +298,7 @@ using std::size_t;
|
|||||||
#if defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG))
|
#if defined(NDEBUG) || defined(__OPTIMIZE__) || (defined(_MSC_VER) && !defined(_DEBUG))
|
||||||
// If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode,
|
// If NDEBUG is set, or __OPTIMIZE__ is set, or we are under MSVC in release mode,
|
||||||
// then do away with asserts and use __assume.
|
// then do away with asserts and use __assume.
|
||||||
|
// We still recommend that our users set NDEBUG in release mode.
|
||||||
#if SIMDJSON_VISUAL_STUDIO
|
#if SIMDJSON_VISUAL_STUDIO
|
||||||
#define SIMDJSON_UNREACHABLE() __assume(0)
|
#define SIMDJSON_UNREACHABLE() __assume(0)
|
||||||
#define SIMDJSON_ASSUME(COND) __assume(COND)
|
#define SIMDJSON_ASSUME(COND) __assume(COND)
|
||||||
@@ -373,7 +374,7 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SIMDJSON_EXCEPTIONS
|
#ifndef SIMDJSON_EXCEPTIONS
|
||||||
#if __cpp_exceptions
|
#if defined(__cpp_exceptions) || defined(_CPPUNWIND)
|
||||||
#define SIMDJSON_EXCEPTIONS 1
|
#define SIMDJSON_EXCEPTIONS 1
|
||||||
#else
|
#else
|
||||||
#define SIMDJSON_EXCEPTIONS 0
|
#define SIMDJSON_EXCEPTIONS 0
|
||||||
@@ -576,12 +577,14 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
// even if we do not have C++17 support.
|
// even if we do not have C++17 support.
|
||||||
#ifdef __cpp_lib_string_view
|
#ifdef __cpp_lib_string_view
|
||||||
#define SIMDJSON_HAS_STRING_VIEW
|
#define SIMDJSON_HAS_STRING_VIEW
|
||||||
|
#include <string_view>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Some systems have string_view even if we do not have C++17 support,
|
// Some systems have string_view even if we do not have C++17 support,
|
||||||
// and even if __cpp_lib_string_view is undefined, it is the case
|
// and even if __cpp_lib_string_view is undefined, it is the case
|
||||||
// with Apple clang version 11.
|
// with Apple clang version 11.
|
||||||
// We must handle it. *This is important.*
|
// We must handle it. *This is important.*
|
||||||
|
#ifndef _MSC_VER
|
||||||
#ifndef SIMDJSON_HAS_STRING_VIEW
|
#ifndef SIMDJSON_HAS_STRING_VIEW
|
||||||
#if defined __has_include
|
#if defined __has_include
|
||||||
// do not combine the next #if with the previous one (unsafe)
|
// do not combine the next #if with the previous one (unsafe)
|
||||||
@@ -597,6 +600,7 @@ double from_chars(const char *first, const char* end) noexcept;
|
|||||||
#endif // __has_include (<string_view>)
|
#endif // __has_include (<string_view>)
|
||||||
#endif // defined __has_include
|
#endif // defined __has_include
|
||||||
#endif // def SIMDJSON_HAS_STRING_VIEW
|
#endif // def SIMDJSON_HAS_STRING_VIEW
|
||||||
|
#endif // def _MSC_VER
|
||||||
// end of complicated but important routine to try to detect string_view.
|
// end of complicated but important routine to try to detect string_view.
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -2339,16 +2343,25 @@ namespace std {
|
|||||||
// It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer
|
// It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer
|
||||||
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails to
|
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails to
|
||||||
// set the __OPTIMIZE__ macro).
|
// set the __OPTIMIZE__ macro).
|
||||||
|
// We make it so that if NDEBUG is defined, then SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
|
// is not defined, irrespective of the compiler.
|
||||||
|
// We recommend that users set NDEBUG in release builds, so that
|
||||||
|
// SIMDJSON_DEVELOPMENT_CHECKS is not defined in release builds by default,
|
||||||
|
// irrespective of the compiler.
|
||||||
#ifndef SIMDJSON_DEVELOPMENT_CHECKS
|
#ifndef SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// Visual Studio seems to set _DEBUG for debug builds.
|
// Visual Studio seems to set _DEBUG for debug builds.
|
||||||
#ifdef _DEBUG
|
// We set SIMDJSON_DEVELOPMENT_CHECKS to 1 if _DEBUG is defined
|
||||||
|
// and NDEBUG is not defined.
|
||||||
|
#if defined(_DEBUG) && !defined(NDEBUG)
|
||||||
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
// All other compilers appear to set __OPTIMIZE__ to a positive integer
|
// All other compilers appear to set __OPTIMIZE__ to a positive integer
|
||||||
// when the compiler is optimizing.
|
// when the compiler is optimizing.
|
||||||
#ifndef __OPTIMIZE__
|
// We only set SIMDJSON_DEVELOPMENT_CHECKS if both __OPTIMIZE__
|
||||||
|
// and NDEBUG are not defined.
|
||||||
|
#if !defined(__OPTIMIZE__) && !defined(NDEBUG)
|
||||||
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
#define SIMDJSON_DEVELOPMENT_CHECKS 1
|
||||||
#endif // __OPTIMIZE__
|
#endif // __OPTIMIZE__
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
@@ -2431,7 +2444,7 @@ enum error_code {
|
|||||||
SUCCESS = 0, ///< No error
|
SUCCESS = 0, ///< No error
|
||||||
CAPACITY, ///< This parser can't support a document that big
|
CAPACITY, ///< This parser can't support a document that big
|
||||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||||
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
|
||||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||||
STRING_ERROR, ///< Problem while parsing a string
|
STRING_ERROR, ///< Problem while parsing a string
|
||||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||||
@@ -2456,13 +2469,21 @@ enum error_code {
|
|||||||
PARSER_IN_USE, ///< parser is already in use.
|
PARSER_IN_USE, ///< parser is already in use.
|
||||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
|
||||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||||
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||||
NUM_ERROR_CODES
|
NUM_ERROR_CODES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some errors are fatal and invalidate the document. This function returns true if the
|
||||||
|
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
|
||||||
|
* Once a fatal error is encountered, the on-demand document is no longer valid and
|
||||||
|
* processing should stop.
|
||||||
|
*/
|
||||||
|
inline bool is_fatal(error_code error) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||||
@@ -2599,6 +2620,7 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
|||||||
* @throw simdjson_error if there was an error.
|
* @throw simdjson_error if there was an error.
|
||||||
*/
|
*/
|
||||||
simdjson_inline operator T&&() && noexcept(false);
|
simdjson_inline operator T&&() && noexcept(false);
|
||||||
|
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2655,7 +2677,17 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
|||||||
* @param value The variable to assign the value to. May not be set if there is an error.
|
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
|
simdjson_warn_unused simdjson_inline error_code get(T &value) && noexcept;
|
||||||
|
//
|
||||||
|
/**
|
||||||
|
* Copy the value to a provided std::string, only enabled for std::string_view.
|
||||||
|
*
|
||||||
|
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_inline error_code get(std::string &value) && noexcept
|
||||||
|
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
requires (!std::is_same_v<T, std::string>)
|
||||||
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
;
|
||||||
/**
|
/**
|
||||||
* The error.
|
* The error.
|
||||||
*/
|
*/
|
||||||
@@ -2765,14 +2797,30 @@ SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
|||||||
#undef SIMDJSON_IMPL_CONCEPT
|
#undef SIMDJSON_IMPL_CONCEPT
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||||
|
!std::is_convertible_v<T, const char*>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
|
||||||
|
&& !std::is_same_v<T, std::string_view>
|
||||||
|
&& std::is_default_constructible_v<T>;
|
||||||
|
|
||||||
|
template<typename M>
|
||||||
|
concept string_view_keyed_map = string_view_like<typename M::key_type>
|
||||||
|
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
|
||||||
|
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
|
||||||
|
};
|
||||||
|
|
||||||
/// Check if T is a container that we can append to, including:
|
/// Check if T is a container that we can append to, including:
|
||||||
/// std::vector, std::deque, std::list, std::string, ...
|
/// std::vector, std::deque, std::list, std::string, ...
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept appendable_containers =
|
concept appendable_containers =
|
||||||
details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||||
details::supports_push_back<T> || details::supports_push<T> ||
|
details::supports_push_back<T> || details::supports_push<T> ||
|
||||||
details::supports_add<T> || details::supports_append<T> ||
|
details::supports_add<T> || details::supports_append<T> ||
|
||||||
details::supports_insert<T>;
|
details::supports_insert<T>) && !string_view_keyed_map<T>;
|
||||||
|
|
||||||
/// Insert into the container however possible
|
/// Insert into the container however possible
|
||||||
template <appendable_containers T, typename... Args>
|
template <appendable_containers T, typename... Args>
|
||||||
@@ -2840,6 +2888,8 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
|||||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace concepts
|
} // namespace concepts
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
@@ -4511,6 +4561,11 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint32_t digit_to_val32[886];
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
|
|
||||||
|
inline bool is_fatal(error_code error) noexcept {
|
||||||
|
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
// We store the error code so we can validate the error message is associated with the right code
|
// We store the error code so we can validate the error message is associated with the right code
|
||||||
struct error_code_info {
|
struct error_code_info {
|
||||||
@@ -4632,6 +4687,23 @@ simdjson_warn_unused simdjson_inline error_code simdjson_result<T>::get(T &value
|
|||||||
return std::forward<internal::simdjson_result_base<T>>(*this).get(value);
|
return std::forward<internal::simdjson_result_base<T>>(*this).get(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
simdjson_warn_unused simdjson_inline error_code
|
||||||
|
simdjson_result<T>::get(std::string &value) && noexcept
|
||||||
|
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
requires (!std::is_same_v<T, std::string>)
|
||||||
|
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||||
|
{
|
||||||
|
// SFINAE : n'active que pour T = std::string_view
|
||||||
|
static_assert(std::is_same<T, std::string_view>::value, "simdjson_result<T>::get(std::string&) n'est disponible que pour T = std::string_view");
|
||||||
|
std::string_view v;
|
||||||
|
error_code error = std::forward<simdjson_result<T>>(*this).get(v);
|
||||||
|
if (!error) {
|
||||||
|
value.assign(v.data(), v.size());
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline error_code simdjson_result<T>::error() const noexcept {
|
simdjson_inline error_code simdjson_result<T>::error() const noexcept {
|
||||||
return internal::simdjson_result_base<T>::error();
|
return internal::simdjson_result_base<T>::error();
|
||||||
@@ -4696,7 +4768,7 @@ namespace internal {
|
|||||||
{ SUCCESS, "SUCCESS: No error" },
|
{ SUCCESS, "SUCCESS: No error" },
|
||||||
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
||||||
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
||||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
|
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
|
||||||
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
||||||
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
||||||
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
||||||
@@ -4721,7 +4793,7 @@ namespace internal {
|
|||||||
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
||||||
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
||||||
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
|
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
|
||||||
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||||
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
||||||
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
||||||
@@ -6787,7 +6859,7 @@ public:
|
|||||||
* The memory allocation is strict: you
|
* The memory allocation is strict: you
|
||||||
* can you use this function to increase
|
* can you use this function to increase
|
||||||
* or lower the amount of allocated memory.
|
* or lower the amount of allocated memory.
|
||||||
* Passsing zero clears the memory.
|
* Passing zero clears the memory.
|
||||||
*/
|
*/
|
||||||
error_code allocate(size_t len) noexcept;
|
error_code allocate(size_t len) noexcept;
|
||||||
/** @private Capacity in bytes, in terms
|
/** @private Capacity in bytes, in terms
|
||||||
@@ -9185,7 +9257,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -9695,7 +9767,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -10156,6 +10237,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -15545,7 +15632,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -16055,7 +16142,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -16516,6 +16612,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -21769,7 +21871,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -22279,7 +22381,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -22740,6 +22851,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -28149,7 +28266,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -28659,7 +28776,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -29120,6 +29246,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -34891,7 +35023,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -35401,7 +35533,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -35862,6 +36003,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -41457,7 +41604,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -41967,7 +42114,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -42428,6 +42584,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -47468,7 +47630,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -47978,7 +48140,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -48439,6 +48610,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
@@ -53078,7 +53255,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
|||||||
// floor(log(5**power)/log(2))
|
// floor(log(5**power)/log(2))
|
||||||
//
|
//
|
||||||
// Note that this is not magic: 152170/(1<<16) is
|
// Note that this is not magic: 152170/(1<<16) is
|
||||||
// approximatively equal to log(5)/log(2).
|
// approximately equal to log(5)/log(2).
|
||||||
// The 1<<16 value is a power of two; we could use a
|
// The 1<<16 value is a power of two; we could use a
|
||||||
// larger power of 2 if we wanted to.
|
// larger power of 2 if we wanted to.
|
||||||
//
|
//
|
||||||
@@ -53588,7 +53765,16 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
|
|||||||
if (i > uint64_t(INT64_MAX)) {
|
if (i > uint64_t(INT64_MAX)) {
|
||||||
WRITE_UNSIGNED(i, src, writer);
|
WRITE_UNSIGNED(i, src, writer);
|
||||||
} else {
|
} else {
|
||||||
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(i == 0 && negative) {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
WRITE_DOUBLE(-0.0, src, writer);
|
||||||
|
} else {
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -54049,6 +54235,12 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
|
|||||||
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
if (simdjson_unlikely(digit_count == 19 && memcmp(src, smaller_big_integer, 19) > 0)) {
|
||||||
return number_type::big_integer;
|
return number_type::big_integer;
|
||||||
}
|
}
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
if(digit_count == 1 && src[0] == '0') {
|
||||||
|
// We have to write -0.0 instead of 0
|
||||||
|
return number_type::floating_point_number;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return number_type::signed_integer;
|
return number_type::signed_integer;
|
||||||
}
|
}
|
||||||
// Let us check if we have a big integer (>=2**64).
|
// Let us check if we have a big integer (>=2**64).
|
||||||
|
|||||||
+2845
-421
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ namespace internal {
|
|||||||
{ SUCCESS, "SUCCESS: No error" },
|
{ SUCCESS, "SUCCESS: No error" },
|
||||||
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
||||||
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
||||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
|
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
|
||||||
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
||||||
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
||||||
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
||||||
@@ -36,7 +36,7 @@ namespace internal {
|
|||||||
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
||||||
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
||||||
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
|
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
|
||||||
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||||
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
||||||
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ add_cpp_test(minify_tests LABELS other acceptance per_implementation)
|
|||||||
add_cpp_test(padded_string_tests LABELS other acceptance )
|
add_cpp_test(padded_string_tests LABELS other acceptance )
|
||||||
add_cpp_test(prettify_tests LABELS other acceptance per_implementation)
|
add_cpp_test(prettify_tests LABELS other acceptance per_implementation)
|
||||||
|
|
||||||
if(MSVC AND BUILD_SHARED_LIBS)
|
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||||
# Copy the simdjson dll into the tests directory
|
# Copy the simdjson dll into the tests directory
|
||||||
add_custom_command(TARGET unicode_tests POST_BUILD # Adds a post-build event
|
add_custom_command(TARGET unicode_tests POST_BUILD # Adds a post-build event
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
||||||
|
|||||||
@@ -113,8 +113,25 @@ if(NOT (MSVC AND MSVC_VERSION LESS 1920))
|
|||||||
target_compile_definitions(readme_examples_will_fail_with_exceptions_off PRIVATE SIMDJSON_EXCEPTIONS=0)
|
target_compile_definitions(readme_examples_will_fail_with_exceptions_off PRIVATE SIMDJSON_EXCEPTIONS=0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test C++20 features
|
||||||
|
#
|
||||||
|
|
||||||
if(MSVC AND BUILD_SHARED_LIBS)
|
# Add the tests if we're on:
|
||||||
|
# 1. Visual Studio 2022 v17.6 or later
|
||||||
|
# 2. GCC v14.0.0 or later (GCC v13.0.0 cannot handle pipe oprator of lambda)
|
||||||
|
# 3. Clang v15.0.0 or later (certain version C++ headers occur error when compiling)
|
||||||
|
if(
|
||||||
|
(MSVC AND MSVC_VERSION LESS 1930) OR
|
||||||
|
(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "14.0.0") OR
|
||||||
|
(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0.0")
|
||||||
|
)
|
||||||
|
message(STATUS "compiler id: ${CMAKE_CXX_COMPILER_ID} version: ${CMAKE_CXX_COMPILER_VERSION}")
|
||||||
|
add_cpp_test(ranges_test LABELS dom acceptance per_implementation)
|
||||||
|
set_target_properties(ranges_test PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||||
add_custom_command(TARGET basictests POST_BUILD # Adds a post-build event
|
add_custom_command(TARGET basictests POST_BUILD # Adds a post-build event
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
||||||
"$<TARGET_FILE:simdjson>" # <--this is in-file
|
"$<TARGET_FILE:simdjson>" # <--this is in-file
|
||||||
@@ -135,4 +152,4 @@ if(NOT MSVC)
|
|||||||
if(NOT ${REPORTED_SIMDJSON_VERSION} STREQUAL ${SIMDJSON_LIB_VERSION})
|
if(NOT ${REPORTED_SIMDJSON_VERSION} STREQUAL ${SIMDJSON_LIB_VERSION})
|
||||||
message(FATAL_ERROR "The library target does not have the proper version information." )
|
message(FATAL_ERROR "The library target does not have the proper version information." )
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
|||||||
|
|
||||||
#include "gason.h"
|
#include "gason.h"
|
||||||
|
|
||||||
#include "json11.hpp"
|
|
||||||
|
|
||||||
#include "rapidjson/document.h"
|
#include "rapidjson/document.h"
|
||||||
#include "rapidjson/reader.h" // you have to check in the submodule
|
#include "rapidjson/reader.h" // you have to check in the submodule
|
||||||
#include "rapidjson/stringbuffer.h"
|
#include "rapidjson/stringbuffer.h"
|
||||||
@@ -122,10 +120,6 @@ int main(int argc, char *argv[]) {
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
bool rapid_correct = (d.Parse((const char *)buffer).HasParseError() == false);
|
bool rapid_correct = (d.Parse((const char *)buffer).HasParseError() == false);
|
||||||
|
|
||||||
std::string json11err;
|
|
||||||
bool dropbox_correct = ((json11::Json::parse(buffer, json11err).is_null()) ||
|
|
||||||
(!json11err.empty())) == false;
|
|
||||||
bool fastjson_correct = fastjson_parse(buffer);
|
bool fastjson_correct = fastjson_parse(buffer);
|
||||||
JsonValue value;
|
JsonValue value;
|
||||||
JsonAllocator allocator;
|
JsonAllocator allocator;
|
||||||
@@ -174,8 +168,6 @@ int main(int argc, char *argv[]) {
|
|||||||
rapid_correct_checkencoding ? "correct" : "invalid");
|
rapid_correct_checkencoding ? "correct" : "invalid");
|
||||||
printf("sajson : %s \n",
|
printf("sajson : %s \n",
|
||||||
sajson_correct ? "correct" : "invalid");
|
sajson_correct ? "correct" : "invalid");
|
||||||
printf("dropbox : %s \n",
|
|
||||||
dropbox_correct ? "correct" : "invalid");
|
|
||||||
printf("fastjson : %s \n",
|
printf("fastjson : %s \n",
|
||||||
fastjson_correct ? "correct" : "invalid");
|
fastjson_correct ? "correct" : "invalid");
|
||||||
printf("gason : %s \n",
|
printf("gason : %s \n",
|
||||||
|
|||||||
@@ -399,7 +399,11 @@ namespace number_tests {
|
|||||||
|
|
||||||
bool specific_tests() {
|
bool specific_tests() {
|
||||||
std::cout << __func__ << std::endl;
|
std::cout << __func__ << std::endl;
|
||||||
return basic_test_64bit("-1e-999", -0.0) &&
|
return
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
basic_test_64bit("-0", -0.0) &&
|
||||||
|
#endif // SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
basic_test_64bit("-1e-999", -0.0) &&
|
||||||
basic_test_64bit("-2402844368454405395.2",-2402844368454405395.2) &&
|
basic_test_64bit("-2402844368454405395.2",-2402844368454405395.2) &&
|
||||||
basic_test_64bit("4503599627370496.5", 4503599627370496.5) &&
|
basic_test_64bit("4503599627370496.5", 4503599627370496.5) &&
|
||||||
basic_test_64bit("4503599627475352.5", 4503599627475352.5) &&
|
basic_test_64bit("4503599627475352.5", 4503599627475352.5) &&
|
||||||
@@ -458,6 +462,31 @@ namespace parse_api_tests {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
bool issue_2375() {
|
||||||
|
TEST_START();
|
||||||
|
std::string jsonData =
|
||||||
|
R"eos({"asset":{"version":"1.0"},"geometricError":100,"root":{"boundingVolume":{"region":[10,0,10,10,0,109]},"geometricError":100,"refine":"ADD","children":[{"boundingVolume":{"region":[20,0,20,0,0,20]},"geometricError":70,"content":{"url":"city/tileset.json"}},{"transform":[4,1,0,0,-0.7,3.1,3.8,0,0.9,-3.7,3.21,0,12,-47,40,1],"boundingVolume":{"region":[-1.3,0.6,-1.39,0.6,0,20]},"geometricError":0,"content":{"url":"building.b3dm"}},{"transform":[0.9,0.2,0,0,-0.15,0.62,0.76,0,0.19,-0.74,0.64,0,12,-47,40,1],"viewerRequestVolume":{"region":[-1.3,0.6,-1.31,0.6,0,20]},"boundingVolume":{"region":[-1.31,0.6,-1.3,0.6,0,20]},"geometricError":0,"content":{"url":"points.pnts"}}]}})eos";
|
||||||
|
|
||||||
|
simdjson::dom::parser parser;
|
||||||
|
auto json = parser.parse(jsonData.data(), jsonData.size());
|
||||||
|
const simdjson::dom::element jsonElement = json.value();
|
||||||
|
const simdjson::dom::element rootElement = jsonElement["root"];
|
||||||
|
|
||||||
|
if (jsonElement["asset"]["gltfUpAxis"].is_string()) {
|
||||||
|
if (jsonElement["asset"]["gltfUpAxis"].get_string().value_unsafe() == std::string_view("Z")) {
|
||||||
|
printf("up\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootElement.is_object()) {
|
||||||
|
printf("I can confirm that root is an object!\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
printf("root is not an object!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool issue679() {
|
bool issue679() {
|
||||||
std::cout << "Running " << __func__ << std::endl;
|
std::cout << "Running " << __func__ << std::endl;
|
||||||
auto input = "[1, 2, 3]"_padded;
|
auto input = "[1, 2, 3]"_padded;
|
||||||
@@ -742,6 +771,7 @@ namespace parse_api_tests {
|
|||||||
parser_load_exception() &&
|
parser_load_exception() &&
|
||||||
parser_load_many_exception() &&
|
parser_load_many_exception() &&
|
||||||
issue679() &&
|
issue679() &&
|
||||||
|
issue_2375() &&
|
||||||
#endif
|
#endif
|
||||||
true;
|
true;
|
||||||
}
|
}
|
||||||
@@ -1245,7 +1275,6 @@ namespace dom_api_tests {
|
|||||||
bool numeric_values_exception() {
|
bool numeric_values_exception() {
|
||||||
std::cout << "Running " << __func__ << std::endl;
|
std::cout << "Running " << __func__ << std::endl;
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
|
|
||||||
ASSERT_EQUAL( uint64_t(parser.parse("0"_padded)), 0);
|
ASSERT_EQUAL( uint64_t(parser.parse("0"_padded)), 0);
|
||||||
ASSERT_EQUAL( int64_t(parser.parse("0"_padded)), 0);
|
ASSERT_EQUAL( int64_t(parser.parse("0"_padded)), 0);
|
||||||
ASSERT_EQUAL( double(parser.parse("0"_padded)), 0);
|
ASSERT_EQUAL( double(parser.parse("0"_padded)), 0);
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <ranges>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include "simdjson.h"
|
||||||
|
#include "test_macros.h"
|
||||||
|
#include "test_main.h"
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
namespace ranges_test {
|
||||||
|
|
||||||
|
bool printout() {
|
||||||
|
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;
|
||||||
|
auto justmodel = [](auto car) { return car["model"]; };
|
||||||
|
for (auto car :
|
||||||
|
parser.parse(cars_json).get_array() | std::views::transform(justmodel)) {
|
||||||
|
std::cout << car << std::endl;
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkvalues() {
|
||||||
|
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;
|
||||||
|
auto justmodel = [](auto car) -> std::string_view {
|
||||||
|
return car["model"].get_string();
|
||||||
|
};
|
||||||
|
auto cars =
|
||||||
|
parser.parse(cars_json).get_array() | std::views::transform(justmodel);
|
||||||
|
|
||||||
|
const std::vector<std::string_view> expected{"Camry", "Soul", "Tercel"};
|
||||||
|
ASSERT_TRUE(std::ranges::equal(cars, expected));
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool run() {
|
||||||
|
return
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
printout() && checkvalues() &&
|
||||||
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ranges_test
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return test_main(argc, argv, ranges_test::run);
|
||||||
|
}
|
||||||
@@ -42,9 +42,9 @@ if(HAVE_POSIX_FORK AND HAVE_POSIX_WAIT) # assert tests use fork and wait, which
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Copy the simdjson dll into the tests directory
|
# Copy the simdjson dll into the tests directory
|
||||||
if(MSVC AND BUILD_SHARED_LIBS)
|
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||||
add_custom_command(TARGET ondemand_parse_api_tests POST_BUILD # Adds a post-build event
|
add_custom_command(TARGET ondemand_parse_api_tests POST_BUILD # Adds a post-build event
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
||||||
"$<TARGET_FILE:simdjson>" # <--this is in-file
|
"$<TARGET_FILE:simdjson>" # <--this is in-file
|
||||||
"$<TARGET_FILE_DIR:ondemand_parse_api_tests>") # <--this is out-file path
|
"$<TARGET_FILE_DIR:ondemand_parse_api_tests>") # <--this is out-file path
|
||||||
endif(MSVC AND BUILD_SHARED_LIBS)
|
endif(WIN32 AND BUILD_SHARED_LIBS)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
@@ -238,6 +240,40 @@ bool optional_car_deserialize() {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool car_deserialize_to_map() {
|
||||||
|
TEST_START();
|
||||||
|
std::map<std::string,std::string> expected = { {"make", "Toyota"}, {"model", "Camry"}};
|
||||||
|
padded_string json =
|
||||||
|
R"( { "make": "Toyota", "model": "Camry" })"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
|
||||||
|
static_assert(simdjson::concepts::string_view_keyed_map<std::map<std::string, std::string>>, "should be custom deserializable");
|
||||||
|
using map_type = typename std::map<std::string,std::string>;
|
||||||
|
static_assert(simdjson::custom_deserializable<map_type,simdjson::ondemand::value>, "should be custom deserializable");
|
||||||
|
map_type brands;
|
||||||
|
error = doc.get<map_type>().get(brands);
|
||||||
|
ASSERT_TRUE(brands == expected);
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool car_deserialize_with_map() {
|
||||||
|
TEST_START();
|
||||||
|
padded_string json =
|
||||||
|
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
|
"tire_pressure": [ 40.1, 39.9 ] }
|
||||||
|
})"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
|
||||||
|
std::map<std::string,Car> car;
|
||||||
|
error = doc.get<std::map<std::string,Car>>().get(car);
|
||||||
|
std::optional<Car> expected = Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}};
|
||||||
|
ASSERT_TRUE(car["car1"] == expected);
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
bool car_doc_deserialize() {
|
bool car_doc_deserialize() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
@@ -320,7 +356,9 @@ bool car_unique_ptr_deserialize() {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool run() { return list_car_deserialize()
|
bool run() { return car_deserialize_with_map()
|
||||||
|
&& car_deserialize_to_map()
|
||||||
|
&& list_car_deserialize()
|
||||||
&& optional_car_deserialize()
|
&& optional_car_deserialize()
|
||||||
&& car_unique_ptr_deserialize()
|
&& car_unique_ptr_deserialize()
|
||||||
&& vector_car_deserialize()
|
&& vector_car_deserialize()
|
||||||
|
|||||||
@@ -83,6 +83,31 @@ bool custom_test() {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool uint8_t_test() {
|
||||||
|
TEST_START();
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
const simdjson::padded_string json =
|
||||||
|
R"({"data" : [1,2,3,4]})"_padded;
|
||||||
|
simdjson::ondemand::document d = parser.iterate(json);
|
||||||
|
std::vector<uint8_t> array = d["data"].get<std::vector<uint8_t>>();
|
||||||
|
std::vector<uint8_t> expected = {1, 2, 3, 4};
|
||||||
|
ASSERT_EQUAL(array, expected);
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool append_test() {
|
||||||
|
TEST_START();
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
const simdjson::padded_string json =
|
||||||
|
R"({"data" : [1,2,3,4]})"_padded;
|
||||||
|
simdjson::ondemand::document d = parser.iterate(json);
|
||||||
|
std::vector<uint32_t> array = {0, 0};
|
||||||
|
d["data"].get<std::vector<uint32_t>>(array);
|
||||||
|
std::vector<uint32_t> expected = {0, 0, 1, 2, 3, 4};
|
||||||
|
ASSERT_EQUAL(array, expected);
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
bool readme_test() {
|
bool readme_test() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
auto const json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
auto const json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||||
@@ -162,6 +187,8 @@ bool simple_document_test_no_except() {
|
|||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
#if SIMDJSON_EXCEPTIONS && defined(__cpp_concepts)
|
#if SIMDJSON_EXCEPTIONS && defined(__cpp_concepts)
|
||||||
|
append_test() &&
|
||||||
|
uint8_t_test() &&
|
||||||
readme_test() &&
|
readme_test() &&
|
||||||
custom_test() &&
|
custom_test() &&
|
||||||
simple_document_test() &&
|
simple_document_test() &&
|
||||||
|
|||||||
@@ -5,23 +5,51 @@ using namespace simdjson;
|
|||||||
|
|
||||||
namespace misc_tests {
|
namespace misc_tests {
|
||||||
using namespace std;
|
using namespace std;
|
||||||
bool issue2322() {
|
bool issue2354() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
std::vector<std::pair<std::string, bool>> examples = {{R"("hello")", false},
|
auto json = "true "_padded;
|
||||||
{R"(\"hello)", true},
|
ondemand::parser parser;
|
||||||
{R"("hello\")", true},
|
ondemand::document doc;
|
||||||
{R"("hel\"lo")", false},
|
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||||
{R"("hel\\lo")", false},
|
bool b;
|
||||||
{R"(\"hel\\\"lo\")", true},
|
ASSERT_SUCCESS(doc.get_bool().get(b));
|
||||||
{R"(\\"hel\\\"lo\")", false}};
|
ASSERT_TRUE(b);
|
||||||
for (std::pair<std::string, bool> v : examples) {
|
TEST_SUCCEED();
|
||||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first),
|
}
|
||||||
v.second);
|
bool issue2355() {
|
||||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first.c_str()),
|
TEST_START();
|
||||||
v.second);
|
simdjson::ondemand::parser parser;
|
||||||
|
auto json = "[\"extra close\"]]"_padded;
|
||||||
|
ondemand::document doc;
|
||||||
|
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||||
|
simdjson::ondemand::array test;
|
||||||
|
ASSERT_SUCCESS(doc.get_array().get(test));
|
||||||
|
for(auto vale : test) {
|
||||||
|
std::string_view str;
|
||||||
|
ASSERT_SUCCESS(vale.get_string().get(str));
|
||||||
|
ASSERT_EQUAL(str, "extra close");
|
||||||
|
}
|
||||||
|
ASSERT_FALSE(doc.at_end());
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool issue2322() {
|
||||||
|
TEST_START();
|
||||||
|
std::vector<std::pair<std::string, bool>> examples = {{R"("hello")", false},
|
||||||
|
{R"(\"hello)", true},
|
||||||
|
{R"("hello\")", true},
|
||||||
|
{R"("hel\"lo")", false},
|
||||||
|
{R"("hel\\lo")", false},
|
||||||
|
{R"(\"hel\\\"lo\")", true},
|
||||||
|
{R"(\\"hel\\\"lo\")", false}};
|
||||||
|
for (std::pair<std::string, bool> v : examples) {
|
||||||
|
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first),
|
||||||
|
v.second);
|
||||||
|
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first.c_str()),
|
||||||
|
v.second);
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
TEST_SUCCEED();
|
|
||||||
}
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
// user reported an asan error:
|
// user reported an asan error:
|
||||||
bool issue2199() {
|
bool issue2199() {
|
||||||
@@ -655,6 +683,8 @@ bool issue2322() {
|
|||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
|
issue2355() &&
|
||||||
|
issue2354() &&
|
||||||
issue2322() &&
|
issue2322() &&
|
||||||
issue2312() &&
|
issue2312() &&
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|||||||
@@ -312,7 +312,30 @@ namespace number_tests {
|
|||||||
ASSERT_EQUAL(number.get_number_type(), ondemand::number_type::floating_point_number);
|
ASSERT_EQUAL(number.get_number_type(), ondemand::number_type::floating_point_number);
|
||||||
ASSERT_EQUAL(number.get_double(), 1e9);
|
ASSERT_EQUAL(number.get_double(), 1e9);
|
||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool minus_zero() {
|
||||||
|
TEST_START();
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto json = "-0"_padded;
|
||||||
|
ondemand::document doc;
|
||||||
|
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||||
|
ondemand::number number;
|
||||||
|
ASSERT_SUCCESS(doc.get_number().get(number));
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
ASSERT_EQUAL(number.get_number_type(), ondemand::number_type::floating_point_number);
|
||||||
|
#else
|
||||||
|
ASSERT_EQUAL(number.get_number_type(), ondemand::number_type::signed_integer);
|
||||||
|
#endif
|
||||||
|
ondemand::number_type nt{};
|
||||||
|
ASSERT_SUCCESS(doc.get_number_type().get(nt));
|
||||||
|
#if SIMDJSON_MINUS_ZERO_AS_FLOAT
|
||||||
|
ASSERT_EQUAL(nt, ondemand::number_type::floating_point_number);
|
||||||
|
#else
|
||||||
|
ASSERT_EQUAL(nt, ondemand::number_type::signed_integer);
|
||||||
|
#endif
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
bool issue1878() {
|
bool issue1878() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
@@ -504,7 +527,8 @@ namespace number_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return gigantic_big_int() &&
|
return minus_zero() &&
|
||||||
|
gigantic_big_int() &&
|
||||||
big_int_not_zero() &&
|
big_int_not_zero() &&
|
||||||
negative_big_int() &&
|
negative_big_int() &&
|
||||||
issue2099() &&
|
issue2099() &&
|
||||||
|
|||||||
@@ -23,6 +23,24 @@ namespace object_tests {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool testing_to_string() {
|
||||||
|
TEST_START();
|
||||||
|
auto json = R"({"\u0062\u0065\u0062\u0065": 2} })"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||||
|
ondemand::object object;
|
||||||
|
ASSERT_SUCCESS(doc.get_object().get(object));
|
||||||
|
for (auto field : object) {
|
||||||
|
std::string key;
|
||||||
|
ASSERT_SUCCESS(field.unescaped_key().get(key));
|
||||||
|
ASSERT_EQUAL(key, "bebe");
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool issue1977() {
|
bool issue1977() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
auto json = R"({"1": 2} foo })"_padded;
|
auto json = R"({"1": 2} foo })"_padded;
|
||||||
@@ -258,6 +276,19 @@ namespace object_tests {
|
|||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
bool testing_to_string_exception() {
|
||||||
|
TEST_START();
|
||||||
|
auto json = R"({"\u0062\u0065\u0062\u0065": 2} })"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::object object = doc.get_object();
|
||||||
|
for (auto field : object) {
|
||||||
|
std::string key;
|
||||||
|
ASSERT_SUCCESS(field.unescaped_key().get(key));
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
bool issue1965() {
|
bool issue1965() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
std::string str = "{\"query\":\"ah\"}";
|
std::string str = "{\"query\":\"ah\"}";
|
||||||
@@ -1310,9 +1341,11 @@ namespace object_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return issue1979() &&
|
return testing_to_string() &&
|
||||||
|
issue1979() &&
|
||||||
issue1977() &&
|
issue1977() &&
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
testing_to_string_exception() &&
|
||||||
issue1965() &&
|
issue1965() &&
|
||||||
#endif
|
#endif
|
||||||
issue1974a() &&
|
issue1974a() &&
|
||||||
|
|||||||
@@ -10,6 +10,37 @@ using namespace std;
|
|||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
using error_code = simdjson::error_code;
|
using error_code = simdjson::error_code;
|
||||||
|
|
||||||
|
bool fatal_error() {
|
||||||
|
TEST_START();
|
||||||
|
padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
auto errordoc = parser.iterate(badjson).get(doc);
|
||||||
|
if(errordoc != simdjson::SUCCESS) { return false; }
|
||||||
|
simdjson::ondemand::value v;
|
||||||
|
auto error = doc.get_object()["year"].get(v);
|
||||||
|
ASSERT_TRUE(simdjson::is_fatal(error));
|
||||||
|
ASSERT_FALSE(doc.is_alive());
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
bool to_string_object() {
|
||||||
|
TEST_START();
|
||||||
|
auto json = R"({"\u0062\u0065\u0062\u0065": 2} })"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc;
|
||||||
|
auto error = parser.iterate(json).get(doc);
|
||||||
|
if(error) { return false; }
|
||||||
|
ondemand::object object;
|
||||||
|
error = doc.get_object().get(object);
|
||||||
|
if(error) { return false; }
|
||||||
|
for (auto field : object) {
|
||||||
|
std::string key;
|
||||||
|
error = field.unescaped_key().get(key);
|
||||||
|
if(error) { return false; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool simplepad() {
|
bool simplepad() {
|
||||||
std::string json = "[1]";
|
std::string json = "[1]";
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -22,14 +53,14 @@ bool string1() {
|
|||||||
const char * data = "my data"; // 7 bytes
|
const char * data = "my data"; // 7 bytes
|
||||||
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||||
std::cout << my_padded_data << std::endl;
|
std::cout << my_padded_data << std::endl;
|
||||||
return true;
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string2() {
|
bool string2() {
|
||||||
std::string data = "my data";
|
std::string data = "my data";
|
||||||
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||||
std::cout << my_padded_data << std::endl;
|
std::cout << my_padded_data << std::endl;
|
||||||
return true;
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool to_string_example_no_except() {
|
bool to_string_example_no_except() {
|
||||||
@@ -272,6 +303,22 @@ bool at_end() {
|
|||||||
TEST_SUCCEED();
|
TEST_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool at_end_array() {
|
||||||
|
TEST_START();
|
||||||
|
auto json = R"(["extra close"]])"_padded;
|
||||||
|
ondemand::parser parser;
|
||||||
|
ondemand::document doc = parser.iterate(json);
|
||||||
|
ondemand::array array = doc.get_array();
|
||||||
|
for (std::string_view values : array) {
|
||||||
|
std::cout << values << std::endl;
|
||||||
|
}
|
||||||
|
if(!doc.at_end()) {
|
||||||
|
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
bool examplecrt() {
|
bool examplecrt() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
padded_string padded_input_json = R"([
|
padded_string padded_input_json = R"([
|
||||||
@@ -1893,6 +1940,7 @@ bool value_raw_json_object() {
|
|||||||
#endif
|
#endif
|
||||||
bool run() {
|
bool run() {
|
||||||
return true
|
return true
|
||||||
|
&& fatal_error()
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
#if SIMDJSON_CPLUSPLUS17
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
&& big_int_array()
|
&& big_int_array()
|
||||||
@@ -1956,8 +2004,9 @@ bool run() {
|
|||||||
&& current_location_tape_error_with_except()
|
&& current_location_tape_error_with_except()
|
||||||
&& examplecrt()
|
&& examplecrt()
|
||||||
&& examplecrt_realloc()
|
&& examplecrt_realloc()
|
||||||
|
&& at_end_array()
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "simdjson.h"
|
#include "simdjson.h"
|
||||||
#include "cast_tester.h"
|
#include "cast_tester.h"
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
|
#include "test_main.h"
|
||||||
|
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
bool test_ondemand(simdjson::ondemand::parser &parser, const simdjson::padded_string &json, const F& f) {
|
bool test_ondemand(simdjson::ondemand::parser &parser, const simdjson::padded_string &json, const F& f) {
|
||||||
@@ -43,45 +44,5 @@ bool test_ondemand_doc(const simdjson::padded_string &json, const F& f) {
|
|||||||
const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793;
|
const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793;
|
||||||
#define SIMDJSON_SHOW_DEFINE(x) printf("%s=%s\n", #x, SIMDJSON_STRINGIFY(x))
|
#define SIMDJSON_SHOW_DEFINE(x) printf("%s=%s\n", #x, SIMDJSON_STRINGIFY(x))
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
int test_main(int argc, char *argv[], const F& test_function) {
|
|
||||||
std::cout << std::unitbuf;
|
|
||||||
int c;
|
|
||||||
while ((c = getopt(argc, argv, "a:")) != -1) {
|
|
||||||
switch (c) {
|
|
||||||
case 'a': {
|
|
||||||
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
|
|
||||||
if (!impl) {
|
|
||||||
std::fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
simdjson::get_active_implementation() = impl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
std::fprintf(stderr, "Unexpected argument %c\n", c);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is put here deliberately to check that the documentation is correct (README),
|
|
||||||
// should this fail to compile, you should update the documentation:
|
|
||||||
if (simdjson::get_active_implementation()->name() == "unsupported") {
|
|
||||||
std::printf("unsupported CPU\n");
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
// We want to know what we are testing.
|
|
||||||
std::cout << "builtin_implementation -- " << simdjson::builtin_implementation()->name() << std::endl;
|
|
||||||
std::cout << "------------------------------------------------------------" << std::endl;
|
|
||||||
|
|
||||||
std::cout << "Running tests." << std::endl;
|
|
||||||
if (test_function()) {
|
|
||||||
std::cout << "Success!" << std::endl;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
} else {
|
|
||||||
std::cerr << "FAILED." << std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ONDEMAND_TEST_ONDEMAND_H
|
#endif // ONDEMAND_TEST_ONDEMAND_H
|
||||||
|
|||||||
+15
-1
@@ -46,6 +46,21 @@ simdjson_inline simdjson::error_code to_error_code(const simdjson::simdjson_resu
|
|||||||
return result.error();
|
return result.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
|
||||||
|
os << "["; // Start with opening bracket
|
||||||
|
if (!vec.empty()) {
|
||||||
|
// Print first element without leading comma
|
||||||
|
os << static_cast<uint16_t>(vec[0]);
|
||||||
|
// Print remaining elements with commas
|
||||||
|
for (size_t i = 1; i < vec.size(); ++i) {
|
||||||
|
os << ", " << static_cast<uint16_t>(vec[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "]"; // End with closing bracket
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
simdjson_inline bool assert_success(const T &actual, const char *operation = "result") {
|
simdjson_inline bool assert_success(const T &actual, const char *operation = "result") {
|
||||||
simdjson::error_code error = to_error_code(actual);
|
simdjson::error_code error = to_error_code(actual);
|
||||||
@@ -124,5 +139,4 @@ simdjson_inline bool assert_iterate_error(T &arr, simdjson::error_code expected,
|
|||||||
#define RUN_TEST(ACTUAL) do { if (!(ACTUAL)) { return false; } } while (0);
|
#define RUN_TEST(ACTUAL) do { if (!(ACTUAL)) { return false; } } while (0);
|
||||||
#define TEST_FAIL(MESSAGE) do { std::cerr << "FAIL: " << (MESSAGE) << std::endl; return false; } while (0);
|
#define TEST_FAIL(MESSAGE) do { std::cerr << "FAIL: " << (MESSAGE) << std::endl; return false; } while (0);
|
||||||
#define TEST_SUCCEED() do { return true; } while (0);
|
#define TEST_SUCCEED() do { return true; } while (0);
|
||||||
|
|
||||||
#endif // TEST_MACROS_H
|
#endif // TEST_MACROS_H
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#ifndef TEST_MAIN_H
|
||||||
|
#define TEST_MAIN_H
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "simdjson.h"
|
||||||
|
|
||||||
|
// technically not a macro, but we want to share this function across tests for both ondemand and dom.
|
||||||
|
template<typename F>
|
||||||
|
int test_main(int argc, char *argv[], const F& test_function) {
|
||||||
|
std::cout << std::unitbuf;
|
||||||
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "a:")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'a': {
|
||||||
|
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
|
||||||
|
if (!impl) {
|
||||||
|
std::fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
simdjson::get_active_implementation() = impl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
std::fprintf(stderr, "Unexpected argument %c\n", c);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is put here deliberately to check that the documentation is correct (README),
|
||||||
|
// should this fail to compile, you should update the documentation:
|
||||||
|
if (simdjson::get_active_implementation()->name() == "unsupported") {
|
||||||
|
std::printf("unsupported CPU\n");
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
// We want to know what we are testing.
|
||||||
|
std::cout << "builtin_implementation -- " << simdjson::builtin_implementation()->name() << std::endl;
|
||||||
|
std::cout << "------------------------------------------------------------" << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Running tests." << std::endl;
|
||||||
|
if (test_function()) {
|
||||||
|
std::cout << "Success!" << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else {
|
||||||
|
std::cerr << "FAILED." << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // TEST_MAIN_H
|
||||||
Reference in New Issue
Block a user