Compare commits

...

31 Commits

Author SHA1 Message Date
Daniel Lemire 8aae14931d release candidate 4.0.2 (#2441)
* release candidate 4.0.2

* more fixes

* fixing typos

* adding macro check
2025-09-15 09:17:43 -06:00
Daniel Lemire ef3d1ac25f fixing 2440 2025-09-14 08:09:27 -06:00
Daniel Lemire 9292480a9b removing leftover <experimental/...> (#2438) 2025-09-14 08:00:26 -06:00
Daniel Lemire 611ea97dbd Add C++26 reflection example link to README 2025-09-12 21:22:45 -04:00
Daniel Lemire f249e7e128 patch release 2025-09-12 19:26:58 -04:00
Marian Klymov 44fddaa807 Replace POSITION_INDEPENDENT_CODE with INTERFACE_POSITION_INDEPENDENT_CODE for older CMake (#2437) 2025-09-12 19:26:22 -04:00
Daniel Lemire be16e1ae04 removing space 2025-09-11 20:58:31 -04:00
Daniel Lemire 124a33c160 Update JSON example and add section on special cases
Removed code block formatting for JSON example and added a section header for special cases.
2025-09-11 19:32:38 -04:00
Daniel Lemire a0b870e9c2 Add example for deserializing 'Car' type
Updated the documentation to include an example of deserializing a 'Car' type using simdjson.
2025-09-11 19:31:15 -04:00
Daniel Lemire 68699eb73c release 4.0.0 2025-09-11 19:25:10 -04:00
Daniel Lemire 06453f1637 Remove Fuzzing Status badge from README
Removed Fuzzing Status badge from README.
2025-09-09 18:44:21 -04:00
Daniel Lemire eb828d97ba fixing a few typos 2025-09-09 18:41:00 -04:00
Daniel Lemire 00f84fb448 simplify 2025-09-09 14:21:14 -04:00
Daniel Lemire 5bf0954c6e hop 2025-09-08 19:26:34 -04:00
Daniel Lemire 3056d54fa3 adding instructions 2025-09-08 17:47:14 -04:00
Daniel Lemire 241b9f6ea7 adding bad/good player test 2025-09-08 17:04:52 -04:00
Daniel Lemire 015daad6a9 Merge branch 'master' of github.com:simdjson/simdjson 2025-09-05 19:50:05 -04:00
Daniel Lemire fc3b7766c0 typo fix 2025-09-05 19:49:57 -04:00
Daniel Lemire b5c78288e5 can we run the address sanitizer under VS in CI ? (#2435)
* can we run the address sanitizer under VS in CI ?

* fixed typo
2025-09-05 18:32:15 -04:00
Daniel Lemire bd86bb0cfb adding UTF-8 test 2025-09-05 14:56:02 -04:00
Daniel Lemire 4840a0347c extra documentation. 2025-09-05 14:44:53 -04:00
Daniel Lemire 7f68baec1e minor tweak 2025-09-05 08:01:04 -04:00
Daniel Lemire e2ea5fb8de This PR adds -> and * operators to our error types and it (#2433)
improves slightly the documentation.
2025-09-04 22:35:01 -04:00
Daniel Lemire 7dfd165ecd Merge branch 'master' of github.com:simdjson/simdjson 2025-09-04 09:46:07 -04:00
Daniel Lemire 4dfa0a2407 guarding 2025-09-03 16:45:09 -04:00
Daniel Lemire e252a21f65 removing expand workaround (#2431)
* removing expland workaround

* minor fixes
2025-09-03 13:30:35 -04:00
Daniel Lemire 89f2b634df guarding from benchmark + rvv 2025-09-02 13:06:25 -04:00
Daniel Lemire addca203d5 adding a 'car builder' benchmark (#2428)
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2025-08-26 09:16:18 -04:00
Felipe Monteiro 1825d7e88c Add "node:" prefix on fs import (#2426) 2025-08-25 10:21:13 -04:00
Daniel Lemire f87d6af3e9 fix issue 2424 (#2425) 2025-08-24 16:04:56 -04:00
Daniel Lemire 8fff57578c let us default on developer mode when building with VScode 2025-08-23 20:59:58 -04:00
48 changed files with 2806 additions and 960 deletions
+49 -4
View File
@@ -1,8 +1,53 @@
Short title (summary):
Description
- What did you change and why? (1-3 sentences)
- Issue reproduced / related issue: link the issue if relevant (e.g. #123)
Type of change
- [ ] Bug fix
- [ ] New feature
- [ ] Refactor / cleanup
- [ ] Documentation / tests
- [ ] Other (please describe):
How to verify / test
- Add additional tests to verify bugs or new features.
- If you claim performance gains, you should provide benchmark numbers using high quality benchmarking code.
Our tests check whether you have introduced trailing white space. If such a test fails, please check the "artifacts button" above, which if you click it gives a link to a downloadable file to help you identify the issue. You can also run scripts/remove_trailing_whitespace.sh locally if you have a bash shell and the sed command available on your system.
Please read before contributing:
- CONTRIBUTING: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
- HACKING: https://github.com/simdjson/simdjson/blob/master/HACKING.md
If you plan to contribute to simdjson, please read our
CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
If you can, we recommend running our tests with the sanitizers turned on.
For non-Visual Studio users, it is as easy as doing:
```bash
cmake -B build -D SIMDJSON_SANITIZE=ON -D SIMDJSON_DEVELOPER_MODE=ON
cmake --build build
ctest --test-dir build
```
Our CI checks, among other things, for trailing whitespace. If a test fails for that reason,
use the "artifacts" button to download the artifact and inspect the problematic lines,
or run `scripts/remove_trailing_whitespace.sh` locally if you have a bash shell and `sed`.
Checklist before submitting
- [ ] I added/updated tests covering my change (if applicable)
- [ ] Code builds locally and passes my check
- [ ] Documentation / README updated if needed
- [ ] Commits are atomic and messages are clear
- [ ] I linked the related issue (if applicable)
Final notes
- For large PRs, prefer smaller incremental PRs or request staged review.
Thanks for the contribution!
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu rvv VLEN=1024 (clang 18)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
sudo apt-get update -q -y
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-18
- name: Build
run: |
CXX=clang++-18 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv_zvbb" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=1024
run: |
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,zvbb=on,vlen=1024,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu rvv VLEN=128 (clang 17)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
sudo apt-get update -q -y
sudo apt-get install -y cmake make g++-riscv64-linux-gnu qemu-user-static clang-17
- name: Build
run: |
CXX=clang++-17 CXXFLAGS="--target=riscv64-linux-gnu -march=rv64gcv" \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=128
run: |
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,vlen=128,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu rvv VLEN=256 (gcc 14)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
sudo apt-get update -q -y
sudo apt-get install -y cmake make g++-14-riscv64-linux-gnu qemu-user-static
- name: Build
run: |
CXX=riscv64-linux-gnu-g++-14 CXXFLAGS=-march=rv64gcv \
cmake --toolchain=cmake/toolchains-ci/riscv64-linux-gnu.cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build/ -j$(nproc)
- name: Test VLEN=256
run: |
export QEMU_LD_PREFIX="/usr/riscv64-linux-gnu"
export QEMU_CPU="rv64,v=on,zvbb=on,vlen=256,rvv_ta_all_1s=on,rvv_ma_all_1s=on"
ctest --timeout 1800 --output-on-failure --test-dir build -j $(nproc)
@@ -0,0 +1,22 @@
name: Ubuntu 24.04 CI (CXX 20, noexcept)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-24.04
strategy:
matrix:
cxx: [g++-13, clang++-16]
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Prepare
run: cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_EXCEPTIONS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -B build
env:
CXX: ${{matrix.cxx}}
- name: Build
run: cmake --build build -j=2
- name: Test
run: ctest --output-on-failure --test-dir build
+30
View File
@@ -0,0 +1,30 @@
name: VS17-CI-SANITIZE
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: Debug}
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: Release}
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF, build_type: RelWithDebInfo}
steps:
- name: checkout
uses: actions/checkout@v4
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSANITIZE=ON -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
- name: Build
run: cmake --build build --config ${{matrix.build_type}} --verbose
- name: Run tests
run: |
cd build
ctest -C ${{matrix.build_type}} -LE explicitonly --output-on-failure
+3
View File
@@ -3,6 +3,9 @@
{"column": 95 },
{"column": 120 }
],
"cmake.configureArgs": [
"-DSIMDJSON_DEVELOPER_MODE=ON"
],
"files.trimTrailingWhitespace": true,
"files.associations": {
".clangd": "yaml",
+3 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 4.0.0
VERSION 4.0.2
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "28.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "28" CACHE STRING "simdjson library soversion")
set(SIMDJSON_LIB_VERSION "27.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "27" CACHE STRING "simdjson library soversion")
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "4.0.0"
PROJECT_NUMBER = "4.0.2"
# 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
+46 -8
View File
@@ -20,13 +20,54 @@ If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://gi
Build Quickstart
------------------------------
For non-Windows system,
```bash
mkdir build
cd build
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build .
cmake -B -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build build
ctest --test-dir build
```
It is similar for Visual Studio users, please see the CMake or Visual Studio documentation.
By default the library is built in Release mode.
Assertions and development checks
------------------------------
We do not use conventional `assert` in simdjson. Instead we use the macro
`SIMDJSON_ASSUME`:
```cpp
SIMDJSON_ASSUME(something_that_is_true());
```
Sometimes, you need to do a bit more work that a simple check.
The `SIMDJSON_DEVELOPMENT_CHECKS` macro is true only in Debug mode unless manually set.
It is acceptable to add checks that you would not do in Release mode as long as
they are guarded:
```cpp
#if SIMDJSON_DEVELOPMENT_CHECKS
// do sanity checks here
```
Working with sanitizers
------------------------------
The simdjson library must be memory-safe. We cannot allow buffer overruns.
During development, if you system supports it, we recommend configuring
the project with `-D SIMDJSON_SANITIZE=ON`.
```bash
cmake -B -D SIMDJSON_SANITIZE=ON -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build build
ctest --test-dir build
```
Design notes
------------------------------
@@ -103,12 +144,9 @@ simdjson's source structure, from the top level, looks like this:
* generic/stage2/*.h: `simdjson::<implementation>::stage2` namespace. Generic implementation of the tape creator, which consumes the index from stage 1 and actually parses numbers and string and such. Used for the DOM interface.
Other important files and directories:
* **.drone.yml:** Definitions for Drone CI.
* **.appveyor.yml:** Definitions for Appveyor CI (Windows).
* **.circleci:** Definitions for Circle CI.
* **.github/workflows:** Definitions for GitHub Actions (CI).
* **singleheader:** Contains generated `simdjson.h` and `simdjson.cpp` that we release. The files `singleheader/simdjson.h` and `singleheader/simdjson.cpp` should never be edited by hand.
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script).
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script). If you add a new implementation (e.g., rvv), you need to edit this file (IMPLEMENTATIONS).
* **benchmark:** This is where we do benchmarking. Benchmarking is core to every change we make; the
cardinal rule is don't regress performance without knowing exactly why, and what you're trading
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnecessary system calls. We recommend checking the performance as follows:
+1 -2
View File
@@ -1,5 +1,3 @@
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
[![][license img]][license] [![][licensemit img]][licensemit]
@@ -121,6 +119,7 @@ Godbolt
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
* [C++26 reflection example](https://godbolt.org/z/xK5TGKdPb)
Performance results
-------------------
+10 -7
View File
@@ -35,13 +35,16 @@ if (TARGET benchmark::benchmark)
endif()
endif()
if(SIMDJSON_STATIC_REFLECTION)
add_subdirectory(static_reflect)
endif(SIMDJSON_STATIC_REFLECTION)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-std=c++20" SIMDJSON_COMPILER_SUPPORTS_CXX20)
if(SIMDJSON_EXCEPTIONS AND SIMDJSON_COMPILER_SUPPORTS_CXX20)
add_subdirectory(from)
endif()
if(SIMDJSON_STATIC_REFLECTION)
add_subdirectory(static_reflect)
else()
if(SIMDJSON_EXCEPTIONS AND SIMDJSON_COMPILER_SUPPORTS_CXX20)
add_subdirectory(from)
add_subdirectory(car_builder)
endif()
endif(SIMDJSON_STATIC_REFLECTION)
+14
View File
@@ -0,0 +1,14 @@
# Executable
add_executable(benchmark_car_builder benchmark_car_builder.cpp)
# Compile for C++20.
target_compile_features(benchmark_car_builder PRIVATE cxx_std_20)
# Check if -march=native is supported
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-march=native" SIMDJSON_SUPPORTS_MARCH_NATIVE)
if(SIMDJSON_SUPPORTS_MARCH_NATIVE)
target_compile_options(benchmark_car_builder PRIVATE -march=native)
endif()
target_include_directories(benchmark_car_builder PRIVATE ${CMAKE_CURRENT_LIST_DIR}/..)
@@ -0,0 +1,127 @@
#include "event_counter.h"
#include <random>
#include <vector>
#include <simdjson.h>
event_collector collector;
struct Car {
std::string make;
std::string model;
int64_t year; // We deliberately do not include the tire pressure.
};
std::vector<Car> generate_random_cars(size_t count) {
static const std::vector<std::string> makes = {"Toyota", "Honda", "Ford",
"BMW", "Mazda"};
static const std::vector<std::string> models = {"Camry", "Civic", "Focus",
"320i", "3"};
static thread_local std::mt19937 rng{std::random_device{}()};
std::uniform_int_distribution<int> make_dist(0, makes.size() - 1);
std::uniform_int_distribution<int> model_dist(0, models.size() - 1);
std::uniform_int_distribution<int64_t> year_dist(2000, 2025);
std::uniform_real_distribution<double> pressure_dist(30.0, 45.0);
std::vector<Car> cars;
cars.reserve(count);
for (size_t i = 0; i < count; ++i) {
Car car;
car.make = makes[make_dist(rng)];
car.model = models[model_dist(rng)];
car.year = year_dist(rng);
cars.push_back(std::move(car));
}
return cars;
}
std::string_view serialize(simdjson::builder::string_builder &sb,
const std::vector<Car> &cars) {
sb.clear();
sb.start_array();
for (const auto &car : cars) {
sb.start_object();
sb.append_key_value("make", car.make);
sb.append_comma();
sb.append_key_value("model", car.model);
sb.append_comma();
sb.append_key_value("year", car.year);
sb.end_object();
}
sb.end_array();
std::string_view result;
if (sb.view().get(result)) {
return ""; // unexpected (error)
}
return result;
}
double pretty_print(const std::string &name, size_t num_chars,
std::pair<event_aggregate, size_t> result) {
const auto &agg = result.first;
size_t N = result.second;
num_chars *= N;
printf("%-40s : %8.2f ns %8.2f GB/s", name.c_str(),
agg.elapsed_ns() / num_chars, num_chars / agg.elapsed_ns());
if (collector.has_events()) {
printf(" %8.2f GHz %8.2f cycles/char %8.2f ins./char %8.2f i/c",
agg.cycles() / agg.elapsed_ns(), agg.cycles() / num_chars,
agg.instructions() / num_chars, agg.instructions() / agg.cycles());
}
printf("\n");
return num_chars / agg.elapsed_ns();
}
template <class function_type>
std::pair<event_aggregate, size_t>
bench(const function_type &&function, size_t min_repeat = 100,
size_t min_time_ns = 40'000'000, size_t max_repeat = 10000000) {
size_t N = min_repeat;
if (N == 0) {
N = 1;
}
event_aggregate warm_aggregate{};
for (size_t i = 0; i < N; i++) {
std::atomic_thread_fence(std::memory_order_acquire);
collector.start();
function();
std::atomic_thread_fence(std::memory_order_release);
event_count allocate_count = collector.end();
warm_aggregate << allocate_count;
if ((i + 1 == N) && (warm_aggregate.total_elapsed_ns() < min_time_ns) &&
(N < max_repeat)) {
N *= 10;
}
}
event_aggregate aggregate{};
for (size_t i = 0; i < 10; i++) {
std::atomic_thread_fence(std::memory_order_acquire);
collector.start();
for (size_t i = 0; i < N; i++) {
function();
}
std::atomic_thread_fence(std::memory_order_release);
event_count allocate_count = collector.end();
aggregate << allocate_count;
}
return {aggregate, N};
}
void run_benchmarks() {
std::vector<Car> source = generate_random_cars(100000);
simdjson::builder::string_builder sb;
size_t volume = serialize(sb, source).size();
pretty_print("string_builder", volume, bench([&source, &sb]() -> size_t {
return serialize(sb, source).size();
}));
}
int main() {
for (size_t trial = 0; trial < 3; trial++) {
printf("Trial %zu:\n", trial + 1);
run_benchmarks();
printf("\n");
}
return EXIT_SUCCESS;
}
+3 -2
View File
@@ -2,8 +2,9 @@
add_executable(from_benchmark from_benchmark.cpp)
# Compile for C++20.
target_compile_features(from_benchmark PRIVATE cxx_std_20)
if(CMAKE_CXX_STANDARD LESS 20)
target_compile_features(from_benchmark PRIVATE cxx_std_20)
endif()
# Check if -march=native is supported
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-march=native" SIMDJSON_SUPPORTS_MARCH_NATIVE)
+4 -1
View File
@@ -4,7 +4,7 @@
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)
set_target_properties(simdjson-internal-flags PROPERTIES INTERFACE_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)
@@ -32,6 +32,9 @@ undefined behavior.")
link_libraries(
-fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all
)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_options(-fsanitize=address)
link_libraries(-fsanitize=address)
else()
message(
STATUS
@@ -0,0 +1,4 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR riscv64)
set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-riscv64-static")
+130 -18
View File
@@ -54,7 +54,7 @@ The simdjson library is widely deployed in popular systems such as the Node.js r
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 discourage against using GCC under Windows: there [is a long-running bug with GCC under Windows](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412).
- Visual Studio 2017 or better. We support the LLVM clang compiler under Visual Studio (clang-cl) as well 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 discourage using GCC under Windows: there [is a long-running bug with GCC under Windows](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412).
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.
@@ -78,14 +78,14 @@ c++ myproject.cpp simdjson.cpp
```
Note:
- We recommend that you use simdjson by copying the single-header `simdjson.h` file along with the source file `simdjson.cpp` directly in your project, as they are part of [every release](https://github.com/simdjson/simdjson/releases) as assets. In this manner, you only have to compile `simdjson.cpp` as any other source file: it works well in every development environment. However, you may also use simdjson as a git submodule ([example](https://github.com/simdjson/cmakedemo)), using FetchContent ([example](https://github.com/simdjson/cmake_demo_single_file)), with ExternalProject_Add ([example](https://github.com/simdjson/cmakedemo_externalproject)) or with CPM ([example](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples/simdjson)).
- We recommend that you use simdjson by copying the single-header `simdjson.h` file along with the source file `simdjson.cpp` directly into your project, as they are part of [every release](https://github.com/simdjson/simdjson/releases) as assets. In this manner, you only have to compile `simdjson.cpp` as any other source file: it works well in every development environment. However, you may also use simdjson as a git submodule ([example](https://github.com/simdjson/cmakedemo)), using FetchContent ([example](https://github.com/simdjson/cmake_demo_single_file)), with ExternalProject_Add ([example](https://github.com/simdjson/cmakedemo_externalproject)) or with CPM ([example](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples/simdjson)).
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`).
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`) if you want your binaries to run everywhere.
Using simdjson with package managers
------------------
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. E.g., [we provide an complete example with vcpkg](https://github.com/simdjson/simdjson-vcpkg) that works under Windows. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. E.g., [we provide a complete example with vcpkg](https://github.com/simdjson/simdjson-vcpkg) that works under Windows. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
@@ -320,7 +320,7 @@ At the cost of some memory allocation, you may convert your `std::string_view` i
For convenience, we also allow [storing an escaped string directly into an existing string instance](#storing-directly-into-an-existing-string-instance).
The `std::string_view` class has become standard as part of C++17 but it is not always available
on compilers which only supports C++11. When we detect that `string_view` is natively
on compilers that only supports C++11. When we detect that `string_view` is natively
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
When we detect that it is unavailable,
@@ -343,7 +343,7 @@ We recommend that you first compile and run your code in debug mode:
The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1` in debug mode. Because
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
because you may want the checks while building with optimizations, 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
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
@@ -371,9 +371,8 @@ and arrays (`simdjson::ondemand::array`).
We also have a generic ephemeral type (`simdjson::ondemand::value`) which represents a potential
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
an array or an object. Both generic types (`simdjson::ondemand::document` and
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing the
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`,
`json_type::boolean`, `json_type::null`). The `type()` method does not consume nor validate the value: e.g., you must still call `is_null()` to check that the value is a `null` even if `json_type::null` is returned. Starting with simdjson 4.0, we return `json_type::unknown` for bad tokens such as the `NaN` token in `{"key":NaN}`. A `json_type::unknown` type value indicates an error in the JSON document but you might still be able to proceed, see [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string). A generic value (`simdjson::ondemand::value`)
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing indicating the type (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`,
`json_type::boolean`, `json_type::null`, and `json_type::unknown` for unrecognized types). The `type()` method does not consume nor validate the value: e.g., you must still call `is_null()` to check that the value is a `null` even if `json_type::null` is returned. Starting with simdjson 4.0, we return `json_type::unknown` for bad tokens such as the `NaN` token in `{"key":NaN}`. A `json_type::unknown` type value indicates an error in the JSON document but you might still be able to proceed, see [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string). A generic value (`simdjson::ondemand::value`)
is only valid temporarily, as soon as you access other values, other keys in objects, etc.
it becomes invalid: you should therefore consume the value immediately by converting it to a
scalar type, an array or an object.
@@ -406,7 +405,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
`get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for `ondemand::object` and `ondemand::array`. An exception may be thrown if
the cast is not possible: there error code is `simdjson::INCORRECT_TYPE` (see [Error handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
the cast is not possible: the error code is `simdjson::INCORRECT_TYPE` (see [Error handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content.
The `get_string()` returns a valid UTF-8 string, after
@@ -453,7 +452,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
scan through the object looking for the field with the matching string, doing a character-by-character
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Generally, you should not mix and match iterating through an object (`for(auto field : object) {...}`) and key accesses (`object["foo"]`): if you need to iterate through an object after a key access, you need to call `reset()` on the object. Whenever you call `reset()`, you need to keep in mind that though you can iterate over the array repeatedly, values should be consumedonly once (e.g., repeatedly calling `unescaped_key()` on the same key is forbidden). Keep in mind that On-Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Generally, you should not mix and match iterating through an object (`for(auto field : object) {...}`) and key accesses (`object["foo"]`): if you need to iterate through an object after a key access, you need to call `reset()` on the object. Whenever you call `reset()`, you need to keep in mind that though you can iterate over the array repeatedly, values should be consumedonly once (e.g., repeatedly calling `unescaped_key()` on the same key is forbidden). Keep in mind that On-Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code
is in error. Furthermore, you can only consume one field at a time, on the same object. The
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
@@ -516,7 +515,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> double y = doc["y"]; // The cursor is now after the 2 (at })
> double x = doc["x"]; // Success: [] loops back around to find "x"
> ```
* **Output to strings:** Given a document, a value, an array or an object in a JSON document, you can output a JSON string version suitable to be parsed again as JSON content: `simdjson::to_json_string(element)`. A call to `to_json_string` consumes fully the element: if you apply it on a document, the JSON pointer is advanced to the end of the document. The `simdjson::to_json_string` does not allocate memory. The `to_json_string` function should not be confused with retrieving the value of a string instance which are escaped and represented using a lightweight `std::string_view` instance pointing at an internal string buffer inside the parser instance. To illustrate, the first of the following two code segments will print the unescaped string `"test"` complete with the quote whereas the second one will print the escaped content of the string (without the quotes).
* **Output to strings:** Given a document, a value, an array or an object in a JSON document, you can output a JSON string version suitable to be parsed again as JSON content: `simdjson::to_json_string(element)`. A call to `to_json_string` consumes fully the element: if you apply it on a document, the internal pointer is advanced to the end of the document. The `simdjson::to_json_string` does not allocate memory. The `to_json_string` function should not be confused with retrieving the value of a string instance which are escaped and represented using a lightweight `std::string_view` instance pointing at an internal string buffer inside the parser instance. To illustrate, the first of the following two code segments will print the unescaped string `"test"` complete with the quote whereas the second one will print the escaped content of the string (without the quotes).
> ```C++
> // serialize a JSON to an escaped std::string instance so that it can be parsed again as JSON
> auto silly_json = R"( { "test": "result" } )"_padded;
@@ -1376,7 +1375,16 @@ your code with the `SIMDJSON_STATIC_REFLECTION` macro set:
Then you can deserialize a type such as `Car` automatically:
```cpp
```C++
struct Car {
std::string make;
std::string model;
int year;
std::vector<float> tire_pressure;
};
std::string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] } )";
simdjson::ondemand::parser parser;
@@ -1385,6 +1393,75 @@ Car c = doc.get<Car>();
```
We try to automate the parsing of any given structure or class
by looking at its non-static public members. At compile-time,
the library looks at a simple structre like `Car` and
maps it to parsing code. We call the default constructor,
and then assign values to the public members.
#### Special cases
However, there are instances where the construction cannot
be easily automated. Let us consider a class without any
public member.
```cpp
class MyDate {
public:
void assign(std::string_view str) {
date_str = str;
}
const std::string& to_string() const {
return date_str;
}
private:
std::string date_str;
};
```
This class has a default constructor, but it must be initialized
with the `assign` method. We need to help the library with
a `tag_invoke` function (just as in the C++20 case).
```cpp
namespace simdjson {
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, MyDate& date) {
std::string_view str;
auto error = val.get_string().get(str);
if(error) { return error; }
date.assign(str);
return simdjson::SUCCESS;
}
} // namespace simdjson
```
Once this is done, we can now automatically parse a custom type
like `complicated_weather_data` containing `MyDate` values.
```cpp
struct complicated_weather_data {
std::vector<MyDate> time;
std::vector<float> temperature;
};
```
The code might as simple as the following.
```cpp
auto padded = R"({"time":["2023-03-15T12:00:00Z"],"temperature":[42]})"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(padded);
complicated_weather_data p = doc.get<>(complicated_weather_data);
```
Thus you can combine C++26 static reflection with custom deserialization
functions.
You can also automatically serialize the `Car` instance to a JSON string, see
our [Builder documentation](builder.md).
@@ -1460,9 +1537,9 @@ If you find yourself needing only fast Unicode functions, consider using the sim
JSON Pointer
------------
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the `at_pointer()` method, letting you reach further down into the document in a single call. JSON pointer is supported by both the [DOM approach](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#json-pointer) as well as the On-Demand approach.
The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rfc6901) through the `at_pointer()` method, letting you reach further down into the document in a single call. JSON Pointer is supported by both the [DOM approach](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#json-pointer) as well as the On-Demand approach.
**Note:** The On-Demand implementation of JSON pointer relies on `find_field` which implies that it does not unescape keys when matching.
**Note:** The On-Demand implementation of JSON Pointer relies on `find_field` which implies that it does not unescape keys when matching.
Consider the following example:
@@ -1482,7 +1559,7 @@ index allows you to select the indexed node. Within objects, the string value of
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
'~0' respectively. An empty JSON Pointer Path refers to the whole document.
For multiple JSON pointer queries on a document, one can call `at_pointer` multiple times.
For multiple JSON Pointer queries on a document, one can call `at_pointer` multiple times.
```c++
auto cars_json = R"( [
@@ -1637,7 +1714,7 @@ x = obj.at_path("$.d.foo2.a.2"); // 30
Error handling
--------------
Error handing with exception and a single try/catch clause makes the code simple, but it gives you little control over errors. For easier debugging or more robust error handling, you may want to consider our exception-free approach.
Error handling with exception and a single try/catch clause makes the code simple, but it gives you little control over errors. For easier debugging or more robust error handling, you may want to consider our exception-free approach.
The entire simdjson API is usable with and without exceptions. All simdjson APIs that can fail return `simdjson_result<T>`, which is a &lt;value, error_code&gt;
pair. You can retrieve the value with .get() without generating an exception, like so:
@@ -3099,10 +3176,45 @@ Performance tips
- The On-Demand front-end works best when doing a single pass over the input: avoid calling `count_elements`, `rewind`, `reset` and similar methods.
- If you are familiar with assembly language, you may use the online tool godbolt to explore the compiled code. The following example may work: [https://godbolt.org/z/xE4GWs573](https://godbolt.org/z/xE4GWs573).
- Given a field `field` in an object, calling `field.key()` is often faster than `field.unescaped_key()` so if you do not need an unescaped `std::string_view` instance, prefer `field.key()`. Similarly, we expect `field.escaped_key()` to be faster than `field.unescaped_key()` even though both return a `std::string_view` instance.
- 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 release builds, we recommend setting the `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.
- Never seek to access a field twice (e.g., o["data"] and later again o["data"]). Instead capture once an ondemand::value and reuse it.
- If you must access several different keys in an object, it might be preferable to iterate through all the fields in the object instead, and branch on the field keys.
- If you must access several different keys in an object, it might be preferable to iterate through all the fields in the object instead, and branch on the field keys. Consider this example.
```cpp
auto json = R"({"price": 123.456789, "volume": 9999,
"timestamp": "2025-09-04T09:45:00Z",
"symbol": "XYZ", "currency": "USD", "change": 1.23,
"isActive": true})"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
for(auto keyvalue : doc.get_object()) {
simdjson::ondemand::raw_json_string key = keyvalue.key();
switch(key[0]) {
case 'p': // price
if (key == "price") {
std::string_view price_str = keyvalue.value().raw_json();
std::cout << "Price: " << price_str << std::endl;
}
break;
case 'v': // volume
if (key == "volume") {
std::string_view volume_str = keyvalue.value().raw_json();
std::cout << "Volume: " << volume_str << std::endl;
}
break;
case 't': // timestamp
if (key == "timestamp") {
std::string_view timestamp = keyvalue.value();
std::cout << "Timestamp: " << timestamp << std::endl;
}
break;
default: break;
}
}
```
- If possible, refer to each object and array in your code once. For example, the following code repeatedly refers to the `"data"` key to create an object...
```C++
std::string_view make = o["data"]["make"];
+2 -2
View File
@@ -46,7 +46,7 @@ After writting the content, if you have reasons to believe that the content migh
- `validate_unicode()`: Checks if the content in the JSON buffer is valid UTF-8. Returns: true if the content is valid UTF-8, false otherwise.
You might need to do unicode validation if you have strings in your data structures containing
malformed UTF-8.
malformed UTF-8. Note that we do not automatically call `validate_unicode()`.
Once you are satisfied, you can recover the string as follows:
@@ -54,7 +54,7 @@ Once you are satisfied, you can recover the string as follows:
- `operator std::string_view()`: Converts the JSON buffer to an std::string_view. (Might throw if an error occurred.)
- `view()`: Returns a view of the written JSON buffer as a `simdjson_result<std::string_view>`.
The later method (`view()`) is recommended.
The later method (`view()`) is recommended. For performance reasons, we expect you to explicitly call `validate_unicode()` as needed (e.g., prior to calling `view()`).
Example: string_builder
---------------------------
+1 -1
View File
@@ -18,7 +18,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
auto error = parser.parse(str).get(elem);
if (error) { return 0; }
std::string minified=simdjson::minify(elem);
std::string minified = simdjson::minify(elem);
(void)minified;
return 0;
}
+1
View File
@@ -10,6 +10,7 @@
#include "simdjson/error.h"
#include "simdjson/portability.h"
#include "simdjson/concepts.h"
#include "simdjson/constevalutil.h"
/**
* @brief The top level simdjson namespace, containing everything the library provides.
+53
View File
@@ -0,0 +1,53 @@
#ifndef SIMDJSON_CONSTEVALUTIL_H
#define SIMDJSON_CONSTEVALUTIL_H
#include <string>
#include <string_view>
#include <array>
#if SIMDJSON_CONSTEVAL
namespace simdjson {
namespace constevalutil {
constexpr static std::array<uint8_t, 256> json_quotable_character = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
constexpr static std::array<std::string_view, 32> control_chars = {
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006",
"\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r",
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014",
"\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
"\\u001c", "\\u001d", "\\u001e", "\\u001f"};
// unoptimized, meant for compile-time execution
consteval std::string consteval_to_quoted_escaped(std::string_view input) {
std::string out = "\"";
for (char c : input) {
if (json_quotable_character[uint8_t(c)]) {
if (c == '"') {
out.append("\\\"");
} else if (c == '\\') {
out.append("\\\\");
} else {
std::string_view v = control_chars[uint8_t(c)];
out.append(v);
}
} else {
out.push_back(c);
}
}
out.push_back('"');
return out;
}
} // namespace constevalutil
} // namespace simdjson
#endif // SIMDJSON_CONSTEVAL
#endif // SIMDJSON_CONSTEVALUTIL_H
+31
View File
@@ -67,8 +67,38 @@ simdjson_inline error_code simdjson_result_base<T>::error() const noexcept {
return this->second;
}
template<typename T>
simdjson_inline bool simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<internal::simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -93,6 +123,7 @@ simdjson_inline simdjson_result_base<T>::operator T&&() && noexcept(false) {
#endif // SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline const T& simdjson_result_base<T>::value_unsafe() const& noexcept {
return this->first;
+28 -1
View File
@@ -108,6 +108,10 @@ namespace internal {
/**
* The result of a simdjson operation that could fail.
*
* IMPORTANT: For the ondemand API, we use implementation_simdjson_result_base<T> as a base class
* to avoid some compilation issue. Thus, if you modify this class, please ensure that the ondemand
* implementation_simdjson_result_base<T> is also modified.
*
* Gives the option of reading error codes, or throwing an exception by casting to the desired result.
*
* This is a base class for implementations that want to add functions to the result type for
@@ -168,8 +172,27 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
* Dereference operator to access the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
/**
* Get the result value.
*
@@ -253,6 +276,7 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
*/
template<typename T>
struct simdjson_result : public internal::simdjson_result_base<T> {
/**
* @private Create a new empty result with error = UNINITIALIZED.
*/
@@ -306,8 +330,11 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
*/
simdjson_inline error_code error() const noexcept;
#if SIMDJSON_EXCEPTIONS
#if SIMDJSON_EXCEPTIONS
using internal::simdjson_result_base<T>::operator*;
using internal::simdjson_result_base<T>::operator->;
/**
* Get the result value.
*
@@ -33,8 +33,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -74,6 +74,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -81,6 +86,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -942,6 +942,9 @@ public:
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
#if SIMDJSON_EXCEPTIONS
using SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator*;
using SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::document>::operator->;
template <class T, typename std::enable_if<std::is_same<T, SIMDJSON_IMPLEMENTATION::ondemand::document>::value == false>::type>
explicit simdjson_inline operator T() noexcept(false);
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
@@ -13,7 +13,7 @@
#include <charconv>
#include <cstring>
#include <experimental/meta>
#include <meta>
#include <memory>
#include <optional>
#include <string_view>
@@ -89,9 +89,6 @@ template<typename number_type,
constexpr void atom(string_builder &b, const number_type t) {
b.append(t);
}
#if SIMDJSON_CONSTEVAL
consteval std::string consteval_to_quoted_escaped(std::string_view input);
#endif
template <class T>
requires(std::is_class_v<T> && !container_but_not_string<T> &&
@@ -106,10 +103,10 @@ template <class T>
constexpr void atom(string_builder &b, const T &t) {
int i = 0;
b.append('{');
[:expand(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked())):] >> [&]<auto dm>() {
template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
if (i != 0)
b.append(',');
constexpr auto key = std::define_static_string(consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
b.append_raw(key);
b.append(':');
atom(b, t.[:dm:]);
@@ -143,21 +140,16 @@ template <typename T>
requires(std::is_enum_v<T>)
void atom(string_builder &b, const T &e) {
#if SIMDJSON_STATIC_REFLECTION
std::string_view result = "<unnamed>";
[:expand(std::meta::enumerators_of(^^T)):] >> [&]<auto enum_val>{
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
template for (constexpr auto enum_val : enumerators) {
constexpr auto enum_str = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(enum_val)));
if (e == [:enum_val:]) {
result = std::meta::identifier_of(enum_val);
b.append_raw(enum_str);
return;
}
};
if (result != "<unnamed>") {
b.append_raw("\"");
b.append_raw(result);
b.append_raw("\"");
} else {
// Fallback to integer if enum value not found
atom(b, static_cast<std::underlying_type_t<T>>(e));
}
// Fallback to integer if enum value not found
atom(b, static_cast<std::underlying_type_t<T>>(e));
#else
// Fallback: serialize as integer if reflection not available
atom(b, static_cast<std::underlying_type_t<T>>(e));
@@ -241,10 +233,10 @@ template <class Z>
void append(string_builder &b, const Z &z) {
int i = 0;
b.append('{');
[:expand(std::meta::nonstatic_data_members_of(^^Z, std::meta::access_context::unchecked())):] >> [&]<auto dm>() {
template for (constexpr auto dm : std::define_static_array(std::meta::nonstatic_data_members_of(^^Z, std::meta::access_context::unchecked()))) {
if (i != 0)
b.append(',');
constexpr auto key = std::define_static_string(consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
constexpr auto key = std::define_static_string(constevalutil::consteval_to_quoted_escaped(std::meta::identifier_of(dm)));
b.append_raw(key);
b.append(':');
atom(b, z.[:dm:]);
@@ -155,12 +155,17 @@ find_next_json_quotable_character(const std::string_view view,
}
SIMDJSON_CONSTEXPR_LAMBDA static std::string_view control_chars[] = {
"\\x0000", "\\x0001", "\\x0002", "\\x0003", "\\x0004", "\\x0005", "\\x0006",
"\\x0007", "\\x0008", "\\t", "\\n", "\\x000b", "\\f", "\\r",
"\\x000e", "\\x000f", "\\x0010", "\\x0011", "\\x0012", "\\x0013", "\\x0014",
"\\x0015", "\\x0016", "\\x0017", "\\x0018", "\\x0019", "\\x001a", "\\x001b",
"\\x001c", "\\x001d", "\\x001e", "\\x001f"};
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006",
"\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r",
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014",
"\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
"\\u001c", "\\u001d", "\\u001e", "\\u001f"};
// All Unicode characters may be placed within the quotation marks, except for the
// characters that MUST be escaped: quotation mark, reverse solidus, and the control
// characters (U+0000 through U+001F).
// There are two-character sequence escape representations of some popular characters:
// \", \\, \b, \f, \n, \r, \t.
SIMDJSON_CONSTEXPR_LAMBDA void escape_json_char(char c, char *&out) {
if (c == '"') {
memcpy(out, "\\\"", 2);
@@ -201,29 +206,6 @@ inline size_t write_string_escaped(const std::string_view input, char *out) {
return out - initout;
}
#if SIMDJSON_CONSTEVAL
// unoptimized, meant for compile-time execution
consteval std::string consteval_to_quoted_escaped(std::string_view input) {
std::string out = "\"";
for (char c : input) {
if (json_quotable_character[uint8_t(c)]) {
if (c == '"') {
out.append("\\\"");
} else if (c == '\\') {
out.append("\\\\");
} else {
std::string_view v = control_chars[uint8_t(c)];
out.append(v);
}
} else {
out.push_back(c);
}
}
out.push_back('"');
return out;
}
#endif // SIMDJSON_CONSTEVAL
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),
@@ -15,8 +15,13 @@ namespace ondemand {
simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
simdjson_inline const char * raw_json_string::raw() const noexcept {
return reinterpret_cast<const char *>(buf);
}
simdjson_inline char raw_json_string::operator[](size_t i) const noexcept {
return reinterpret_cast<const char *>(buf)[i];
}
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0};
@@ -193,6 +198,10 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
if (error()) { return error(); }
return first.raw();
}
simdjson_inline char simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::operator[](size_t i) const noexcept {
if (error()) { return error(); }
return first[i];
}
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept {
if (error()) { return error(); }
return first.unescape(iter, allow_replacement);
@@ -58,6 +58,12 @@ public:
*/
simdjson_inline const char * raw() const noexcept;
/**
* Get the character at index i. This is unchecked.
* [0] when the string is of length 0 returns the final quote (").
*/
simdjson_inline char operator[](size_t i) const noexcept;
/**
* This compares the current instance to the std::string_view target: returns true if
* they are byte-by-byte equal (no escaping is done) on target.size() characters,
@@ -197,10 +203,10 @@ public:
simdjson_inline ~simdjson_result() noexcept = default; ///< @private
simdjson_inline simdjson_result<const char *> raw() const noexcept;
simdjson_inline char operator[](size_t) const noexcept;
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept;
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept;
};
} // namespace simdjson
#endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_H
@@ -253,7 +253,9 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deser
using value_type = typename std::remove_cvref_t<T>::value_type;
// Check if the value is null
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset(); // Set to nullopt
return SUCCESS;
}
@@ -275,32 +277,6 @@ constexpr bool user_defined_type = (std::is_class_v<T>
!concepts::appendable_containers<T> && !require_custom_serialization<T>);
// workaround from
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2996r10.html#back-and-forth
// for missing expansion statements
namespace __impl {
template<auto... vals>
struct replicator_type {
template<typename F>
constexpr void operator>>(F body) const {
(body.template operator()<vals>(), ...);
}
};
template<auto... vals>
replicator_type<vals...> replicator = {};
}
template<typename R>
consteval auto expand(R range) {
std::vector<std::meta::info> args;
for (auto r : range) {
args.push_back(reflect_constant(r));
}
return substitute(^^__impl::replicator, args);
}
// end of workaround
template <typename T, typename ValT>
requires(user_defined_type<T> && std::is_class_v<T>)
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
@@ -311,9 +287,8 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
SIMDJSON_TRY(val.get_object().get(obj));
}
error_code e = simdjson::SUCCESS;
[:expand(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked())):] >> [&]<auto mem>() {
if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
template for (constexpr auto mem : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
// Note: removed static assert as optional types are now handled generically
// as long we are succesful or the field is not found, we continue
@@ -332,16 +307,15 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
#if SIMDJSON_STATIC_REFLECTION
std::string_view str;
SIMDJSON_TRY(val.get_string().get(str));
bool found = false;
[:expand(std::meta::enumerators_of(^^T)):] >> [&]<auto enum_val>{
if (!found && str == std::meta::identifier_of(enum_val)) {
constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
template for (constexpr auto enum_val : enumerators) {
if (str == std::meta::identifier_of(enum_val)) {
out = [:enum_val:];
found = true;
return SUCCESS;
}
};
return found ? SUCCESS : INCORRECT_TYPE;
return INCORRECT_TYPE;
#else
// Fallback: deserialize as integer if reflection not available
std::underlying_type_t<T> int_val;
@@ -389,7 +363,9 @@ error_code tag_invoke(deserialize_tag, simdjson_value &val, std::shared_ptr<T> &
// Unique pointers
////////////////////////////////////////
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<bool> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -402,7 +378,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<bool> &out) no
}
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int64_t> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -415,7 +393,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int64_t> &out)
}
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<uint64_t> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -428,7 +408,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<uint64_t> &out
}
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<double> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -441,7 +423,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<double> &out)
}
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string_view> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -458,7 +442,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string_vi
// Shared pointers
////////////////////////////////////////
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<bool> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -471,7 +457,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<bool> &out) no
}
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<int64_t> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -484,7 +472,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<int64_t> &out)
}
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<uint64_t> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -497,7 +487,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<uint64_t> &out
}
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<double> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -510,7 +502,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<double> &out)
}
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string_view> &out) noexcept {
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset();
return SUCCESS;
}
@@ -532,7 +526,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string_vi
////////////////////////////////////////
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string> &out) noexcept {
// Check if the value is null
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset(); // Set to nullptr
return SUCCESS;
}
@@ -548,7 +544,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string> &
error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string> &out) noexcept {
// Check if the value is null
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset(); // Set to nullptr
return SUCCESS;
}
@@ -564,7 +562,9 @@ error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string> &
error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int> &out) noexcept {
// Check if the value is null
if (val.is_null()) {
bool is_null_value;
SIMDJSON_TRY( val.is_null().get(is_null_value) );
if (is_null_value) {
out.reset(); // Set to nullptr
return SUCCESS;
}
+3 -1
View File
@@ -79,7 +79,9 @@ public:
using value_type = typename std::remove_cvref_t<T>::value_type;
// Check if the value is null
if (is_null()) {
bool is_null_value;
SIMDJSON_TRY( is_null().get(is_null_value) );
if (is_null_value) {
out.reset(); // Set to nullopt
return SUCCESS;
}
+16
View File
@@ -45,6 +45,22 @@ using std::size_t;
#define SIMDJSON_IS_ARM64 1
#elif defined(__riscv) && __riscv_xlen == 64
#define SIMDJSON_IS_RISCV64 1
#if __riscv_v_intrinsic >= 11000
#define SIMDJSON_HAS_RVV_INTRINSICS 1
#endif
#define SIMDJSON_HAS_ZVBB_INTRINSICS \
0 // there is currently no way to detect this
#if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && \
__riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
// RISC-V V extension
#define SIMDJSON_IS_RVV 1
#if SIMDJSON_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000
// RISC-V Vector Basic Bit-manipulation
#define SIMDJSON_IS_ZVBB 1
#endif
#endif
#elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64)
+2 -2
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "4.0.0"
#define SIMDJSON_VERSION "4.0.2"
namespace simdjson {
enum {
@@ -19,7 +19,7 @@ enum {
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 0
SIMDJSON_VERSION_REVISION = 2
};
} // namespace simdjson
+33
View File
@@ -78,3 +78,36 @@ You can modify the source code with your favorite editor and run again steps 5 (
You can create a new docker shell at any time by running step 3 (bash script).
## Using static reflection in your own projects
You can import simdjson in your own CMake project. You can configure your project like so:
```
# Fetch simdjson from GitHub
# Replace GIT_TAG by the commit you require.
include(FetchContent)
FetchContent_Declare(
simdjson
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
GIT_TAG 015daad6a95a4f67c08ed5980d24b57be221c38f
CMAKE_ARGS -DSIMDJSON_STATIC_REFLECTION=ON
)
FetchContent_MakeAvailable(simdjson)
##########
# You may also use CPM.
# https://github.com/cpm-cmake/CPM.cmake
# CPMAddPackage(
# NAME simdjson
# GITHUB_REPOSITORY simdjson/simdjson
# GIT_TAG 015daad6a95a4f67c08ed5980d24b57be221c38f
# OPTIONS "SIMDJSON_STATIC_REFLECTION ON"
# )
target_link_libraries(webservice PRIVATE simdjson::simdjson)
```
Replace the `GIT_TAG` by the appropriate value.
Once C++26 support will be officially available in mainstream compilers,
we will simplify these instructions and it will no longer be needed
to specify `SIMDJSON_STATIC_REFLECTION`.
+1 -1
View File
@@ -1,5 +1,5 @@
var fs = require('fs');
var fs = require('node:fs');
var faker = require('faker');
+34
View File
@@ -22,6 +22,9 @@ rules = """
We refer your to the HACKING.md file for more information on how the project is organized.
If you are trying to add a new implementation, you need to edit the amalgamate.py script
to add your implementation to the IMPLEMENTATIONS list.
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
@@ -480,11 +483,42 @@ AMAL_C = os.path.join(AMALGAMATE_OUTPUT_PATH, "simdjson.cpp")
DEMOCPP = os.path.join(AMALGAMATE_OUTPUT_PATH, "amalgamate_demo.cpp")
README = os.path.join(AMALGAMATE_OUTPUT_PATH, "README.md")
def validate_implementations():
"""Scan include/simdjson/*/implementation.h and compare with IMPLEMENTATIONS list."""
include_simdjson_path = os.path.join(PROJECTPATH, 'include', 'simdjson')
found_implementations = set()
if os.path.exists(include_simdjson_path):
for item in os.listdir(include_simdjson_path):
item_path = os.path.join(include_simdjson_path, item)
if os.path.isdir(item_path):
impl_h_path = os.path.join(item_path, 'implementation.h')
if os.path.exists(impl_h_path) and item != 'builtin': # Ignore builtin
found_implementations.add(item)
expected_implementations = set(IMPLEMENTATIONS)
if found_implementations != expected_implementations:
missing = expected_implementations - found_implementations
extra = found_implementations - expected_implementations
warning = "Warning: IMPLEMENTATIONS list does not match found implementations.\n"
if missing:
warning += f"Missing in filesystem: {sorted(missing)}\n"
if extra:
warning += f"Extra in filesystem: {sorted(extra)}\n"
print(warning)
return False
return True
def read_version():
with open(os.path.join(PROJECTPATH, 'include/simdjson/simdjson_version.h')) as f:
return re.search(r'\d+\.\d+\.\d+', f.read()).group(0)
version = read_version()
if not validate_implementations():
print("Validation failed. Please update IMPLEMENTATIONS list in amalgamate.py.")
sys.exit(1)
else:
print("implementation validated")
Amalgamator.amalgamate(AMAL_H, "simdjson.h", ['include'], timestamp, version).validate_all_files_used('include')
Amalgamator.amalgamate(AMAL_C, "simdjson.cpp", ['src', 'include'], timestamp, version).validate_all_files_used('src')
+484 -2
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2025-08-19 20:53:13 -0400. version 4.0.0 Do not edit! */
/* auto-generated on 2025-09-14 09:01:41 -0600. version 4.0.2 Do not edit! */
/* including simdjson.cpp: */
/* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP
@@ -193,6 +193,22 @@ using std::size_t;
#define SIMDJSON_IS_ARM64 1
#elif defined(__riscv) && __riscv_xlen == 64
#define SIMDJSON_IS_RISCV64 1
#if __riscv_v_intrinsic >= 11000
#define SIMDJSON_HAS_RVV_INTRINSICS 1
#endif
#define SIMDJSON_HAS_ZVBB_INTRINSICS \
0 // there is currently no way to detect this
#if SIMDJSON_HAS_RVV_INTRINSICS && __riscv_vector && \
__riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
// RISC-V V extension
#define SIMDJSON_IS_RVV 1
#if SIMDJSON_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000
// RISC-V Vector Basic Bit-manipulation
#define SIMDJSON_IS_ZVBB 1
#endif
#endif
#elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64)
@@ -2574,6 +2590,10 @@ namespace internal {
/**
* The result of a simdjson operation that could fail.
*
* IMPORTANT: For the ondemand API, we use implementation_simdjson_result_base<T> as a base class
* to avoid some compilation issue. Thus, if you modify this class, please ensure that the ondemand
* implementation_simdjson_result_base<T> is also modified.
*
* Gives the option of reading error codes, or throwing an exception by casting to the desired result.
*
* This is a base class for implementations that want to add functions to the result type for
@@ -2634,8 +2654,27 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
* Dereference operator to access the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
/**
* Get the result value.
*
@@ -2719,6 +2758,7 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
*/
template<typename T>
struct simdjson_result : public internal::simdjson_result_base<T> {
/**
* @private Create a new empty result with error = UNINITIALIZED.
*/
@@ -2772,8 +2812,11 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
*/
simdjson_inline error_code error() const noexcept;
#if SIMDJSON_EXCEPTIONS
#if SIMDJSON_EXCEPTIONS
using internal::simdjson_result_base<T>::operator*;
using internal::simdjson_result_base<T>::operator->;
/**
* Get the result value.
*
@@ -2975,6 +3018,62 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
#endif // SIMDJSON_SUPPORTS_CONCEPTS
#endif // SIMDJSON_CONCEPTS_H
/* end file simdjson/concepts.h */
/* including simdjson/constevalutil.h: #include "simdjson/constevalutil.h" */
/* begin file simdjson/constevalutil.h */
#ifndef SIMDJSON_CONSTEVALUTIL_H
#define SIMDJSON_CONSTEVALUTIL_H
#include <string>
#include <string_view>
#include <array>
#if SIMDJSON_CONSTEVAL
namespace simdjson {
namespace constevalutil {
constexpr static std::array<uint8_t, 256> json_quotable_character = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
constexpr static std::array<std::string_view, 32> control_chars = {
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006",
"\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r",
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014",
"\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
"\\u001c", "\\u001d", "\\u001e", "\\u001f"};
// unoptimized, meant for compile-time execution
consteval std::string consteval_to_quoted_escaped(std::string_view input) {
std::string out = "\"";
for (char c : input) {
if (json_quotable_character[uint8_t(c)]) {
if (c == '"') {
out.append("\\\"");
} else if (c == '\\') {
out.append("\\\\");
} else {
std::string_view v = control_chars[uint8_t(c)];
out.append(v);
}
} else {
out.push_back(c);
}
}
out.push_back('"');
return out;
}
} // namespace constevalutil
} // namespace simdjson
#endif // SIMDJSON_CONSTEVAL
#endif // SIMDJSON_CONSTEVALUTIL_H
/* end file simdjson/constevalutil.h */
/**
* @brief The top level simdjson namespace, containing everything the library provides.
@@ -4702,8 +4801,38 @@ simdjson_inline error_code simdjson_result_base<T>::error() const noexcept {
return this->second;
}
template<typename T>
simdjson_inline bool simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<internal::simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -4728,6 +4857,7 @@ simdjson_inline simdjson_result_base<T>::operator T&&() && noexcept(false) {
#endif // SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline const T& simdjson_result_base<T>::value_unsafe() const& noexcept {
return this->first;
@@ -9158,6 +9288,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -9165,6 +9300,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -10583,8 +10728,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -15598,6 +15772,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -15605,6 +15784,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -17023,8 +17212,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -21893,6 +22111,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -21900,6 +22123,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -23318,8 +23551,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -28345,6 +28607,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -28352,6 +28619,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -29770,8 +30047,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -35156,6 +35462,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -35163,6 +35474,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -36581,8 +36902,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -41789,6 +42139,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -41796,6 +42151,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -43214,8 +43579,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -47868,6 +48262,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -47875,6 +48274,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -49293,8 +49702,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
@@ -53539,6 +53977,11 @@ struct implementation_simdjson_result_base {
*/
simdjson_inline error_code error() const noexcept;
/**
* Whether there is a value.
*/
simdjson_inline bool has_value() const noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -53546,6 +53989,16 @@ struct implementation_simdjson_result_base {
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T& operator*() & noexcept(false);
simdjson_inline T&& operator*() && noexcept(false);
/**
* Arrow operator to access members of the contained value.
*
* @throw simdjson_error if there was an error.
*/
simdjson_inline T* operator->() noexcept(false);
simdjson_inline const T* operator->() const noexcept(false);
simdjson_inline T& value() & noexcept(false);
/**
@@ -54964,8 +55417,37 @@ simdjson_inline error_code implementation_simdjson_result_base<T>::error() const
return this->second;
}
template<typename T>
simdjson_inline bool implementation_simdjson_result_base<T>::has_value() const noexcept {
return this->error() == SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::operator*() & noexcept(false) {
return this->value();
}
template<typename T>
simdjson_inline T&& implementation_simdjson_result_base<T>::operator*() && noexcept(false) {
return std::forward<implementation_simdjson_result_base<T>>(*this).value();
}
template<typename T>
simdjson_inline T* implementation_simdjson_result_base<T>::operator->() noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline const T* implementation_simdjson_result_base<T>::operator->() const noexcept(false) {
if (this->error()) { throw simdjson_error(this->error()); }
return &this->first;
}
template<typename T>
simdjson_inline T& implementation_simdjson_result_base<T>::value() & noexcept(false) {
if (error()) { throw simdjson_error(error()); }
+1238 -804
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
@@ -16,6 +16,66 @@ struct Car {
namespace builder_tests {
using namespace std;
bool allchar_test() {
TEST_START();
auto get_utf8_codepoints = []() -> std::string {
std::string result;
for (char32_t cp = 0; cp <= 0x10FFFF; ++cp) {
if ((cp >= 0xD800 && cp <= 0xDFFF) || cp > 0x10FFFF) {
continue; // Skip surrogate pairs and invalid codepoints
}
if (cp < 0x80) {
result += static_cast<char>(cp);
} else if (cp < 0x800) {
result += static_cast<char>(0xC0 | (cp >> 6));
result += static_cast<char>(0x80 | (cp & 0x3F));
} else if (cp < 0x10000) {
result += static_cast<char>(0xE0 | (cp >> 12));
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
result += static_cast<char>(0x80 | (cp & 0x3F));
} else {
result += static_cast<char>(0xF0 | (cp >> 18));
result += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
result += static_cast<char>(0x80 | (cp & 0x3F));
}
}
return result;
};
auto allutf8 = get_utf8_codepoints();
simdjson::builder::string_builder sb;
sb.start_object();
sb.append_key_value("input", allutf8);
sb.end_object();
std::string_view p;
ASSERT_TRUE(sb.validate_unicode());
auto result = sb.view().get(p);
ASSERT_SUCCESS(result);
simdjson::padded_string output = p;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(output).get(doc));
std::string_view recovered;
ASSERT_SUCCESS(doc["input"].get(recovered));
ASSERT_EQUAL(recovered, allutf8);
simdjson::dom::parser domparser;
simdjson::dom::element elem;
ASSERT_SUCCESS(domparser.parse(output).get(elem));
ASSERT_SUCCESS(elem["input"].get(recovered));
ASSERT_EQUAL(recovered, allutf8);
TEST_SUCCEED();
}
bool bad_utf8_test() {
TEST_START();
std::string bad_utf8 = "\xFF";
simdjson::builder::string_builder sb;
sb.start_object();
sb.append_key_value("input", bad_utf8);
sb.end_object();
ASSERT_FALSE(sb.validate_unicode())
TEST_SUCCEED();
}
#if SIMDJSON_EXCEPTIONS
bool string_convertion_except() {
TEST_START();
@@ -449,6 +509,8 @@ namespace builder_tests {
#endif
bool run() {
return
allchar_test() &&
bad_utf8_test() &&
various_integers() &&
various_unsigned_integers() &&
car_test_long() &&
@@ -131,6 +131,7 @@ namespace builder_tests {
// Deserialize
ondemand::parser parser;
std::cout << json << std::endl;
auto doc_result = parser.iterate(pad(json));
ASSERT_SUCCESS(doc_result);
+13
View File
@@ -1795,6 +1795,18 @@ namespace validate_tests {
return true;
}
bool shall_not_parse() {
std::cout << "Running " << __func__ << std::endl;
auto test = "{\"joe\":\"\xf0\x8f\xbf\xbf\"}"_padded;
simdjson::dom::parser parser;
simdjson::dom::element doc;
auto error = parser.parse(test).get(doc);
if(error) {
return true; // expected
}
return false;
}
bool test_validate() {
std::cout << "Running " << __func__ << std::endl;
const std::string test = R"({ "foo" : 1, "bar" : [ 1, 2, 3 ], "baz": { "a": 1, "b": 2, "c": 3 } })";
@@ -1860,6 +1872,7 @@ namespace validate_tests {
}
bool run() {
return issue1187() &&
shall_not_parse() &&
test_range() &&
test_issue1169_long() &&
test_issue1169() &&
+2 -1
View File
@@ -8,7 +8,7 @@
using namespace simdjson;
namespace ranges_test {
#if SIMDJSON_EXCEPTIONS
bool printout() {
TEST_START();
auto cars_json = R"( [
@@ -43,6 +43,7 @@ namespace ranges_test {
ASSERT_TRUE(std::ranges::equal(cars, expected));
TEST_SUCCEED();
}
#endif // SIMDJSON_EXCEPTIONS
bool run() {
return
+77
View File
@@ -7,6 +7,39 @@
#include <string>
#include <vector>
#if SIMDJSON_STATIC_REFLECTION
class MyDate {
public:
void assign(std::string_view str) {
date_str = str;
}
const std::string& to_string() const {
return date_str;
}
private:
std::string date_str;
};
namespace simdjson {
template <typename simdjson_value>
auto tag_invoke(deserialize_tag, simdjson_value &val, MyDate& date) {
std::string_view str;
auto error = val.get_string().get(str);
if(error) { return error; }
date.assign(str);
return simdjson::SUCCESS;
}
} // namespace simdjson
struct complicated_weather_data {
std::vector<MyDate> time;
std::vector<float> temperature;
};
#endif
#ifdef __cpp_lib_ranges
namespace convert_tests {
@@ -87,6 +120,47 @@ bool simple() {
TEST_SUCCEED();
}
struct BadPlayer {
int username; // Oops, should be string!
int level;
double health;
};
#if SIMDJSON_STATIC_REFLECTION
bool bad_player() {
TEST_START();
// username is a string but we declared it as an int
std::string json = R"({"username":"Alice","level":42,"health":100.0})";
simdjson::padded_string padded(json);
BadPlayer p;
simdjson::ondemand::parser parser;
auto doc = parser.iterate(padded);
ASSERT_FAILURE(doc.get(p));
TEST_SUCCEED();
}
bool good_player() {
TEST_START();
std::string json = R"({"username":123,"level":42,"health":100.0})";
simdjson::padded_string padded(json);
BadPlayer p;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(padded).get(doc));
ASSERT_SUCCESS(doc.get(p));
TEST_SUCCEED();
}
bool complicated_weather_test() {
TEST_START();
std::string json = R"({"time":["2023-03-15T12:00:00Z"],"temperature":[42]})";
simdjson::padded_string padded(json);
complicated_weather_data p;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(padded).get(doc));
ASSERT_SUCCESS(doc.get(p));
TEST_SUCCEED();
}
#endif
bool broken() {
TEST_START();
simdjson::padded_string short_json_cars = R"( { "make )"_padded;
@@ -340,6 +414,9 @@ bool test_to_vs_from_equivalence() {
#endif // SIMDJSON_EXCEPTIONS
bool run() {
return
#if SIMDJSON_STATIC_REFLECTION
bad_player() && good_player() && complicated_weather_test() &&
#endif
#if SIMDJSON_EXCEPTIONS && SIMDJSON_SUPPORTS_CONCEPTS
broken() && simple() && simple_optional() && with_parser() && to_array() &&
to_bad_array() &&
+20
View File
@@ -397,6 +397,25 @@ namespace error_tests {
}
#endif // SIMDJSON_EXCEPTIONS
#if SIMDJSON_EXCEPTIONS
bool operator_tests() {
TEST_START();
ondemand::parser parser;
// Test successful case
auto json = R"({ "key": "value", "number": 42 })"_padded;
parser.iterate(json).value(); // Test operator*
*parser.iterate(json); // Test operator*
auto doc_result = parser.iterate(json);
ASSERT_SUCCESS(doc_result.error());
ASSERT_TRUE(doc_result.has_value());
double x = doc_result->find_field("number").get<double>();
ASSERT_EQUAL(x, 42.0);
TEST_SUCCEED();
}
#endif // SIMDJSON_EXCEPTIONS
bool run() {
return
issue2120() &&
@@ -419,6 +438,7 @@ namespace error_tests {
#if SIMDJSON_EXCEPTIONS
invalid_type() &&
simple_error_example_except() &&
operator_tests() &&
#endif
true;
}
@@ -1441,6 +1441,41 @@ bool simple_error_example() {
#include "simdjson.h"
#include <iostream>
void scan_json_object_keys() {
auto json = R"({"price": 123.456789, "volume": 9999,
"timestamp": "2025-09-04T09:45:00Z",
"symbol": "XYZ", "currency": "USD", "change": 1.23,
"isActive": true})"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
for(auto keyvalue : doc.get_object()) {
simdjson::ondemand::raw_json_string key = keyvalue.key();
switch(key[0]) {
case 'p': // price
if (key == "price") {
std::string_view price_str = keyvalue.value().raw_json();
std::cout << "Price: " << price_str << std::endl;
}
break;
case 'v': // volume
if (key == "volume") {
std::string_view volume_str = keyvalue.value().raw_json();
std::cout << "Volume: " << volume_str << std::endl;
}
break;
case 't': // timestamp
if (key == "timestamp") {
std::string_view timestamp = keyvalue.value();
std::cout << "Timestamp: " << timestamp << std::endl;
}
break;
default: break;
}
}
}
// prints the content of the array as hexadecimal 64-bit integers
void f(simdjson::ondemand::array v) {
for(uint64_t val : v) {