Compare commits

..

53 Commits

Author SHA1 Message Date
Daniel Lemire 8c1bfe782b Adds 'current_depth()'. (#1824) 2022-05-17 18:06:42 -04:00
Daniel Lemire 730939f01c Better documentation regarding the direct get_number_type() method. (#1821) 2022-05-13 15:31:09 -04:00
Daniel Lemire b169dc2ea7 Fixing get_number_type() (#1819) 2022-05-12 12:15:38 -04:00
Andrea Pappacoda 1aa1d537fe docs(basics): ondemand::element -> ::document (#1810)
simdjson::ondemand::element doesn't exist
2022-05-05 14:55:22 -04:00
Richard Ebeling c122462278 [skip ci] Fix accidental pastes in doc/basics.md (#1809)
Co-authored-by: Richard Ebeling <He3lixxx@users.noreply.github.com>
2022-05-02 08:13:55 -04:00
Daniel Lemire b6b338bea9 This simplifies the build somewhat by always including developer-options.cmake (#1806) 2022-04-27 12:51:04 -04:00
Dirk Stolle f72636b5b0 fix a typo in documentation (#1807) 2022-04-26 18:01:12 -04:00
Daniel Lemire f6a2bac11b what happens if we remove this check for CI? (#1804) 2022-04-23 14:09:22 -04:00
Daniel Lemire e4ddc5446b Fixing typo. 2022-04-10 08:16:46 -04:00
PavelP e0e0aa9e7b Update simdjson.h to include simdjson_version.h (#1794)
After this change amalgamated simdjson.h has version info at the beginning of the file.
2022-03-19 08:00:24 -04:00
Daniel Lemire 9f0a2e0e86 Update to vs17 (required) (#1795)
* Update to vs17 (required)

* Moving to windows-latest.

* Dropping old vs
2022-03-19 08:00:06 -04:00
Andrei Gritsiuk 203c03e90b resolves #1784 - GCC 11.1.0 and CLang 12.0.0 complain on 'and' operator in padded_string-inl.h (#1785)
Co-authored-by: Andrei <C:\Users\Andrei\AppData\Roaming\The Bat!>
2022-01-31 11:38:54 -05:00
Ivan Volnov 6698eb96b9 Fix C++20 build warnings (#1782) (#1787)
* Fix C++20 build warnings (#1782)

* Build fix for ppc64 (#1782)
2022-01-20 14:16:27 -05:00
pkubaj 30f7de387c Fix build on FreeBSD/powerpc64* (#1786)
FreeBSD uses sys/endian.h and bswap64().
2022-01-18 11:21:47 -05:00
Piotr Doan e0788507fe Missing value::get() template specialization for number (#1779) 2022-01-11 12:07:20 -05:00
Daniel Lemire e4740c87fb Update README.md 2022-01-11 12:05:16 -05:00
Daniel Lemire 5beef701e7 Update CONTRIBUTORS 2022-01-03 15:55:47 -05:00
Daniel Lemire c6f9c93c33 Use static variables to enforce initialization order. (#1773) (#1777)
Fixes https://github.com/simdjson/simdjson/issues/1771

Co-authored-by: Hao Chen <chenhao.yalier@gmail.com>
2022-01-03 15:54:57 -05:00
Daniel Lemire 3a93e45dd1 Removing scoop support. 2021-12-30 12:10:11 -05:00
Daniel Lemire 6db8ceb46c Verify and fix 1768. (#1769)
* Verify and fix 1768.

* Breaking down the namespaces for C++11 compilers.
2021-12-21 15:12:38 -05:00
Daniel Lemire 23651f0d41 Updating a macro. 2021-12-21 09:54:02 -05:00
N. Kolotov 7e1893db42 Added SIMDJSON_ prefix to STRINGIFY and to NO_SANITIZE_UNDEFINED macros. (#1766) 2021-12-21 09:53:06 -05:00
Daniel Lemire b4b1927b0f Making the documentation more explicit. (#1765) 2021-12-21 09:51:20 -05:00
Daniel Lemire e275589832 Update implementation-selection.md 2021-12-07 13:15:05 -05:00
epoll-reactor 69ee84973a Fix some typos in source files. (#1761)
Co-authored-by: epoll-reactor <>
2021-12-06 16:56:15 -05:00
epoll-reactor 76bed68ec3 Fix broken link in basics documentation. (#1760) 2021-12-04 12:21:08 -05:00
epoll-reactor 003d970cd2 Fix -Wredundant-decls warning in json_type.h. (#1759)
Co-authored-by: threadpoolexecutor <davidkor77@gmail.com>
2021-12-02 13:49:48 -05:00
DavidKorczynski 4aaf3f030c Add CIFuzz integration (#1757)
Signed-off-by: David Korczynski <david@adalogics.com>
2021-11-30 10:14:26 -05:00
Daniel Lemire 2763f7e719 Fixing issue 1755 (#1756) 2021-11-24 09:28:28 -05:00
strager 39035c39be Fix typos in comments (#1754) 2021-11-19 09:44:10 -05:00
strager ac179ff40f Fix broken links in documentation (#1753) 2021-11-12 08:47:22 -05:00
Tyler Kennedy b41bece32c Fix a couple of broken links in the basics.md TOC (#1752) 2021-11-07 19:58:32 -05:00
Daniel Lemire 9cb0c5f92d Patching. (#1750) 2021-11-05 19:46:57 -04:00
Daniel Lemire 1dec7b04fe Remark. 2021-11-05 13:32:45 -04:00
strager c6eb6f98b8 Fix typos in documentation (#1747)
The variable is called LOG_ENABLED, not ENABLE_LOGGING. Fix the
documentation in json_iterator.h.
2021-11-03 10:13:13 -04:00
Daniel Lemire 1b01969bda Adding tests for issue 1745. (#1746)
* Adding tests for issue 1745.

* Tweaking the documentation so that it is clearer.
2021-11-03 10:12:18 -04:00
Daniel Lemire 17f3148ac7 Version 1.0.2. 2021-10-27 19:29:42 -04:00
Daniel Lemire 35b4a48e99 Fixing issue 1742 (#1743)
* Fix for issue 1742.

* Some additional tests.
2021-10-27 19:25:23 -04:00
mir4cle c0d18452fc Add an option to get current location from value (#1738)
Co-authored-by: Igor Logvanev <igor.logvanev@aimtech.team>
2021-10-24 16:55:49 -04:00
Daniel Lemire e5c9a310cf Preparing release 1.0.1. 2021-10-20 12:18:04 -04:00
Daniel Lemire 6d308a08c5 Fixing issue 1736 (#1737)
* Fixing issue 1736

* Updating google benchmark.

* Minor trimming.

* Using the variable (to silence a warning).

* Adding assignment operator.
2021-10-20 12:15:35 -04:00
Daniel Lemire 9e477ddb00 Let us try to improve the documentation so that it is clearer. (#1733)
* Let us try to improve the documentation so that it is clearer.

* Minor tweaks.
2021-10-19 13:09:41 -04:00
Daniel Lemire b7c4d1eeef Adding test for issue 1729. (#1730)
* Adding test for issue 1729.

* Adding comment.

* Trying to move to 11.7.

* Tweaking.

* More tweaking.

* Adding additional test.

* Missing "<<".

* Minor update.

* Removing legacy systems.
2021-10-13 09:30:37 -04:00
Daniel Lemire 4a2f10ebcf Let us trim out these legacy systems from CI. 2021-10-12 18:24:03 -04:00
Daniel Lemire 41cb909604 Minor change to handle paranoid compilers. (#1732) 2021-10-12 17:23:45 -04:00
Daniel Lemire 91908ade4d Additional documentation following issue 1723 (#1724)
* Some extra documentation regarding issue 1723.

* Adding comments.

* Minor fix.

* [no ci] more documentation
2021-10-09 11:41:20 -04:00
Daniel Lemire 9a32c48098 Cleaning up the single-header demo. (#1731)
* Cleaning up the single-header demo.

* Updating xcode
2021-10-09 11:34:21 -04:00
Daniel Lemire d996ffc494 Minor typo. (#1721)
* Minor typo.

* Minor fixes.

* Patching...
2021-09-25 11:34:44 -04:00
Daniel Lemire d56fdc3d04 [no ci] deleting an irrelevant comment. 2021-09-22 18:06:59 -04:00
Daniel Lemire 1dce4fed6e [no ci] moving documentation bit to the right location. (#1719) 2021-09-20 09:33:21 -04:00
Daniel Lemire cae5e5342f Additional ndjson tests. (#1717)
* Additional ndjson tests.

* Switching the data source.

* Fixing.
2021-09-18 16:29:10 -04:00
Madhur Chauhan 4e609aa955 fix redundant ; in document-inl.h (#1715) 2021-09-17 14:02:03 -04:00
Paul Dreik d28e5534d9 ignore unused variable (#1714) 2021-09-12 17:37:58 -04:00
92 changed files with 1653 additions and 765 deletions
-42
View File
@@ -1,46 +1,4 @@
kind: pipeline
name: i386-gcc # we do not support 32-bit systems, but we run tests
platform: { os: linux, arch: amd64 }
steps:
- name: Build and Test
image: i386/ubuntu
environment:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
- apt-get install -y g++ cmake gcc git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: i386-clang # we do not support 32-bit systems, but we run tests
platform: { os: linux, arch: amd64 }
steps:
- name: Build and Test
image: i386/ubuntu
environment:
CC: clang-6.0
CXX: clang++-6.0
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
- apt-get install -y clang++-6.0 cmake git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: gcc9
platform: { os: linux, arch: amd64 }
steps:
+24
View File
@@ -0,0 +1,24 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'simdjson'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'simdjson'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
xcversion select 11.2.1
xcversion select 11.7
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
-63
View File
@@ -1,63 +0,0 @@
name: MinGW32-CI
on: [push, pull_request]
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-gcc
runs-on: windows-2016
env:
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
CC: gcc
CXX: g++
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
- uses: actions/checkout@v2
- uses: actions/cache@v2 # we cache the scoop setup with 32-bit GCC
id: cache
with:
path: |
C:\ProgramData\scoop
key: scoop32 # static key: should be good forever
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Setup Windows # This should almost never run if the cache works.
if: steps.cache.outputs.cache-hit != 'true'
shell: powershell
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
scoop install sudo --global
sudo scoop install git --global
sudo scoop install ninja --global
sudo scoop install cmake --global
sudo scoop install gcc --arch 32bit --global
$env:path
Write-Host 'Everything has been installed, you are good!'
- name: Build and Test 32-bit x86
shell: powershell
run: |
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
g++ --version
cmake --version
ninja --version
git --version
mkdir build32
cd build32
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
cmake --build . --target acceptance_tests --verbose
ctest -L acceptance --output-on-failure
-69
View File
@@ -1,69 +0,0 @@
name: MinGW64-CI
on: [push, pull_request]
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-gcc
runs-on: windows-2016
env:
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
CC: gcc
CXX: g++
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
- uses: actions/checkout@v2
- uses: actions/cache@v2 # we cache the scoop setup with 64-bit GCC
id: cache
with:
path: |
C:\ProgramData\scoop
key: scoop64 # static key: should be good forever
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Setup Windows # This should almost never run if the cache works.
if: steps.cache.outputs.cache-hit != 'true'
shell: powershell
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
scoop install sudo --global
sudo scoop install git --global
sudo scoop install ninja --global
sudo scoop install cmake --global
sudo scoop install gcc --arch 64bit --global
$env:path
Write-Host 'Everything has been installed, you are good!'
- name: Build and Test 64-bit x64
shell: powershell
run: |
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
g++ --version
cmake --version
ninja --version
git --version
mkdir build64
cd build64
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
cmake --build . --target acceptance_tests --verbose
ctest -L acceptance --output-on-failure
cd ..
mkdir build64debug
cd build64debug
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
cmake --build . --target acceptance_tests --verbose
ctest -L acceptance --output-on-failure
-6
View File
@@ -17,15 +17,9 @@ jobs:
- msystem: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Release
- msystem: "MINGW32"
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
type: Release
- msystem: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Debug
- msystem: "MINGW32"
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
type: Debug
env:
CMAKE_GENERATOR: Ninja
-6
View File
@@ -19,15 +19,9 @@ jobs:
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Release
- msystem: "MINGW32"
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
type: Release
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Debug
- msystem: "MINGW32"
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
type: Debug
env:
CMAKE_GENERATOR: Ninja
-44
View File
@@ -1,44 +0,0 @@
name: VS15-CI
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs15
runs-on: windows-2016
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 15 2017, arch: Win32, static: ON}
- {gen: Visual Studio 15 2017, arch: Win32, static: OFF}
- {gen: Visual Studio 15 2017, arch: x64, static: ON}
- {gen: Visual Studio 15 2017, arch: x64, static: OFF}
steps:
- name: checkout
uses: actions/checkout@v2
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
run: cmake --build build --config Release --verbose
- name: Run Release tests
run: |
cd build
ctest -C Release -LE explicitonly --output-on-failure
- name: Run Debug tests
run: |
cd build
ctest -C Debug -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config Release
- name: Test Installation
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
cmake --build build_install_test --config Release
@@ -1,10 +1,10 @@
name: VS16-ARM-CI
name: VS17-ARM-CI
on: [push, pull_request]
jobs:
ci:
name: windows-vs16
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
@@ -1,4 +1,4 @@
name: VS16-CI
name: VS17-CI
on: [push, pull_request]
@@ -7,16 +7,16 @@ jobs:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs16
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 16 2019, arch: Win32, static: ON}
- {gen: Visual Studio 16 2019, arch: Win32, static: OFF}
- {gen: Visual Studio 16 2019, arch: x64, static: ON}
- {gen: Visual Studio 16 2019, arch: x64, static: OFF}
- {gen: Visual Studio 17 2022, arch: Win32, static: ON}
- {gen: Visual Studio 17 2022, arch: Win32, static: OFF}
- {gen: Visual Studio 17 2022, arch: x64, static: ON}
- {gen: Visual Studio 17 2022, arch: x64, static: OFF}
steps:
- name: checkout
uses: actions/checkout@v2
@@ -1,4 +1,4 @@
name: VS16-CLANG-CI
name: VS17-CLANG-CI
on: [push, pull_request]
@@ -7,7 +7,7 @@ jobs:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs16
name: windows-vs17
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
@@ -15,7 +15,7 @@ jobs:
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS16 Clang'
- name: 'Run CMake with VS17 Clang'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
@@ -1,4 +1,4 @@
name: VS16-Ninja-CI
name: VS17-Ninja-CI
on: [push, pull_request]
@@ -7,7 +7,7 @@ jobs:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs16
name: windows-vs17
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
@@ -15,7 +15,7 @@ jobs:
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS16'
- name: 'Run CMake with VS17'
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
@@ -1,10 +1,10 @@
name: VS16-NoExcept-CI
name: VS17-NoExcept-CI
on: [push, pull_request]
jobs:
ci:
name: windows-vs16
name: windows-vs17
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
@@ -12,7 +12,7 @@ jobs:
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS16'
- name: 'Run CMake with VS17'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
+3 -11
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 1.0.0
VERSION 1.0.2
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -49,19 +49,10 @@ endif()
if(is_top_project)
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
if("$ENV{CI}")
set(SIMDJSON_DEVELOPER_MODE ON CACHE INTERNAL "")
endif()
endif()
include(cmake/handle-deprecations.cmake)
if(SIMDJSON_DEVELOPER_MODE)
include(cmake/developer-options.cmake)
else()
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
endif()
include(cmake/developer-options.cmake)
# ---- simdjson library ----
@@ -180,6 +171,7 @@ endif()
# ---- Developer mode extras ----
if(NOT SIMDJSON_DEVELOPER_MODE)
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
return()
elseif(NOT is_top_project)
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
+1
View File
@@ -37,5 +37,6 @@ Furkan Taşkale
Brendan Knapp
Danila Kutenin
Pavel Pavlov
Hao Chen
# if you have contributed to the project and your name does not
# appear in this list, please let us know!
+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 = "1.0.0"
PROJECT_NUMBER = "1.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
+1
View File
@@ -138,6 +138,7 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
About simdjson
+2 -2
View File
@@ -97,9 +97,9 @@ struct option_struct {
verbose = true;
break;
case 'a': {
auto impl = simdjson::available_implementations[optarg];
auto impl = simdjson::get_available_implementations()[optarg];
if(impl && impl->supported_by_runtime_system()) {
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
} else {
std::cerr << "implementation " << optarg << " not found or not supported " << std::endl;
}
+5 -5
View File
@@ -66,7 +66,7 @@ void print_usage(ostream& out) {
out << "-H - Make the buffers hot (reduce page allocation and related OS tasks during parsing) [default]" << endl;
out << "-a IMPL - Use the given parser implementation. By default, detects the most advanced" << endl;
out << " implementation supported on the host machine." << endl;
for (auto impl : simdjson::available_implementations) {
for (auto impl : simdjson::get_available_implementations()) {
if(impl->supported_by_runtime_system()) {
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << endl;
}
@@ -116,10 +116,10 @@ struct option_struct {
verbose = true;
break;
case 'a': {
const implementation *impl = simdjson::available_implementations[optarg];
const implementation *impl = simdjson::get_available_implementations()[optarg];
if ((!impl) || (!impl->supported_by_runtime_system())) {
std::string exit_message = string("Unsupported option value -a ") + optarg + ": expected -a with one of ";
for (auto imple : simdjson::available_implementations) {
for (auto imple : simdjson::get_available_implementations()) {
if(imple->supported_by_runtime_system()) {
exit_message += imple->name();
exit_message += " ";
@@ -127,7 +127,7 @@ struct option_struct {
}
exit_usage(exit_message);
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
case 'C':
@@ -175,7 +175,7 @@ int main(int argc, char *argv[]) {
option_struct options(argc, argv);
if (options.verbose) {
verbose_stream = &cout;
verbose() << "Implementation: " << simdjson::active_implementation->name() << endl;
verbose() << "Implementation: " << simdjson::get_active_implementation()->name() << endl;
}
// Start collecting events. We put this early so if it prints an error message, it's the
@@ -10,8 +10,8 @@ void maybe_display_implementation() {
static bool displayed_implementation = false;
if(!displayed_implementation) {
displayed_implementation = true;
std::cout << "simdjson::dom implementation: " << simdjson::active_implementation->name() << std::endl;
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::active_implementation->name() << std::endl;
std::cout << "simdjson::dom implementation: " << simdjson::get_active_implementation()->name() << std::endl;
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
std::cout << "simdjson::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
}
}
+2 -1
View File
@@ -13,8 +13,9 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_TESTING)
set_off(BENCHMARK_ENABLE_INSTALL)
set_off(BENCHMARK_ENABLE_WERROR)
import_dependency(google_benchmarks google/benchmark 8982e1e)
import_dependency(google_benchmarks google/benchmark f91b6b4)
add_dependency(google_benchmarks)
endif()
+82 -53
View File
@@ -16,10 +16,10 @@ An overview of what you need to know to use simdjson, with examples.
* [UTF-8 validation (alone)](#utf-8-validation-alone)
* [JSON Pointer](#json-pointer)
* [Error Handling](#error-handling)
* [Error Handling Example without Exceptions](#error-handling-example-without-exceptions)
* [Error Handling Example without Exceptions](#error-handling-examples-without-exceptions)
* [Disabling Exceptions](#disabling-exceptions)
* [Exceptions](#exceptions)
* [Current location in document](#current-location-in-documnet)
* [Current location in document](#current-location-in-document)
* [Rewinding](#rewinding)
* [Direct Access to the Raw String](#direct-access-to-the-raw-string)
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
@@ -54,6 +54,7 @@ c++ myproject.cpp simdjson.cpp
Note:
- 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++17 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`).
Using simdjson with package managers
------------------
@@ -127,19 +128,23 @@ The Basics: Loading and Parsing JSON Documents
----------------------------------------------
The simdjson library allows you to navigate and validate JSON documents ([RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html)).
As required by the standard, your JSON document should be Unicode (UTF-8) strings.
As required by the standard, your JSON document should be in a Unicode (UTF-8) string. The whole
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
inputs before or after a document.
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can access by creating a `ondemand::parser` and calling the `iterate()` method:
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
quickly indexes the input string and may detect some errors. The following example illustrates
how to get started with an input JSON file (`"twitter.json"`):
```c++
ondemand::parser parser;
auto json = padded_string::load("twitter.json");
auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json'.
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
```
Or by creating a padded string---for efficiency reasons, simdjson requires a string with a few
bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
You can also create a padded string---for efficiency reasons, simdjson requires a string
with a few bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
```c++
ondemand::parser parser;
@@ -196,7 +201,8 @@ allocations during parsing when using simdjson. [See our performance notes for d
C++11 Support and string_view
-------------
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11). It is also a strict requirement: we have no plan to support older C++ compilers.
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11).
It is also a strict requirement: we have no plan to support older C++ compilers.
We represent parsed Unicode (UTF-8) strings in simdjson using the `std::string_view` class. It avoids
the need to copy the data, as would be necessary with the `std::string` class. It also
@@ -214,7 +220,6 @@ is often best viewed as a temporary string value that is tied to the document yo
At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances:
`std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17).
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
available, we define the macro `SIMDJSON_HAS_STRING_VIEW`.
@@ -232,24 +237,38 @@ transcode the UTF-8 strings produced by the simdjson library to other formats. S
Using the Parsed JSON
---------------------
We recommend that you first compile and run your code in Debug mode (with `NDEBUG`
undefined). When you do so, the simdjson library runs additional sanity tests on
your code to help ensure that you are using the library in a safe manner. Once
your code has been tested, you can then run it in Release mode (with `NDEBUG`
defined) for best performance. Alternatively, 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.
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
idiomatic C++ iterators, operators and casts. Besides the documents instances and
idiomatic C++ iterators, operators and casts. Besides the document instances and
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
and arrays (`simdjson::ondemand::array`).
We also have a generic type (`simdjson::ondemand::value`) which represent 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`).
We also have a generic 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`).
Advanced users who need to determine the number types (integer or float) dynamically,
should review our section [dynamic number types](#dynamic-number-types). Indeed,
we have an additional `ondemand::number` type which may represent either integers
or floating-point values, depending on how the numbers are formatted.
floating-point values followed by an integer.
While you are accessing the document, the `document` instance should remain in scope:
it is your "iterator" which keeps track of where you are in the JSON document.
By design, there is one and only one `document` instance per JSON document.
We invite you to keep the following rules in mind:
1. While you are accessing the document, the `document` instance should remain in scope: it is your "iterator" which keeps track of where you are in the JSON document. By design, there is one and only one `document` instance per JSON document.
2. Because On Demand is really just an iterator, you must fully consume the current object or array before accessing a sibling object or array.
3. Values can only be consumed once, you should get the values and store them if you plan to need them multiple times. You are expected to access the keys of an object just once. You are expected to go through the values of an array just once.
The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
@@ -259,16 +278,24 @@ support for users who avoid exceptions. See [the simdjson error handling documen
However, it is not fully validated. On Demand only fully validates the values you use and the
structure leading to it.
* **Extracting Values:** You can cast a JSON element to a native type:
`double(element)` or `double x = json_element`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
ondemand::object and ondemand::array. At this point, the number, string or boolean will be parsed,
or the initial `[` or `{` will be verified. An exception is thrown if the cast is not possible.
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
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. An exception is thrown if
the cast is not possible.
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
> parsed a value (such as by casting to double), you cannot get at it again.
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
* **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. 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.
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. If you consume an
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]`, your code
is in error. Furthermore, you can only consume one field at a time, on the same object. Thus
if you have retrieved `content["bids"].get_array()` and you later call `content["asks"].get_array()`, then the
first array should no longer be accessed: it would be unsafe to do so. You can detect such mistakes by first
compiling and running the code in Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
@@ -683,30 +710,23 @@ auto cars_json = R"( [
] )"_padded;
ondemand::parser parser;
ondemand::document cars;
std::vector<double> measured;
parser.iterate(cars_json).get(cars);
ondemand::document cars = parser.iterate(cars_json);
std::vector<car_type> content;
for (int i = 0; i < 3; i++) {
ondemand::object obj;
std::string json_pointer = "/" + std::to_string(i);
// Each successive at_pointer call invalidates
// previously parsed values, strings, objects and array.
cars.at_pointer(json_pointer).get(obj);
ondemand::object obj(cars.at_pointer(json_pointer).get_object());
// We materialize the object.
std::string_view make;
ASSERT_SUCCESS(obj["make"].get(make));
std::string_view model;
ASSERT_SUCCESS(obj["model"].get(model));
uint64_t year;
ASSERT_SUCCESS(obj["year"].get(year));
std::string_view make = obj["make"];
std::string_view model = obj["model"];
uint64_t year(obj["year"]);
// We materialize the array.
ondemand::array arr;
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
ondemand::array arr(obj["tire_pressure"].get_array());
std::vector<double> values;
for(auto x : arr) {
double value_double;
ASSERT_SUCCESS(x.get(value_double));
double value_double(x.get_double());
values.push_back(value_double);
}
content.emplace_back(make, model, year, std::move(values));
@@ -741,12 +761,16 @@ The entire simdjson API is usable with and without exceptions. All simdjson APIs
pair. You can retrieve the value with .get() without generating an exception, like so:
```c++
ondemand::element doc;
ondemand::document doc;
auto error = parser.iterate(json).get(doc);
if (error) { cerr << error << endl; exit(1); }
```
When you use the code this way, it is your responsibility to check for error before using the
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
When you use the code without exceptions, it is your responsibility to check for error before using the
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
set of warnings: they can identify variables that are written to but never otherwise accessed.
@@ -868,6 +892,9 @@ int main(void) {
}
```
The `at` method can only be called once on an array. It cannot be used
to iterate through the values of an array.
### Error Handling Examples without Exceptions
This is how the example in "Using the Parsed JSON" could be written using only error code checking (without exceptions):
@@ -1119,7 +1146,7 @@ Direct Access to the Raw String
The simdjson library makes explicit assumptions about types. For examples, numbers
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
have different needs. For example, some users might want to support big infloating-point number followed by an integer.tegers.
have different needs. For example, some users might want to support big integers.
The library makes this possible by providing a `raw_json_token` method which returns
a `std::string_view` instance containing the value as a string which you may then
parse as you see fit.
@@ -1153,11 +1180,19 @@ The `raw_json_token()` should be fast and free of allocation.
Newline-Delimited JSON (ndjson) and JSON lines
----------------------------------------------
The simdjson library also supports multithreaded JSON streaming through a large file containing many
smaller JSON documents in either [ndjson](http://ndjson.org) or [JSON lines](http://jsonlines.org)
format. If your JSON documents all contain arrays or objects, we even support direct file
concatenation without whitespace. The concatenated file has no size restrictions (including larger
than 4GB), though each individual document must be no larger than 4 GB.
When processing large inputs (e.g., in the context of data engineering), engineers commonly
serialize data into streams of multiple JSON documents. That is, instead of one large
(e.g., 2 GB) JSON document containing multiple records, it is often preferable to
write out multiple records as independent JSON documents, to be read one-by-one.
The simdjson library also supports multithreaded JSON streaming through a large file
containing many smaller JSON documents in either [ndjson](http://ndjson.org)
or [JSON lines](http://jsonlines.org) format. If your JSON documents all contain arrays
or objects, we even support direct file concatenation without whitespace. However, if there
is content between your JSON documents, it should be exclusively ASCII white-space characters.
The concatenated file has no size restrictions (including larger than 4GB), though each
individual document must be no larger than 4 GB.
Here is an example:
@@ -1366,10 +1401,6 @@ You must check the type before accessing the value: it is an error to call `get_
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
If you only need to compute `v.get_number().get_number_type()` on
a `document` or `value` instance, you should call directly the faster method
`v.get_number_type()` which does not generate an
intermediate `number` instance.
Consider the following example:
```C++
@@ -1382,9 +1413,7 @@ Consider the following example:
std::cout << "negative: " << val.is_negative() << " ";
std::cout << "is_integer: " << val.is_integer() << " ";
ondemand::number num = val.get_number();
// direct computation without materializing the number:
ondemand::number_type dt = val.get_number_type();
if(t != dt) { throw std::runtime_error("bug"); }
ondemand::number_type t = num.get_number_type();
switch(t) {
case ondemand::number_type::signed_integer:
std::cout << "integer: " << int64_t(num) << " ";
@@ -1438,8 +1467,8 @@ The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.o
- A single string or a single number is considered to be a valid JSON document.
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
- We parse integers and floating-point numbers afloating-point number followed by an integer.s separate types which allows us to support all signed (two's complement) 64-bit integersfloating-point number followed by an integer., like a Java `long` or a C/C++ `long long` and all 64-bit unsigned integers. When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
- We support the full range of 64-bit floating-point numbers (binary64). The values range from `std::numeric_limits<double>::lowest()` to `std::numefloating-point number followed by an integer.ric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document. Numbers are parsed with a perfect accuracy (ULP 0): the nearest floating-point value is chosen, rounding to even when needed. If you serialized your floating-point numbers with 17floating-point value followed by an integer. significant digits in a standard compliant manner, the simdjson library is guaranfloating-point number followed by an integer.teed to recover the same numbers, exactly.
- We parse integers and floating-point numbers as separate types which allows us to support all signed (two's complement) 64-bit integers, like a Java `long` or a C/C++ `long long` and all 64-bit unsigned integers. When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
- We support the full range of 64-bit floating-point numbers (binary64). The values range from `std::numeric_limits<double>::lowest()` to `std::numeric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document. Numbers are parsed with a perfect accuracy (ULP 0): the nearest floating-point value is chosen, rounding to even when needed. If you serialized your floating-point numbers with 17 significant digits in a standard compliant manner, the simdjson library is guaranteed to recover the same numbers, exactly.
- The specification states that JSON text exchanged between systems that are not part of a closed ecosystem MUST be encoded using UTF-8. The simdjson library does full UTF-8 validation as part of the parsing. The specification states that implementations MUST NOT add a byte order mark: the simdjson library rejects documents starting with a byte order mark.
- The simdjson library validates string content for unescaped characters. Unescaped line breaks and tabs in strings are not allowed.
- The simdjson library accepts objects with repeated keys: all of the name/value pairs, including duplicates, are reported. We do not enforce key uniqueness.
+11 -4
View File
@@ -3,8 +3,8 @@ The Document-Object-Model (DOM) front-end
An overview of what you need to know to use simdjson, with examples.
* [DOM vs On Demand](#dom-vs-ondemand)
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
* [DOM vs On Demand](#dom-vs-on-demand)
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents-using-the-dom-front-end)
* [Using the Parsed JSON](#using-the-parsed-json)
* [C++17 Support](#c17-support)
* [JSON Pointer](#json-pointer)
@@ -81,7 +81,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
* **Object Iteration:** You can iterate through an object's fields, too: `for (auto [key, value] : object)`
* **Array Index:** To get at an array value by index, use the at() method: `array.at(0)` gets the
first element.
first element. The at() method has linear-time complexity so it should not be used to iterate over the values of an array.
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
> O(1) operation, which it is not presently in simdjson. Instead, you should iterate over the elements
> using a for-loop, as in our examples.
@@ -249,7 +249,11 @@ auto error = parser.parse(json).get(doc);
if (error) { cerr << error << endl; exit(1); }
```
When you use the code this way, it is your responsibility to check for error before using the
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
When you use the code without exceptions, it is your responsibility to check for error before using the
result: if there is an error, the result value will not be valid and using it will caused undefined
behavior.
@@ -318,6 +322,9 @@ int main(void) {
}
```
The `at()` method has linear-time complexity: it should not be used to iterate
over the content of an array.
### Error Handling Example
This is how the example in "Using the Parsed JSON" could be written using only error code checking:
+13 -13
View File
@@ -50,9 +50,9 @@ Inspecting the Detected Implementation
You can check what implementation is running with `active_implementation`:
```c++
cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "Detected the best implementation for your machine: " << simdjson::active_implementation->name();
cout << "(" << simdjson::active_implementation->description() << ")" << endl;
cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
```
Implementation detection will happen in this case when you first call `name()`.
@@ -63,7 +63,7 @@ Querying Available Implementations
You can list all available implementations, regardless of which one was selected:
```c++
for (auto implementation : simdjson::available_implementations) {
for (auto implementation : simdjson::get_available_implementations()) {
cout << implementation->name() << ": " << implementation->description() << endl;
}
```
@@ -71,10 +71,10 @@ for (auto implementation : simdjson::available_implementations) {
And look them up by name:
```c++
cout << simdjson::available_implementations["fallback"]->description() << endl;
cout << simdjson::get_available_implementations()["fallback"]->description() << endl;
```
Though the fallback implementation should always be available, others might be missing. When
an implementation is not available, the bracket call `simdjson::available_implementations[name]`
an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
will return the null pointer.
The available implementations have been compiled but may not necessarily be run safely on your system
@@ -90,18 +90,18 @@ can select the CPU architecture yourself:
```c++
// Use the fallback implementation, even though my machine is fast enough for anything
simdjson::active_implementation = simdjson::available_implementations["fallback"];
simdjson::get_active_implementation() = simdjson::get_available_implementations()["fallback"];
```
You are responsible for ensuring that the requirements of the selected implementation match your current system.
Furthermore, you should check that the implementation is available before setting it to `simdjson::active_implementation`
Furthermore, you should check that the implementation is available before setting it to `simdjson::get_active_implementation()`
by comparing it with the null pointer.
```c++
auto my_implementation = simdjson::available_implementations["haswell"];
auto my_implementation = simdjson::get_available_implementations()["haswell"];
if(! my_implementation) { exit(1); }
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
simdjson::active_implementation = my_implementation;
simdjson::get_active_implementation() = my_implementation;
```
Checking that an Implementation can Run on your System
@@ -110,12 +110,12 @@ Checking that an Implementation can Run on your System
You should call `supported_by_runtime_system()` to compare the processor's features with the need of the implementation.
```c++
for (auto implementation : simdjson::available_implementations) {
for (auto implementation : simdjson::get_available_implementations()) {
if(implementation->supported_by_runtime_system()) {
cout << implementation->name() << ": " << implementation->description() << endl;
}
}
```
The call to `supported_by_runtime_system()` maybe relatively expensive. Do not call `supported_by_runtime_system()` each
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
The call to `supported_by_runtime_system()` may be relatively expensive. Do not call `supported_by_runtime_system()` each
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
+6 -2
View File
@@ -1,7 +1,9 @@
iterate_many
==========
An interface providing features to work with files or streams containing multiple small JSON documents. Given an input such as
When serializing large databases, it is often better to write out many independent JSON
documents, instead of one large monolithic document containing many records. The simdjson
library provides high-speed access to files or streams containing multiple small JSON documents separated by ASCII white-space characters. Given an input such as
```JSON
{"text":"a"}
{"text":"b"}
@@ -114,7 +116,9 @@ Whitespace Characters:
- **Linefeed**
- **Carriage return**
- **Horizontal tab**
- **Nothing**
If your documents are all objects or arrays, then you may even have nothing between them.
E.g., `[1,2]{"32":1}` is recognized as two documents.
Some official formats **(non-exhaustive list)**:
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
-37
View File
@@ -709,42 +709,6 @@ in production systems:
}
```
### Long-Running Processes and Memory Capacity
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. Similarly to the DOM-based approach (see [here](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#server-loops-long-running-processes-and-memory-capacity)]), On Demand also lets you adjust the maximal capacity that the parser can process:
* You can set an upper bound (*max_capacity*) when construction the parser:
```C++
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
The capacity will grow as the parser encounters larger documents up to 1 MB.
* You can also allocate a *fixed capacity* that will never grow:
```C++
ondemand::parser parser(1000*1000);
parser.allocate(1000*1000) // Fix the capacity to 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
You can also manually set the maximal capacity using the method `set_max_capacity()`.
### Benefits of the On Demand Approach
We expect that the On Demand approach has many of the performance benefits of the schema-based approach, while providing a flexibility that is similar to that of the DOM-based approach.
@@ -764,7 +728,6 @@ There are currently additional technical limitations which we expect to resolve
* The simdjson library offers runtime dispatching which allows you to compile one binary and have it run at full speed on different processors, taking advantage of the specific features of the processor. The On Demand API has limited runtime dispatch support. Under x64 systems, to fully benefit from the On Demand API, we recommend that you compile your code for a specific processor. E.g., if your processor supports AVX2 instructions, you should compile your binary executable with AVX2 instruction support (by using your compiler's commands). If you are sufficiently technically proficient, you can implement runtime dispatching within your application, by compiling your On Demand code for different processors.
* There is an initial phase which scans the entire document quickly, irrespective of the size of the document. We plan to break this phase into distinct steps for large files in a future release as we have done with other components of our API (e.g., `parse_many`).
* The On Demand API does not support JSON Pointer. This capability is currently limited to our core API.
### Applicability of the On Demand Approach
+37
View File
@@ -56,6 +56,43 @@ or simply
```
Server Loops: Long-Running Processes and Memory Capacity
---------------------------------
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. On Demand also lets you adjust the maximal capacity that the parser can process:
* You can set an upper bound (*max_capacity*) when construction the parser:
```C++
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
The capacity will grow as the parser encounters larger documents up to 1 MB.
* You can also allocate a *fixed capacity* that will never grow:
```C++
ondemand::parser parser(1000*1000);
parser.allocate(1000*1000) // Fix the capacity to 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
You can also manually set the maximal capacity using the method `set_max_capacity()`.
Large files and huge page support
---------------------------------
+1 -1
View File
@@ -93,7 +93,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
std::size_t nerrors=0;
for(std::size_t i=0; i<Nimplementations; ++i) {
auto& e=implementations[i];
simdjson::active_implementation=e.impl;
simdjson::get_active_implementation()=e.impl;
e.error=e.parser.parse(Data,Size).get(e.element);
if(e.error) {
++nerrors;
+17 -15
View File
@@ -8,24 +8,26 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzData fd(Data, Size);
const auto batch_size=static_cast<size_t>(fd.getInt<0,1000>());
const auto json=simdjson::padded_string{fd.remainder_as_stringview()};
const auto batch_size = static_cast<size_t>(fd.getInt<0,1000>());
const auto json = simdjson::padded_string{fd.remainder_as_stringview()};
simdjson::dom::parser parser;
#if SIMDJSON_EXCEPTIONS
try {
#endif
simdjson::dom::document_stream docs;
if(parser.parse_many(json,batch_size).get(docs)) {
return 0;
}
size_t bool_count=0;
simdjson::dom::document_stream docs;
if(parser.parse_many(json,batch_size).get(docs)) { return 0; }
size_t bool_count1 = 0;
size_t total_count1 = 0;
for (auto doc : docs) {
bool_count+=doc.is_bool();
total_count1++;
bool_count1 += doc.is_bool();
}
#if SIMDJSON_EXCEPTIONS
} catch(...) {
// Restart, if we made it this far, the document *must* be accessible.
if(parser.parse_many(json,batch_size).get(docs)) { return EXIT_FAILURE; }
size_t bool_count2 = 0;
size_t total_count2 = 0;
for (auto doc : docs) {
total_count2++;
bool_count2 += doc.is_bool();
}
#endif
// They should agree!!!
if((total_count2 != total_count1) || (bool_count2 != bool_count1)) { return EXIT_FAILURE; }
return 0;
}
+1 -1
View File
@@ -17,7 +17,7 @@
std::vector<const simdjson::implementation*>
get_runtime_supported_implementations() {
std::vector<const simdjson::implementation*> ret;
for(auto& e: simdjson::available_implementations) {
for(auto& e: simdjson::get_available_implementations()) {
if(e->supported_by_runtime_system()) {
ret.emplace_back(e);
}
+1
View File
@@ -34,6 +34,7 @@
}
*/
#include "simdjson/simdjson_version.h"
#include "simdjson/dom.h"
#include "simdjson/builtin.h"
+2 -2
View File
@@ -8,7 +8,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
@@ -73,7 +73,7 @@ simdjson_really_inline uint64_t reverse_bits(uint64_t input_num) {
* greating or equal to 63 in which case we trigger undefined behavior, but the output
* of such undefined behavior is never used.
**/
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
}
+1 -1
View File
@@ -132,7 +132,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
simdjson_really_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
simdjson_really_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
simdjson_really_inline Mask operator==(const simd8<T> other) const { return vceqq_u8(*this, other); }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
template<int N=1>
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
+1 -1
View File
@@ -176,7 +176,7 @@ inline error_code parser::allocate(size_t capacity, size_t max_depth) noexcept {
if (implementation) {
err = implementation->allocate(capacity, max_depth);
} else {
err = simdjson::active_implementation->create_dom_parser_implementation(capacity, max_depth, implementation);
err = simdjson::get_active_implementation()->create_dom_parser_implementation(capacity, max_depth, implementation);
}
if (err) { return err; }
return SUCCESS;
+6 -1
View File
@@ -157,7 +157,10 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
size_t i = 0;
// Fast path for the case where we have no control character, no ", and no backslash.
// This should include most keys.
constexpr static bool needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//
// We would like to use 'bool' but some compilers take offense to bitwise operation
// with bool types.
constexpr static char needs_escaping[] = {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,
@@ -169,6 +172,8 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
for(;i + 8 <= unescaped.length(); i += 8) {
// Poor's man vectorization. This could get much faster if we used SIMD.
//
// It is not the case that replacing '|' with '||' would be neutral performance-wise.
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
+6 -1
View File
@@ -7,7 +7,12 @@
namespace simdjson {
/**
* All possible errors returned by simdjson.
* All possible errors returned by simdjson. These error codes are subject to change
* and not all simdjson kernel returns the same error code given the same input: it is not
* well defined which error a given input should produce.
*
* Only SUCCESS evaluates to false as a Boolean. All other error codes will evaluate
* to true as a Boolean.
*/
enum error_code {
SUCCESS = 0, ///< No error
+14 -6
View File
@@ -361,7 +361,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
}
template<typename I>
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
const uint8_t digit = static_cast<uint8_t>(c - '0');
if (digit > 9) {
@@ -609,7 +609,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
}
@@ -732,7 +732,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -782,7 +782,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -830,9 +830,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
// instance.
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@@ -1065,6 +1067,11 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
if ( p == src ) { return NUMBER_ERROR; }
if (jsoncharutils::is_structural_or_whitespace(*p)) {
// We have an integer.
// If the number is negative and valid, it must be a signed integer.
if(negative) { return ondemand::number_type::signed_integer; }
// We want values larger or equal to 9223372036854775808 to be unsigned
// integers, and the other values to be signed integers.
int digit_count = int(p - src);
if(digit_count >= 19) {
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
@@ -1074,6 +1081,7 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
}
return ondemand::number_type::signed_integer;
}
// Hopefully, we have 'e' or 'E' or '.'.
return ondemand::number_type::floating_point_number;
}
+1 -1
View File
@@ -104,7 +104,7 @@ public:
/**
* Get the value at the given index. This function has linear-time complexity.
* This function should only be called once as the array iterator is not reset between each call.
* This function should only be called once on an array instance since the array iterator is not reset between each call.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
@@ -24,6 +24,10 @@ inline simdjson_result<const char *> document::current_location() noexcept {
return iter.current_location();
}
inline int32_t document::current_depth() const noexcept {
return iter.depth();
}
inline bool document::is_alive() noexcept {
return iter.is_alive();
}
@@ -471,6 +475,11 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
return first.current_location();
}
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_depth() const noexcept {
if (error()) { return error(); }
return first.current_depth();
}
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::raw_json_token() noexcept {
if (error()) { return error(); }
return first.raw_json_token();
@@ -527,7 +536,8 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); };
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
simdjson_really_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
@@ -715,4 +725,4 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
}
} // namespace simdjson
} // namespace simdjson
+52 -6
View File
@@ -94,6 +94,8 @@ public:
*
* The string is guaranteed to be valid UTF-8.
*
* Important: Calling get_string() twice on the same document is an error.
*
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -267,7 +269,7 @@ public:
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
/**
* Get the value at the given index in the array. This function has linear-time complexity.
* This function should only be called once as the array iterator is not reset between each call.
* This function should only be called once on an array instance since the array iterator is not reset between each call.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
@@ -303,6 +305,18 @@ public:
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
*
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to
* a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
* is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -326,6 +340,17 @@ public:
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
* field wasn't there when they aren't).
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to a key
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
* is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -374,7 +399,14 @@ public:
*/
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
/**
* Determine the number type (integer or floating-point number).
* Determine the number type (integer or floating-point number) as quickly
* as possible. This function does not fully validate the input. It is
* useful when you only need to classify the numbers, without parsing them.
*
* If you are planning to retrieve the value or you need full validation,
* consider using the get_number() method instead: it will fully parse
* and validate the input, and give you access to the type:
* get_number().get_number_type().
*
* get_number_type() is number_type::unsigned_integer if we have
* an integer greater or equal to 9223372036854775808
@@ -382,8 +414,7 @@ public:
* integer that is less than 9223372036854775808
* Otherwise, get_number_type() has value number_type::floating_point_number
*
* This function req
* uires processing the number string, but it is expected
* This function requires processing the number string, but it is expected
* to be faster than get_number().get_number_type() because it is does not
* parse the number value.
*
@@ -399,7 +430,7 @@ public:
* type.
*
* number.get_number_type() is number_type::signed_integer if we have
* a integer in [-9223372036854775808,9223372036854775808)
* an integer in [-9223372036854775808,9223372036854775808)
* You can recover the value by calling number.get_int64() and you
* have that number.is_int64() is true.
*
@@ -464,6 +495,17 @@ public:
*/
inline simdjson_result<const char *> current_location() noexcept;
/**
* Returns the current depth in the document if in bounds.
*
* E.g.,
* 0 = finished with document
* 1 = document root value (could be [ or {, not yet known)
* 2 = , or } inside root array/object
* 3 = key or value inside root array/object.
*/
simdjson_really_inline int32_t current_depth() const noexcept;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
* https://tools.ietf.org/html/rfc6901 standard.
@@ -498,7 +540,7 @@ public:
simdjson_really_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
/**
* Consumes the document and returns a string_view instance corresponding to the
* document as represented in JSON. It points inside the original byte array containg
* document as represented in JSON. It points inside the original byte array containing
* the JSON document.
*/
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
@@ -541,6 +583,7 @@ public:
simdjson_really_inline document_reference() noexcept;
simdjson_really_inline document_reference(document &d) noexcept;
simdjson_really_inline document_reference(const document_reference &other) noexcept = default;
simdjson_really_inline document_reference& operator=(const document_reference &other) noexcept = default;
simdjson_really_inline void rewind() noexcept;
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
@@ -583,6 +626,7 @@ public:
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline bool is_negative() noexcept;
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
@@ -649,6 +693,7 @@ public:
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline bool is_negative() noexcept;
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
@@ -709,6 +754,7 @@ public:
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline bool is_negative() noexcept;
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
@@ -53,17 +53,6 @@ inline void json_iterator::rewind() noexcept {
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
/***
* WARNING:
* Inside an object, a string value is a depth of +1 compared to the object. Yet a key
* is at the same depth as the object.
* But json_iterator cannot easily tell whether we are pointing at a key or a string value.
* Instead, it assumes that if you are pointing at a string, then it is a value, not a key.
* To be clear...
* the following code assumes that we are *not* pointing at a key. If we are then a bug
* will follow. Unfortunately, it is not possible for the json_iterator its to make this
* check.
*/
if (depth() <= parent_depth) { return SUCCESS; }
switch (*return_current_and_advance()) {
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
@@ -91,19 +80,18 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child
if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
#endif // SIMDJSON_CHECK_EOF
break;
/*case '"':
case '"':
if(*peek() == ':') {
// we are at a key!!! This is
// only possible if someone searched
// for a key in an object and the key
// was not found but our code then
// decided the consume the separating
// comma before returning.
// We are at a key!!!
// This might happen if you just started an object and you skip it immediately.
// Performance note: it would be nice to get rid of this check as it is somewhat
// expensive.
// https://github.com/simdjson/simdjson/issues/1742
logger::log_value(*this, "key");
advance(); // eat up the ':'
return_current_and_advance(); // eat up the ':'
break; // important!!!
}
simdjson_fallthrough;*/
simdjson_fallthrough;
// Anything else must be a scalar value
default:
// For the first scalar, we will have incremented depth already, so we decrement it here.
@@ -111,7 +111,6 @@ protected:
uint64_t unsigned_integer;
} payload{0};
number_type type{number_type::signed_integer};
friend class value_iterator;
};
/**
@@ -37,6 +37,17 @@ public:
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to a
* key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
* is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -63,6 +74,16 @@ public:
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
* that only one field is returned.
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to a key
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -21,7 +21,7 @@ simdjson_warn_unused simdjson_really_inline error_code parser::allocate(size_t n
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
} else {
SIMDJSON_TRY( simdjson::active_implementation->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
}
_capacity = new_capacity;
_max_depth = new_max_depth;
+11 -4
View File
@@ -54,6 +54,11 @@ public:
* ondemand::parser parser;
* document doc = parser.iterate(json);
*
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
* Otherwise the iterate method may return an error. In particular, the whole input should be
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
* document.
*
* ### IMPORTANT: Validate what you use
*
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
@@ -166,16 +171,18 @@ public:
* ### Format
*
* The buffer must contain a series of one or more JSON documents, concatenated into a single
* buffer, separated by whitespace. It effectively parses until it has a fully valid document,
* buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
* then starts parsing the next document at that point. (It does this with more parallelism and
* lookahead than you might think, though.)
*
* documents that consist of an object or array may omit the whitespace between them, concatenating
* with no separator. documents that consist of a single primitive (i.e. documents that are not
* arrays or objects) MUST be separated with whitespace.
* with no separator. Documents that consist of a single primitive (i.e. documents that are not
* arrays or objects) MUST be separated with ASCII whitespace.
*
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
*
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
* Setting batch_size to excessively large or excesively small values may impact negatively the
* Setting batch_size to excessively large or excessively small values may impact negatively the
* performance.
*
* ### REQUIRED: Buffer Padding
@@ -99,6 +99,7 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
}
} // namespace simdjson
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value x) {
@@ -216,3 +217,4 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
}
}
#endif
}}} // namespace simdjson::SIMDJSON_IMPLEMENTATION::ondemand
@@ -29,6 +29,14 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> x);
} // namespace simdjson
/**
* We want to support argument-dependent lookup (ADL).
* Hence we should define operator<< in the namespace
* where the argument (here value, object, etc.) resides.
* Credit: @madhur4127
* See https://github.com/simdjson/simdjson/issues/1768
*/
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
/**
* Print JSON to an output stream.
@@ -78,3 +86,4 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::object> x);
#endif
}}} // namespace simdjson::SIMDJSON_IMPLEMENTATION::ondemand
@@ -62,6 +62,7 @@ template<> simdjson_really_inline simdjson_result<array> value::get() noexcept {
template<> simdjson_really_inline simdjson_result<object> value::get() noexcept { return get_object(); }
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(); }
template<> simdjson_really_inline simdjson_result<number> value::get() noexcept { return get_number(); }
template<> simdjson_really_inline simdjson_result<double> value::get() noexcept { return get_double(); }
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
template<> simdjson_really_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
@@ -114,6 +115,13 @@ simdjson_really_inline simdjson_result<size_t> value::count_elements() & noexcep
iter.move_at_start();
return answer;
}
simdjson_really_inline simdjson_result<size_t> value::count_fields() & noexcept {
simdjson_result<size_t> answer;
auto a = get_object();
answer = a.count_fields();
iter.move_at_start();
return answer;
}
simdjson_really_inline simdjson_result<value> value::at(size_t index) noexcept {
auto a = get_array();
return a.at(index);
@@ -169,6 +177,14 @@ simdjson_really_inline std::string_view value::raw_json_token() noexcept {
return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
}
simdjson_really_inline simdjson_result<const char *> value::current_location() noexcept {
return iter.json_iter().current_location();
}
simdjson_really_inline int32_t value::current_depth() const noexcept{
return iter.json_iter().depth();
}
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
json_type t;
SIMDJSON_TRY(type().get(t));
@@ -207,6 +223,10 @@ simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMEN
if (error()) { return error(); }
return first.count_elements();
}
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::count_fields() & noexcept {
if (error()) { return error(); }
return first.count_fields();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at(size_t index) noexcept {
if (error()) { return error(); }
return first.at(index);
@@ -379,6 +399,16 @@ simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSO
return first.raw_json_token();
}
simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_location() noexcept {
if (error()) { return error(); }
return first.current_location();
}
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
if (error()) { return error(); }
return first.current_depth();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
if (error()) { return error(); }
return first.at_pointer(json_pointer);
+49 -3
View File
@@ -121,6 +121,9 @@ public:
*
* Equivalent to get<std::string_view>().
*
* Important: a value should be consumed once. Calling get_string() twice on the same value
* is an error.
*
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -244,9 +247,24 @@ public:
* safe to continue.
*/
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
/**
* This method scans the object and counts the number of key-value pairs.
* The count_fields method should always be called before you have begun
* iterating through the object: it is expected that you are pointing at
* the beginning of the object.
* The runtime complexity is linear in the size of the object. After
* calling this function, if successful, the object is 'rewinded' at its
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
*
* To check that an object is empty, it is more performant to use
* the is_empty() method on the object instance.
*/
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
/**
* Get the value at the given index in the array. This function has linear-time complexity.
* This function should only be called once as the array iterator is not reset between each call.
* This function should only be called once on an array instance since the array iterator is not reset between each call.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
@@ -351,7 +369,14 @@ public:
*/
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
/**
* Determine the number type (integer or floating-point number).
* Determine the number type (integer or floating-point number) as quickly
* as possible. This function does not fully validate the input. It is
* useful when you only need to classify the numbers, without parsing them.
*
* If you are planning to retrieve the value or you need full validation,
* consider using the get_number() method instead: it will fully parse
* and validate the input, and give you access to the type:
* get_number().get_number_type().
*
* get_number_type() is number_type::unsigned_integer if we have
* an integer greater or equal to 9223372036854775808
@@ -375,7 +400,7 @@ public:
* type.
*
* number.get_number_type() is number_type::signed_integer if we have
* a integer in [-9223372036854775808,9223372036854775808)
* an integer in [-9223372036854775808,9223372036854775808)
* You can recover the value by calling number.get_int64() and you
* have that number.is_int64() is true.
*
@@ -425,6 +450,22 @@ public:
*/
simdjson_really_inline std::string_view raw_json_token() noexcept;
/**
* Returns the current location in the document if in bounds.
*/
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
/**
* Returns the current depth in the document if in bounds.
*
* E.g.,
* 0 = finished with document
* 1 = document root value (could be [ or {, not yet known)
* 2 = , or } inside root array/object
* 3 = key or value inside root array/object.
*/
simdjson_really_inline int32_t current_depth() const noexcept;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
* https://tools.ietf.org/html/rfc6901 standard.
@@ -552,6 +593,7 @@ public:
simdjson_really_inline operator bool() noexcept(false);
#endif
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at(size_t index) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> begin() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
@@ -624,6 +666,10 @@ public:
/** @copydoc simdjson_really_inline std::string_view value::raw_json_token() const noexcept */
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
/** @copydoc simdjson_really_inline simdjson_result<const char *> current_location() noexcept */
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
/** @copydoc simdjson_really_inline int32_t current_depth() const noexcept */
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
};
@@ -76,7 +76,7 @@ public:
/**
* Get the depth of this value.
*/
simdjson_really_inline depth_t depth() const noexcept;
simdjson_really_inline int32_t depth() const noexcept;
/**
* Get the JSON type of this value.
+1 -1
View File
@@ -8,7 +8,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
return (int)_tzcnt_u64(input_num);
+1 -1
View File
@@ -45,7 +45,7 @@ namespace simd {
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline Mask operator==(const simd8<T> other) const { return _mm256_cmpeq_epi8(*this, other); }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm256_cmpeq_epi8(lhs, rhs); }
static const int SIZE = sizeof(base<T>::value);
+8 -8
View File
@@ -56,7 +56,7 @@ public:
/**
* The name of this implementation.
*
* const implementation *impl = simdjson::active_implementation;
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
@@ -66,7 +66,7 @@ public:
/**
* The description of this implementation.
*
* const implementation *impl = simdjson::active_implementation;
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
@@ -95,7 +95,7 @@ public:
/**
* @private For internal implementation use
*
* const implementation *impl = simdjson::active_implementation;
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @param capacity The largest document that will be passed to the parser.
@@ -189,10 +189,10 @@ public:
*
* Case sensitive.
*
* const implementation *impl = simdjson::available_implementations["westmere"];
* const implementation *impl = simdjson::get_available_implementations()["westmere"];
* if (!impl) { exit(1); }
* if (!imp->supported_by_runtime_system()) { exit(1); }
* simdjson::active_implementation = impl;
* simdjson::get_active_implementation() = impl;
*
* @param name the implementation to find, e.g. "westmere", "haswell", "arm64"
* @return the implementation, or nullptr if the parse failed.
@@ -210,7 +210,7 @@ public:
* This is used to initialize the implementation on startup.
*
* const implementation *impl = simdjson::available_implementation::detect_best_supported();
* simdjson::active_implementation = impl;
* simdjson::get_active_implementation() = impl;
*
* @return the most advanced supported implementation for the current host, or an
* implementation that returns UNSUPPORTED_ARCHITECTURE if there is no supported
@@ -242,14 +242,14 @@ private:
/**
* The list of available implementations compiled into simdjson.
*/
extern SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list available_implementations;
extern SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations();
/**
* The active implementation.
*
* Automatically initialized on first use to the most advanced implementation supported by this hardware.
*/
extern SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation> active_implementation;
extern SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation();
} // namespace simdjson
+4
View File
@@ -18,9 +18,13 @@
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
#define SIMDJSON_IMPLEMENTATION_HASWELL (SIMDJSON_IS_X86_64)
#endif
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
#else
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#endif
// Default Westmere to on if this is x86-64, unless we'll always select Haswell.
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
+1 -1
View File
@@ -51,7 +51,7 @@ inline padded_string::padded_string(size_t length) noexcept
}
inline padded_string::padded_string(const char *data, size_t length) noexcept
: viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
if ((data != nullptr) and (data_ptr != nullptr)) {
if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, data, length);
}
}
+9 -9
View File
@@ -71,10 +71,10 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
#endif // SIMDJSON_IS_32BITS
// this is almost standard?
#undef STRINGIFY_IMPLEMENTATION_
#undef STRINGIFY
#define STRINGIFY_IMPLEMENTATION_(a) #a
#define STRINGIFY(a) STRINGIFY_IMPLEMENTATION_(a)
#undef SIMDJSON_STRINGIFY_IMPLEMENTATION_
#undef SIMDJSON_STRINGIFY
#define SIMDJSON_STRINGIFY_IMPLEMENTATION_(a) #a
#define SIMDJSON_STRINGIFY(a) SIMDJSON_STRINGIFY_IMPLEMENTATION_(a)
// Our fast kernels require 64-bit systems.
//
@@ -98,13 +98,13 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
// til 8.0 so SIMDJSON_TARGET_REGION and SIMDJSON_UNTARGET_REGION must be *outside* of a
// namespace.
#define SIMDJSON_TARGET_REGION(T) \
_Pragma(STRINGIFY( \
_Pragma(SIMDJSON_STRINGIFY( \
clang attribute push(__attribute__((target(T))), apply_to = function)))
#define SIMDJSON_UNTARGET_REGION _Pragma("clang attribute pop")
#elif defined(__GNUC__)
// GCC is easier
#define SIMDJSON_TARGET_REGION(T) \
_Pragma("GCC push_options") _Pragma(STRINGIFY(GCC target(T)))
_Pragma("GCC push_options") _Pragma(SIMDJSON_STRINGIFY(GCC target(T)))
#define SIMDJSON_UNTARGET_REGION _Pragma("GCC pop_options")
#endif // clang then gcc
@@ -138,11 +138,11 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
#if defined(__clang__)
#define NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
#define SIMDJSON_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
#elif defined(__GNUC__)
#define NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
#define SIMDJSON_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
#else
#define NO_SANITIZE_UNDEFINED
#define SIMDJSON_NO_SANITIZE_UNDEFINED
#endif
#ifdef SIMDJSON_VISUAL_STUDIO
+1 -1
View File
@@ -8,7 +8,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
+8
View File
@@ -1,7 +1,11 @@
#ifndef SIMDJSON_PPC64_NUMBERPARSING_H
#define SIMDJSON_PPC64_NUMBERPARSING_H
#if defined(__linux__)
#include <byteswap.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#endif
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
@@ -14,7 +18,11 @@ parse_eight_digits_unrolled(const uint8_t *chars) {
uint64_t val;
std::memcpy(&val, chars, sizeof(uint64_t));
#ifdef __BIG_ENDIAN__
#if defined(__linux__)
val = bswap_64(val);
#elif defined(__FreeBSD__)
val = bswap64(val);
#endif
#endif
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
+2 -2
View File
@@ -69,8 +69,8 @@ struct base8 : base<simd8<T>> {
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline Mask operator==(const simd8<T> other) const {
return (__m128i)vec_cmpeq(this->value, (__m128i)other);
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) {
return (__m128i)vec_cmpeq(lhs.value, (__m128i)rhs);
}
static const int SIZE = sizeof(base<simd8<T>>::value);
+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 1.0.0
#define SIMDJSON_VERSION 1.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
+1 -1
View File
@@ -8,7 +8,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
+1 -1
View File
@@ -44,7 +44,7 @@ namespace simd {
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline Mask operator==(const simd8<T> other) const { return _mm_cmpeq_epi8(*this, other); }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
static const int SIZE = sizeof(base<simd8<T>>::value);
+5 -4
View File
@@ -7,7 +7,7 @@ int main(int argc, char *argv[]) {
std::cerr << "Please specify at least one file name and" << std::endl;
std::cerr << "up to two files." << std::endl;
std::cerr << "The first file should be a JSON document." << std::endl;
std::cerr << "The secod file should container many JSON documents."
std::cerr << "The second file should container many JSON documents."
<< std::endl;
std::cerr << "Try the test files: jsonexamples/twitter.json "
"jsonexamples/amazon_cellphones.ndjson"
@@ -39,7 +39,7 @@ int main(int argc, char *argv[]) {
std::cout << error << std::endl;
return EXIT_FAILURE;
}
std::cout << "document has the following type at the root: " << type
std::cout << "if valid, the document has the following type at the root: " << type
<< std::endl;
if (argc == 2) {
@@ -73,8 +73,9 @@ int main(int argc, char *argv[]) {
std::cout << error << std::endl;
return EXIT_FAILURE;
} else {
std::cout << "iterate_many valid" << std::endl;
std::cout << "found " << counter << " documents" << std::endl;
std::cout << "I found " << counter << " potential JSON documents." << std::endl;
}
std::cout << "For more information on how simdjson works, please refer to our documentation." << std::endl;
std::cout << "https://github.com/simdjson/simdjson/blob/master/doc/basics.md" << std::endl;
return EXIT_SUCCESS;
}
+85 -58
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2021-09-07 14:34:40 -0400. Do not edit! */
/* auto-generated on 2022-01-31 11:38:54 -0500. Do not edit! */
/* begin file src/simdjson.cpp */
#include "simdjson.h"
@@ -2620,19 +2620,34 @@ namespace internal {
// without requiring a static initializer.
#if SIMDJSON_IMPLEMENTATION_HASWELL
const haswell::implementation haswell_singleton{};
static const haswell::implementation* get_haswell_singleton() {
static const haswell::implementation haswell_singleton{};
return &haswell_singleton;
}
#endif
#if SIMDJSON_IMPLEMENTATION_WESTMERE
const westmere::implementation westmere_singleton{};
static const westmere::implementation* get_westmere_singleton() {
static const westmere::implementation westmere_singleton{};
return &westmere_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_WESTMERE
#if SIMDJSON_IMPLEMENTATION_ARM64
const arm64::implementation arm64_singleton{};
static const arm64::implementation* get_arm64_singleton() {
static const arm64::implementation arm64_singleton{};
return &arm64_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_ARM64
#if SIMDJSON_IMPLEMENTATION_PPC64
const ppc64::implementation ppc64_singleton{};
static const ppc64::implementation* get_ppc64_singleton() {
static const ppc64::implementation ppc64_singleton{};
return &ppc64_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_PPC64
#if SIMDJSON_IMPLEMENTATION_FALLBACK
const fallback::implementation fallback_singleton{};
static const fallback::implementation* get_fallback_singleton() {
static const fallback::implementation fallback_singleton{};
return &fallback_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_FALLBACK
/**
@@ -2661,25 +2676,26 @@ private:
const implementation *set_best() const noexcept;
};
const detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton;
const std::initializer_list<const implementation *> available_implementation_pointers {
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
static const std::initializer_list<const implementation *> available_implementation_pointers {
#if SIMDJSON_IMPLEMENTATION_HASWELL
&haswell_singleton,
get_haswell_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_WESTMERE
&westmere_singleton,
get_westmere_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_ARM64
&arm64_singleton,
get_arm64_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_PPC64
&ppc64_singleton,
get_ppc64_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_FALLBACK
&fallback_singleton,
get_fallback_singleton(),
#endif
}; // available_implementation_pointers
}; // available_implementation_pointers
return available_implementation_pointers;
}
// So we can return UNSUPPORTED_ARCHITECTURE from the parser when there is no support
class unsupported_implementation final : public implementation {
@@ -2707,25 +2723,28 @@ public:
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
};
const unsupported_implementation unsupported_singleton{};
const unsupported_implementation* get_unsupported_singleton() {
static const unsupported_implementation unsupported_singleton{};
return &unsupported_singleton;
}
size_t available_implementation_list::size() const noexcept {
return internal::available_implementation_pointers.size();
return internal::get_available_implementation_pointers().size();
}
const implementation * const *available_implementation_list::begin() const noexcept {
return internal::available_implementation_pointers.begin();
return internal::get_available_implementation_pointers().begin();
}
const implementation * const *available_implementation_list::end() const noexcept {
return internal::available_implementation_pointers.end();
return internal::get_available_implementation_pointers().end();
}
const implementation *available_implementation_list::detect_best_supported() const noexcept {
// They are prelisted in priority order, so we just go down the list
uint32_t supported_instruction_sets = internal::detect_supported_architectures();
for (const implementation *impl : internal::available_implementation_pointers) {
for (const implementation *impl : internal::get_available_implementation_pointers()) {
uint32_t required_instruction_sets = impl->required_instruction_sets();
if ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets) { return impl; }
}
return &unsupported_singleton; // this should never happen?
return get_unsupported_singleton(); // this should never happen?
}
const implementation *detect_best_supported_implementation_on_first_use::set_best() const noexcept {
@@ -2735,31 +2754,39 @@ const implementation *detect_best_supported_implementation_on_first_use::set_bes
SIMDJSON_POP_DISABLE_WARNINGS
if (force_implementation_name) {
auto force_implementation = available_implementations[force_implementation_name];
auto force_implementation = get_available_implementations()[force_implementation_name];
if (force_implementation) {
return active_implementation = force_implementation;
return get_active_implementation() = force_implementation;
} else {
// Note: abort() and stderr usage within the library is forbidden.
return active_implementation = &unsupported_singleton;
return get_active_implementation() = get_unsupported_singleton();
}
}
return active_implementation = available_implementations.detect_best_supported();
return get_active_implementation() = get_available_implementations().detect_best_supported();
}
} // namespace internal
SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list available_implementations{};
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation> active_implementation{&internal::detect_best_supported_implementation_on_first_use_singleton};
SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations() {
static const internal::available_implementation_list available_implementations{};
return available_implementations;
}
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation() {
static const internal::detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton;
static internal::atomic_ptr<const implementation> active_implementation{&detect_best_supported_implementation_on_first_use_singleton};
return active_implementation;
}
simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, size_t &dst_len) noexcept {
return active_implementation->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len);
return get_active_implementation()->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len);
}
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
return active_implementation->validate_utf8(buf, len);
return get_active_implementation()->validate_utf8(buf, len);
}
const implementation * builtin_implementation() {
static const implementation * builtin_impl = available_implementations[STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
assert(builtin_impl);
return builtin_impl;
}
@@ -3473,11 +3500,11 @@ simdjson_really_inline uint64_t follows(const uint64_t match, uint64_t &overflow
simdjson_really_inline json_block json_scanner::next(const simd::simd8x64<uint8_t>& in) {
json_string_block strings = string_scanner.next(in);
// identifies the white-space and the structurat characters
// identifies the white-space and the structural characters
json_character_block characters = json_character_block::classify(in);
// The term "scalar" refers to anything except structural characters and white space
// (so letters, numbers, quotes).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
//
// A terminal quote should either be followed by a structural character (comma, brace, bracket, colon)
// or nothing. However, we still want ' "a string"true ' to mark the 't' of 'true' as a potential
@@ -4246,25 +4273,25 @@ public:
/**
* Log that a value has been found.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_value(const char *type) const noexcept;
/**
* Log the start of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_start_value(const char *type) const noexcept;
/**
* Log the end of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_end_value(const char *type) const noexcept;
/**
* Log an error.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_error(const char *error) const noexcept;
@@ -5574,25 +5601,25 @@ public:
/**
* Log that a value has been found.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_value(const char *type) const noexcept;
/**
* Log the start of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_start_value(const char *type) const noexcept;
/**
* Log the end of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_end_value(const char *type) const noexcept;
/**
* Log an error.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_error(const char *error) const noexcept;
@@ -6937,11 +6964,11 @@ simdjson_really_inline uint64_t follows(const uint64_t match, uint64_t &overflow
simdjson_really_inline json_block json_scanner::next(const simd::simd8x64<uint8_t>& in) {
json_string_block strings = string_scanner.next(in);
// identifies the white-space and the structurat characters
// identifies the white-space and the structural characters
json_character_block characters = json_character_block::classify(in);
// The term "scalar" refers to anything except structural characters and white space
// (so letters, numbers, quotes).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
//
// A terminal quote should either be followed by a structural character (comma, brace, bracket, colon)
// or nothing. However, we still want ' "a string"true ' to mark the 't' of 'true' as a potential
@@ -7709,25 +7736,25 @@ public:
/**
* Log that a value has been found.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_value(const char *type) const noexcept;
/**
* Log the start of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_start_value(const char *type) const noexcept;
/**
* Log the end of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_end_value(const char *type) const noexcept;
/**
* Log an error.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_error(const char *error) const noexcept;
@@ -9063,11 +9090,11 @@ simdjson_really_inline uint64_t follows(const uint64_t match, uint64_t &overflow
simdjson_really_inline json_block json_scanner::next(const simd::simd8x64<uint8_t>& in) {
json_string_block strings = string_scanner.next(in);
// identifies the white-space and the structurat characters
// identifies the white-space and the structural characters
json_character_block characters = json_character_block::classify(in);
// The term "scalar" refers to anything except structural characters and white space
// (so letters, numbers, quotes).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
//
// A terminal quote should either be followed by a structural character (comma, brace, bracket, colon)
// or nothing. However, we still want ' "a string"true ' to mark the 't' of 'true' as a potential
@@ -9836,25 +9863,25 @@ public:
/**
* Log that a value has been found.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_value(const char *type) const noexcept;
/**
* Log the start of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_start_value(const char *type) const noexcept;
/**
* Log the end of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_end_value(const char *type) const noexcept;
/**
* Log an error.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_error(const char *error) const noexcept;
@@ -11225,11 +11252,11 @@ simdjson_really_inline uint64_t follows(const uint64_t match, uint64_t &overflow
simdjson_really_inline json_block json_scanner::next(const simd::simd8x64<uint8_t>& in) {
json_string_block strings = string_scanner.next(in);
// identifies the white-space and the structurat characters
// identifies the white-space and the structural characters
json_character_block characters = json_character_block::classify(in);
// The term "scalar" refers to anything except structural characters and white space
// (so letters, numbers, quotes).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
//
// A terminal quote should either be followed by a structural character (comma, brace, bracket, colon)
// or nothing. However, we still want ' "a string"true ' to mark the 't' of 'true' as a potential
@@ -11997,25 +12024,25 @@ public:
/**
* Log that a value has been found.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_value(const char *type) const noexcept;
/**
* Log the start of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_start_value(const char *type) const noexcept;
/**
* Log the end of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_end_value(const char *type) const noexcept;
/**
* Log an error.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_error(const char *error) const noexcept;
+255 -123
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2021-09-07 14:34:40 -0400. Do not edit! */
/* auto-generated on 2022-01-31 11:38:54 -0500. Do not edit! */
/* begin file include/simdjson.h */
#ifndef SIMDJSON_H
#define SIMDJSON_H
@@ -36,6 +36,34 @@
}
*/
/* begin file include/simdjson/simdjson_version.h */
// /include/simdjson/simdjson_version.h automatically generated by release.py,
// do not change by hand
#ifndef SIMDJSON_SIMDJSON_VERSION_H
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 1.0.2
namespace simdjson {
enum {
/**
* The major version (MAJOR.minor.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MAJOR = 1,
/**
* The minor version (major.MINOR.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MINOR = 0,
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 2
};
} // namespace simdjson
#endif // SIMDJSON_SIMDJSON_VERSION_H
/* end file include/simdjson/simdjson_version.h */
/* begin file include/simdjson/dom.h */
#ifndef SIMDJSON_DOM_H
#define SIMDJSON_DOM_H
@@ -160,10 +188,10 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
#endif // SIMDJSON_IS_32BITS
// this is almost standard?
#undef STRINGIFY_IMPLEMENTATION_
#undef STRINGIFY
#define STRINGIFY_IMPLEMENTATION_(a) #a
#define STRINGIFY(a) STRINGIFY_IMPLEMENTATION_(a)
#undef SIMDJSON_STRINGIFY_IMPLEMENTATION_
#undef SIMDJSON_STRINGIFY
#define SIMDJSON_STRINGIFY_IMPLEMENTATION_(a) #a
#define SIMDJSON_STRINGIFY(a) SIMDJSON_STRINGIFY_IMPLEMENTATION_(a)
// Our fast kernels require 64-bit systems.
//
@@ -187,13 +215,13 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
// til 8.0 so SIMDJSON_TARGET_REGION and SIMDJSON_UNTARGET_REGION must be *outside* of a
// namespace.
#define SIMDJSON_TARGET_REGION(T) \
_Pragma(STRINGIFY( \
_Pragma(SIMDJSON_STRINGIFY( \
clang attribute push(__attribute__((target(T))), apply_to = function)))
#define SIMDJSON_UNTARGET_REGION _Pragma("clang attribute pop")
#elif defined(__GNUC__)
// GCC is easier
#define SIMDJSON_TARGET_REGION(T) \
_Pragma("GCC push_options") _Pragma(STRINGIFY(GCC target(T)))
_Pragma("GCC push_options") _Pragma(SIMDJSON_STRINGIFY(GCC target(T)))
#define SIMDJSON_UNTARGET_REGION _Pragma("GCC pop_options")
#endif // clang then gcc
@@ -227,11 +255,11 @@ use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
#if defined(__clang__)
#define NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
#define SIMDJSON_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
#elif defined(__GNUC__)
#define NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
#define SIMDJSON_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
#else
#define NO_SANITIZE_UNDEFINED
#define SIMDJSON_NO_SANITIZE_UNDEFINED
#endif
#ifdef SIMDJSON_VISUAL_STUDIO
@@ -2182,34 +2210,6 @@ SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_UNDESIRED_WARNINGS
// Public API
/* begin file include/simdjson/simdjson_version.h */
// /include/simdjson/simdjson_version.h automatically generated by release.py,
// do not change by hand
#ifndef SIMDJSON_SIMDJSON_VERSION_H
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 1.0.0
namespace simdjson {
enum {
/**
* The major version (MAJOR.minor.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MAJOR = 1,
/**
* The minor version (major.MINOR.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MINOR = 0,
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 0
};
} // namespace simdjson
#endif // SIMDJSON_SIMDJSON_VERSION_H
/* end file include/simdjson/simdjson_version.h */
/* begin file include/simdjson/error.h */
#ifndef SIMDJSON_ERROR_H
#define SIMDJSON_ERROR_H
@@ -2219,7 +2219,12 @@ enum {
namespace simdjson {
/**
* All possible errors returned by simdjson.
* All possible errors returned by simdjson. These error codes are subject to change
* and not all simdjson kernel returns the same error code given the same input: it is not
* well defined which error a given input should produce.
*
* Only SUCCESS evaluates to false as a Boolean. All other error codes will evaluate
* to true as a Boolean.
*/
enum error_code {
SUCCESS = 0, ///< No error
@@ -3247,7 +3252,7 @@ public:
/**
* The name of this implementation.
*
* const implementation *impl = simdjson::active_implementation;
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
@@ -3257,7 +3262,7 @@ public:
/**
* The description of this implementation.
*
* const implementation *impl = simdjson::active_implementation;
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
@@ -3286,7 +3291,7 @@ public:
/**
* @private For internal implementation use
*
* const implementation *impl = simdjson::active_implementation;
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @param capacity The largest document that will be passed to the parser.
@@ -3380,10 +3385,10 @@ public:
*
* Case sensitive.
*
* const implementation *impl = simdjson::available_implementations["westmere"];
* const implementation *impl = simdjson::get_available_implementations()["westmere"];
* if (!impl) { exit(1); }
* if (!imp->supported_by_runtime_system()) { exit(1); }
* simdjson::active_implementation = impl;
* simdjson::get_active_implementation() = impl;
*
* @param name the implementation to find, e.g. "westmere", "haswell", "arm64"
* @return the implementation, or nullptr if the parse failed.
@@ -3401,7 +3406,7 @@ public:
* This is used to initialize the implementation on startup.
*
* const implementation *impl = simdjson::available_implementation::detect_best_supported();
* simdjson::active_implementation = impl;
* simdjson::get_active_implementation() = impl;
*
* @return the most advanced supported implementation for the current host, or an
* implementation that returns UNSUPPORTED_ARCHITECTURE if there is no supported
@@ -3433,14 +3438,14 @@ private:
/**
* The list of available implementations compiled into simdjson.
*/
extern SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list available_implementations;
extern SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations();
/**
* The active implementation.
*
* Automatically initialized on first use to the most advanced implementation supported by this hardware.
*/
extern SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation> active_implementation;
extern SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation();
} // namespace simdjson
@@ -3686,7 +3691,7 @@ inline padded_string::padded_string(size_t length) noexcept
}
inline padded_string::padded_string(const char *data, size_t length) noexcept
: viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
if ((data != nullptr) and (data_ptr != nullptr)) {
if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, data, length);
}
}
@@ -8672,7 +8677,7 @@ inline error_code parser::allocate(size_t capacity, size_t max_depth) noexcept {
if (implementation) {
err = implementation->allocate(capacity, max_depth);
} else {
err = simdjson::active_implementation->create_dom_parser_implementation(capacity, max_depth, implementation);
err = simdjson::get_active_implementation()->create_dom_parser_implementation(capacity, max_depth, implementation);
}
if (err) { return err; }
return SUCCESS;
@@ -8995,7 +9000,10 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
size_t i = 0;
// Fast path for the case where we have no control character, no ", and no backslash.
// This should include most keys.
constexpr static bool needs_escaping[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
//
// We would like to use 'bool' but some compilers take offense to bitwise operation
// with bool types.
constexpr static char needs_escaping[] = {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,
@@ -9007,6 +9015,8 @@ simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
for(;i + 8 <= unescaped.length(); i += 8) {
// Poor's man vectorization. This could get much faster if we used SIMD.
//
// It is not the case that replacing '|' with '||' would be neutral performance-wise.
if(needs_escaping[uint8_t(unescaped[i])] | needs_escaping[uint8_t(unescaped[i+1])]
| needs_escaping[uint8_t(unescaped[i+2])] | needs_escaping[uint8_t(unescaped[i+3])]
| needs_escaping[uint8_t(unescaped[i+4])] | needs_escaping[uint8_t(unescaped[i+5])]
@@ -9415,9 +9425,13 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256];
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
#define SIMDJSON_IMPLEMENTATION_HASWELL (SIMDJSON_IS_X86_64)
#endif
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
#else
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#endif
// Default Westmere to on if this is x86-64, unless we'll always select Haswell.
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
@@ -9593,7 +9607,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
@@ -9658,7 +9672,7 @@ simdjson_really_inline uint64_t reverse_bits(uint64_t input_num) {
* greating or equal to 63 in which case we trigger undefined behavior, but the output
* of such undefined behavior is never used.
**/
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
}
@@ -9855,7 +9869,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
simdjson_really_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
simdjson_really_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
simdjson_really_inline Mask operator==(const simd8<T> other) const { return vceqq_u8(*this, other); }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
template<int N=1>
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
@@ -11016,7 +11030,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
}
template<typename I>
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
const uint8_t digit = static_cast<uint8_t>(c - '0');
if (digit > 9) {
@@ -11264,7 +11278,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
}
@@ -11387,7 +11401,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -11437,7 +11451,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -11485,9 +11499,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
// instance.
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@@ -12847,7 +12863,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
}
template<typename I>
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
const uint8_t digit = static_cast<uint8_t>(c - '0');
if (digit > 9) {
@@ -13095,7 +13111,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
}
@@ -13218,7 +13234,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -13268,7 +13284,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -13316,9 +13332,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
// instance.
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@@ -13952,7 +13970,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
return (int)_tzcnt_u64(input_num);
@@ -14078,7 +14096,7 @@ namespace simd {
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline Mask operator==(const simd8<T> other) const { return _mm256_cmpeq_epi8(*this, other); }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm256_cmpeq_epi8(lhs, rhs); }
static const int SIZE = sizeof(base<T>::value);
@@ -15163,7 +15181,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
}
template<typename I>
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
const uint8_t digit = static_cast<uint8_t>(c - '0');
if (digit > 9) {
@@ -15411,7 +15429,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
}
@@ -15534,7 +15552,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -15584,7 +15602,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -15632,9 +15650,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
// instance.
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@@ -16223,7 +16243,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
@@ -16397,8 +16417,8 @@ struct base8 : base<simd8<T>> {
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline Mask operator==(const simd8<T> other) const {
return (__m128i)vec_cmpeq(this->value, (__m128i)other);
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) {
return (__m128i)vec_cmpeq(lhs.value, (__m128i)rhs);
}
static const int SIZE = sizeof(base<simd8<T>>::value);
@@ -17189,7 +17209,11 @@ simdjson_unused simdjson_warn_unused simdjson_really_inline error_code parse_str
#ifndef SIMDJSON_PPC64_NUMBERPARSING_H
#define SIMDJSON_PPC64_NUMBERPARSING_H
#if defined(__linux__)
#include <byteswap.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#endif
namespace simdjson {
namespace ppc64 {
@@ -17202,7 +17226,11 @@ parse_eight_digits_unrolled(const uint8_t *chars) {
uint64_t val;
std::memcpy(&val, chars, sizeof(uint64_t));
#ifdef __BIG_ENDIAN__
#if defined(__linux__)
val = bswap_64(val);
#elif defined(__FreeBSD__)
val = bswap64(val);
#endif
#endif
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
@@ -17578,7 +17606,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
}
template<typename I>
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
const uint8_t digit = static_cast<uint8_t>(c - '0');
if (digit > 9) {
@@ -17826,7 +17854,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
}
@@ -17949,7 +17977,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -17999,7 +18027,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -18047,9 +18075,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
// instance.
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@@ -18659,7 +18689,7 @@ namespace {
// We sometimes call trailing_zero on inputs that are zero,
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
NO_SANITIZE_UNDEFINED
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
@@ -18793,7 +18823,7 @@ namespace simd {
simdjson_really_inline base8() : base<simd8<T>>() {}
simdjson_really_inline base8(const __m128i _value) : base<simd8<T>>(_value) {}
simdjson_really_inline Mask operator==(const simd8<T> other) const { return _mm_cmpeq_epi8(*this, other); }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm_cmpeq_epi8(lhs, rhs); }
static const int SIZE = sizeof(base<simd8<T>>::value);
@@ -19851,7 +19881,7 @@ error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
}
template<typename I>
NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
SIMDJSON_NO_SANITIZE_UNDEFINED // We deliberately allow overflow here and check later
simdjson_really_inline bool parse_digit(const uint8_t c, I &i) {
const uint8_t digit = static_cast<uint8_t>(c - '0');
if (digit > 9) {
@@ -20099,7 +20129,7 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INVALID_NUMBER(src); }
}
@@ -20222,7 +20252,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -20272,7 +20302,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
@@ -20320,9 +20350,11 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned_
// - That is smaller than the smallest possible 20-digit number the user could write:
// 10,000,000,000,000,000,000.
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
// - The value we are looking at is less than or equal to INT64_MAX.
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
// Note: we use src[1] and not src[0] because src[0] is the quote character in this
// instance.
if (src[1] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@@ -21033,7 +21065,6 @@ protected:
uint64_t unsigned_integer;
} payload{0};
number_type type{number_type::signed_integer};
friend class value_iterator;
};
/**
@@ -22497,7 +22528,7 @@ public:
/**
* Get the value at the given index. This function has linear-time complexity.
* This function should only be called once as the array iterator is not reset between each call.
* This function should only be called once on an array instance since the array iterator is not reset between each call.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
@@ -22679,6 +22710,8 @@ public:
*
* The string is guaranteed to be valid UTF-8.
*
* Important: Calling get_string() twice on the same document is an error.
*
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -22852,7 +22885,7 @@ public:
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
/**
* Get the value at the given index in the array. This function has linear-time complexity.
* This function should only be called once as the array iterator is not reset between each call.
* This function should only be called once on an array instance since the array iterator is not reset between each call.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
@@ -22888,6 +22921,18 @@ public:
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
*
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to
* a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
* is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -22911,6 +22956,17 @@ public:
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
* field wasn't there when they aren't).
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to a key
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
* is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -22984,7 +23040,7 @@ public:
* type.
*
* number.get_number_type() is number_type::signed_integer if we have
* a integer in [-9223372036854775808,9223372036854775808)
* an integer in [-9223372036854775808,9223372036854775808)
* You can recover the value by calling number.get_int64() and you
* have that number.is_int64() is true.
*
@@ -23083,7 +23139,7 @@ public:
simdjson_really_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
/**
* Consumes the document and returns a string_view instance corresponding to the
* document as represented in JSON. It points inside the original byte array containg
* document as represented in JSON. It points inside the original byte array containing
* the JSON document.
*/
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
@@ -23126,6 +23182,7 @@ public:
simdjson_really_inline document_reference() noexcept;
simdjson_really_inline document_reference(document &d) noexcept;
simdjson_really_inline document_reference(const document_reference &other) noexcept = default;
simdjson_really_inline document_reference& operator=(const document_reference &other) noexcept = default;
simdjson_really_inline void rewind() noexcept;
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
@@ -23430,6 +23487,9 @@ public:
*
* Equivalent to get<std::string_view>().
*
* Important: a value should be consumed once. Calling get_string() twice on the same value
* is an error.
*
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -23553,9 +23613,24 @@ public:
* safe to continue.
*/
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
/**
* This method scans the object and counts the number of key-value pairs.
* The count_fields method should always be called before you have begun
* iterating through the object: it is expected that you are pointing at
* the beginning of the object.
* The runtime complexity is linear in the size of the object. After
* calling this function, if successful, the object is 'rewinded' at its
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
*
* To check that an object is empty, it is more performant to use
* the is_empty() method on the object instance.
*/
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
/**
* Get the value at the given index in the array. This function has linear-time complexity.
* This function should only be called once as the array iterator is not reset between each call.
* This function should only be called once on an array instance since the array iterator is not reset between each call.
*
* @return The value at the given index, or:
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
@@ -23684,7 +23759,7 @@ public:
* type.
*
* number.get_number_type() is number_type::signed_integer if we have
* a integer in [-9223372036854775808,9223372036854775808)
* an integer in [-9223372036854775808,9223372036854775808)
* You can recover the value by calling number.get_int64() and you
* have that number.is_int64() is true.
*
@@ -23734,6 +23809,11 @@ public:
*/
simdjson_really_inline std::string_view raw_json_token() noexcept;
/**
* Returns the current location in the document if in bounds.
*/
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
* https://tools.ietf.org/html/rfc6901 standard.
@@ -23861,6 +23941,7 @@ public:
simdjson_really_inline operator bool() noexcept(false);
#endif
simdjson_really_inline simdjson_result<size_t> count_elements() & noexcept;
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> at(size_t index) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array_iterator> begin() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
@@ -23933,6 +24014,9 @@ public:
/** @copydoc simdjson_really_inline std::string_view value::raw_json_token() const noexcept */
simdjson_really_inline simdjson_result<std::string_view> raw_json_token() noexcept;
/** @copydoc simdjson_really_inline simdjson_result<const char *> current_location() noexcept */
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
};
@@ -24050,6 +24134,17 @@ public:
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to a
* key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
* is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -24076,6 +24171,16 @@ public:
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
* that only one field is returned.
*
* You must consume the fields on an object one at a time. A request for a new key
* invalidates previous field values: it makes them unsafe. E.g., the array
* given by content["bids"].get_array() should not be accessed after you have called
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
* OUT_OF_ORDER_ITERATION error is generated.
*
* You are expected to access keys only once. You should access the value corresponding to a key
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
@@ -24271,6 +24376,11 @@ public:
* ondemand::parser parser;
* document doc = parser.iterate(json);
*
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
* Otherwise the iterate method may return an error. In particular, the whole input should be
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
* document.
*
* ### IMPORTANT: Validate what you use
*
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
@@ -24383,16 +24493,18 @@ public:
* ### Format
*
* The buffer must contain a series of one or more JSON documents, concatenated into a single
* buffer, separated by whitespace. It effectively parses until it has a fully valid document,
* buffer, separated by ASCII whitespace. It effectively parses until it has a fully valid document,
* then starts parsing the next document at that point. (It does this with more parallelism and
* lookahead than you might think, though.)
*
* documents that consist of an object or array may omit the whitespace between them, concatenating
* with no separator. documents that consist of a single primitive (i.e. documents that are not
* arrays or objects) MUST be separated with whitespace.
* with no separator. Documents that consist of a single primitive (i.e. documents that are not
* arrays or objects) MUST be separated with ASCII whitespace.
*
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
*
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
* Setting batch_size to excessively large or excesively small values may impact negatively the
* Setting batch_size to excessively large or excessively small values may impact negatively the
* performance.
*
* ### REQUIRED: Buffer Padding
@@ -24854,6 +24966,14 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::array> x);
} // namespace simdjson
/**
* We want to support argument-dependent lookup (ADL).
* Hence we should define operator<< in the namespace
* where the argument (here value, object, etc.) resides.
* Credit: @madhur4127
* See https://github.com/simdjson/simdjson/issues/1768
*/
namespace simdjson { namespace SIMDJSON_BUILTIN_IMPLEMENTATION { namespace ondemand {
/**
* Print JSON to an output stream.
@@ -24903,6 +25023,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_BUILTIN_IM
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::object> x);
#endif
}}} // namespace simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand
/* end file include/simdjson/generic/ondemand/serialization.h */
/* end file include/simdjson/generic/ondemand.h */
@@ -25608,17 +25729,6 @@ inline void json_iterator::rewind() noexcept {
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
/***
* WARNING:
* Inside an object, a string value is a depth of +1 compared to the object. Yet a key
* is at the same depth as the object.
* But json_iterator cannot easily tell whether we are pointing at a key or a string value.
* Instead, it assumes that if you are pointing at a string, then it is a value, not a key.
* To be clear...
* the following code assumes that we are *not* pointing at a key. If we are then a bug
* will follow. Unfortunately, it is not possible for the json_iterator its to make this
* check.
*/
if (depth() <= parent_depth) { return SUCCESS; }
switch (*return_current_and_advance()) {
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
@@ -25646,19 +25756,18 @@ simdjson_warn_unused simdjson_really_inline error_code json_iterator::skip_child
if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
#endif // SIMDJSON_CHECK_EOF
break;
/*case '"':
case '"':
if(*peek() == ':') {
// we are at a key!!! This is
// only possible if someone searched
// for a key in an object and the key
// was not found but our code then
// decided the consume the separating
// comma before returning.
// We are at a key!!!
// This might happen if you just started an object and you skip it immediately.
// Performance note: it would be nice to get rid of this check as it is somewhat
// expensive.
// https://github.com/simdjson/simdjson/issues/1742
logger::log_value(*this, "key");
advance(); // eat up the ':'
return_current_and_advance(); // eat up the ':'
break; // important!!!
}
simdjson_fallthrough;*/
simdjson_fallthrough;
// Anything else must be a scalar value
default:
// For the first scalar, we will have incremented depth already, so we decrement it here.
@@ -27789,7 +27898,7 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
simdjson_really_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); };
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
@@ -28044,6 +28153,7 @@ template<> simdjson_really_inline simdjson_result<array> value::get() noexcept {
template<> simdjson_really_inline simdjson_result<object> value::get() noexcept { return get_object(); }
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(); }
template<> simdjson_really_inline simdjson_result<number> value::get() noexcept { return get_number(); }
template<> simdjson_really_inline simdjson_result<double> value::get() noexcept { return get_double(); }
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
template<> simdjson_really_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
@@ -28096,6 +28206,13 @@ simdjson_really_inline simdjson_result<size_t> value::count_elements() & noexcep
iter.move_at_start();
return answer;
}
simdjson_really_inline simdjson_result<size_t> value::count_fields() & noexcept {
simdjson_result<size_t> answer;
auto a = get_object();
answer = a.count_fields();
iter.move_at_start();
return answer;
}
simdjson_really_inline simdjson_result<value> value::at(size_t index) noexcept {
auto a = get_array();
return a.at(index);
@@ -28151,6 +28268,10 @@ simdjson_really_inline std::string_view value::raw_json_token() noexcept {
return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
}
simdjson_really_inline simdjson_result<const char *> value::current_location() noexcept {
return iter.json_iter().current_location();
}
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
json_type t;
SIMDJSON_TRY(type().get(t));
@@ -28189,6 +28310,10 @@ simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_BUILTIN_
if (error()) { return error(); }
return first.count_elements();
}
simdjson_really_inline simdjson_result<size_t> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::count_fields() & noexcept {
if (error()) { return error(); }
return first.count_fields();
}
simdjson_really_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::at(size_t index) noexcept {
if (error()) { return error(); }
return first.at(index);
@@ -28361,6 +28486,11 @@ simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSO
return first.raw_json_token();
}
simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::current_location() noexcept {
if (error()) { return error(); }
return first.current_location();
}
simdjson_really_inline simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
if (error()) { return error(); }
return first.at_pointer(json_pointer);
@@ -28703,7 +28833,7 @@ simdjson_warn_unused simdjson_really_inline error_code parser::allocate(size_t n
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
} else {
SIMDJSON_TRY( simdjson::active_implementation->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
}
_capacity = new_capacity;
_max_depth = new_max_depth;
@@ -29323,6 +29453,7 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
}
} // namespace simdjson
namespace simdjson { namespace SIMDJSON_BUILTIN_IMPLEMENTATION { namespace ondemand {
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand::value x) {
@@ -29440,6 +29571,7 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_BUILTIN_IM
}
}
#endif
}}} // namespace simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand
/* end file include/simdjson/generic/ondemand/serialization-inl.h */
/* end file include/simdjson/generic/ondemand-inl.h */
+2 -2
View File
@@ -124,11 +124,11 @@ simdjson_really_inline uint64_t follows(const uint64_t match, uint64_t &overflow
simdjson_really_inline json_block json_scanner::next(const simd::simd8x64<uint8_t>& in) {
json_string_block strings = string_scanner.next(in);
// identifies the white-space and the structurat characters
// identifies the white-space and the structural characters
json_character_block characters = json_character_block::classify(in);
// The term "scalar" refers to anything except structural characters and white space
// (so letters, numbers, quotes).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
// We want follows_scalar to mark anything that follows a non-quote scalar (so letters and numbers).
//
// A terminal quote should either be followed by a structural character (comma, brace, bracket, colon)
// or nothing. However, we still want ' "a string"true ' to mark the 't' of 'true' as a potential
+4 -4
View File
@@ -80,25 +80,25 @@ public:
/**
* Log that a value has been found.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_value(const char *type) const noexcept;
/**
* Log the start of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_start_value(const char *type) const noexcept;
/**
* Log the end of a multipart value.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_end_value(const char *type) const noexcept;
/**
* Log an error.
*
* Set ENABLE_LOGGING=true in logger.h to see logging.
* Set LOG_ENABLED=true in logger.h to see logging.
*/
simdjson_really_inline void log_error(const char *error) const noexcept;
+56 -29
View File
@@ -15,19 +15,34 @@ namespace internal {
// without requiring a static initializer.
#if SIMDJSON_IMPLEMENTATION_HASWELL
const haswell::implementation haswell_singleton{};
static const haswell::implementation* get_haswell_singleton() {
static const haswell::implementation haswell_singleton{};
return &haswell_singleton;
}
#endif
#if SIMDJSON_IMPLEMENTATION_WESTMERE
const westmere::implementation westmere_singleton{};
static const westmere::implementation* get_westmere_singleton() {
static const westmere::implementation westmere_singleton{};
return &westmere_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_WESTMERE
#if SIMDJSON_IMPLEMENTATION_ARM64
const arm64::implementation arm64_singleton{};
static const arm64::implementation* get_arm64_singleton() {
static const arm64::implementation arm64_singleton{};
return &arm64_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_ARM64
#if SIMDJSON_IMPLEMENTATION_PPC64
const ppc64::implementation ppc64_singleton{};
static const ppc64::implementation* get_ppc64_singleton() {
static const ppc64::implementation ppc64_singleton{};
return &ppc64_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_PPC64
#if SIMDJSON_IMPLEMENTATION_FALLBACK
const fallback::implementation fallback_singleton{};
static const fallback::implementation* get_fallback_singleton() {
static const fallback::implementation fallback_singleton{};
return &fallback_singleton;
}
#endif // SIMDJSON_IMPLEMENTATION_FALLBACK
/**
@@ -56,25 +71,26 @@ private:
const implementation *set_best() const noexcept;
};
const detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton;
const std::initializer_list<const implementation *> available_implementation_pointers {
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
static const std::initializer_list<const implementation *> available_implementation_pointers {
#if SIMDJSON_IMPLEMENTATION_HASWELL
&haswell_singleton,
get_haswell_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_WESTMERE
&westmere_singleton,
get_westmere_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_ARM64
&arm64_singleton,
get_arm64_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_PPC64
&ppc64_singleton,
get_ppc64_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_FALLBACK
&fallback_singleton,
get_fallback_singleton(),
#endif
}; // available_implementation_pointers
}; // available_implementation_pointers
return available_implementation_pointers;
}
// So we can return UNSUPPORTED_ARCHITECTURE from the parser when there is no support
class unsupported_implementation final : public implementation {
@@ -102,25 +118,28 @@ public:
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
};
const unsupported_implementation unsupported_singleton{};
const unsupported_implementation* get_unsupported_singleton() {
static const unsupported_implementation unsupported_singleton{};
return &unsupported_singleton;
}
size_t available_implementation_list::size() const noexcept {
return internal::available_implementation_pointers.size();
return internal::get_available_implementation_pointers().size();
}
const implementation * const *available_implementation_list::begin() const noexcept {
return internal::available_implementation_pointers.begin();
return internal::get_available_implementation_pointers().begin();
}
const implementation * const *available_implementation_list::end() const noexcept {
return internal::available_implementation_pointers.end();
return internal::get_available_implementation_pointers().end();
}
const implementation *available_implementation_list::detect_best_supported() const noexcept {
// They are prelisted in priority order, so we just go down the list
uint32_t supported_instruction_sets = internal::detect_supported_architectures();
for (const implementation *impl : internal::available_implementation_pointers) {
for (const implementation *impl : internal::get_available_implementation_pointers()) {
uint32_t required_instruction_sets = impl->required_instruction_sets();
if ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets) { return impl; }
}
return &unsupported_singleton; // this should never happen?
return get_unsupported_singleton(); // this should never happen?
}
const implementation *detect_best_supported_implementation_on_first_use::set_best() const noexcept {
@@ -130,31 +149,39 @@ const implementation *detect_best_supported_implementation_on_first_use::set_bes
SIMDJSON_POP_DISABLE_WARNINGS
if (force_implementation_name) {
auto force_implementation = available_implementations[force_implementation_name];
auto force_implementation = get_available_implementations()[force_implementation_name];
if (force_implementation) {
return active_implementation = force_implementation;
return get_active_implementation() = force_implementation;
} else {
// Note: abort() and stderr usage within the library is forbidden.
return active_implementation = &unsupported_singleton;
return get_active_implementation() = get_unsupported_singleton();
}
}
return active_implementation = available_implementations.detect_best_supported();
return get_active_implementation() = get_available_implementations().detect_best_supported();
}
} // namespace internal
SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list available_implementations{};
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation> active_implementation{&internal::detect_best_supported_implementation_on_first_use_singleton};
SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations() {
static const internal::available_implementation_list available_implementations{};
return available_implementations;
}
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation() {
static const internal::detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton;
static internal::atomic_ptr<const implementation> active_implementation{&detect_best_supported_implementation_on_first_use_singleton};
return active_implementation;
}
simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, size_t &dst_len) noexcept {
return active_implementation->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len);
return get_active_implementation()->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len);
}
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
return active_implementation->validate_utf8(buf, len);
return get_active_implementation()->validate_utf8(buf, len);
}
const implementation * builtin_implementation() {
static const implementation * builtin_impl = available_implementations[STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
assert(builtin_impl);
return builtin_impl;
}
+2 -2
View File
@@ -3,7 +3,7 @@
#include <cstring>
int main(int argc, const char *argv[]) {
std::cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << " is running the " << simdjson::active_implementation->name() << " implementation." << std::endl;
std::cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << " is running the " << simdjson::get_active_implementation()->name() << " implementation." << std::endl;
const char *expected_implementation = nullptr;
if (argc > 1) {
expected_implementation = argv[1];
@@ -15,7 +15,7 @@ int main(int argc, const char *argv[]) {
}
std::cout << "No expected implementation argument, but SIMDJSON_FORCE_IMPLEMENTATION is set to " << expected_implementation << ", so we'll check for that." << std::endl;
}
if (strcmp(expected_implementation, simdjson::active_implementation->name().c_str())) {
if (strcmp(expected_implementation, simdjson::get_active_implementation()->name().c_str())) {
std::cerr << "Wrong implementation! Expected " << expected_implementation << "." << std::endl;
return EXIT_FAILURE;
}
+8 -8
View File
@@ -32,7 +32,7 @@
#endif
const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793;
#define SIMDJSON_SHOW_DEFINE(x) printf("%s=%s\n", #x, STRINGIFY(x))
#define SIMDJSON_SHOW_DEFINE(x) printf("%s=%s\n", #x, SIMDJSON_STRINGIFY(x))
namespace number_tests {
@@ -1617,12 +1617,12 @@ namespace validate_tests {
bool test_random() {
std::cout << "Running " << __func__ << std::endl;
std::vector<uint8_t> source(64,' ');
const simdjson::implementation *impl_fallback = simdjson::available_implementations["fallback"];
const simdjson::implementation *impl_fallback = simdjson::get_available_implementations()["fallback"];
if(!impl_fallback) { return true; }
for(size_t i = 0; i < 10000; i++) {
std::vector<uint8_t>& s(source);
s[i%64] ^= uint8_t(1235 * i);
const bool active_ok = simdjson::active_implementation->validate_utf8((const char*)s.data(), s.size());
const bool active_ok = simdjson::get_active_implementation()->validate_utf8((const char*)s.data(), s.size());
const bool fallback_ok = impl_fallback->validate_utf8((const char*)s.data(), s.size());
if(active_ok != fallback_ok) { return false; }
s[i%64] ^= uint8_t(1235 * i);
@@ -2137,7 +2137,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -2146,7 +2146,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
@@ -2156,12 +2156,12 @@ int main(int argc, char *argv[]) {
}
// this is put here deliberately to check that the documentation is correct (README),
// should this fail to compile, you should update the documentation:
if (simdjson::active_implementation->name() == "unsupported") {
if (simdjson::get_active_implementation()->name() == "unsupported") {
printf("unsupported CPU\n");
}
// We want to know what we are testing.
std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
std::cout << " (" << simdjson::active_implementation->description() << ")" << std::endl;
std::cout << "Running tests against this implementation: " << simdjson::get_active_implementation()->name();
std::cout << " (" << simdjson::get_active_implementation()->description() << ")" << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
std::cout << "Running basic tests." << std::endl;
+25 -7
View File
@@ -858,7 +858,24 @@ namespace document_stream_tests {
for (auto doc : docs) {
bool_count += doc.is_bool();
}
return true;
return (bool_count == 0);
}
bool fuzzaccess() {
std::cout << "Running " << __func__ << std::endl;
// Issue 38801 in oss-fuzz
auto json = "\xff \n~~\n{}"_padded;
simdjson::dom::parser parser;
simdjson::dom::document_stream docs;
ASSERT_SUCCESS(parser.parse_many(json).get(docs));
size_t bool_count = 0;
size_t total_count = 0;
for (auto doc : docs) {
total_count++;
bool_count += doc.is_bool();
}
return (bool_count == 0) && (total_count == 1);
}
bool baby_fuzzer() {
@@ -892,7 +909,8 @@ namespace document_stream_tests {
}
bool run() {
return baby_fuzzer() &&
return fuzzaccess() &&
baby_fuzzer() &&
issue1649() &&
adversarial_single_document_array() &&
adversarial_single_document() &&
@@ -934,7 +952,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -943,7 +961,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
@@ -954,12 +972,12 @@ int main(int argc, char *argv[]) {
// this is put here deliberately to check that the documentation is correct (README),
// should this fail to compile, you should update the documentation:
if (simdjson::active_implementation->name() == "unsupported") {
if (simdjson::get_active_implementation()->name() == "unsupported") {
printf("unsupported CPU\n");
}
// We want to know what we are testing.
std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
std::cout << " (" << simdjson::active_implementation->description() << ")" << std::endl;
std::cout << "Running tests against this implementation: " << simdjson::get_active_implementation()->name();
std::cout << " (" << simdjson::get_active_implementation()->description() << ")" << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
std::cout << "Running document_stream tests." << std::endl;
+5 -5
View File
@@ -197,7 +197,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -206,7 +206,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
@@ -217,12 +217,12 @@ int main(int argc, char *argv[]) {
// this is put here deliberately to check that the documentation is correct (README),
// should this fail to compile, you should update the documentation:
if (simdjson::active_implementation->name() == "unsupported") {
if (simdjson::get_active_implementation()->name() == "unsupported") {
printf("unsupported CPU\n");
}
// We want to know what we are testing.
std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
std::cout << " (" << simdjson::active_implementation->description() << ")" << std::endl;
std::cout << "Running tests against this implementation: " << simdjson::get_active_implementation()->name();
std::cout << " (" << simdjson::get_active_implementation()->description() << ")" << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
std::cout << "Running document tests." << std::endl;
+5 -5
View File
@@ -194,7 +194,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -203,7 +203,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
@@ -214,12 +214,12 @@ int main(int argc, char *argv[]) {
// this is put here deliberately to check that the documentation is correct (README),
// should this fail to compile, you should update the documentation:
if (simdjson::active_implementation->name() == "unsupported") {
if (simdjson::get_active_implementation()->name() == "unsupported") {
printf("unsupported CPU\n");
}
// We want to know what we are testing.
std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
std::cout << " (" << simdjson::active_implementation->description() << ")" << std::endl;
std::cout << "Running tests against this implementation: " << simdjson::get_active_implementation()->name();
std::cout << " (" << simdjson::get_active_implementation()->description() << ")" << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
std::cout << "Running error tests." << std::endl;
if (!(true
+2 -2
View File
@@ -117,7 +117,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -126,7 +126,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
+2 -2
View File
@@ -115,7 +115,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -124,7 +124,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
-2
View File
@@ -179,7 +179,6 @@ static bool has_extension(const char *filename, const char *extension) {
bool validate(const char *dirname) {
parse_error = 0;
size_t total_count = 0;
const char *extension = ".json";
size_t dirlen = std::strlen(dirname);
struct dirent **entry_list;
@@ -215,7 +214,6 @@ bool validate(const char *dirname) {
float_count = 0;
int_count = 0;
invalid_count = 0;
total_count += float_count + int_count + invalid_count;
simdjson::dom::parser parser;
auto err = parser.parse(p).error();
bool isok = (err == simdjson::error_code::SUCCESS);
+5 -5
View File
@@ -158,7 +158,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -167,7 +167,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
@@ -178,12 +178,12 @@ int main(int argc, char *argv[]) {
// this is put here deliberately to check that the documentation is correct (README),
// should this fail to compile, you should update the documentation:
if (simdjson::active_implementation->name() == "unsupported") {
if (simdjson::get_active_implementation()->name() == "unsupported") {
printf("unsupported CPU\n");
}
// We want to know what we are testing.
std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
std::cout << " (" << simdjson::active_implementation->description() << ")" << std::endl;
std::cout << "Running tests against this implementation: " << simdjson::get_active_implementation()->name();
std::cout << " (" << simdjson::get_active_implementation()->description() << ")" << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
if(optind >= argc) {
std::cerr << "Usage: " << argv[0] << " <directorywithjsonfiles>"
+2 -2
View File
@@ -158,7 +158,7 @@ int main(int argc, char *argv[]) {
while ((c = getopt(argc, argv, "a:m:h")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
@@ -167,7 +167,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "The selected implementation does not match your current CPU: -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
case 'h': {
+9 -9
View File
@@ -263,9 +263,9 @@ void basics_ndjson_parse_many() {
}
}
void implementation_selection_1() {
cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "Detected the best implementation for your machine: " << simdjson::active_implementation->name();
cout << "(" << simdjson::active_implementation->description() << ")" << endl;
cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
}
void unescaped_key() {
@@ -288,32 +288,32 @@ void unescaped_key() {
}
void implementation_selection_2() {
for (auto implementation : simdjson::available_implementations) {
for (auto implementation : simdjson::get_available_implementations()) {
cout << implementation->name() << ": " << implementation->description() << endl;
}
}
void implementation_selection_2_safe() {
for (auto implementation : simdjson::available_implementations) {
for (auto implementation : simdjson::get_available_implementations()) {
if(implementation->supported_by_runtime_system()) {
cout << implementation->name() << ": " << implementation->description() << endl;
}
}
}
void implementation_selection_3() {
cout << simdjson::available_implementations["fallback"]->description() << endl;
cout << simdjson::get_available_implementations()["fallback"]->description() << endl;
}
void implementation_selection_safe() {
auto my_implementation = simdjson::available_implementations["haswell"];
auto my_implementation = simdjson::get_available_implementations()["haswell"];
if(! my_implementation) { exit(1); }
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
simdjson::active_implementation = my_implementation;
simdjson::get_active_implementation() = my_implementation;
}
void implementation_selection_4() {
// Use the fallback implementation, even though my machine is fast enough for anything
simdjson::active_implementation = simdjson::available_implementations["fallback"];
simdjson::get_active_implementation() = simdjson::get_available_implementations()["fallback"];
}
void ondemand_performance_1() {
+31
View File
@@ -423,6 +423,36 @@ namespace array_tests {
ASSERT_TRUE(is_empty);
return true;
}
bool issue1742() {
TEST_START();
auto json = R"( {
"code": 0,
"method": "subscribe",
"result": {
"instrument_name": "DAI_USDC",
"subscription": "trade.DAI_USDC",
"channel": "trade",
"data": [
[1,2,3,4]
]
}
} )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
simdjson::ondemand::array data;
ASSERT_SUCCESS(doc["result"]["data"].get_array().get(data));
for (auto d : data) {
simdjson::ondemand::array arr;
ASSERT_SUCCESS(d.get_array().get(arr));
size_t count;
ASSERT_SUCCESS(arr.count_elements().get(count));
ASSERT_EQUAL(count, 4);
}
TEST_SUCCEED();
}
bool value_to_array(simdjson::ondemand::value val) {
ondemand::json_type t;
ASSERT_SUCCESS(val.type().get(t));
@@ -780,6 +810,7 @@ namespace array_tests {
bool run() {
return
issue1742() &&
empty_rewind_convoluted() &&
empty_rewind() &&
iterate_empty_array_count() &&
@@ -9,10 +9,190 @@ namespace document_stream_tests {
bool process_doc(T &docref) {
int64_t val;
ASSERT_SUCCESS(docref.at_pointer("/4").get(val));
//ASSERT_SUCCESS(err);
ASSERT_EQUAL(val, 5);
return true;
}
bool truncated_utf8() {
TEST_START();
// truncated UTF-8
auto json = "\"document1\" \xC3"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
auto oderror = parser.iterate_many(json).get(stream);
if (oderror) {
std::cerr << "ondemand iterate_many error: " << oderror << std::endl;
return false;
}
int document_index = 0;
auto i = stream.begin();
for (; i != stream.end(); ++i) {
ondemand::document_reference doc;
auto err = (*i).get(doc);
document_index++;
// With the fallback routine, we might detect a 'document' since
// it does not do UTF-8 validation in stage one, but it will do
// so when we access the document.
if(err == SUCCESS) {
ondemand::json_type t;
err = doc.type().get(t);
}
if((err == SUCCESS) && (document_index != 1)) {
std::cerr << "Only the first document should be valid." << std::endl;
return false;
}
if((err != SUCCESS) && (document_index != 2)) {
std::cerr << "ondemand iterate_many error: " << err << std::endl;
return false;
}
}
if(document_index < 1) {
std::cerr << "ondemand should have accessed at least one document" << std::endl;
return false;
}
TEST_SUCCEED();
}
bool issue1729() {
// This example is not a good application of iterate_many since there is
// a single JSON document.
TEST_START();
auto json = R"({
"t": 5649,
"ng": 5,
"lu": 4086,
"g": [{
"t": "Temps",
"xvy": 0,
"pd": 60,
"sz": 3,
"l": [
"Low Temp",
"High Temp",
"Smooth Avg"
],
"c": [
"green",
"orange",
"cyan"
],
"d": [
80.48750305,
80.82499694,
80.65625
]
},
{
"t": "Pump Status",
"xvy": 0,
"pd": 60,
"sz": 3,
"l": [
"Pump",
"Thermal",
"Light"
],
"c": [
"green",
"orange",
"cyan"
],
"d": [
0,
0,
0
]
},
{
"t": "Lux",
"xvy": 0,
"pd": 60,
"sz": 4,
"l": [
"Value",
"Smooth",
"Low",
"High"
],
"c": [
"green",
"orange",
"cyan",
"yellow"
],
"d": [
2274.62939453,
2277.45947265,
4050,
4500
]
},
{
"t": "Temp Diff",
"xvy": 0,
"pd": 60,
"sz": 4,
"l": [
"dFarenheit",
"sum",
"Low",
"High"
],
"c": [
"green",
"orange",
"cyan",
"yellow"
],
"d": [
0,
0,
0.5,
10
]
},
{
"t": "Power",
"xvy": 0,
"pd": 60,
"sz": 3,
"l": [
"watts (est. light) ",
"watts (1.9~gpm) ",
"watts (1gpm) "
],
"c": [
"green",
"orange",
"cyan"
],
"d": [
181.78063964,
114.88922882,
59.35943603
]
}
]
})"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
auto oderror = parser.iterate_many(json).get(stream);
if (oderror) {
std::cerr << "ondemand iterate_many error: " << oderror << std::endl;
return false;
}
auto i = stream.begin();
for (; i != stream.end(); ++i) {
ondemand::document_reference doc;
auto err = (*i).get(doc);
if(err != SUCCESS) {
std::cerr << "ondemand iterate_many error: " << err << std::endl;
return false;
}
}
TEST_SUCCEED();
}
bool issue1683() {
TEST_START();
@@ -511,8 +691,34 @@ namespace document_stream_tests {
TEST_SUCCEED();
}
bool fuzzaccess() {
TEST_START();
// Issue 38801 in oss-fuzz
auto json = "\xff \n~~\n{}"_padded;
ondemand::parser parser;
ondemand::document_stream docs;
ASSERT_SUCCESS(parser.iterate_many(json).get(docs));
size_t bool_count = 0;
size_t total_count = 0;
for (auto doc : docs) {
total_count++;
bool b;
if(doc.get_bool().get(b) == SUCCESS) { bool_count +=b; }
// If we don't access the document at all, other than get_bool(),
// then some simdjson kernels will allow you to iterate through
// 3 'documents'. By asking for the type, we make the iteration
// terminate after the first 'document'.
ondemand::json_type t;
if(doc.type().get(t) != SUCCESS) { break; }
}
return (bool_count == 0) && (total_count == 1);
}
bool run() {
return
truncated_utf8() &&
issue1729() &&
fuzzaccess() &&
issue1683() &&
issue1668() &&
issue1668_long() &&
@@ -237,6 +237,27 @@ namespace error_location_tests {
ASSERT_EQUAL(ptr, "13.34.514 ");
TEST_SUCCEED();
}
bool current_location_in_value() {
TEST_START();
auto json = R"( {"a": {"b": "c"}} )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
simdjson_result<ondemand::value> a = doc["a"];
ASSERT_SUCCESS(a);
const char * ptr;
ASSERT_SUCCESS(a.current_location().get(ptr));
ASSERT_EQUAL(ptr, R"({"b": "c"}} )");
simdjson_result<ondemand::value> b = a["b"];
ASSERT_SUCCESS(b);
ASSERT_SUCCESS(b.current_location().get(ptr));
ASSERT_EQUAL(ptr, R"("c"}} )");
double d;
ASSERT_ERROR(b.get_double().get(d), INCORRECT_TYPE);
ASSERT_SUCCESS(b.current_location().get(ptr));
ASSERT_EQUAL(ptr, R"("c"}} )");
TEST_SUCCEED();
}
bool run() {
return array() &&
@@ -253,6 +274,7 @@ namespace error_location_tests {
object_with_no_such_field() &&
number_parsing_error() &&
number_parsing_root_error() &&
current_location_in_value() &&
true;
}
@@ -346,8 +346,49 @@ namespace json_pointer_tests {
TEST_SUCCEED();
}
#if SIMDJSON_EXCEPTIONS
bool json_pointer_invalidation_exceptions() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
ondemand::parser parser;
std::vector<double> measured;
ondemand::document cars = parser.iterate(cars_json);
std::vector<car_type> content;
for (int i = 0; i < 3; i++) {
std::string json_pointer = "/" + std::to_string(i);
// Each successive at_pointer call invalidates
// previously parsed values, strings, objects and array.
ondemand::object obj(cars.at_pointer(json_pointer).get_object());
// We materialize the object.
std::string_view make = obj["make"];
std::string_view model = obj["model"];
uint64_t year(obj["year"]);
// We materialize the array.
ondemand::array arr(obj["tire_pressure"].get_array());
std::vector<double> values;
for(auto x : arr) {
double value_double(x.get_double());
values.push_back(value_double);
}
content.emplace_back(make, model, year, std::move(values));
}
std::string expected[] = {"Toyota", "Kia", "Toyota"};
for (car_type c : content) {
std::cout << c.make << " " << c.model << " " << c.year << "\n";
}
TEST_SUCCEED();
}
#endif
bool run() {
return
#if SIMDJSON_EXCEPTIONS
json_pointer_invalidation_exceptions() &&
#endif
many_json_pointers_array() &&
many_json_pointers_object() &&
many_json_pointers_object_array() &&
@@ -54,12 +54,12 @@ namespace number_in_string_tests {
bool array_int() {
TEST_START();
auto json = R"(["1", "2", "-3", "1000", "-7844"])"_padded;
auto json = R"(["1", "2", "-3", "1000", "-7844", "-9223372036854775807", "9223372036854775807"])"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
size_t counter{0};
std::vector<int> expected = {1, 2, -3, 1000, -7844};
std::vector<int64_t> expected = {1, 2, -3, 1000, -7844, INT64_C(-9223372036854775807), INT64_C(9223372036854775807) };
int64_t i;
for (auto value : doc) {
ASSERT_SUCCESS(value.get_int64_in_string().get(i));
@@ -70,12 +70,12 @@ namespace number_in_string_tests {
bool array_unsigned() {
TEST_START();
auto json = R"(["1", "2", "24", "9000", "156934"])"_padded;
auto json = R"(["1", "2", "24", "9000", "156934", "10588030077111859193", "18446744073709551615"])"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
size_t counter{0};
std::vector<int> expected = {1, 2, 24, 9000, 156934};
std::vector<uint64_t> expected = {1, 2, 24, 9000, 156934, UINT64_C(10588030077111859193), UINT64_C(18446744073709551615)};
uint64_t u;
for (auto value : doc) {
ASSERT_SUCCESS(value.get_uint64_in_string().get(u));
@@ -86,7 +86,7 @@ namespace number_in_string_tests {
bool object() {
TEST_START();
auto json = R"({"a":"1.2", "b":"-2.342e2", "c":"22", "d":"-112358", "e":"1080", "f":"123456789"})"_padded;
auto json = R"({"a":"1.2", "b":"-2.342e2", "c":"22", "d":"-112358", "e":"1080", "f":"123456789", "g":"10588030077111859193"})"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
@@ -110,6 +110,8 @@ namespace number_in_string_tests {
ASSERT_EQUAL(u,expected[counter++]);
ASSERT_SUCCESS(doc.find_field("f").get_uint64_in_string().get(u));
ASSERT_EQUAL(u,expected[counter++]);
ASSERT_SUCCESS(doc.find_field("g").get_uint64_in_string().get(u));
ASSERT_EQUAL(u, UINT64_C(10588030077111859193));
TEST_SUCCEED();
}
@@ -131,7 +133,7 @@ namespace number_in_string_tests {
ASSERT_SUCCESS(parser.iterate(int_doc).get(doc));
ASSERT_SUCCESS(doc.get_int64_in_string().get(i));
ASSERT_EQUAL(i,-243);
// Unsinged integer
// Unsigned integer
ASSERT_SUCCESS(parser.iterate(uint_doc).get(doc));
ASSERT_SUCCESS(doc.get_uint64_in_string().get(u));
ASSERT_EQUAL(u,212213);
+6 -4
View File
@@ -197,16 +197,18 @@ namespace number_tests {
bool get_number_tests() {
TEST_START();
ondemand::parser parser;
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999])"_padded;
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999,-9223372036854775807,-9223372036854775808])"_padded;
ondemand::number_type expectedtypes[] = {ondemand::number_type::floating_point_number,
ondemand::number_type::signed_integer,
ondemand::number_type::signed_integer,
ondemand::number_type::floating_point_number,
ondemand::number_type::signed_integer,
ondemand::number_type::unsigned_integer
ondemand::number_type::unsigned_integer,
ondemand::number_type::signed_integer,
ondemand::number_type::signed_integer
};
bool is_negative[] = {false, false, false, false, true, false};
bool is_integer[] = {false, true, true, false, true, true};
bool is_negative[] = {false, false, false, false, true, false, true, true};
bool is_integer[] = {false, true, true, false, true, true, true, true};
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
+258
View File
@@ -6,6 +6,108 @@ using namespace simdjson;
namespace object_tests {
using namespace std;
using simdjson::ondemand::json_type;
bool issue1745() {
TEST_START();
auto json = R"({
"keys": [
{
"kid": "bbd2ac7c4c5eb8adc8eeffbc8f5a2dd6cf7545e4",
"e": "AQAB",
"alg": "RS256",
"use": "sig",
"n": "y930dtGTeMG52IPsKmMuEpPHLaxuYQlduZd6BqFVjc2-UFZR8fNqtnYzAjbXWJD_Tqxgdlj_MW4vogvX4sHwVpZONvdyeGoIyDQtis6iuGQhQamV85F_JbrEUnEw3QCO87Liz5UXG6BK2HRyPhDfMex1_tO0ROmySLFdCTS17D0wah71Ibpi0gI8LUi6kzVRjYDIC1oE-iK3Y9s88Bi4ZGYJxXAbnNwbwVkGOKCXja9k0jjBGRxZD-4KDuf493lFOOEGSLDA2Qp9rDqrURP12XYgvf_zJx_kSDipnr0gL6Vz2n3H4-XN4tA45zuzRkHoE7-XexPq-tv7kQ8pSjY2uQ",
"kty": "RSA"
},
{
"kty": "RSA",
"n": "zMHxWuxztMKXdBhv3rImlUvW_yp6nO03cVXPyA0Vyq0-M7LfOJJIF-OdNoRGdsFPHVKCFoo6qGhR8rBCmMxA4fM-Ubk5qKuUqCN9eP3yZJq8Cw9tUrt_qh7uW-qfMr0upcyeSHhC_zW1lTGs5sowDorKN_jQ1Sfh9hfBxfc8T7dQAAgEqqMcE3u-2J701jyhJz0pvurCfziiB3buY6SGREhBQwNwpnQjt_lE2U4km8FS0woPzt0ccE3zsGL2qM-LWZbOm9aXquSnqNJLt3tGVvShnev-GiJ1XfQ3EWm0f4w0TX9fTOkxstl0vo_vW_FjGQ0D1pXSjqb7n-hAdXwc9w",
"alg": "RS256",
"kid": "85828c59284a69b54b27483e487c3bd46cd2a2b3",
"e": "AQAB",
"use": "sig"
}
]
}
})"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
for (auto items_instance : doc["keys"]) {
ondemand::object items;
ASSERT_SUCCESS(items_instance.get_object().get(items));
std::string_view kty_value;
ASSERT_SUCCESS(items["kty"].get_string().get(kty_value));
std::string_view use_value;
ASSERT_SUCCESS(items["use"].get_string().get(use_value));
if (kty_value != "RSA" && use_value != "sig") { continue; }
std::string_view str;
ASSERT_SUCCESS(items["alg"].get_string().get(str));
ASSERT_EQUAL(str, "RS256");
ASSERT_EQUAL(use_value, "sig");
ASSERT_EQUAL(kty_value, "RSA");
ASSERT_SUCCESS(items["n"].get_string().get(str));
ASSERT_EQUAL(str.size(), 342);
ASSERT_SUCCESS(items["e"].get_string().get(str));
ASSERT_EQUAL(str, "AQAB");
}
TEST_SUCCEED();
}
bool issue1723() {
TEST_START();
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({
"contents":
{
"bids":[
{"offset":"1", "price":"1.1", "size":"4.1"}
],
"asks":[
{"offset":"1111", "price":"1.100", "size":"114.1"}
]
}
})"_padded;
simdjson::ondemand::document doc;
auto error = parser.iterate(docdata).get(doc);
if(error) { return false; }
ondemand::object content;
error = doc.get_object().find_field("contents").get(content);
if(error) { return false; }
ondemand::array bids;
error = content["bids"].get_array().get(bids);
if(error) { return false; }
for (auto aux : bids) {
uint64_t id;
error = aux["offset"].get_uint64_in_string().get(id);
if(error) { return false; }
double price;
error = aux["price"].get_double_in_string().get(price);
if(error) { return false; }
double size;
error = aux["size"].get_double_in_string().get(size);
if(error) { return false; }
std::cout << id << " " << price << " " << size << std::endl;
}
ondemand::array asks;
error = content["asks"].get_array().get(asks);
if(error) { return false; }
for (auto aux : asks) {
uint64_t id;
error = aux["offset"].get_uint64_in_string().get(id);
if(error) { return false; }
double price;
error = aux["price"].get_double_in_string().get(price);
if(error) { return false; }
double size;
error = aux["size"].get_double_in_string().get(size);
if(error) { return false; }
std::cout << id << " " << price << " " << size << std::endl;
}
return true;
}
// In this test, no non-trivial object in an array have a missing key
bool no_missing_keys() {
TEST_START();
@@ -123,6 +225,83 @@ namespace object_tests {
}
#if SIMDJSON_EXCEPTIONS
bool issue1745_with_exceptions() {
TEST_START();
auto json = R"({
"keys": [
{
"kid": "bbd2ac7c4c5eb8adc8eeffbc8f5a2dd6cf7545e4",
"e": "AQAB",
"alg": "RS256",
"use": "sig",
"n": "y930dtGTeMG52IPsKmMuEpPHLaxuYQlduZd6BqFVjc2-UFZR8fNqtnYzAjbXWJD_Tqxgdlj_MW4vogvX4sHwVpZONvdyeGoIyDQtis6iuGQhQamV85F_JbrEUnEw3QCO87Liz5UXG6BK2HRyPhDfMex1_tO0ROmySLFdCTS17D0wah71Ibpi0gI8LUi6kzVRjYDIC1oE-iK3Y9s88Bi4ZGYJxXAbnNwbwVkGOKCXja9k0jjBGRxZD-4KDuf493lFOOEGSLDA2Qp9rDqrURP12XYgvf_zJx_kSDipnr0gL6Vz2n3H4-XN4tA45zuzRkHoE7-XexPq-tv7kQ8pSjY2uQ",
"kty": "RSA"
},
{
"kty": "RSA",
"n": "zMHxWuxztMKXdBhv3rImlUvW_yp6nO03cVXPyA0Vyq0-M7LfOJJIF-OdNoRGdsFPHVKCFoo6qGhR8rBCmMxA4fM-Ubk5qKuUqCN9eP3yZJq8Cw9tUrt_qh7uW-qfMr0upcyeSHhC_zW1lTGs5sowDorKN_jQ1Sfh9hfBxfc8T7dQAAgEqqMcE3u-2J701jyhJz0pvurCfziiB3buY6SGREhBQwNwpnQjt_lE2U4km8FS0woPzt0ccE3zsGL2qM-LWZbOm9aXquSnqNJLt3tGVvShnev-GiJ1XfQ3EWm0f4w0TX9fTOkxstl0vo_vW_FjGQ0D1pXSjqb7n-hAdXwc9w",
"alg": "RS256",
"kid": "85828c59284a69b54b27483e487c3bd46cd2a2b3",
"e": "AQAB",
"use": "sig"
}
]
}
})"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
for (auto items : doc["keys"]) {
std::string_view kty_value = items["kty"].get_string();
std::string_view use_value = items["use"].get_string();
if (kty_value != "RSA" && use_value != "sig") { continue; }
std::string_view str = items["alg"].get_string();
if(str != "RS256") { return false; }
if(use_value != "sig") { return false; }
if(kty_value != "RSA") { return false; }
str = items["n"].get_string();
if(str.size() != 342) { return false; }
str = items["e"].get_string();
if(str != "AQAB") { return false; }
}
TEST_SUCCEED();
}
bool issue1723_except() {
TEST_START();
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({
"contents":
{
"bids":[
{"offset":"1", "price":"1.1", "size":"4.1"}
],
"asks":[
{"offset":"1111", "price":"1.100", "size":"114.1"}
]
}
})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
ondemand::object content = doc.get_object().find_field("contents");
ondemand::array bids = content["bids"].get_array();
std::cout << "bids:" << std::endl;
for (auto aux : bids) {
uint64_t id = aux["offset"].get_uint64_in_string();
double price = aux["price"].get_double_in_string();
double size = aux["size"].get_double_in_string();
std::cout << id << " " << price << " " << size << std::endl;
}
ondemand::array asks = content["asks"].get_array();
std::cout << "asks:" << std::endl;
for (auto aux : asks) {
uint64_t id = aux["offset"].get_uint64_in_string();
double price = aux["price"].get_double_in_string();
double size = aux["size"].get_double_in_string();
std::cout << id << " " << price << " " << size << std::endl;
}
return true;
}
// used in issue_1521
// difficult to use as a lambda because it is recursive.
void broken_descend(ondemand::object node) {
@@ -717,6 +896,79 @@ namespace object_tests {
TEST_SUCCEED();
}
bool issue1742() {
TEST_START();
auto json = R"( {
"code": 0,
"method": "subscribe",
"result": {
"instrument_name": "DAI_USDC",
"subscription": "trade.DAI_USDC",
"channel": "trade",
"data": [
{
"dataTime": 1635315736764,
"d": 1928673075051012900,
"s": "SELL",
"p": 1.0004,
"q": 0.01,
"t": 1635315736763,
"i": "DAI_USDC"
}
]
}
} )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
simdjson::ondemand::array data;
ASSERT_SUCCESS(doc["result"]["data"].get_array().get(data));
for (auto d : data) {
simdjson::ondemand::object obj;
ASSERT_SUCCESS(d.get_object().get(obj));
size_t count;
ASSERT_SUCCESS(obj.count_fields().get(count));
ASSERT_EQUAL(count, 7);
}
TEST_SUCCEED();
}
bool issue1742_value() {
TEST_START();
auto json = R"( {
"code": 0,
"method": "subscribe",
"result": {
"instrument_name": "DAI_USDC",
"subscription": "trade.DAI_USDC",
"channel": "trade",
"data": [
{
"dataTime": 1635315736764,
"d": 1928673075051012900,
"s": "SELL",
"p": 1.0004,
"q": 0.01,
"t": 1635315736763,
"i": "DAI_USDC"
}
]
}
} )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
simdjson::ondemand::array data;
ASSERT_SUCCESS(doc["result"]["data"].get_array().get(data));
for (auto d : data) {
size_t count;
ASSERT_SUCCESS(d.count_fields().get(count));
ASSERT_EQUAL(count, 7);
}
TEST_SUCCEED();
}
bool iterate_basic_object_count() {
TEST_START();
auto json = R"( {"a":-55, "b":3.23, "c":100000000000000000000, "d":true, "e":null} )"_padded;
@@ -824,12 +1076,18 @@ namespace object_tests {
bool run() {
return
issue1745() &&
issue1742() &&
issue1742_value() &&
issue1723() &&
value_search_unescaped_key() &&
missing_key_continue() &&
no_missing_keys() &&
missing_keys() &&
missing_keys_for_empty_top_level_object() &&
#if SIMDJSON_EXCEPTIONS
issue1745_with_exceptions() &&
issue1723_except() &&
fixed_broken_issue_1521() &&
issue_1521() &&
broken_issue_1521() &&
@@ -109,6 +109,85 @@ bool basics_treewalk() {
return true;
}
void print_depth_space(ondemand::value element) {
for(auto i = 0; i < element.current_depth(); i++) {
cout << " ";
}
}
void recursive_print_json_breakline(ondemand::value element) {
bool add_comma;
switch (element.type()) {
case ondemand::json_type::array:
cout << endl;
print_depth_space(element);
cout << "[";
add_comma = false;
for (auto child : element.get_array()) {
if (add_comma) {
print_depth_space(element);
cout << ",";
}
// We need the call to value() to get
// an ondemand::value type.
recursive_print_json_breakline(child.value());
add_comma = true;
}
cout << "]";
break;
case ondemand::json_type::object:
cout << endl;
print_depth_space(element);
cout << "{";
add_comma = false;
for (auto field : element.get_object()) {
if (add_comma) {
print_depth_space(element);
cout << ",";
}
// key() returns the key as it appears in the raw
// JSON document, if we want the unescaped key,
// we should do field.unescaped_key().
cout << "\"" << field.key() << "\": ";
recursive_print_json_breakline(field.value());
add_comma = true;
}
cout << "}\n";
break;
case ondemand::json_type::number:
// assume it fits in a double
cout << element.get_double();
break;
case ondemand::json_type::string:
// get_string() would return escaped string, but
// we are happy with unescaped string.
cout << "\"" << element.get_raw_json_string() << "\"";
break;
case ondemand::json_type::boolean:
cout << element.get_bool();
break;
case ondemand::json_type::null:
cout << "null";
break;
}
}
bool basics_treewalk_breakline() {
padded_string json[3] = {R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded, R"( {"key":"value"} )"_padded, "[12,3]"_padded};
ondemand::parser parser;
for(size_t i = 0 ; i < 3; i++) {
ondemand::document doc = parser.iterate(json[i]);
ondemand::value val = doc;
recursive_print_json_breakline(val);
std::cout << std::endl;
}
return true;
}
bool basics_1() {
TEST_START();
@@ -882,6 +961,7 @@ bool current_location_no_error() {
int main() {
#if SIMDJSON_EXCEPTIONS
basics_treewalk();
basics_treewalk_breakline();
#endif
if (
true
@@ -13,6 +13,26 @@
#include <vector>
#include "simdjson.h"
/**
* What follows is merely a compilation test to verify
* https://github.com/simdjson/simdjson/issues/1768
* It deliberately resides before any namespace declaration
* within this file.
*/
namespace issue1768 {
template <typename T> void print(const T &a) { std::cout << a; }
} // namespace NA
void issue1768_test() {
simdjson::ondemand::object obj;
issue1768::print(obj);
}
/**
* End of 1768 compilation check.
*/
using namespace simdjson;
#include "test_ondemand.h"
@@ -438,6 +458,9 @@ bool run() {
} // namespace tostring_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, tostring_tests::run);
}
+4 -4
View File
@@ -41,7 +41,7 @@ bool test_ondemand_doc(const simdjson::padded_string &json, const F& f) {
}
const size_t AMAZON_CELLPHONES_NDJSON_DOC_COUNT = 793;
#define SIMDJSON_SHOW_DEFINE(x) printf("%s=%s\n", #x, STRINGIFY(x))
#define SIMDJSON_SHOW_DEFINE(x) printf("%s=%s\n", #x, SIMDJSON_STRINGIFY(x))
template<typename F>
int test_main(int argc, char *argv[], const F& test_function) {
@@ -50,12 +50,12 @@ int test_main(int argc, char *argv[], const F& test_function) {
while ((c = getopt(argc, argv, "a:")) != -1) {
switch (c) {
case 'a': {
const simdjson::implementation *impl = simdjson::available_implementations[optarg];
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
if (!impl) {
std::fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
default:
@@ -66,7 +66,7 @@ int test_main(int argc, char *argv[], const F& test_function) {
// this is put here deliberately to check that the documentation is correct (README),
// should this fail to compile, you should update the documentation:
if (simdjson::active_implementation->name() == "unsupported") {
if (simdjson::get_active_implementation()->name() == "unsupported") {
std::printf("unsupported CPU\n");
std::abort();
}
+1 -1
View File
@@ -255,7 +255,7 @@ void puzzler() {
}
std::cout << "\"" << std::endl;
bool is_ok{true};
for(const auto& e: simdjson::available_implementations) {
for(const auto& e: simdjson::get_available_implementations()) {
if(!e->supported_by_runtime_system()) { continue; }
const bool current = e->validate_utf8(bad64, length);
std::cout << e->name() << " returns " << current << std::endl;
+2 -2
View File
@@ -20,9 +20,9 @@ int main(int argc, const char *argv[]) {
std::string progName = "json2json";
std::string progUsage = "json2json version ";
progUsage += STRINGIFY(SIMDJSON_VERSION);
progUsage += SIMDJSON_STRINGIFY(SIMDJSON_VERSION);
progUsage += " (";
progUsage += simdjson::active_implementation->name();
progUsage += simdjson::get_active_implementation()->name();
progUsage += ")\n";
progUsage += "Reads json in, out the result of the parsing.\n";
progUsage += argv[0];
+4 -4
View File
@@ -31,7 +31,7 @@ int main(int argc, const char *argv[]) {
std::stringstream ss;
ss << "Parser implementation (by default, detects the most advanced implementation supported on the host machine)." << std::endl;
ss << "Available parser implementations:" << std::endl;
for (auto impl : simdjson::available_implementations) {
for (auto impl : simdjson::get_available_implementations()) {
if(impl->supported_by_runtime_system()) {
ss << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << std::endl;
}
@@ -55,7 +55,7 @@ int main(int argc, const char *argv[]) {
return EXIT_FAILURE;
}
if(result.count("arch")) {
const simdjson::implementation *impl = simdjson::available_implementations[result["arch"].as<std::string>().c_str()];
const simdjson::implementation *impl = simdjson::get_available_implementations()[result["arch"].as<std::string>().c_str()];
if(!impl) {
usage("Unsupported implementation.");
return EXIT_FAILURE;
@@ -64,7 +64,7 @@ int main(int argc, const char *argv[]) {
usage("The selected implementation does not match your current CPU.");
return EXIT_FAILURE;
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
}
std::string filename = result["file"].as<std::string>();
@@ -77,7 +77,7 @@ int main(int argc, const char *argv[]) {
}
simdjson::padded_string copy(p.length()); // does not need to be padded after all!
size_t copy_len;
error = simdjson::active_implementation->minify((const uint8_t*)p.data(), p.length(), (uint8_t*)copy.data(), copy_len);
error = simdjson::get_active_implementation()->minify((const uint8_t*)p.data(), p.length(), (uint8_t*)copy.data(), copy_len);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
printf("%s", copy.data());
return EXIT_SUCCESS;