mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e1d07ee86 | |||
| 9de1b45e30 | |||
| 7a73230459 | |||
| 667f488c2c | |||
| e6c90b8efb | |||
| 7c450fbb70 | |||
| 4e1e002cb0 | |||
| de196dd7a3 | |||
| 08cb8dd81c | |||
| 57d54792ba | |||
| 79879802f9 | |||
| fbe955e9a4 | |||
| a49ac04046 | |||
| 49c7654a70 | |||
| 3e777c1759 | |||
| a410c723c8 | |||
| f91a1ae07e | |||
| c3954b1fb8 | |||
| ce74ece545 | |||
| dd4dce848e | |||
| e8f370b085 | |||
| 645033a8c8 | |||
| 3b5ceeb80d | |||
| 82433a67f9 |
+8
-4
@@ -8,7 +8,7 @@ steps:
|
|||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||||
@@ -19,6 +19,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
||||||
@@ -35,7 +36,7 @@ steps:
|
|||||||
CC: clang-6.0
|
CC: clang-6.0
|
||||||
CXX: clang++-6.0
|
CXX: clang++-6.0
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
- mkdir build
|
- mkdir build
|
||||||
@@ -43,6 +44,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
||||||
@@ -100,7 +102,7 @@ steps:
|
|||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||||
@@ -111,6 +113,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
@@ -126,7 +129,7 @@ steps:
|
|||||||
environment:
|
environment:
|
||||||
CC: clang-9
|
CC: clang-9
|
||||||
CXX: clang++-9
|
CXX: clang++-9
|
||||||
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
|
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
|
||||||
BUILD_FLAGS: -- -j
|
BUILD_FLAGS: -- -j
|
||||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||||
commands:
|
commands:
|
||||||
@@ -135,6 +138,7 @@ steps:
|
|||||||
- cmake $CMAKE_FLAGS ..
|
- cmake $CMAKE_FLAGS ..
|
||||||
- cmake --build . $BUILD_FLAGS
|
- cmake --build . $BUILD_FLAGS
|
||||||
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
|
||||||
|
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ jobs:
|
|||||||
whitespace:
|
whitespace:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Remove whitespace and check the diff
|
- name: Remove whitespace and check the diff
|
||||||
run: |
|
run: |
|
||||||
set -eu
|
set -eu
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ jobs:
|
|||||||
chmod +x llvm.sh
|
chmod +x llvm.sh
|
||||||
sudo ./llvm.sh $CLANGVERSION
|
sudo ./llvm.sh $CLANGVERSION
|
||||||
|
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
id: cache-corpus
|
id: cache-corpus
|
||||||
with:
|
with:
|
||||||
path: out/
|
path: out/
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ jobs:
|
|||||||
CMAKE_GENERATOR: Ninja
|
CMAKE_GENERATOR: Ninja
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
@@ -38,6 +38,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
|
||||||
cmake --build . --verbose
|
cmake --build . --verbose
|
||||||
ctest -j4 --output-on-failure -LE explicitonly
|
ctest -j4 --output-on-failure -LE explicitonly
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ jobs:
|
|||||||
CMAKE_GENERATOR: Ninja
|
CMAKE_GENERATOR: Ninja
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ jobs:
|
|||||||
CC: clang-7
|
CC: clang-7
|
||||||
CXX: clang++-7
|
CXX: clang++-7
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
name: Ubuntu 20.04 CI (GCC 8)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-build:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
env:
|
||||||
|
CXX: g++-8
|
||||||
|
CC: gcc-8
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install GCC 8
|
||||||
|
run: sudo apt-get install -y g++-8
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir builddebug &&
|
||||||
|
cd builddebug &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cd .. &&
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cmake --install . &&
|
||||||
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
|
cd ../tests/installation_tests/find &&
|
||||||
|
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Ubuntu 22.04 CI (CLANG 13)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-build:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install clang++-13
|
||||||
|
run: sudo apt-get install -y clang++-13
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Ubuntu 22.04 CI (GCC 12)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-build:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Install gcc12
|
||||||
|
run: sudo apt-get install -y g++-12
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Ubuntu 22.04 CI (GCC 11)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-build:
|
||||||
|
if: >-
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||||
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: dependencies/.cache
|
||||||
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir builddebug &&
|
||||||
|
cd builddebug &&
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cd .. &&
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest -j --output-on-failure -LE explicitonly &&
|
||||||
|
cmake --install . &&
|
||||||
|
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||||
|
cd ../tests/installation_tests/find &&
|
||||||
|
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
- {arch: ARM64}
|
- {arch: ARM64}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Use cmake
|
- name: Use cmake
|
||||||
run: |
|
run: |
|
||||||
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||||
|
|||||||
@@ -13,16 +13,16 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- {gen: Visual Studio 17 2022, arch: Win32, static: ON}
|
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
|
||||||
- {gen: Visual Studio 17 2022, arch: Win32, static: OFF}
|
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
|
||||||
- {gen: Visual Studio 17 2022, arch: x64, static: ON}
|
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
|
||||||
- {gen: Visual Studio 17 2022, arch: x64, static: OFF}
|
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
|
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||||
- name: Build Debug
|
- name: Build Debug
|
||||||
run: cmake --build build --config Debug --verbose
|
run: cmake --build build --config Debug --verbose
|
||||||
- name: Build Release
|
- name: Build Release
|
||||||
|
|||||||
@@ -9,23 +9,33 @@ jobs:
|
|||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||||
name: windows-vs17
|
name: windows-vs17
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- {gen: Visual Studio 17 2022, arch: x64}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: checkout
|
||||||
- uses: actions/cache@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
- name: Configure
|
||||||
path: dependencies/.cache
|
run: |
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||||
- name: 'Run CMake with VS17 Clang'
|
- name: Build Debug
|
||||||
uses: lukka/run-cmake@v3
|
run: cmake --build build --config Debug --verbose
|
||||||
with:
|
- name: Build Release
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
run: cmake --build build --config Release --verbose
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
- name: Run Release tests
|
||||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
run: |
|
||||||
cmakeBuildType: Release
|
cd build
|
||||||
buildWithCMake: true
|
ctest -C Release -LE explicitonly --output-on-failure
|
||||||
cmakeAppendedArgs: -T ClangCL -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
- name: Run Debug tests
|
||||||
buildWithCMakeArgs: --config Release
|
run: |
|
||||||
|
cd build
|
||||||
- name: 'Run CTest'
|
ctest -C Debug -LE explicitonly --output-on-failure
|
||||||
run: ctest -C Release -LE explicitonly --output-on-failure
|
- name: Install
|
||||||
working-directory: "${{ github.workspace }}/../../_temp/windows"
|
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,45 +0,0 @@
|
|||||||
name: VS17-Ninja-CI
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
if: >-
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
|
||||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
|
||||||
name: windows-vs17
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: dependencies/.cache
|
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
|
||||||
- name: 'Run CMake with VS17'
|
|
||||||
uses: lukka/run-cmake@v2
|
|
||||||
with:
|
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
|
||||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
|
||||||
cmakeBuildType: Release
|
|
||||||
buildWithCMake: true
|
|
||||||
cmakeAppendedArgs: -G Ninja -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
|
|
||||||
buildWithCMakeArgs: --config Release
|
|
||||||
- name: 'Run CTest'
|
|
||||||
run: ctest -C Release -LE explicitonly --output-on-failure
|
|
||||||
working-directory: "${{ github.workspace }}/../../_temp/windows"
|
|
||||||
- name: 'Install with CMake'
|
|
||||||
uses: lukka/run-cmake@v3
|
|
||||||
with:
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
|
||||||
buildWithCMakeArgs: '--target install'
|
|
||||||
- name: 'Test Installation with CMake'
|
|
||||||
uses: lukka/run-cmake@v3
|
|
||||||
with:
|
|
||||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
|
||||||
cmakeListsTxtPath: '${{ github.workspace }}/tests/installation_tests/find/CMakeLists.txt'
|
|
||||||
cmakeBuildType: Release
|
|
||||||
buildWithCMake: true
|
|
||||||
buildDirectory: '${{ github.workspace }}/tests/installation_tests/find/buildDirectory'
|
|
||||||
cmakeAppendedArgs: -G Ninja
|
|
||||||
buildWithCMakeArgs: '--config Release --verbose'
|
|
||||||
@@ -7,8 +7,8 @@ jobs:
|
|||||||
name: windows-vs17
|
name: windows-vs17
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: dependencies/.cache
|
path: dependencies/.cache
|
||||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
project(
|
project(
|
||||||
simdjson
|
simdjson
|
||||||
# The version number is modified by tools/release.py
|
# The version number is modified by tools/release.py
|
||||||
VERSION 1.0.2
|
VERSION 2.0.4
|
||||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||||
HOMEPAGE_URL "https://simdjson.org/"
|
HOMEPAGE_URL "https://simdjson.org/"
|
||||||
LANGUAGES CXX C
|
LANGUAGES CXX C
|
||||||
@@ -20,8 +20,8 @@ string(
|
|||||||
# ---- Options, variables ----
|
# ---- Options, variables ----
|
||||||
|
|
||||||
# These version numbers are modified by tools/release.py
|
# These version numbers are modified by tools/release.py
|
||||||
set(SIMDJSON_LIB_VERSION "9.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "11.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "9" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "11" CACHE STRING "simdjson library soversion")
|
||||||
|
|
||||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -62,13 +62,13 @@ Pull Requests
|
|||||||
|
|
||||||
Pull requests are always invited. However, we ask that you follow these guidelines:
|
Pull requests are always invited. However, we ask that you follow these guidelines:
|
||||||
|
|
||||||
- It is wiser to discuss your ideas first as part of an issue before you start coding. If you omit this step and code first, be prepare to have your code receive scrutiny and be dropped.
|
- It is wise to discuss your ideas first as part of an issue before you start coding. If you omit this step and code first, be prepared to have your code receive scrutiny and be dropped.
|
||||||
- Users should provide a rationale for their changes. Does it improve performance? Does it add a feature? Does it improve maintainability? Does fix a bug? This must be explicitly stated as part of the pull request. Do not propose changes based on taste or intuition. We do not delegate programming to tools: that some tool suggested a code change is not reason enough to change the code.
|
- Users should provide a rationale for their changes. Does it improve performance? Does it add a feature? Does it improve maintainability? Does it fix a bug? This must be explicitly stated as part of the pull request. Do not propose changes based on taste or intuition. We do not delegate programming to tools: that some tool suggested a code change is not reason enough to change the code.
|
||||||
1. When your code improves performance, please document the gains with a benchmark using hard numbers.
|
1. When your code improves performance, please document the gains with a benchmark using hard numbers.
|
||||||
2. If your code fixes a bug, please be either fix a failing test, or propose a new test.
|
2. If your code fixes a bug, please either fix a failing test, or propose a new test.
|
||||||
3. Other types of changes must be clearly motivated. We openly discourage changes with no identifiable benefits.
|
3. Other types of changes must be clearly motivated. We openly discourage changes with no identifiable benefits.
|
||||||
- Changes should be focused and minimal. You should change as few lines of code as possible. Please do not reformat or touch files needlessly.
|
- Changes should be focused and minimal. You should change as few lines of code as possible. Please do not reformat or touch files needlessly.
|
||||||
- New features must be accompanied of new tests, in general.
|
- New features must be accompanied by new tests, in general.
|
||||||
- Your code should pass our continuous-integration tests. It is your responsibility to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
|
- Your code should pass our continuous-integration tests. It is your responsibility to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
|
||||||
- An exception to this would be changes to non-code files, such as documentation and assets, or trivial changes to code, such as comments, where it is encouraged to explicitly ask for skipping a CI run using the `[skip ci]` prefix in your Pull Request title **and** in the first line of the most recent commit in a push. Example for such a commit: `[skip ci] Fixed typo in power_of_ten's docs`
|
- An exception to this would be changes to non-code files, such as documentation and assets, or trivial changes to code, such as comments, where it is encouraged to explicitly ask for skipping a CI run using the `[skip ci]` prefix in your Pull Request title **and** in the first line of the most recent commit in a push. Example for such a commit: `[skip ci] Fixed typo in power_of_ten's docs`
|
||||||
This benefits the project in such a way that the CI pipeline is not burdened by running jobs on changes that don't change any behavior in the code, which reduces wait times for other Pull Requests that do change behavior and require testing.
|
This benefits the project in such a way that the CI pipeline is not burdened by running jobs on changes that don't change any behavior in the code, which reduces wait times for other Pull Requests that do change behavior and require testing.
|
||||||
|
|||||||
+4
-1
@@ -38,5 +38,8 @@ Brendan Knapp
|
|||||||
Danila Kutenin
|
Danila Kutenin
|
||||||
Pavel Pavlov
|
Pavel Pavlov
|
||||||
Hao Chen
|
Hao Chen
|
||||||
# if you have contributed to the project and your name does not
|
Nicolas Boyer
|
||||||
|
Kim Walisch and Jatin Bhateja (AVX-512 bitset decoder)
|
||||||
|
Fangzheng Zhang and Weiqiang Wan (AVX-512 kernel)
|
||||||
|
# if you have contributed to the project and your name does not
|
||||||
# appear in this list, please let us know!
|
# appear in this list, please let us know!
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "1.0.2"
|
PROJECT_NUMBER = "2.0.4"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[/badge.svg)](https://simdjson.org/plots.html)
|
[/badge.svg)](https://simdjson.org/plots.html)
|
||||||

|

|
||||||

|

|
||||||
[![][license img]][license] [](https://simdjson.org/api/1.0.0/index.html)
|
[![][license img]][license] [](https://simdjson.org/api/2.0.0/index.html)
|
||||||
|
|
||||||
simdjson : Parsing gigabytes of JSON per second
|
simdjson : Parsing gigabytes of JSON per second
|
||||||
===============================================
|
===============================================
|
||||||
|
|||||||
@@ -4,8 +4,12 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace amazon_cellphones {
|
namespace amazon_cellphones {
|
||||||
|
|
||||||
|
const bool UNTHREADED = false;
|
||||||
|
const bool THREADED = true;
|
||||||
|
|
||||||
using namespace json_benchmark;
|
using namespace json_benchmark;
|
||||||
|
|
||||||
struct brand {
|
struct brand {
|
||||||
@@ -59,10 +63,11 @@ struct runner : public file_runner<I> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
|
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
@@ -8,12 +8,16 @@ namespace amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom {
|
struct simdjson_dom {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
dom::parser parser{};
|
dom::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
auto stream = parser.parse_many(json);
|
auto stream = parser.parse_many(json);
|
||||||
auto i = stream.begin();
|
auto i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -37,7 +41,10 @@ struct simdjson_dom {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom)->UseManualTime();
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ namespace amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_ondemand {
|
struct simdjson_ondemand {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
ondemand::document_stream stream = parser.iterate_many(json);
|
ondemand::document_stream stream = parser.iterate_many(json);
|
||||||
ondemand::document_stream::iterator i = stream.begin();
|
ondemand::document_stream::iterator i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -58,7 +62,10 @@ struct simdjson_ondemand {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand)->UseManualTime();
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -204,10 +204,13 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of 1-7-structural misses per 8-structural flip
|
// Rate of 1-7-structural misses per 8-structural flip
|
||||||
double struct1_7_miss_rate(BenchmarkStage stage) const {
|
double struct1_7_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return struct7_miss[stage].best.branch_misses() - struct7[stage].best.branch_misses() / double(struct7_miss.stats->blocks_with_1_structural_flipped);
|
return struct7_miss[stage].best.branch_misses() - struct7[stage].best.branch_misses() / double(struct7_miss.stats->blocks_with_1_structural_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra cost of an 8-15 structural block over a 1-7 structural block
|
// Extra cost of an 8-15 structural block over a 1-7 structural block
|
||||||
double struct8_15_cost(BenchmarkStage stage) const {
|
double struct8_15_cost(BenchmarkStage stage) const {
|
||||||
return cost_per_block(stage, struct15, struct15.stats->blocks_with_8_structurals, struct7);
|
return cost_per_block(stage, struct15, struct15.stats->blocks_with_8_structurals, struct7);
|
||||||
@@ -218,8 +221,12 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of 8-15-structural misses per 8-structural flip
|
// Rate of 8-15-structural misses per 8-structural flip
|
||||||
double struct8_15_miss_rate(BenchmarkStage stage) const {
|
double struct8_15_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(struct15_miss[stage].best.branch_misses() - struct15[stage].best.branch_misses()) / double(struct15_miss.stats->blocks_with_8_structurals_flipped);
|
return double(struct15_miss[stage].best.branch_misses() - struct15[stage].best.branch_misses()) / double(struct15_miss.stats->blocks_with_8_structurals_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra cost of a 16+-structural block over an 8-15 structural block (actual varies based on # of structurals!)
|
// Extra cost of a 16+-structural block over an 8-15 structural block (actual varies based on # of structurals!)
|
||||||
@@ -232,10 +239,15 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of 16-structural misses per 16-structural flip
|
// Rate of 16-structural misses per 16-structural flip
|
||||||
double struct16_miss_rate(BenchmarkStage stage) const {
|
double struct16_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(struct23_miss[stage].best.branch_misses() - struct23[stage].best.branch_misses()) / double(struct23_miss.stats->blocks_with_16_structurals_flipped);
|
return double(struct23_miss[stage].best.branch_misses() - struct23[stage].best.branch_misses()) / double(struct23_miss.stats->blocks_with_16_structurals_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Extra cost of having UTF-8 in a block
|
// Extra cost of having UTF-8 in a block
|
||||||
double utf8_cost(BenchmarkStage stage) const {
|
double utf8_cost(BenchmarkStage stage) const {
|
||||||
return cost_per_block(stage, utf8, utf8.stats->blocks_with_utf8, struct7_full);
|
return cost_per_block(stage, utf8, utf8.stats->blocks_with_utf8, struct7_full);
|
||||||
@@ -246,10 +258,13 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of UTF-8 misses per UTF-8 flip
|
// Rate of UTF-8 misses per UTF-8 flip
|
||||||
double utf8_miss_rate(BenchmarkStage stage) const {
|
double utf8_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(utf8_miss[stage].best.branch_misses() - utf8[stage].best.branch_misses()) / double(utf8_miss.stats->blocks_with_utf8_flipped);
|
return double(utf8_miss[stage].best.branch_misses() - utf8[stage].best.branch_misses()) / double(utf8_miss.stats->blocks_with_utf8_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra cost of having escapes in a block
|
// Extra cost of having escapes in a block
|
||||||
double escape_cost(BenchmarkStage stage) const {
|
double escape_cost(BenchmarkStage stage) const {
|
||||||
return cost_per_block(stage, escape, escape.stats->blocks_with_escapes, struct7_full);
|
return cost_per_block(stage, escape, escape.stats->blocks_with_escapes, struct7_full);
|
||||||
@@ -260,10 +275,15 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
// Rate of escape misses per escape flip
|
// Rate of escape misses per escape flip
|
||||||
double escape_miss_rate(BenchmarkStage stage) const {
|
double escape_miss_rate(BenchmarkStage stage) const {
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
if (!has_events()) { return 1; }
|
if (!has_events()) { return 1; }
|
||||||
return double(escape_miss[stage].best.branch_misses() - escape[stage].best.branch_misses()) / double(escape_miss.stats->blocks_with_escapes_flipped);
|
return double(escape_miss[stage].best.branch_misses() - escape[stage].best.branch_misses()) / double(escape_miss.stats->blocks_with_escapes_flipped);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double calc_expected_feature_cost(BenchmarkStage stage, const benchmarker& file) const {
|
double calc_expected_feature_cost(BenchmarkStage stage, const benchmarker& file) const {
|
||||||
// Expected base ns/block (empty)
|
// Expected base ns/block (empty)
|
||||||
json_stats& stats = *file.stats;
|
json_stats& stats = *file.stats;
|
||||||
@@ -300,7 +320,6 @@ struct feature_benchmarker {
|
|||||||
double calc_expected(BenchmarkStage stage, const benchmarker& file) const {
|
double calc_expected(BenchmarkStage stage, const benchmarker& file) const {
|
||||||
return calc_expected_feature_cost(stage, file) + calc_expected_miss_cost(stage, file);
|
return calc_expected_feature_cost(stage, file) + calc_expected_miss_cost(stage, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(const option_struct& options) const {
|
void print(const option_struct& options) const {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Features in ns/block (64 bytes):\n");
|
printf("Features in ns/block (64 bytes):\n");
|
||||||
@@ -359,6 +378,22 @@ struct feature_benchmarker {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
|
||||||
|
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
|
||||||
|
double calc = features.calc_expected(stage, results);
|
||||||
|
double calc_misses = features.calc_expected_misses(stage, results);
|
||||||
|
double calc_miss_cost = features.calc_expected_miss_cost(stage, results);
|
||||||
|
printf(" | %-8s ", benchmark_stage_name(stage));
|
||||||
|
printf("| %-15s ", filename);
|
||||||
|
printf("| %8.3g ", features.calc_expected_feature_cost(stage, results));
|
||||||
|
printf("| %8.3g ", calc_miss_cost);
|
||||||
|
printf("| %8.3g ", calc);
|
||||||
|
printf("| %8.3g ", actual);
|
||||||
|
printf("| %+8.3g ", actual - calc);
|
||||||
|
printf("| %13llu ", (long long unsigned)(calc_misses));
|
||||||
|
}
|
||||||
|
#else
|
||||||
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
|
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
|
||||||
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
|
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
|
||||||
double calc = features.calc_expected(stage, results);
|
double calc = features.calc_expected(stage, results);
|
||||||
@@ -382,6 +417,7 @@ void print_file_effectiveness(BenchmarkStage stage, const char* filename, const
|
|||||||
}
|
}
|
||||||
printf("|\n");
|
printf("|\n");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
// Read options
|
// Read options
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define __BENCHMARKER_H
|
#define __BENCHMARKER_H
|
||||||
|
|
||||||
#include "event_counter.h"
|
#include "event_counter.h"
|
||||||
#include "simdjson.h" // For SIMDJSON_DISABLE_DEPRECATED_WARNINGS
|
#include "simdjson.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@@ -423,7 +423,7 @@ struct benchmarker {
|
|||||||
stage.instructions() / static_cast<double>(stats->structurals),
|
stage.instructions() / static_cast<double>(stats->structurals),
|
||||||
stage.instructions() / static_cast<double>(stage.cycles())
|
stage.instructions() / static_cast<double>(stage.cycles())
|
||||||
);
|
);
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
// NOTE: removed cycles/miss because it is a somewhat misleading stat
|
// NOTE: removed cycles/miss because it is a somewhat misleading stat
|
||||||
printf("%s%-13s: %7.0f branch misses (%6.2f%%) - %.0f cache misses (%6.2f%%) - %.2f cache references\n",
|
printf("%s%-13s: %7.0f branch misses (%6.2f%%) - %.0f cache misses (%6.2f%%) - %.2f cache references\n",
|
||||||
prefix,
|
prefix,
|
||||||
@@ -434,6 +434,7 @@ struct benchmarker {
|
|||||||
percent(stage.cache_misses(), all_stages_without_allocation.cache_misses()),
|
percent(stage.cache_misses(), all_stages_without_allocation.cache_misses()),
|
||||||
stage.cache_references()
|
stage.cache_references()
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ simdjson_really_inline void simdjson_process_atom(stat_t &s,
|
|||||||
} else if(element.is<double>()) {
|
} else if(element.is<double>()) {
|
||||||
s.float_count++;
|
s.float_count++;
|
||||||
} else if (element.is<bool>()) {
|
} else if (element.is<bool>()) {
|
||||||
simdjson::error_code err;
|
|
||||||
bool v;
|
bool v;
|
||||||
err = element.get(v);
|
simdjson::error_code error;
|
||||||
|
if ((error = element.get(v))) { std::cerr << error << std::endl; abort(); }
|
||||||
if (v) {
|
if (v) {
|
||||||
s.true_count++;
|
s.true_count++;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
#ifndef __EVENT_COUNTER_H
|
#ifndef __EVENT_COUNTER_H
|
||||||
#define __EVENT_COUNTER_H
|
#define __EVENT_COUNTER_H
|
||||||
|
|
||||||
|
#ifndef SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
#ifdef __aarch64__
|
||||||
|
// on ARM, we use just cycles and instructions
|
||||||
|
#define SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS 1
|
||||||
|
#else
|
||||||
|
// elsewhere, we try to use four counters.
|
||||||
|
#define SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
@@ -46,6 +55,12 @@ struct event_count {
|
|||||||
event_count(const event_count& other): elapsed(other.elapsed), event_counts(other.event_counts) { }
|
event_count(const event_count& other): elapsed(other.elapsed), event_counts(other.event_counts) { }
|
||||||
|
|
||||||
// The types of counters (so we can read the getter more easily)
|
// The types of counters (so we can read the getter more easily)
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
enum event_counter_types {
|
||||||
|
CPU_CYCLES,
|
||||||
|
INSTRUCTIONS
|
||||||
|
};
|
||||||
|
#else
|
||||||
enum event_counter_types {
|
enum event_counter_types {
|
||||||
CPU_CYCLES,
|
CPU_CYCLES,
|
||||||
INSTRUCTIONS,
|
INSTRUCTIONS,
|
||||||
@@ -53,15 +68,16 @@ struct event_count {
|
|||||||
CACHE_REFERENCES,
|
CACHE_REFERENCES,
|
||||||
CACHE_MISSES
|
CACHE_MISSES
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
double elapsed_sec() const { return duration<double>(elapsed).count(); }
|
double elapsed_sec() const { return duration<double>(elapsed).count(); }
|
||||||
double elapsed_ns() const { return duration<double, std::nano>(elapsed).count(); }
|
double elapsed_ns() const { return duration<double, std::nano>(elapsed).count(); }
|
||||||
double cycles() const { return static_cast<double>(event_counts[CPU_CYCLES]); }
|
double cycles() const { return static_cast<double>(event_counts[CPU_CYCLES]); }
|
||||||
double instructions() const { return static_cast<double>(event_counts[INSTRUCTIONS]); }
|
double instructions() const { return static_cast<double>(event_counts[INSTRUCTIONS]); }
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
double branch_misses() const { return static_cast<double>(event_counts[BRANCH_MISSES]); }
|
double branch_misses() const { return static_cast<double>(event_counts[BRANCH_MISSES]); }
|
||||||
double cache_references() const { return static_cast<double>(event_counts[CACHE_REFERENCES]); }
|
double cache_references() const { return static_cast<double>(event_counts[CACHE_REFERENCES]); }
|
||||||
double cache_misses() const { return static_cast<double>(event_counts[CACHE_MISSES]); }
|
double cache_misses() const { return static_cast<double>(event_counts[CACHE_MISSES]); }
|
||||||
|
#endif
|
||||||
event_count& operator=(const event_count& other) {
|
event_count& operator=(const event_count& other) {
|
||||||
this->elapsed = other.elapsed;
|
this->elapsed = other.elapsed;
|
||||||
this->event_counts = other.event_counts;
|
this->event_counts = other.event_counts;
|
||||||
@@ -105,9 +121,11 @@ struct event_aggregate {
|
|||||||
double elapsed_ns() const { return total.elapsed_ns() / iterations; }
|
double elapsed_ns() const { return total.elapsed_ns() / iterations; }
|
||||||
double cycles() const { return total.cycles() / iterations; }
|
double cycles() const { return total.cycles() / iterations; }
|
||||||
double instructions() const { return total.instructions() / iterations; }
|
double instructions() const { return total.instructions() / iterations; }
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
double branch_misses() const { return total.branch_misses() / iterations; }
|
double branch_misses() const { return total.branch_misses() / iterations; }
|
||||||
double cache_references() const { return total.cache_references() / iterations; }
|
double cache_references() const { return total.cache_references() / iterations; }
|
||||||
double cache_misses() const { return total.cache_misses() / iterations; }
|
double cache_misses() const { return total.cache_misses() / iterations; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct event_collector {
|
struct event_collector {
|
||||||
@@ -117,11 +135,16 @@ struct event_collector {
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
|
||||||
event_collector(bool quiet = false) : linux_events(vector<int>{
|
event_collector(bool quiet = false) : linux_events(vector<int>{
|
||||||
|
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
|
PERF_COUNT_HW_CPU_CYCLES,
|
||||||
|
PERF_COUNT_HW_INSTRUCTIONS,
|
||||||
|
#else
|
||||||
PERF_COUNT_HW_CPU_CYCLES,
|
PERF_COUNT_HW_CPU_CYCLES,
|
||||||
PERF_COUNT_HW_INSTRUCTIONS,
|
PERF_COUNT_HW_INSTRUCTIONS,
|
||||||
PERF_COUNT_HW_BRANCH_MISSES,
|
PERF_COUNT_HW_BRANCH_MISSES,
|
||||||
PERF_COUNT_HW_CACHE_REFERENCES,
|
PERF_COUNT_HW_CACHE_REFERENCES,
|
||||||
PERF_COUNT_HW_CACHE_MISSES
|
PERF_COUNT_HW_CACHE_MISSES
|
||||||
|
#endif
|
||||||
}, quiet) {}
|
}, quiet) {}
|
||||||
bool has_events() {
|
bool has_events() {
|
||||||
return linux_events.is_working();
|
return linux_events.is_working();
|
||||||
|
|||||||
@@ -58,10 +58,11 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
|
|||||||
if (collector.has_events()) {
|
if (collector.has_events()) {
|
||||||
state.counters["instructions"] = events.instructions();
|
state.counters["instructions"] = events.instructions();
|
||||||
state.counters["cycles"] = events.cycles();
|
state.counters["cycles"] = events.cycles();
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
state.counters["branch_miss"] = events.branch_misses();
|
state.counters["branch_miss"] = events.branch_misses();
|
||||||
state.counters["cache_miss"] = events.cache_misses();
|
state.counters["cache_miss"] = events.cache_misses();
|
||||||
state.counters["cache_ref"] = events.cache_references();
|
state.counters["cache_ref"] = events.cache_references();
|
||||||
|
#endif
|
||||||
state.counters["instructions_per_byte"] = events.instructions() / double(bench.bytes_per_iteration());
|
state.counters["instructions_per_byte"] = events.instructions() / double(bench.bytes_per_iteration());
|
||||||
state.counters["instructions_per_cycle"] = events.instructions() / events.cycles();
|
state.counters["instructions_per_cycle"] = events.instructions() / events.cycles();
|
||||||
state.counters["cycles_per_byte"] = events.cycles() / double(bench.bytes_per_iteration());
|
state.counters["cycles_per_byte"] = events.cycles() / double(bench.bytes_per_iteration());
|
||||||
@@ -69,9 +70,11 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
|
|||||||
|
|
||||||
state.counters["best_instructions"] = events.best.instructions();
|
state.counters["best_instructions"] = events.best.instructions();
|
||||||
state.counters["best_cycles"] = events.best.cycles();
|
state.counters["best_cycles"] = events.best.cycles();
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
state.counters["best_branch_miss"] = events.best.branch_misses();
|
state.counters["best_branch_miss"] = events.best.branch_misses();
|
||||||
state.counters["best_cache_miss"] = events.best.cache_misses();
|
state.counters["best_cache_miss"] = events.best.cache_misses();
|
||||||
state.counters["best_cache_ref"] = events.best.cache_references();
|
state.counters["best_cache_ref"] = events.best.cache_references();
|
||||||
|
#endif
|
||||||
|
|
||||||
state.counters["best_instructions_per_byte"] = events.best.instructions() / double(bench.bytes_per_iteration());
|
state.counters["best_instructions_per_byte"] = events.best.instructions() / double(bench.bytes_per_iteration());
|
||||||
state.counters["best_instructions_per_cycle"] = events.best.instructions() / events.best.cycles();
|
state.counters["best_instructions_per_cycle"] = events.best.instructions() / events.best.cycles();
|
||||||
@@ -92,9 +95,11 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
|
|||||||
if (collector.has_events()) {
|
if (collector.has_events()) {
|
||||||
label << " instructions=" << setw(12) << uint64_t(events.best.instructions()) << setw(0);
|
label << " instructions=" << setw(12) << uint64_t(events.best.instructions()) << setw(0);
|
||||||
label << " cycles=" << setw(12) << uint64_t(events.best.cycles()) << setw(0);
|
label << " cycles=" << setw(12) << uint64_t(events.best.cycles()) << setw(0);
|
||||||
|
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
|
||||||
label << " branch_miss=" << setw(8) << uint64_t(events.best.branch_misses()) << setw(0);
|
label << " branch_miss=" << setw(8) << uint64_t(events.best.branch_misses()) << setw(0);
|
||||||
label << " cache_miss=" << setw(8) << uint64_t(events.best.cache_misses()) << setw(0);
|
label << " cache_miss=" << setw(8) << uint64_t(events.best.cache_misses()) << setw(0);
|
||||||
label << " cache_ref=" << setw(10) << uint64_t(events.best.cache_references()) << setw(0);
|
label << " cache_ref=" << setw(10) << uint64_t(events.best.cache_references()) << setw(0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
label << " items=" << setw(10) << bench.items_per_iteration() << setw(0);
|
label << " items=" << setw(10) << bench.items_per_iteration() << setw(0);
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
namespace large_amazon_cellphones {
|
namespace large_amazon_cellphones {
|
||||||
|
|
||||||
|
const bool UNTHREADED = false;
|
||||||
|
const bool THREADED = true;
|
||||||
|
|
||||||
static const simdjson::padded_string &get_built_json();
|
static const simdjson::padded_string &get_built_json();
|
||||||
|
|
||||||
using namespace json_benchmark;
|
using namespace json_benchmark;
|
||||||
@@ -81,11 +84,11 @@ static const simdjson::padded_string &get_built_json() {
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom;
|
struct simdjson_dom;
|
||||||
|
|
||||||
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
|
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
|
||||||
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
|
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace large_amazon_cellphones
|
} // namespace large_amazon_cellphones
|
||||||
@@ -9,12 +9,16 @@ namespace large_amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_dom {
|
struct simdjson_dom {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
dom::parser parser{};
|
dom::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
auto stream = parser.parse_many(json);
|
auto stream = parser.parse_many(json);
|
||||||
auto i = stream.begin();
|
auto i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -38,7 +42,10 @@ struct simdjson_dom {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace large_amazon_cellphones
|
} // namespace large_amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ namespace large_amazon_cellphones {
|
|||||||
|
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
|
||||||
|
template<bool threaded>
|
||||||
struct simdjson_ondemand {
|
struct simdjson_ondemand {
|
||||||
using StringType = std::string;
|
using StringType = std::string;
|
||||||
|
|
||||||
ondemand::parser parser{};
|
ondemand::parser parser{};
|
||||||
|
|
||||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
parser.threaded = threaded;
|
||||||
|
#endif
|
||||||
ondemand::document_stream stream = parser.iterate_many(json);
|
ondemand::document_stream stream = parser.iterate_many(json);
|
||||||
ondemand::document_stream::iterator i = stream.begin();
|
ondemand::document_stream::iterator i = stream.begin();
|
||||||
++i; // Skip first line
|
++i; // Skip first line
|
||||||
@@ -58,7 +62,10 @@ struct simdjson_ondemand {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand)->UseManualTime();
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
|
||||||
|
#ifdef SIMDJSON_THREADS_ENABLED
|
||||||
|
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace amazon_cellphones
|
} // namespace amazon_cellphones
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,18 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
|||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(
|
||||||
|
SIMDJSON_AVX512_ALLOWED
|
||||||
|
"Enable AVX-512 instructions (only affects processors and compilers with AVX-512 support)."
|
||||||
|
ON
|
||||||
|
)
|
||||||
|
if(SIMDJSON_AVX512_ALLOWED)
|
||||||
|
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=1)
|
||||||
|
else()
|
||||||
|
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=0)
|
||||||
|
message(STATUS "AVX-512 instructions are not allowed.")
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
||||||
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Implementation selection
|
# Implementation selection
|
||||||
#
|
#
|
||||||
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell arm64 ppc64)
|
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64)
|
||||||
|
|
||||||
set(
|
set(
|
||||||
SIMDJSON_IMPLEMENTATION ""
|
SIMDJSON_IMPLEMENTATION ""
|
||||||
@@ -15,7 +15,7 @@ set(
|
|||||||
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
||||||
CACHE STRING "\
|
CACHE STRING "\
|
||||||
Semicolon-separated list of implementations to exclude \
|
Semicolon-separated list of implementations to exclude \
|
||||||
(haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
|
(icelake/haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
|
||||||
implementations that are unsupported at compile time or cannot be selected at \
|
implementations that are unsupported at compile time or cannot be selected at \
|
||||||
runtime."
|
runtime."
|
||||||
)
|
)
|
||||||
|
|||||||
+4
-1
@@ -32,9 +32,12 @@ An overview of what you need to know to use simdjson, with examples.
|
|||||||
Requirements
|
Requirements
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- A recent compiler (LLVM clang6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
||||||
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
||||||
|
|
||||||
|
|
||||||
|
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better).
|
||||||
|
|
||||||
Including simdjson
|
Including simdjson
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -160,6 +160,8 @@ You should not expect the simdjson library to cause *downclocking* of your recen
|
|||||||
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
|
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
|
||||||
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
|
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
|
||||||
|
|
||||||
The simdjson library does not currently support AVX-512 instructions and it does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors.
|
The simdjson library does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors, except when AVX-512 is allowed and
|
||||||
|
detected. However, we only allow AVX-512 on recent processors (Ice Lake/Tiger Lake or better) where [little to no frequency throttling is expected](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html). If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
|
||||||
|
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
|
||||||
|
|
||||||
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
|
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace arm64
|
} // namespace arm64
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
// Determine the best builtin implementation
|
// Determine the best builtin implementation
|
||||||
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
|
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||||
#if SIMDJSON_CAN_ALWAYS_RUN_HASWELL
|
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
|
||||||
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION icelake
|
||||||
|
#elif SIMDJSON_CAN_ALWAYS_RUN_HASWELL
|
||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell
|
||||||
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
|
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE
|
||||||
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere
|
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
|
|
||||||
#define SIMDJSON_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
|
#define SIMDJSON_PUSH_DISABLE_WARNINGS _Pragma("GCC diagnostic push")
|
||||||
// gcc doesn't seem to disable all warnings with all and extra, add warnings here as necessary
|
// gcc doesn't seem to disable all warnings with all and extra, add warnings here as necessary
|
||||||
|
// We do it separately for clang since it has different warnings.
|
||||||
|
#ifdef __clang__
|
||||||
|
// clang is missing -Wmaybe-uninitialized.
|
||||||
#define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
#define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
|
||||||
@@ -134,6 +137,22 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
|
|||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
||||||
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable)
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable)
|
||||||
|
#else // __clang__
|
||||||
|
#define SIMDJSON_PUSH_DISABLE_ALL_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wall) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wconversion) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wextra) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wattributes) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wimplicit-fallthrough) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wnon-virtual-dtor) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wreturn-type) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable) \
|
||||||
|
SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized)
|
||||||
|
#endif // __clang__
|
||||||
|
|
||||||
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
|
||||||
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
||||||
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
|
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fallback
|
} // namespace fallback
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ simdjson_really_inline simdjson_result<std::string_view> array::raw_json() noexc
|
|||||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcept {
|
simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcept {
|
||||||
size_t count{0};
|
size_t count{0};
|
||||||
@@ -101,6 +102,7 @@ simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcep
|
|||||||
iter.reset_array();
|
iter.reset_array();
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
simdjson_really_inline simdjson_result<bool> array::is_empty() & noexcept {
|
simdjson_really_inline simdjson_result<bool> array::is_empty() & noexcept {
|
||||||
bool is_not_empty;
|
bool is_not_empty;
|
||||||
|
|||||||
@@ -47,6 +47,27 @@ inline void json_iterator::rewind() noexcept {
|
|||||||
_depth = 1;
|
_depth = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool json_iterator::balanced() const noexcept {
|
||||||
|
token_iterator ti(token);
|
||||||
|
int32_t count{0};
|
||||||
|
ti.set_position( root_position() );
|
||||||
|
while(ti.peek() <= peek_last()) {
|
||||||
|
switch (*ti.return_current_and_advance())
|
||||||
|
{
|
||||||
|
case '[': case '{':
|
||||||
|
count++;
|
||||||
|
break;
|
||||||
|
case ']': case '}':
|
||||||
|
count--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
|
// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
|
||||||
// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
|
// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
|
||||||
// skip_child() function is not marked inline).
|
// skip_child() function is not marked inline).
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public:
|
|||||||
* This is not null-terminated; it is a view into the JSON.
|
* This is not null-terminated; it is a view into the JSON.
|
||||||
*
|
*
|
||||||
* You may be pointing outside of the input buffer: it is not generally
|
* You may be pointing outside of the input buffer: it is not generally
|
||||||
* safe to derefence this pointer.
|
* safe to dereference this pointer.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline const uint8_t *unsafe_pointer() const noexcept;
|
simdjson_really_inline const uint8_t *unsafe_pointer() const noexcept;
|
||||||
/**
|
/**
|
||||||
@@ -251,6 +251,13 @@ public:
|
|||||||
* as if it had just been created.
|
* as if it had just been created.
|
||||||
*/
|
*/
|
||||||
inline void rewind() noexcept;
|
inline void rewind() noexcept;
|
||||||
|
/**
|
||||||
|
* This checks whether the {,},[,] are balanced so that the document
|
||||||
|
* ends with proper zero depth. This requires scanning the whole document
|
||||||
|
* and it may be expensive. It is expected that it will be rarely called.
|
||||||
|
* It does not attempt to match { with } and [ with ].
|
||||||
|
*/
|
||||||
|
inline bool balanced() const noexcept;
|
||||||
protected:
|
protected:
|
||||||
simdjson_really_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
|
simdjson_really_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
|
||||||
/// The last token before the end
|
/// The last token before the end
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ inline void log_headers() noexcept {
|
|||||||
printf("# skip says 'this is a structural or value I am skipping'\n");
|
printf("# skip says 'this is a structural or value I am skipping'\n");
|
||||||
printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
|
printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
|
||||||
printf("#\n");
|
printf("#\n");
|
||||||
printf("# The identation of the terms (array, string,...) indicates the depth,\n");
|
printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
|
||||||
printf("# in addition to the depth being displayed.\n");
|
printf("# in addition to the depth being displayed.\n");
|
||||||
printf("#\n");
|
printf("#\n");
|
||||||
printf("# Every token in the document has a single depth determined by the tokens before it,\n");
|
printf("# Every token in the document has a single depth determined by the tokens before it,\n");
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public:
|
|||||||
* instance: there is no rewind and no invalidation.
|
* instance: there is no rewind and no invalidation.
|
||||||
*
|
*
|
||||||
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
||||||
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceeding
|
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
|
||||||
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
||||||
*
|
*
|
||||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
|
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
|
||||||
@@ -168,7 +168,7 @@ public:
|
|||||||
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
simdjson_really_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||||
/**
|
/**
|
||||||
* Consumes the object and returns a string_view instance corresponding to the
|
* Consumes the object and returns a string_view instance corresponding to the
|
||||||
* object as represented in JSON. It points inside the original byte array containg
|
* object as represented in JSON. It points inside the original byte array containing
|
||||||
* the JSON document.
|
* the JSON document.
|
||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ simdjson_really_inline bool object_iterator::operator!=(const object_iterator &)
|
|||||||
return iter.is_open();
|
return iter.is_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
|
simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
|
||||||
// TODO this is a safety rail ... users should exit loops as soon as they receive an error.
|
// TODO this is a safety rail ... users should exit loops as soon as they receive an error.
|
||||||
// Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
|
// Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
|
||||||
@@ -38,6 +40,7 @@ simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
|
|||||||
if ((error = iter.has_next_field().get(has_value) )) { return *this; };
|
if ((error = iter.has_next_field().get(has_value) )) { return *this; };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
//
|
//
|
||||||
// ### Live States
|
// ### Live States
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ simdjson_really_inline raw_json_string::raw_json_string(const uint8_t * _buf) no
|
|||||||
|
|
||||||
simdjson_really_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
simdjson_really_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
||||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(uint8_t *&dst) const noexcept {
|
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(uint8_t *&dst) const noexcept {
|
||||||
uint8_t *end = stringparsing::parse_string(buf, dst);
|
uint8_t *end = parse_string(buf, dst);
|
||||||
if (!end) { return STRING_ERROR; }
|
if (!end) { return STRING_ERROR; }
|
||||||
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||||
dst = end;
|
dst = end;
|
||||||
|
|||||||
@@ -116,6 +116,26 @@ public:
|
|||||||
static simdjson_really_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
|
static simdjson_really_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
|
||||||
static simdjson_really_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
|
static simdjson_really_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||||
|
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
||||||
|
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
||||||
|
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
||||||
|
*
|
||||||
|
* This unescape function is a low-level function. If you want a more user-friendly approach, you should
|
||||||
|
* avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
|
||||||
|
* instead of get_raw_json_string()).
|
||||||
|
*
|
||||||
|
* ## IMPORTANT: string_view lifetime
|
||||||
|
*
|
||||||
|
* The string_view is only valid as long as the bytes in dst.
|
||||||
|
*
|
||||||
|
* @param dst A pointer to a buffer at least large enough to write this string as well as
|
||||||
|
* an additional SIMDJSON_PADDING bytes.
|
||||||
|
* @return A string_view pointing at the unescaped string in dst
|
||||||
|
* @error STRING_ERROR if escapes are incorrect.
|
||||||
|
*/
|
||||||
|
simdjson_really_inline simdjson_result<std::string_view> unescape(uint8_t *&dst) const noexcept;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
@@ -130,20 +150,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
simdjson_really_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
|
simdjson_really_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
|
||||||
*
|
|
||||||
* ## IMPORTANT: string_view lifetime
|
|
||||||
*
|
|
||||||
* The string_view is only valid as long as the bytes in dst.
|
|
||||||
*
|
|
||||||
* @param dst A pointer to a buffer at least large enough to write this string as well as a \0.
|
|
||||||
* dst will be updated to the next unused location (just after the \0 written out at
|
|
||||||
* the end of this string).
|
|
||||||
* @return A string_view pointing at the unescaped string in dst
|
|
||||||
* @error STRING_ERROR if escapes are incorrect.
|
|
||||||
*/
|
|
||||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(uint8_t *&dst) const noexcept;
|
|
||||||
/**
|
/**
|
||||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -497,7 +497,7 @@ public:
|
|||||||
* to call at_pointer on the same array.
|
* to call at_pointer on the same array.
|
||||||
*
|
*
|
||||||
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
||||||
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceeding
|
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
|
||||||
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
||||||
*
|
*
|
||||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
||||||
|
|||||||
@@ -39,9 +39,22 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// current document. It only works in the normal mode where we have indexed a single document.
|
// current document. It only works in the normal mode where we have indexed a single document.
|
||||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||||
// one root element.
|
// one root element.
|
||||||
if (! _json_iter->streaming() && (*_json_iter->peek_last() != '}')) {
|
if ( ! _json_iter->streaming() ) {
|
||||||
_json_iter->abandon();
|
if (*_json_iter->peek_last() != '}') {
|
||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
_json_iter->abandon();
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing } at end");
|
||||||
|
}
|
||||||
|
// If the last character is } *and* the first gibberish character is also '}'
|
||||||
|
// then on-demand could accidentally go over. So we need additional checks.
|
||||||
|
// https://github.com/simdjson/simdjson/issues/1834
|
||||||
|
// Checking that the document is balanced requires a full scan which is potentially
|
||||||
|
// expensive, but it only happens in edge cases where the first padding character is
|
||||||
|
// a closing bracket.
|
||||||
|
if ((*_json_iter->peek(_json_iter->end_position()) == '}') && (!_json_iter->balanced())) {
|
||||||
|
_json_iter->abandon();
|
||||||
|
// The exact error would require more work. It will typically be an unclosed object.
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return started_object();
|
return started_object();
|
||||||
}
|
}
|
||||||
@@ -167,6 +180,8 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||||
|
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
||||||
/**
|
/**
|
||||||
* When find_field_unordered_raw is called, we can either be pointing at the
|
* When find_field_unordered_raw is called, we can either be pointing at the
|
||||||
@@ -354,6 +369,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// never reach this point.
|
// never reach this point.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
|
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::field_key() noexcept {
|
||||||
assert_at_next();
|
assert_at_next();
|
||||||
@@ -408,9 +424,22 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// current document. It only works in the normal mode where we have indexed a single document.
|
// current document. It only works in the normal mode where we have indexed a single document.
|
||||||
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
// Note that adding a check for 'streaming' is not expensive since we only have at most
|
||||||
// one root element.
|
// one root element.
|
||||||
if ( ! _json_iter->streaming() && (*_json_iter->peek_last() != ']')) {
|
if ( ! _json_iter->streaming() ) {
|
||||||
_json_iter->abandon();
|
if (*_json_iter->peek_last() != ']') {
|
||||||
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
_json_iter->abandon();
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "missing ] at end");
|
||||||
|
}
|
||||||
|
// If the last character is ] *and* the first gibberish character is also ']'
|
||||||
|
// then on-demand could accidentally go over. So we need additional checks.
|
||||||
|
// https://github.com/simdjson/simdjson/issues/1834
|
||||||
|
// Checking that the document is balanced requires a full scan which is potentially
|
||||||
|
// expensive, but it only happens in edge cases where the first padding character is
|
||||||
|
// a closing bracket.
|
||||||
|
if ((*_json_iter->peek(_json_iter->end_position()) == ']') && (!_json_iter->balanced())) {
|
||||||
|
_json_iter->abandon();
|
||||||
|
// The exact error would require more work. It will typically be an unclosed array.
|
||||||
|
return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "the document is unbalanced");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return started_array();
|
return started_array();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
// This file contains the common code every implementation uses
|
|
||||||
// It is intended to be included multiple times and compiled multiple times
|
|
||||||
|
|
||||||
namespace simdjson {
|
|
||||||
namespace SIMDJSON_IMPLEMENTATION {
|
|
||||||
namespace {
|
|
||||||
/// @private
|
|
||||||
namespace stringparsing {
|
|
||||||
|
|
||||||
// begin copypasta
|
|
||||||
// These chars yield themselves: " \ /
|
|
||||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
|
||||||
// u not handled in this table as it's complex
|
|
||||||
static const uint8_t escape_map[256] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
|
||||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
|
||||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// handle a unicode codepoint
|
|
||||||
// write appropriate values into dest
|
|
||||||
// src will advance 6 bytes or 12 bytes
|
|
||||||
// dest will advance a variable amount (return via pointer)
|
|
||||||
// return true if the unicode codepoint was valid
|
|
||||||
// We work in little-endian then swap at write time
|
|
||||||
simdjson_warn_unused
|
|
||||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
|
||||||
uint8_t **dst_ptr) {
|
|
||||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
|
||||||
// conversion isn't valid; we defer the check for this to inside the
|
|
||||||
// multilingual plane check
|
|
||||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
|
||||||
*src_ptr += 6;
|
|
||||||
// check for low surrogate for characters outside the Basic
|
|
||||||
// Multilingual Plane.
|
|
||||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
|
||||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
|
||||||
|
|
||||||
// if the first code point is invalid we will get here, as we will go past
|
|
||||||
// the check for being outside the Basic Multilingual plane. If we don't
|
|
||||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
|
||||||
// this check catches both the case of the first code point being invalid
|
|
||||||
// or the second code point being invalid.
|
|
||||||
if ((code_point | code_point_2) >> 16) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
code_point =
|
|
||||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
|
||||||
*src_ptr += 6;
|
|
||||||
}
|
|
||||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
|
||||||
*dst_ptr += offset;
|
|
||||||
return offset > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unescape a string from src to dst, stopping at a final unescaped quote. E.g., if src points at 'joe"', then
|
|
||||||
* dst needs to have four free bytes.
|
|
||||||
*/
|
|
||||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
|
||||||
while (1) {
|
|
||||||
// Copy the next n bytes, and find the backslash and quote in them.
|
|
||||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
|
||||||
// If the next thing is the end quote, copy and return
|
|
||||||
if (bs_quote.has_quote_first()) {
|
|
||||||
// we encountered quotes first. Move dst to point to quotes and exit
|
|
||||||
return dst + bs_quote.quote_index();
|
|
||||||
}
|
|
||||||
if (bs_quote.has_backslash()) {
|
|
||||||
/* find out where the backspace is */
|
|
||||||
auto bs_dist = bs_quote.backslash_index();
|
|
||||||
uint8_t escape_char = src[bs_dist + 1];
|
|
||||||
/* we encountered backslash first. Handle backslash */
|
|
||||||
if (escape_char == 'u') {
|
|
||||||
/* move src/dst up to the start; they will be further adjusted
|
|
||||||
within the unicode codepoint handling code. */
|
|
||||||
src += bs_dist;
|
|
||||||
dst += bs_dist;
|
|
||||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
|
||||||
* write bs_dist+1 characters to output
|
|
||||||
* note this may reach beyond the part of the buffer we've actually
|
|
||||||
* seen. I think this is ok */
|
|
||||||
uint8_t escape_result = escape_map[escape_char];
|
|
||||||
if (escape_result == 0u) {
|
|
||||||
return nullptr; /* bogus escape value is an error */
|
|
||||||
}
|
|
||||||
dst[bs_dist] = escape_result;
|
|
||||||
src += bs_dist + 2;
|
|
||||||
dst += bs_dist + 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* they are the same. Since they can't co-occur, it means we
|
|
||||||
* encountered neither. */
|
|
||||||
src += backslash_and_quote::BYTES_PROCESSED;
|
|
||||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* can't be reached */
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
simdjson_unused simdjson_warn_unused simdjson_really_inline error_code parse_string_to_buffer(const uint8_t *src, uint8_t *¤t_string_buf_loc, std::string_view &s) {
|
|
||||||
if (*(src++) != '"') { return STRING_ERROR; }
|
|
||||||
auto end = stringparsing::parse_string(src, current_string_buf_loc);
|
|
||||||
if (!end) { return STRING_ERROR; }
|
|
||||||
s = std::string_view(reinterpret_cast<const char *>(current_string_buf_loc), end-current_string_buf_loc);
|
|
||||||
current_string_buf_loc = end;
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stringparsing
|
|
||||||
} // unnamed namespace
|
|
||||||
} // namespace SIMDJSON_IMPLEMENTATION
|
|
||||||
} // namespace simdjson
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace haswell
|
} // namespace haswell
|
||||||
|
|||||||
@@ -41,11 +41,7 @@
|
|||||||
// has it as a macro.
|
// has it as a macro.
|
||||||
#ifndef _blsr_u64
|
#ifndef _blsr_u64
|
||||||
// we roll our own
|
// we roll our own
|
||||||
SIMDJSON_TARGET_HASWELL
|
#define _blsr_u64(n) ((n - 1) & n)
|
||||||
static simdjson_really_inline uint64_t _blsr_u64(uint64_t n) {
|
|
||||||
return (n - 1) & n;
|
|
||||||
}
|
|
||||||
SIMDJSON_UNTARGET_HASWELL
|
|
||||||
#endif // _blsr_u64
|
#endif // _blsr_u64
|
||||||
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
|
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_H
|
||||||
|
#define SIMDJSON_ICELAKE_H
|
||||||
|
|
||||||
|
#include "simdjson/implementation-base.h"
|
||||||
|
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
|
||||||
|
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE
|
||||||
|
#define SIMDJSON_TARGET_ICELAKE
|
||||||
|
#define SIMDJSON_UNTARGET_ICELAKE
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_TARGET_ICELAKE SIMDJSON_TARGET_REGION("avx512f,avx512dq,avx512cd,avx512bw,avx512vbmi,avx512vbmi2,avx512vl,avx2,bmi,pclmul,lzcnt")
|
||||||
|
#define SIMDJSON_UNTARGET_ICELAKE SIMDJSON_UNTARGET_REGION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
/**
|
||||||
|
* Implementation for Icelake (Intel AVX512).
|
||||||
|
*/
|
||||||
|
namespace icelake {
|
||||||
|
} // namespace icelake
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
//
|
||||||
|
// These two need to be included outside SIMDJSON_TARGET_ICELAKE
|
||||||
|
//
|
||||||
|
#include "simdjson/icelake/implementation.h"
|
||||||
|
#include "simdjson/icelake/intrinsics.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// The rest need to be inside the region
|
||||||
|
//
|
||||||
|
#include "simdjson/icelake/begin.h"
|
||||||
|
|
||||||
|
// Declarations
|
||||||
|
#include "simdjson/generic/dom_parser_implementation.h"
|
||||||
|
#include "simdjson/icelake/bitmanipulation.h"
|
||||||
|
#include "simdjson/icelake/bitmask.h"
|
||||||
|
#include "simdjson/icelake/simd.h"
|
||||||
|
#include "simdjson/generic/jsoncharutils.h"
|
||||||
|
#include "simdjson/generic/atomparsing.h"
|
||||||
|
#include "simdjson/icelake/stringparsing.h"
|
||||||
|
#include "simdjson/icelake/numberparsing.h"
|
||||||
|
#include "simdjson/icelake/end.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
#endif // SIMDJSON_ICELAKE_H
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#define SIMDJSON_IMPLEMENTATION icelake
|
||||||
|
SIMDJSON_TARGET_ICELAKE
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||||
|
#define SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
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.
|
||||||
|
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);
|
||||||
|
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
////////
|
||||||
|
// You might expect the next line to be equivalent to
|
||||||
|
// return (int)_tzcnt_u64(input_num);
|
||||||
|
// but the generated code differs and might be less efficient?
|
||||||
|
////////
|
||||||
|
return __builtin_ctzll(input_num);
|
||||||
|
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
}
|
||||||
|
|
||||||
|
/* result might be undefined when input_num is zero */
|
||||||
|
simdjson_really_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||||
|
return _blsr_u64(input_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* result might be undefined when input_num is zero */
|
||||||
|
simdjson_really_inline int leading_zeroes(uint64_t input_num) {
|
||||||
|
return int(_lzcnt_u64(input_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
simdjson_really_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||||
|
// note: we do not support legacy 32-bit Windows
|
||||||
|
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
simdjson_really_inline long long int count_ones(uint64_t input_num) {
|
||||||
|
return _popcnt64(input_num);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
simdjson_really_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||||
|
uint64_t *result) {
|
||||||
|
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||||
|
return _addcarry_u64(0, value1, value2,
|
||||||
|
reinterpret_cast<unsigned __int64 *>(result));
|
||||||
|
#else
|
||||||
|
return __builtin_uaddll_overflow(value1, value2,
|
||||||
|
reinterpret_cast<unsigned long long *>(result));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_BITMASK_H
|
||||||
|
#define SIMDJSON_ICELAKE_BITMASK_H
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
|
||||||
|
//
|
||||||
|
// For example, prefix_xor(00100100) == 00011100
|
||||||
|
//
|
||||||
|
simdjson_really_inline uint64_t prefix_xor(const uint64_t bitmask) {
|
||||||
|
// There should be no such thing with a processor supporting avx2
|
||||||
|
// but not clmul.
|
||||||
|
__m128i all_ones = _mm_set1_epi8('\xFF');
|
||||||
|
__m128i result = _mm_clmulepi64_si128(_mm_set_epi64x(0ULL, bitmask), all_ones, 0);
|
||||||
|
return _mm_cvtsi128_si64(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_BITMASK_H
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
SIMDJSON_UNTARGET_ICELAKE
|
||||||
|
#undef SIMDJSON_IMPLEMENTATION
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_IMPLEMENTATION_H
|
||||||
|
#define SIMDJSON_ICELAKE_IMPLEMENTATION_H
|
||||||
|
|
||||||
|
#include "simdjson/implementation.h"
|
||||||
|
|
||||||
|
// The constructor may be executed on any host, so we take care not to use SIMDJSON_TARGET_ICELAKE
|
||||||
|
namespace simdjson {
|
||||||
|
namespace icelake {
|
||||||
|
|
||||||
|
using namespace simdjson;
|
||||||
|
|
||||||
|
class implementation final : public simdjson::implementation {
|
||||||
|
public:
|
||||||
|
simdjson_really_inline implementation() : simdjson::implementation(
|
||||||
|
"icelake",
|
||||||
|
"Intel/AMD AVX512",
|
||||||
|
internal::instruction_set::AVX2 | internal::instruction_set::PCLMULQDQ | internal::instruction_set::BMI1 | internal::instruction_set::BMI2 | internal::instruction_set::AVX512F | internal::instruction_set::AVX512DQ | internal::instruction_set::AVX512CD | internal::instruction_set::AVX512BW | internal::instruction_set::AVX512VL | internal::instruction_set::AVX512VBMI2
|
||||||
|
) {}
|
||||||
|
simdjson_warn_unused error_code create_dom_parser_implementation(
|
||||||
|
size_t capacity,
|
||||||
|
size_t max_length,
|
||||||
|
std::unique_ptr<internal::dom_parser_implementation>& dst
|
||||||
|
) const noexcept final;
|
||||||
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace icelake
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_IMPLEMENTATION_H
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_INTRINSICS_H
|
||||||
|
#define SIMDJSON_ICELAKE_INTRINSICS_H
|
||||||
|
|
||||||
|
#include "simdjson/base.h"
|
||||||
|
|
||||||
|
#ifdef SIMDJSON_VISUAL_STUDIO
|
||||||
|
// under clang within visual studio, this will include <x86intrin.h>
|
||||||
|
#include <intrin.h> // visual studio or clang
|
||||||
|
#else
|
||||||
|
#include <x86intrin.h> // elsewhere
|
||||||
|
#endif // SIMDJSON_VISUAL_STUDIO
|
||||||
|
|
||||||
|
#ifdef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
|
/**
|
||||||
|
* You are not supposed, normally, to include these
|
||||||
|
* headers directly. Instead you should either include intrin.h
|
||||||
|
* or x86intrin.h. However, when compiling with clang
|
||||||
|
* under Windows (i.e., when _MSC_VER is set), these headers
|
||||||
|
* only get included *if* the corresponding features are detected
|
||||||
|
* from macros:
|
||||||
|
* e.g., if __AVX2__ is set... in turn, we normally set these
|
||||||
|
* macros by compiling against the corresponding architecture
|
||||||
|
* (e.g., arch:AVX2, -mavx2, etc.) which compiles the whole
|
||||||
|
* software with these advanced instructions. In simdjson, we
|
||||||
|
* want to compile the whole program for a generic target,
|
||||||
|
* and only target our specific kernels. As a workaround,
|
||||||
|
* we directly include the needed headers. These headers would
|
||||||
|
* normally guard against such usage, but we carefully included
|
||||||
|
* <x86intrin.h> (or <intrin.h>) before, so the headers
|
||||||
|
* are fooled.
|
||||||
|
*/
|
||||||
|
#include <bmiintrin.h> // for _blsr_u64
|
||||||
|
#include <lzcntintrin.h> // for __lzcnt64
|
||||||
|
#include <immintrin.h> // for most things (AVX2, AVX512, _popcnt64)
|
||||||
|
#include <smmintrin.h>
|
||||||
|
#include <tmmintrin.h>
|
||||||
|
#include <avxintrin.h>
|
||||||
|
#include <avx2intrin.h>
|
||||||
|
#include <wmmintrin.h> // for _mm_clmulepi64_si128
|
||||||
|
// Important: we need the AVX-512 headers:
|
||||||
|
#include <avx512fintrin.h>
|
||||||
|
#include <avx512dqintrin.h>
|
||||||
|
#include <avx512cdintrin.h>
|
||||||
|
#include <avx512bwintrin.h>
|
||||||
|
#include <avx512vlintrin.h>
|
||||||
|
#include <avx512vbmiintrin.h>
|
||||||
|
#include <avx512vbmi2intrin.h>
|
||||||
|
// unfortunately, we may not get _blsr_u64, but, thankfully, clang
|
||||||
|
// has it as a macro.
|
||||||
|
#ifndef _blsr_u64
|
||||||
|
// we roll our own
|
||||||
|
#define _blsr_u64(n) ((n - 1) & n)
|
||||||
|
#endif // _blsr_u64
|
||||||
|
#endif // SIMDJSON_CLANG_VISUAL_STUDIO
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_INTRINSICS_H
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_NUMBERPARSING_H
|
||||||
|
#define SIMDJSON_ICELAKE_NUMBERPARSING_H
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static simdjson_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
|
||||||
|
// this actually computes *16* values so we are being wasteful.
|
||||||
|
const __m128i ascii0 = _mm_set1_epi8('0');
|
||||||
|
const __m128i mul_1_10 =
|
||||||
|
_mm_setr_epi8(10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1);
|
||||||
|
const __m128i mul_1_100 = _mm_setr_epi16(100, 1, 100, 1, 100, 1, 100, 1);
|
||||||
|
const __m128i mul_1_10000 =
|
||||||
|
_mm_setr_epi16(10000, 1, 10000, 1, 10000, 1, 10000, 1);
|
||||||
|
const __m128i input = _mm_sub_epi8(
|
||||||
|
_mm_loadu_si128(reinterpret_cast<const __m128i *>(chars)), ascii0);
|
||||||
|
const __m128i t1 = _mm_maddubs_epi16(input, mul_1_10);
|
||||||
|
const __m128i t2 = _mm_madd_epi16(t1, mul_1_100);
|
||||||
|
const __m128i t3 = _mm_packus_epi32(t2, t2);
|
||||||
|
const __m128i t4 = _mm_madd_epi16(t3, mul_1_10000);
|
||||||
|
return _mm_cvtsi128_si32(
|
||||||
|
t4); // only captures the sum of the first 8 digits, drop the rest
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#define SIMDJSON_SWAR_NUMBER_PARSING 1
|
||||||
|
|
||||||
|
#include "simdjson/generic/numberparsing.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_NUMBERPARSING_H
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_SIMD_H
|
||||||
|
#define SIMDJSON_ICELAKE_SIMD_H
|
||||||
|
|
||||||
|
#include "simdjson/internal/simdprune_tables.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#if __GNUC__ == 8
|
||||||
|
#define SIMDJSON_GCC8 1
|
||||||
|
#endif // __GNUC__ == 8
|
||||||
|
#endif // defined(__GNUC__) && !defined(__clang__)
|
||||||
|
|
||||||
|
#if SIMDJSON_GCC8
|
||||||
|
/**
|
||||||
|
* GCC 8 fails to provide _mm512_set_epi8. We roll our own.
|
||||||
|
*/
|
||||||
|
inline __m512i _mm512_set_epi8(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6, uint8_t a7, uint8_t a8, uint8_t a9, uint8_t a10, uint8_t a11, uint8_t a12, uint8_t a13, uint8_t a14, uint8_t a15, uint8_t a16, uint8_t a17, uint8_t a18, uint8_t a19, uint8_t a20, uint8_t a21, uint8_t a22, uint8_t a23, uint8_t a24, uint8_t a25, uint8_t a26, uint8_t a27, uint8_t a28, uint8_t a29, uint8_t a30, uint8_t a31, uint8_t a32, uint8_t a33, uint8_t a34, uint8_t a35, uint8_t a36, uint8_t a37, uint8_t a38, uint8_t a39, uint8_t a40, uint8_t a41, uint8_t a42, uint8_t a43, uint8_t a44, uint8_t a45, uint8_t a46, uint8_t a47, uint8_t a48, uint8_t a49, uint8_t a50, uint8_t a51, uint8_t a52, uint8_t a53, uint8_t a54, uint8_t a55, uint8_t a56, uint8_t a57, uint8_t a58, uint8_t a59, uint8_t a60, uint8_t a61, uint8_t a62, uint8_t a63) {
|
||||||
|
return _mm512_set_epi64(uint64_t(a7) + (uint64_t(a6) << 8) + (uint64_t(a5) << 16) + (uint64_t(a4) << 24) + (uint64_t(a3) << 32) + (uint64_t(a2) << 40) + (uint64_t(a1) << 48) + (uint64_t(a0) << 56),
|
||||||
|
uint64_t(a15) + (uint64_t(a14) << 8) + (uint64_t(a13) << 16) + (uint64_t(a12) << 24) + (uint64_t(a11) << 32) + (uint64_t(a10) << 40) + (uint64_t(a9) << 48) + (uint64_t(a8) << 56),
|
||||||
|
uint64_t(a23) + (uint64_t(a22) << 8) + (uint64_t(a21) << 16) + (uint64_t(a20) << 24) + (uint64_t(a19) << 32) + (uint64_t(a18) << 40) + (uint64_t(a17) << 48) + (uint64_t(a16) << 56),
|
||||||
|
uint64_t(a31) + (uint64_t(a30) << 8) + (uint64_t(a29) << 16) + (uint64_t(a28) << 24) + (uint64_t(a27) << 32) + (uint64_t(a26) << 40) + (uint64_t(a25) << 48) + (uint64_t(a24) << 56),
|
||||||
|
uint64_t(a39) + (uint64_t(a38) << 8) + (uint64_t(a37) << 16) + (uint64_t(a36) << 24) + (uint64_t(a35) << 32) + (uint64_t(a34) << 40) + (uint64_t(a33) << 48) + (uint64_t(a32) << 56),
|
||||||
|
uint64_t(a47) + (uint64_t(a46) << 8) + (uint64_t(a45) << 16) + (uint64_t(a44) << 24) + (uint64_t(a43) << 32) + (uint64_t(a42) << 40) + (uint64_t(a41) << 48) + (uint64_t(a40) << 56),
|
||||||
|
uint64_t(a55) + (uint64_t(a54) << 8) + (uint64_t(a53) << 16) + (uint64_t(a52) << 24) + (uint64_t(a51) << 32) + (uint64_t(a50) << 40) + (uint64_t(a49) << 48) + (uint64_t(a48) << 56),
|
||||||
|
uint64_t(a63) + (uint64_t(a62) << 8) + (uint64_t(a61) << 16) + (uint64_t(a60) << 24) + (uint64_t(a59) << 32) + (uint64_t(a58) << 40) + (uint64_t(a57) << 48) + (uint64_t(a56) << 56));
|
||||||
|
}
|
||||||
|
#endif // SIMDJSON_GCC8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
namespace simd {
|
||||||
|
|
||||||
|
// Forward-declared so they can be used by splat and friends.
|
||||||
|
template<typename Child>
|
||||||
|
struct base {
|
||||||
|
__m512i value;
|
||||||
|
|
||||||
|
// Zero constructor
|
||||||
|
simdjson_really_inline base() : value{__m512i()} {}
|
||||||
|
|
||||||
|
// Conversion from SIMD register
|
||||||
|
simdjson_really_inline base(const __m512i _value) : value(_value) {}
|
||||||
|
|
||||||
|
// Conversion to SIMD register
|
||||||
|
simdjson_really_inline operator const __m512i&() const { return this->value; }
|
||||||
|
simdjson_really_inline operator __m512i&() { return this->value; }
|
||||||
|
|
||||||
|
// Bit operations
|
||||||
|
simdjson_really_inline Child operator|(const Child other) const { return _mm512_or_si512(*this, other); }
|
||||||
|
simdjson_really_inline Child operator&(const Child other) const { return _mm512_and_si512(*this, other); }
|
||||||
|
simdjson_really_inline Child operator^(const Child other) const { return _mm512_xor_si512(*this, other); }
|
||||||
|
simdjson_really_inline Child bit_andnot(const Child other) const { return _mm512_andnot_si512(other, *this); }
|
||||||
|
simdjson_really_inline Child& operator|=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast | other; return *this_cast; }
|
||||||
|
simdjson_really_inline Child& operator&=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast & other; return *this_cast; }
|
||||||
|
simdjson_really_inline Child& operator^=(const Child other) { auto this_cast = static_cast<Child*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward-declared so they can be used by splat and friends.
|
||||||
|
template<typename T>
|
||||||
|
struct simd8;
|
||||||
|
|
||||||
|
template<typename T, typename Mask=simd8<bool>>
|
||||||
|
struct base8: base<simd8<T>> {
|
||||||
|
typedef uint32_t bitmask_t;
|
||||||
|
typedef uint64_t bitmask2_t;
|
||||||
|
|
||||||
|
simdjson_really_inline base8() : base<simd8<T>>() {}
|
||||||
|
simdjson_really_inline base8(const __m512i _value) : base<simd8<T>>(_value) {}
|
||||||
|
|
||||||
|
friend simdjson_really_inline uint64_t operator==(const simd8<T> lhs, const simd8<T> rhs) {
|
||||||
|
return _mm512_cmpeq_epi8_mask(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int SIZE = sizeof(base<T>::value);
|
||||||
|
|
||||||
|
template<int N=1>
|
||||||
|
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||||
|
#if SIMDJSON_GCC8
|
||||||
|
// workaround for compilers unable to figure out that 16 - N is a constant (GCC 8)
|
||||||
|
constexpr int shift = 16 - N;
|
||||||
|
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), shift);
|
||||||
|
#else
|
||||||
|
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), 16 - N);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// SIMD byte mask type (returned by things like eq and gt)
|
||||||
|
template<>
|
||||||
|
struct simd8<bool>: base8<bool> {
|
||||||
|
static simdjson_really_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
|
||||||
|
|
||||||
|
simdjson_really_inline simd8<bool>() : base8() {}
|
||||||
|
simdjson_really_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
|
||||||
|
// Splat constructor
|
||||||
|
simdjson_really_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
|
||||||
|
simdjson_really_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
|
||||||
|
simdjson_really_inline simd8<bool> operator~() const { return *this ^ true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct base8_numeric: base8<T> {
|
||||||
|
static simdjson_really_inline simd8<T> splat(T _value) { return _mm512_set1_epi8(_value); }
|
||||||
|
static simdjson_really_inline simd8<T> zero() { return _mm512_setzero_si512(); }
|
||||||
|
static simdjson_really_inline simd8<T> load(const T values[64]) {
|
||||||
|
return _mm512_loadu_si512(reinterpret_cast<const __m512i *>(values));
|
||||||
|
}
|
||||||
|
// Repeat 16 values as many times as necessary (usually for lookup tables)
|
||||||
|
static simdjson_really_inline simd8<T> repeat_16(
|
||||||
|
T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7,
|
||||||
|
T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15
|
||||||
|
) {
|
||||||
|
return simd8<T>(
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline base8_numeric() : base8<T>() {}
|
||||||
|
simdjson_really_inline base8_numeric(const __m512i _value) : base8<T>(_value) {}
|
||||||
|
|
||||||
|
// Store to array
|
||||||
|
simdjson_really_inline void store(T dst[64]) const { return _mm512_storeu_si512(reinterpret_cast<__m512i *>(dst), *this); }
|
||||||
|
|
||||||
|
// Addition/subtraction are the same for signed and unsigned
|
||||||
|
simdjson_really_inline simd8<T> operator+(const simd8<T> other) const { return _mm512_add_epi8(*this, other); }
|
||||||
|
simdjson_really_inline simd8<T> operator-(const simd8<T> other) const { return _mm512_sub_epi8(*this, other); }
|
||||||
|
simdjson_really_inline simd8<T>& operator+=(const simd8<T> other) { *this = *this + other; return *static_cast<simd8<T>*>(this); }
|
||||||
|
simdjson_really_inline simd8<T>& operator-=(const simd8<T> other) { *this = *this - other; return *static_cast<simd8<T>*>(this); }
|
||||||
|
|
||||||
|
// Override to distinguish from bool version
|
||||||
|
simdjson_really_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
|
||||||
|
|
||||||
|
// Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
|
||||||
|
template<typename L>
|
||||||
|
simdjson_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||||
|
return _mm512_shuffle_epi8(lookup_table, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
|
||||||
|
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
|
||||||
|
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
|
||||||
|
// get written.
|
||||||
|
// Design consideration: it seems like a function with the
|
||||||
|
// signature simd8<L> compress(uint32_t mask) would be
|
||||||
|
// sensible, but the AVX ISA makes this kind of approach difficult.
|
||||||
|
template<typename L>
|
||||||
|
simdjson_really_inline void compress(uint64_t mask, L * output) const {
|
||||||
|
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
simdjson_really_inline simd8<L> lookup_16(
|
||||||
|
L replace0, L replace1, L replace2, L replace3,
|
||||||
|
L replace4, L replace5, L replace6, L replace7,
|
||||||
|
L replace8, L replace9, L replace10, L replace11,
|
||||||
|
L replace12, L replace13, L replace14, L replace15) const {
|
||||||
|
return lookup_16(simd8<L>::repeat_16(
|
||||||
|
replace0, replace1, replace2, replace3,
|
||||||
|
replace4, replace5, replace6, replace7,
|
||||||
|
replace8, replace9, replace10, replace11,
|
||||||
|
replace12, replace13, replace14, replace15
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Signed bytes
|
||||||
|
template<>
|
||||||
|
struct simd8<int8_t> : base8_numeric<int8_t> {
|
||||||
|
simdjson_really_inline simd8() : base8_numeric<int8_t>() {}
|
||||||
|
simdjson_really_inline simd8(const __m512i _value) : base8_numeric<int8_t>(_value) {}
|
||||||
|
// Splat constructor
|
||||||
|
simdjson_really_inline simd8(int8_t _value) : simd8(splat(_value)) {}
|
||||||
|
// Array constructor
|
||||||
|
simdjson_really_inline simd8(const int8_t values[64]) : simd8(load(values)) {}
|
||||||
|
// Member-by-member initialization
|
||||||
|
simdjson_really_inline simd8(
|
||||||
|
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
|
||||||
|
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15,
|
||||||
|
int8_t v16, int8_t v17, int8_t v18, int8_t v19, int8_t v20, int8_t v21, int8_t v22, int8_t v23,
|
||||||
|
int8_t v24, int8_t v25, int8_t v26, int8_t v27, int8_t v28, int8_t v29, int8_t v30, int8_t v31,
|
||||||
|
int8_t v32, int8_t v33, int8_t v34, int8_t v35, int8_t v36, int8_t v37, int8_t v38, int8_t v39,
|
||||||
|
int8_t v40, int8_t v41, int8_t v42, int8_t v43, int8_t v44, int8_t v45, int8_t v46, int8_t v47,
|
||||||
|
int8_t v48, int8_t v49, int8_t v50, int8_t v51, int8_t v52, int8_t v53, int8_t v54, int8_t v55,
|
||||||
|
int8_t v56, int8_t v57, int8_t v58, int8_t v59, int8_t v60, int8_t v61, int8_t v62, int8_t v63
|
||||||
|
) : simd8(_mm512_set_epi8(
|
||||||
|
v63, v62, v61, v60, v59, v58, v57, v56,
|
||||||
|
v55, v54, v53, v52, v51, v50, v49, v48,
|
||||||
|
v47, v46, v45, v44, v43, v42, v41, v40,
|
||||||
|
v39, v38, v37, v36, v35, v34, v33, v32,
|
||||||
|
v31, v30, v29, v28, v27, v26, v25, v24,
|
||||||
|
v23, v22, v21, v20, v19, v18, v17, v16,
|
||||||
|
v15, v14, v13, v12, v11, v10, v9, v8,
|
||||||
|
v7, v6, v5, v4, v3, v2, v1, v0
|
||||||
|
)) {}
|
||||||
|
|
||||||
|
// Repeat 16 values as many times as necessary (usually for lookup tables)
|
||||||
|
simdjson_really_inline static simd8<int8_t> repeat_16(
|
||||||
|
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
|
||||||
|
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
|
||||||
|
) {
|
||||||
|
return simd8<int8_t>(
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order-sensitive comparisons
|
||||||
|
simdjson_really_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return _mm512_max_epi8(*this, other); }
|
||||||
|
simdjson_really_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return _mm512_min_epi8(*this, other); }
|
||||||
|
|
||||||
|
simdjson_really_inline simd8<bool> operator>(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(*this, other),_mm512_set1_epi8(uint8_t(0x80))); }
|
||||||
|
simdjson_really_inline simd8<bool> operator<(const simd8<int8_t> other) const { return _mm512_maskz_abs_epi8(_mm512_cmpgt_epi8_mask(other, *this),_mm512_set1_epi8(uint8_t(0x80))); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unsigned bytes
|
||||||
|
template<>
|
||||||
|
struct simd8<uint8_t>: base8_numeric<uint8_t> {
|
||||||
|
simdjson_really_inline simd8() : base8_numeric<uint8_t>() {}
|
||||||
|
simdjson_really_inline simd8(const __m512i _value) : base8_numeric<uint8_t>(_value) {}
|
||||||
|
// Splat constructor
|
||||||
|
simdjson_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
|
||||||
|
// Array constructor
|
||||||
|
simdjson_really_inline simd8(const uint8_t values[64]) : simd8(load(values)) {}
|
||||||
|
// Member-by-member initialization
|
||||||
|
simdjson_really_inline simd8(
|
||||||
|
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
||||||
|
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15,
|
||||||
|
uint8_t v16, uint8_t v17, uint8_t v18, uint8_t v19, uint8_t v20, uint8_t v21, uint8_t v22, uint8_t v23,
|
||||||
|
uint8_t v24, uint8_t v25, uint8_t v26, uint8_t v27, uint8_t v28, uint8_t v29, uint8_t v30, uint8_t v31,
|
||||||
|
uint8_t v32, uint8_t v33, uint8_t v34, uint8_t v35, uint8_t v36, uint8_t v37, uint8_t v38, uint8_t v39,
|
||||||
|
uint8_t v40, uint8_t v41, uint8_t v42, uint8_t v43, uint8_t v44, uint8_t v45, uint8_t v46, uint8_t v47,
|
||||||
|
uint8_t v48, uint8_t v49, uint8_t v50, uint8_t v51, uint8_t v52, uint8_t v53, uint8_t v54, uint8_t v55,
|
||||||
|
uint8_t v56, uint8_t v57, uint8_t v58, uint8_t v59, uint8_t v60, uint8_t v61, uint8_t v62, uint8_t v63
|
||||||
|
) : simd8(_mm512_set_epi8(
|
||||||
|
v63, v62, v61, v60, v59, v58, v57, v56,
|
||||||
|
v55, v54, v53, v52, v51, v50, v49, v48,
|
||||||
|
v47, v46, v45, v44, v43, v42, v41, v40,
|
||||||
|
v39, v38, v37, v36, v35, v34, v33, v32,
|
||||||
|
v31, v30, v29, v28, v27, v26, v25, v24,
|
||||||
|
v23, v22, v21, v20, v19, v18, v17, v16,
|
||||||
|
v15, v14, v13, v12, v11, v10, v9, v8,
|
||||||
|
v7, v6, v5, v4, v3, v2, v1, v0
|
||||||
|
)) {}
|
||||||
|
|
||||||
|
// Repeat 16 values as many times as necessary (usually for lookup tables)
|
||||||
|
simdjson_really_inline static simd8<uint8_t> repeat_16(
|
||||||
|
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
||||||
|
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
|
||||||
|
) {
|
||||||
|
return simd8<uint8_t>(
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15,
|
||||||
|
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||||
|
v8, v9, v10,v11,v12,v13,v14,v15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saturated math
|
||||||
|
simdjson_really_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return _mm512_adds_epu8(*this, other); }
|
||||||
|
simdjson_really_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return _mm512_subs_epu8(*this, other); }
|
||||||
|
|
||||||
|
// Order-specific operations
|
||||||
|
simdjson_really_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return _mm512_max_epu8(*this, other); }
|
||||||
|
simdjson_really_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return _mm512_min_epu8(other, *this); }
|
||||||
|
// Same as >, but only guarantees true is nonzero (< guarantees true = -1)
|
||||||
|
simdjson_really_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return this->saturating_sub(other); }
|
||||||
|
// Same as <, but only guarantees true is nonzero (< guarantees true = -1)
|
||||||
|
simdjson_really_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return other.saturating_sub(*this); }
|
||||||
|
simdjson_really_inline uint64_t operator<=(const simd8<uint8_t> other) const { return other.max_val(*this) == other; }
|
||||||
|
simdjson_really_inline uint64_t operator>=(const simd8<uint8_t> other) const { return other.min_val(*this) == other; }
|
||||||
|
simdjson_really_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return this->gt_bits(other).any_bits_set(); }
|
||||||
|
simdjson_really_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return this->lt_bits(other).any_bits_set(); }
|
||||||
|
|
||||||
|
// Bit-specific operations
|
||||||
|
simdjson_really_inline simd8<bool> bits_not_set() const { return _mm512_mask_blend_epi8(*this == uint8_t(0), _mm512_set1_epi8(0), _mm512_set1_epi8(-1)); }
|
||||||
|
simdjson_really_inline simd8<bool> bits_not_set(simd8<uint8_t> bits) const { return (*this & bits).bits_not_set(); }
|
||||||
|
simdjson_really_inline simd8<bool> any_bits_set() const { return ~this->bits_not_set(); }
|
||||||
|
simdjson_really_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return ~this->bits_not_set(bits); }
|
||||||
|
|
||||||
|
simdjson_really_inline bool is_ascii() const { return _mm512_movepi8_mask(*this) == 0; }
|
||||||
|
simdjson_really_inline bool bits_not_set_anywhere() const {
|
||||||
|
return !_mm512_test_epi8_mask(*this, *this);
|
||||||
|
}
|
||||||
|
simdjson_really_inline bool any_bits_set_anywhere() const { return !bits_not_set_anywhere(); }
|
||||||
|
simdjson_really_inline bool bits_not_set_anywhere(simd8<uint8_t> bits) const { return !_mm512_test_epi8_mask(*this, bits); }
|
||||||
|
simdjson_really_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return !bits_not_set_anywhere(bits); }
|
||||||
|
template<int N>
|
||||||
|
simdjson_really_inline simd8<uint8_t> shr() const { return simd8<uint8_t>(_mm512_srli_epi16(*this, N)) & uint8_t(0xFFu >> N); }
|
||||||
|
template<int N>
|
||||||
|
simdjson_really_inline simd8<uint8_t> shl() const { return simd8<uint8_t>(_mm512_slli_epi16(*this, N)) & uint8_t(0xFFu << N); }
|
||||||
|
// Get one of the bits and make a bitmask out of it.
|
||||||
|
// e.g. value.get_bit<7>() gets the high bit
|
||||||
|
template<int N>
|
||||||
|
simdjson_really_inline uint64_t get_bit() const { return _mm512_movepi8_mask(_mm512_slli_epi16(*this, 7-N)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct simd8x64 {
|
||||||
|
static constexpr int NUM_CHUNKS = 64 / sizeof(simd8<T>);
|
||||||
|
static_assert(NUM_CHUNKS == 1, "Icelake kernel should use one register per 64-byte block.");
|
||||||
|
const simd8<T> chunks[NUM_CHUNKS];
|
||||||
|
|
||||||
|
simd8x64(const simd8x64<T>& o) = delete; // no copy allowed
|
||||||
|
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
|
||||||
|
simd8x64() = delete; // no default constructor allowed
|
||||||
|
|
||||||
|
simdjson_really_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
|
||||||
|
simdjson_really_inline simd8x64(const simd8<T> chunk0) : chunks{chunk0} {}
|
||||||
|
simdjson_really_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr)} {}
|
||||||
|
|
||||||
|
simdjson_really_inline uint64_t compress(uint64_t mask, T * output) const {
|
||||||
|
this->chunks[0].compress(mask, output);
|
||||||
|
return 64 - count_ones(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline void store(T ptr[64]) const {
|
||||||
|
this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline simd8<T> reduce_or() const {
|
||||||
|
return this->chunks[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline simd8x64<T> bit_or(const T m) const {
|
||||||
|
const simd8<T> mask = simd8<T>::splat(m);
|
||||||
|
return simd8x64<T>(
|
||||||
|
this->chunks[0] | mask
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline uint64_t eq(const T m) const {
|
||||||
|
const simd8<T> mask = simd8<T>::splat(m);
|
||||||
|
return this->chunks[0] == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
|
||||||
|
return this->chunks[0] == other.chunks[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline uint64_t lteq(const T m) const {
|
||||||
|
const simd8<T> mask = simd8<T>::splat(m);
|
||||||
|
return this->chunks[0] <= mask;
|
||||||
|
}
|
||||||
|
}; // struct simd8x64<T>
|
||||||
|
|
||||||
|
} // namespace simd
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_SIMD_H
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef SIMDJSON_ICELAKE_STRINGPARSING_H
|
||||||
|
#define SIMDJSON_ICELAKE_STRINGPARSING_H
|
||||||
|
|
||||||
|
#include "simdjson/base.h"
|
||||||
|
#include "simdjson/icelake/simd.h"
|
||||||
|
#include "simdjson/icelake/bitmanipulation.h"
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace simd;
|
||||||
|
|
||||||
|
// Holds backslashes and quotes locations.
|
||||||
|
struct backslash_and_quote {
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t BYTES_PROCESSED = 32;
|
||||||
|
simdjson_really_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||||
|
|
||||||
|
simdjson_really_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
|
||||||
|
simdjson_really_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
|
||||||
|
simdjson_really_inline int quote_index() { return trailing_zeroes(quote_bits); }
|
||||||
|
simdjson_really_inline int backslash_index() { return trailing_zeroes(bs_bits); }
|
||||||
|
|
||||||
|
uint64_t bs_bits;
|
||||||
|
uint64_t quote_bits;
|
||||||
|
}; // struct backslash_and_quote
|
||||||
|
|
||||||
|
simdjson_really_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||||
|
// this can read up to 15 bytes beyond the buffer size, but we require
|
||||||
|
// SIMDJSON_PADDING of padding
|
||||||
|
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
|
||||||
|
simd8<uint8_t> v(src);
|
||||||
|
// store to dest unconditionally - we can overwrite the bits we don't like later
|
||||||
|
v.store(dst);
|
||||||
|
return {
|
||||||
|
static_cast<uint64_t>(v == '\\'), // bs_bits
|
||||||
|
static_cast<uint64_t>(v == '"'), // quote_bits
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#include "simdjson/generic/stringparsing.h"
|
||||||
|
|
||||||
|
#endif // SIMDJSON_ICELAKE_STRINGPARSING_H
|
||||||
@@ -18,8 +18,6 @@ namespace simdjson {
|
|||||||
* @return true if the string is valid UTF-8.
|
* @return true if the string is valid UTF-8.
|
||||||
*/
|
*/
|
||||||
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) noexcept;
|
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the UTF-8 string.
|
* Validate the UTF-8 string.
|
||||||
*
|
*
|
||||||
@@ -40,6 +38,20 @@ simdjson_really_inline simdjson_warn_unused bool validate_utf8(const std::string
|
|||||||
return validate_utf8(s.data(), s.size());
|
return validate_utf8(s.data(), s.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||||
|
* must be an unescaped quote terminating the string. It returns the final output
|
||||||
|
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||||
|
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||||
|
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||||
|
* SIMDJSON_PADDING bytes.
|
||||||
|
*
|
||||||
|
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
||||||
|
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||||
|
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) noexcept;
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
class document;
|
class document;
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
@@ -136,6 +148,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_warn_unused virtual bool validate_utf8(const char *buf, size_t len) const noexcept = 0;
|
simdjson_warn_unused virtual bool validate_utf8(const char *buf, size_t len) const noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||||
|
* must be an unescaped quote terminating the string. It returns the final output
|
||||||
|
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||||
|
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||||
|
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||||
|
* SIMDJSON_PADDING bytes.
|
||||||
|
*
|
||||||
|
* Overridden by each implementation.
|
||||||
|
*
|
||||||
|
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
||||||
|
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||||
|
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused virtual uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** @private Construct an implementation with the given name and description. For subclasses. */
|
/** @private Construct an implementation with the given name and description. For subclasses. */
|
||||||
simdjson_really_inline implementation(
|
simdjson_really_inline implementation(
|
||||||
|
|||||||
@@ -13,10 +13,45 @@
|
|||||||
#endif
|
#endif
|
||||||
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
|
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
// How do we detect that a compiler supports vbmi2?
|
||||||
|
// For sure if the following header is found, we are ok?
|
||||||
|
#if __has_include(<avx512vbmi2intrin.h>)
|
||||||
|
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER >= 1920
|
||||||
|
// Visual Studio 2019 and up support VBMI2 under x64 even if the header
|
||||||
|
// avx512vbmi2intrin.h is not found.
|
||||||
|
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// By default, we allow AVX512.
|
||||||
|
#ifndef SIMDJSON_AVX512_ALLOWED
|
||||||
|
#define SIMDJSON_AVX512_ALLOWED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Default Icelake to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
||||||
|
// at runtime.
|
||||||
|
#ifndef SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
#define SIMDJSON_IMPLEMENTATION_ICELAKE ((SIMDJSON_IS_X86_64) && (SIMDJSON_AVX512_ALLOWED) && (SIMDJSON_COMPILER_SUPPORTS_VBMI2))
|
||||||
|
#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_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
|
||||||
|
#else
|
||||||
|
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
|
||||||
|
#endif
|
||||||
|
|
||||||
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
|
||||||
// at runtime.
|
// at runtime.
|
||||||
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
|
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
|
||||||
#define SIMDJSON_IMPLEMENTATION_HASWELL (SIMDJSON_IS_X86_64)
|
#define SIMDJSON_IMPLEMENTATION_HASWELL SIMDJSON_IS_X86_64
|
||||||
#endif
|
#endif
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
||||||
@@ -26,7 +61,7 @@
|
|||||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Default Westmere to on if this is x86-64, unless we'll always select Haswell.
|
// Default Westmere to on if this is x86-64. Note that the macro SIMDJSON_REQUIRES_HASWELL appears unused.
|
||||||
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
|
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
|
||||||
#define SIMDJSON_IMPLEMENTATION_WESTMERE (SIMDJSON_IS_X86_64 && !SIMDJSON_REQUIRES_HASWELL)
|
#define SIMDJSON_IMPLEMENTATION_WESTMERE (SIMDJSON_IS_X86_64 && !SIMDJSON_REQUIRES_HASWELL)
|
||||||
#endif
|
#endif
|
||||||
@@ -49,6 +84,7 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
|||||||
// Implementations
|
// Implementations
|
||||||
#include "simdjson/arm64.h"
|
#include "simdjson/arm64.h"
|
||||||
#include "simdjson/fallback.h"
|
#include "simdjson/fallback.h"
|
||||||
|
#include "simdjson/icelake.h"
|
||||||
#include "simdjson/haswell.h"
|
#include "simdjson/haswell.h"
|
||||||
#include "simdjson/ppc64.h"
|
#include "simdjson/ppc64.h"
|
||||||
#include "simdjson/westmere.h"
|
#include "simdjson/westmere.h"
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
simdjson_warn_unused inline error_code allocate(size_t capacity, size_t max_depth) noexcept;
|
simdjson_warn_unused inline error_code allocate(size_t capacity, size_t max_depth) noexcept;
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* The maximum document length this parser supports.
|
* The maximum document length this parser supports.
|
||||||
|
|||||||
@@ -66,7 +66,16 @@ enum instruction_set {
|
|||||||
PCLMULQDQ = 0x10,
|
PCLMULQDQ = 0x10,
|
||||||
BMI1 = 0x20,
|
BMI1 = 0x20,
|
||||||
BMI2 = 0x40,
|
BMI2 = 0x40,
|
||||||
ALTIVEC = 0x80
|
ALTIVEC = 0x80,
|
||||||
|
AVX512F = 0x100,
|
||||||
|
AVX512DQ = 0x200,
|
||||||
|
AVX512IFMA = 0x400,
|
||||||
|
AVX512PF = 0x800,
|
||||||
|
AVX512ER = 0x1000,
|
||||||
|
AVX512CD = 0x2000,
|
||||||
|
AVX512BW = 0x4000,
|
||||||
|
AVX512VL = 0x8000,
|
||||||
|
AVX512VBMI2 = 0x10000
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(__PPC64__)
|
#if defined(__PPC64__)
|
||||||
@@ -96,11 +105,20 @@ static inline uint32_t detect_supported_architectures() {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Can be found on Intel ISA Reference for CPUID
|
// Can be found on Intel ISA Reference for CPUID
|
||||||
constexpr uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7
|
constexpr uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
|
constexpr uint32_t cpuid_avx512f_bit = 1 << 16; ///< @private bit 16 of EBX for EAX=0x7
|
||||||
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
|
constexpr uint32_t cpuid_avx512dq_bit = 1 << 17; ///< @private bit 17 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512ifma_bit = 1 << 21; ///< @private bit 21 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512pf_bit = 1 << 26; ///< @private bit 26 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512cd_bit = 1 << 28; ///< @private bit 28 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512bw_bit = 1 << 30; ///< @private bit 30 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512vl_bit = 1 << 31; ///< @private bit 31 of EBX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_avx512vbmi2_bit = 1 << 6; ///< @private bit 6 of ECX for EAX=0x7
|
||||||
|
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
|
||||||
|
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +164,42 @@ static inline uint32_t detect_supported_architectures() {
|
|||||||
host_isa |= instruction_set::BMI2;
|
host_isa |= instruction_set::BMI2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512f_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512F;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512dq_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512DQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512ifma_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512IFMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512pf_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512PF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512er_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512ER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512cd_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512CD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512bw_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512BW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ebx & cpuid_avx512vl_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512VL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecx & cpuid_avx512vbmi2_bit) {
|
||||||
|
host_isa |= instruction_set::AVX512VBMI2;
|
||||||
|
}
|
||||||
|
|
||||||
// EBX for EAX=0x1
|
// EBX for EAX=0x1
|
||||||
eax = 0x1;
|
eax = 0x1;
|
||||||
cpuid(&eax, &ebx, &ecx, &edx);
|
cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
size_t &dst_len) const noexcept final;
|
size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf,
|
simdjson_warn_unused bool validate_utf8(const char *buf,
|
||||||
size_t len) const noexcept final;
|
size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ppc64
|
} // namespace ppc64
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||||
|
|
||||||
/** The version of simdjson being used (major.minor.revision) */
|
/** The version of simdjson being used (major.minor.revision) */
|
||||||
#define SIMDJSON_VERSION 1.0.2
|
#define SIMDJSON_VERSION 2.0.4
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
/**
|
/**
|
||||||
* The major version (MAJOR.minor.revision) of simdjson being used.
|
* The major version (MAJOR.minor.revision) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_MAJOR = 1,
|
SIMDJSON_VERSION_MAJOR = 2,
|
||||||
/**
|
/**
|
||||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
@@ -19,7 +19,7 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 2
|
SIMDJSON_VERSION_REVISION = 4
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
) const noexcept final;
|
) const noexcept final;
|
||||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace westmere
|
} // namespace westmere
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import subprocess
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import datetime
|
||||||
|
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
sys.stdout.write("Sorry, requires Python 3.x or better\n")
|
sys.stdout.write("Sorry, requires Python 3.x or better\n")
|
||||||
@@ -80,8 +81,10 @@ def dofile(fid, prepath, filename):
|
|||||||
# print(f"// dofile: invoked with prepath={prepath}, filename={filename}",file=fid)
|
# print(f"// dofile: invoked with prepath={prepath}, filename={filename}",file=fid)
|
||||||
file = os.path.join(prepath, filename)
|
file = os.path.join(prepath, filename)
|
||||||
RELFILE = os.path.relpath(file, PROJECTPATH)
|
RELFILE = os.path.relpath(file, PROJECTPATH)
|
||||||
|
# Windows use \ as a directory separator, but we do not want that:
|
||||||
|
OSRELFILE = RELFILE.replace('\\','/')
|
||||||
# Last lines are always ignored. Files should end by an empty lines.
|
# Last lines are always ignored. Files should end by an empty lines.
|
||||||
print(f"/* begin file {RELFILE} */", file=fid)
|
print(f"/* begin file {OSRELFILE} */", file=fid)
|
||||||
includepattern = re.compile('^#include "(.*)"')
|
includepattern = re.compile('^#include "(.*)"')
|
||||||
redefines_simdjson_implementation = re.compile('^#define\s+SIMDJSON_IMPLEMENTATION\s+(.*)')
|
redefines_simdjson_implementation = re.compile('^#define\s+SIMDJSON_IMPLEMENTATION\s+(.*)')
|
||||||
undefines_simdjson_implementation = re.compile('^#undef\s+SIMDJSON_IMPLEMENTATION\s*$')
|
undefines_simdjson_implementation = re.compile('^#undef\s+SIMDJSON_IMPLEMENTATION\s*$')
|
||||||
@@ -113,7 +116,7 @@ def dofile(fid, prepath, filename):
|
|||||||
else:
|
else:
|
||||||
# copy the line, with SIMDJSON_IMPLEMENTATION replace to what it is currently defined to
|
# copy the line, with SIMDJSON_IMPLEMENTATION replace to what it is currently defined to
|
||||||
print(uses_simdjson_implementation.sub(current_implementation+"\\1",line), file=fid)
|
print(uses_simdjson_implementation.sub(current_implementation+"\\1",line), file=fid)
|
||||||
print(f"/* end file {RELFILE} */", file=fid)
|
print(f"/* end file {OSRELFILE} */", file=fid)
|
||||||
|
|
||||||
|
|
||||||
# Get the generation date from git, so the output is reproducible.
|
# Get the generation date from git, so the output is reproducible.
|
||||||
@@ -121,8 +124,12 @@ def dofile(fid, prepath, filename):
|
|||||||
# does not change with locale and timezone at time of generation.
|
# does not change with locale and timezone at time of generation.
|
||||||
# Forcing it to be UTC is difficult, because it needs to be portable
|
# Forcing it to be UTC is difficult, because it needs to be portable
|
||||||
# between gnu date and busybox date.
|
# between gnu date and busybox date.
|
||||||
timestamp = subprocess.run(['git', 'show', '-s', '--format=%ci', 'HEAD'],
|
try:
|
||||||
|
timestamp = subprocess.run(['git', 'show', '-s', '--format=%ci', 'HEAD'],
|
||||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||||
|
except:
|
||||||
|
print("git not found, timestamp based on current time")
|
||||||
|
timestamp = str(datetime.datetime.now())
|
||||||
print(f"timestamp is {timestamp}")
|
print(f"timestamp is {timestamp}")
|
||||||
|
|
||||||
os.makedirs(AMALGAMATE_OUTPUT_PATH, exist_ok=True)
|
os.makedirs(AMALGAMATE_OUTPUT_PATH, exist_ok=True)
|
||||||
|
|||||||
+2358
-15
File diff suppressed because it is too large
Load Diff
+2618
-35
File diff suppressed because it is too large
Load Diff
@@ -109,6 +109,7 @@ simdjson_really_inline simd8<bool> must_be_2_3_continuation(const simd8<uint8_t>
|
|||||||
// Stage 2
|
// Stage 2
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "generic/stage2/stringparsing.h"
|
||||||
#include "generic/stage2/tape_builder.h"
|
#include "generic/stage2/tape_builder.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -151,6 +152,11 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
|||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||||
|
return arm64::stringparsing::parse_string(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
|||||||
//
|
//
|
||||||
// Stage 2
|
// Stage 2
|
||||||
//
|
//
|
||||||
|
#include "generic/stage2/stringparsing.h"
|
||||||
#include "generic/stage2/tape_builder.h"
|
#include "generic/stage2/tape_builder.h"
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
@@ -359,6 +360,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
|||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||||
|
return fallback::stringparsing::parse_string(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ public:
|
|||||||
// base_ptr[base] incrementing base as we go
|
// base_ptr[base] incrementing base as we go
|
||||||
// will potentially store extra values beyond end of valid bits, so base_ptr
|
// will potentially store extra values beyond end of valid bits, so base_ptr
|
||||||
// needs to be large enough to handle this
|
// needs to be large enough to handle this
|
||||||
|
//
|
||||||
|
// If the kernel sets SIMDJSON_CUSTOM_BIT_INDEXER, then it will provide its own
|
||||||
|
// version of the code.
|
||||||
|
#ifdef SIMDJSON_CUSTOM_BIT_INDEXER
|
||||||
|
simdjson_really_inline void write(uint32_t idx, uint64_t bits);
|
||||||
|
#else
|
||||||
simdjson_really_inline void write(uint32_t idx, uint64_t bits) {
|
simdjson_really_inline void write(uint32_t idx, uint64_t bits) {
|
||||||
// In some instances, the next branch is expensive because it is mispredicted.
|
// In some instances, the next branch is expensive because it is mispredicted.
|
||||||
// Unfortunately, in other cases,
|
// Unfortunately, in other cases,
|
||||||
@@ -117,6 +123,8 @@ public:
|
|||||||
this->tail += cnt;
|
this->tail += cnt;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif // SIMDJSON_CUSTOM_BIT_INDEXER
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class json_structural_indexer {
|
class json_structural_indexer {
|
||||||
|
|||||||
@@ -111,12 +111,25 @@ using namespace simd;
|
|||||||
simdjson_really_inline simd8<uint8_t> is_incomplete(const simd8<uint8_t> input) {
|
simdjson_really_inline simd8<uint8_t> is_incomplete(const simd8<uint8_t> input) {
|
||||||
// If the previous input's last 3 bytes match this, they're too short (they ended at EOF):
|
// If the previous input's last 3 bytes match this, they're too short (they ended at EOF):
|
||||||
// ... 1111____ 111_____ 11______
|
// ... 1111____ 111_____ 11______
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
static const uint8_t max_array[64] = {
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 0b11110000u-1, 0b11100000u-1, 0b11000000u-1
|
||||||
|
};
|
||||||
|
#else
|
||||||
static const uint8_t max_array[32] = {
|
static const uint8_t max_array[32] = {
|
||||||
255, 255, 255, 255, 255, 255, 255, 255,
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
255, 255, 255, 255, 255, 255, 255, 255,
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
255, 255, 255, 255, 255, 255, 255, 255,
|
255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
255, 255, 255, 255, 255, 0b11110000u-1, 0b11100000u-1, 0b11000000u-1
|
255, 255, 255, 255, 255, 0b11110000u-1, 0b11100000u-1, 0b11000000u-1
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
const simd8<uint8_t> max_value(&max_array[sizeof(max_array)-sizeof(simd8<uint8_t>)]);
|
const simd8<uint8_t> max_value(&max_array[sizeof(max_array)-sizeof(simd8<uint8_t>)]);
|
||||||
return input.gt_bits(max_value);
|
return input.gt_bits(max_value);
|
||||||
}
|
}
|
||||||
@@ -154,9 +167,13 @@ using namespace simd;
|
|||||||
this->error |= this->prev_incomplete;
|
this->error |= this->prev_incomplete;
|
||||||
} else {
|
} else {
|
||||||
// you might think that a for-loop would work, but under Visual Studio, it is not good enough.
|
// you might think that a for-loop would work, but under Visual Studio, it is not good enough.
|
||||||
static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 2) || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
|
static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 1)
|
||||||
"We support either two or four chunks per 64-byte block.");
|
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|
||||||
if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
|
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
|
||||||
|
"We support one, two or four chunks per 64-byte block.");
|
||||||
|
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
|
||||||
|
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
|
||||||
|
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
|
||||||
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
|
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
|
||||||
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
|
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
|
||||||
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
|
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
// This file contains the common code every implementation uses
|
||||||
|
// It is intended to be included multiple times and compiled multiple times
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
/// @private
|
||||||
|
namespace stringparsing {
|
||||||
|
|
||||||
|
// begin copypasta
|
||||||
|
// These chars yield themselves: " \ /
|
||||||
|
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||||
|
// u not handled in this table as it's complex
|
||||||
|
static const uint8_t escape_map[256] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||||
|
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||||
|
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||||
|
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// handle a unicode codepoint
|
||||||
|
// write appropriate values into dest
|
||||||
|
// src will advance 6 bytes or 12 bytes
|
||||||
|
// dest will advance a variable amount (return via pointer)
|
||||||
|
// return true if the unicode codepoint was valid
|
||||||
|
// We work in little-endian then swap at write time
|
||||||
|
simdjson_warn_unused
|
||||||
|
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||||
|
uint8_t **dst_ptr) {
|
||||||
|
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||||
|
// conversion isn't valid; we defer the check for this to inside the
|
||||||
|
// multilingual plane check
|
||||||
|
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||||
|
*src_ptr += 6;
|
||||||
|
// check for low surrogate for characters outside the Basic
|
||||||
|
// Multilingual Plane.
|
||||||
|
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||||
|
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||||
|
|
||||||
|
// if the first code point is invalid we will get here, as we will go past
|
||||||
|
// the check for being outside the Basic Multilingual plane. If we don't
|
||||||
|
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||||
|
// this check catches both the case of the first code point being invalid
|
||||||
|
// or the second code point being invalid.
|
||||||
|
if ((code_point | code_point_2) >> 16) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
code_point =
|
||||||
|
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||||
|
*src_ptr += 6;
|
||||||
|
}
|
||||||
|
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||||
|
*dst_ptr += offset;
|
||||||
|
return offset > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||||
|
* must be an unescaped quote terminating the string. It returns the final output
|
||||||
|
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||||
|
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||||
|
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||||
|
* SIMDJSON_PADDING bytes.
|
||||||
|
*/
|
||||||
|
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||||
|
while (1) {
|
||||||
|
// Copy the next n bytes, and find the backslash and quote in them.
|
||||||
|
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||||
|
// If the next thing is the end quote, copy and return
|
||||||
|
if (bs_quote.has_quote_first()) {
|
||||||
|
// we encountered quotes first. Move dst to point to quotes and exit
|
||||||
|
return dst + bs_quote.quote_index();
|
||||||
|
}
|
||||||
|
if (bs_quote.has_backslash()) {
|
||||||
|
/* find out where the backspace is */
|
||||||
|
auto bs_dist = bs_quote.backslash_index();
|
||||||
|
uint8_t escape_char = src[bs_dist + 1];
|
||||||
|
/* we encountered backslash first. Handle backslash */
|
||||||
|
if (escape_char == 'u') {
|
||||||
|
/* move src/dst up to the start; they will be further adjusted
|
||||||
|
within the unicode codepoint handling code. */
|
||||||
|
src += bs_dist;
|
||||||
|
dst += bs_dist;
|
||||||
|
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||||
|
* write bs_dist+1 characters to output
|
||||||
|
* note this may reach beyond the part of the buffer we've actually
|
||||||
|
* seen. I think this is ok */
|
||||||
|
uint8_t escape_result = escape_map[escape_char];
|
||||||
|
if (escape_result == 0u) {
|
||||||
|
return nullptr; /* bogus escape value is an error */
|
||||||
|
}
|
||||||
|
dst[bs_dist] = escape_result;
|
||||||
|
src += bs_dist + 2;
|
||||||
|
dst += bs_dist + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* they are the same. Since they can't co-occur, it means we
|
||||||
|
* encountered neither. */
|
||||||
|
src += backslash_and_quote::BYTES_PROCESSED;
|
||||||
|
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* can't be reached */
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_unused simdjson_warn_unused simdjson_really_inline error_code parse_string_to_buffer(const uint8_t *src, uint8_t *¤t_string_buf_loc, std::string_view &s) {
|
||||||
|
if (*(src++) != '"') { return STRING_ERROR; }
|
||||||
|
auto end = stringparsing::parse_string(src, current_string_buf_loc);
|
||||||
|
if (!end) { return STRING_ERROR; }
|
||||||
|
s = std::string_view(reinterpret_cast<const char *>(current_string_buf_loc), end-current_string_buf_loc);
|
||||||
|
current_string_buf_loc = end;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace stringparsing
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
@@ -112,6 +112,7 @@ simdjson_really_inline simd8<bool> must_be_2_3_continuation(const simd8<uint8_t>
|
|||||||
//
|
//
|
||||||
// Stage 2
|
// Stage 2
|
||||||
//
|
//
|
||||||
|
#include "generic/stage2/stringparsing.h"
|
||||||
#include "generic/stage2/tape_builder.h"
|
#include "generic/stage2/tape_builder.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -152,6 +153,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
|||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||||
|
return haswell::stringparsing::parse_string(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
|
|||||||
@@ -0,0 +1,215 @@
|
|||||||
|
#include "simdjson/icelake/begin.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 1
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace simd;
|
||||||
|
|
||||||
|
struct json_character_block {
|
||||||
|
static simdjson_really_inline json_character_block classify(const simd::simd8x64<uint8_t>& in);
|
||||||
|
// ASCII white-space ('\r','\n','\t',' ')
|
||||||
|
simdjson_really_inline uint64_t whitespace() const noexcept;
|
||||||
|
// non-quote structural characters (comma, colon, braces, brackets)
|
||||||
|
simdjson_really_inline uint64_t op() const noexcept;
|
||||||
|
// neither a structural character nor a white-space, so letters, numbers and quotes
|
||||||
|
simdjson_really_inline uint64_t scalar() const noexcept;
|
||||||
|
|
||||||
|
uint64_t _whitespace; // ASCII white-space ('\r','\n','\t',' ')
|
||||||
|
uint64_t _op; // structural characters (comma, colon, braces, brackets but not quotes)
|
||||||
|
};
|
||||||
|
|
||||||
|
simdjson_really_inline uint64_t json_character_block::whitespace() const noexcept { return _whitespace; }
|
||||||
|
simdjson_really_inline uint64_t json_character_block::op() const noexcept { return _op; }
|
||||||
|
simdjson_really_inline uint64_t json_character_block::scalar() const noexcept { return ~(op() | whitespace()); }
|
||||||
|
|
||||||
|
// This identifies structural characters (comma, colon, braces, brackets),
|
||||||
|
// and ASCII white-space ('\r','\n','\t',' ').
|
||||||
|
simdjson_really_inline json_character_block json_character_block::classify(const simd::simd8x64<uint8_t>& in) {
|
||||||
|
// These lookups rely on the fact that anything < 127 will match the lower 4 bits, which is why
|
||||||
|
// we can't use the generic lookup_16.
|
||||||
|
const auto whitespace_table = simd8<uint8_t>::repeat_16(' ', 100, 100, 100, 17, 100, 113, 2, 100, '\t', '\n', 112, 100, '\r', 100, 100);
|
||||||
|
|
||||||
|
// The 6 operators (:,[]{}) have these values:
|
||||||
|
//
|
||||||
|
// , 2C
|
||||||
|
// : 3A
|
||||||
|
// [ 5B
|
||||||
|
// { 7B
|
||||||
|
// ] 5D
|
||||||
|
// } 7D
|
||||||
|
//
|
||||||
|
// If you use | 0x20 to turn [ and ] into { and }, the lower 4 bits of each character is unique.
|
||||||
|
// We exploit this, using a simd 4-bit lookup to tell us which character match against, and then
|
||||||
|
// match it (against | 0x20).
|
||||||
|
//
|
||||||
|
// To prevent recognizing other characters, everything else gets compared with 0, which cannot
|
||||||
|
// match due to the | 0x20.
|
||||||
|
//
|
||||||
|
// NOTE: Due to the | 0x20, this ALSO treats <FF> and <SUB> (control characters 0C and 1A) like ,
|
||||||
|
// and :. This gets caught in stage 2, which checks the actual character to ensure the right
|
||||||
|
// operators are in the right places.
|
||||||
|
const auto op_table = simd8<uint8_t>::repeat_16(
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, ':', '{', // : = 3A, [ = 5B, { = 7B
|
||||||
|
',', '}', 0, 0 // , = 2C, ] = 5D, } = 7D
|
||||||
|
);
|
||||||
|
|
||||||
|
// We compute whitespace and op separately. If later code only uses one or the
|
||||||
|
// other, given the fact that all functions are aggressively inlined, we can
|
||||||
|
// hope that useless computations will be omitted. This is namely case when
|
||||||
|
// minifying (we only need whitespace).
|
||||||
|
|
||||||
|
const uint64_t whitespace = in.eq({
|
||||||
|
_mm512_shuffle_epi8(whitespace_table, in.chunks[0])
|
||||||
|
});
|
||||||
|
// Turn [ and ] into { and }
|
||||||
|
const simd8x64<uint8_t> curlified{
|
||||||
|
in.chunks[0] | 0x20
|
||||||
|
};
|
||||||
|
const uint64_t op = curlified.eq({
|
||||||
|
_mm512_shuffle_epi8(op_table, in.chunks[0])
|
||||||
|
});
|
||||||
|
|
||||||
|
return { whitespace, op };
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline bool is_ascii(const simd8x64<uint8_t>& input) {
|
||||||
|
return input.reduce_or().is_ascii();
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_unused simdjson_really_inline simd8<bool> must_be_continuation(const simd8<uint8_t> prev1, const simd8<uint8_t> prev2, const simd8<uint8_t> prev3) {
|
||||||
|
simd8<uint8_t> is_second_byte = prev1.saturating_sub(0b11000000u-1); // Only 11______ will be > 0
|
||||||
|
simd8<uint8_t> is_third_byte = prev2.saturating_sub(0b11100000u-1); // Only 111_____ will be > 0
|
||||||
|
simd8<uint8_t> is_fourth_byte = prev3.saturating_sub(0b11110000u-1); // Only 1111____ will be > 0
|
||||||
|
// Caller requires a bool (all 1's). All values resulting from the subtraction will be <= 64, so signed comparison is fine.
|
||||||
|
return simd8<int8_t>(is_second_byte | is_third_byte | is_fourth_byte) > int8_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_really_inline simd8<bool> must_be_2_3_continuation(const simd8<uint8_t> prev2, const simd8<uint8_t> prev3) {
|
||||||
|
simd8<uint8_t> is_third_byte = prev2.saturating_sub(0b11100000u-1); // Only 111_____ will be > 0
|
||||||
|
simd8<uint8_t> is_fourth_byte = prev3.saturating_sub(0b11110000u-1); // Only 1111____ will be > 0
|
||||||
|
// Caller requires a bool (all 1's). All values resulting from the subtraction will be <= 64, so signed comparison is fine.
|
||||||
|
return simd8<int8_t>(is_third_byte | is_fourth_byte) > int8_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#include "generic/stage1/utf8_lookup4_algorithm.h"
|
||||||
|
// defining SIMDJSON_CUSTOM_BIT_INDEXER allows us to provide our own bit_indexer::write
|
||||||
|
#define SIMDJSON_CUSTOM_BIT_INDEXER
|
||||||
|
#include "generic/stage1/json_structural_indexer.h"
|
||||||
|
// We must not forget to undefine it now:
|
||||||
|
#undef SIMDJSON_CUSTOM_BIT_INDEXER
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We provide a custom version of bit_indexer::write using
|
||||||
|
* naked intrinsics.
|
||||||
|
* TODO: make this code more elegant.
|
||||||
|
*/
|
||||||
|
// Under GCC 12, the intrinsic _mm512_extracti32x4_epi32 may generate 'maybe uninitialized'.
|
||||||
|
// as a workaround, we disable warnings within the following function.
|
||||||
|
SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||||
|
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace { namespace stage1 {
|
||||||
|
simdjson_really_inline void bit_indexer::write(uint32_t idx, uint64_t bits) {
|
||||||
|
// In some instances, the next branch is expensive because it is mispredicted.
|
||||||
|
// Unfortunately, in other cases,
|
||||||
|
// it helps tremendously.
|
||||||
|
if (bits == 0) { return; }
|
||||||
|
|
||||||
|
const __m512i indexes = _mm512_maskz_compress_epi8(bits, _mm512_set_epi32(
|
||||||
|
0x3f3e3d3c, 0x3b3a3938, 0x37363534, 0x33323130,
|
||||||
|
0x2f2e2d2c, 0x2b2a2928, 0x27262524, 0x23222120,
|
||||||
|
0x1f1e1d1c, 0x1b1a1918, 0x17161514, 0x13121110,
|
||||||
|
0x0f0e0d0c, 0x0b0a0908, 0x07060504, 0x03020100
|
||||||
|
));
|
||||||
|
const __m512i start_index = _mm512_set1_epi32(idx);
|
||||||
|
|
||||||
|
const auto count = count_ones(bits);
|
||||||
|
__m512i t0 = _mm512_cvtepu8_epi32(_mm512_castsi512_si128(indexes));
|
||||||
|
_mm512_storeu_si512(this->tail, _mm512_add_epi32(t0, start_index));
|
||||||
|
|
||||||
|
if(count > 16) {
|
||||||
|
const __m512i t1 = _mm512_cvtepu8_epi32(_mm512_extracti32x4_epi32(indexes, 1));
|
||||||
|
_mm512_storeu_si512(this->tail + 16, _mm512_add_epi32(t1, start_index));
|
||||||
|
if(count > 32) {
|
||||||
|
const __m512i t2 = _mm512_cvtepu8_epi32(_mm512_extracti32x4_epi32(indexes, 2));
|
||||||
|
_mm512_storeu_si512(this->tail + 32, _mm512_add_epi32(t2, start_index));
|
||||||
|
if(count > 48) {
|
||||||
|
const __m512i t3 = _mm512_cvtepu8_epi32(_mm512_extracti32x4_epi32(indexes, 3));
|
||||||
|
_mm512_storeu_si512(this->tail + 48, _mm512_add_epi32(t3, start_index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->tail += count;
|
||||||
|
}
|
||||||
|
}}}}
|
||||||
|
SIMDJSON_POP_DISABLE_WARNINGS
|
||||||
|
|
||||||
|
#include "generic/stage1/utf8_validator.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 2
|
||||||
|
//
|
||||||
|
#include "generic/stage2/stringparsing.h"
|
||||||
|
#include "generic/stage2/tape_builder.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Implementation-specific overrides
|
||||||
|
//
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
namespace {
|
||||||
|
namespace stage1 {
|
||||||
|
|
||||||
|
simdjson_really_inline uint64_t json_string_scanner::find_escaped(uint64_t backslash) {
|
||||||
|
if (!backslash) { uint64_t escaped = prev_escaped; prev_escaped = 0; return escaped; }
|
||||||
|
return find_escaped_branchless(backslash);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace stage1
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
simdjson_warn_unused error_code implementation::minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept {
|
||||||
|
return icelake::stage1::json_minifier::minify<128>(buf, len, dst, dst_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused error_code dom_parser_implementation::stage1(const uint8_t *_buf, size_t _len, stage1_mode streaming) noexcept {
|
||||||
|
this->buf = _buf;
|
||||||
|
this->len = _len;
|
||||||
|
return icelake::stage1::json_structural_indexer::index<128>(_buf, _len, *this, streaming);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t len) const noexcept {
|
||||||
|
return icelake::stage1::generic_validate_utf8(buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
|
||||||
|
return stage2::tape_builder::parse_document<false>(*this, _doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
|
||||||
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||||
|
return icelake::stringparsing::parse_string(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
|
if (error) { return error; }
|
||||||
|
return stage2(_doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#include "simdjson/icelake/end.h"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include "simdjson/icelake/begin.h"
|
||||||
|
|
||||||
|
namespace simdjson {
|
||||||
|
namespace SIMDJSON_IMPLEMENTATION {
|
||||||
|
|
||||||
|
simdjson_warn_unused error_code implementation::create_dom_parser_implementation(
|
||||||
|
size_t capacity,
|
||||||
|
size_t max_depth,
|
||||||
|
std::unique_ptr<internal::dom_parser_implementation>& dst
|
||||||
|
) const noexcept {
|
||||||
|
dst.reset( new (std::nothrow) dom_parser_implementation() );
|
||||||
|
if (!dst) { return MEMALLOC; }
|
||||||
|
if (auto err = dst->set_capacity(capacity))
|
||||||
|
return err;
|
||||||
|
if (auto err = dst->set_max_depth(max_depth))
|
||||||
|
return err;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SIMDJSON_IMPLEMENTATION
|
||||||
|
} // namespace simdjson
|
||||||
|
|
||||||
|
#include "simdjson/icelake/end.h"
|
||||||
|
|
||||||
+18
-1
@@ -14,6 +14,12 @@ namespace internal {
|
|||||||
// Static array of known implementations. We're hoping these get baked into the executable
|
// Static array of known implementations. We're hoping these get baked into the executable
|
||||||
// without requiring a static initializer.
|
// without requiring a static initializer.
|
||||||
|
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
static const icelake::implementation* get_icelake_singleton() {
|
||||||
|
static const icelake::implementation icelake_singleton{};
|
||||||
|
return &icelake_singleton;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
||||||
static const haswell::implementation* get_haswell_singleton() {
|
static const haswell::implementation* get_haswell_singleton() {
|
||||||
static const haswell::implementation haswell_singleton{};
|
static const haswell::implementation haswell_singleton{};
|
||||||
@@ -66,6 +72,9 @@ public:
|
|||||||
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override {
|
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override {
|
||||||
return set_best()->validate_utf8(buf, len);
|
return set_best()->validate_utf8(buf, len);
|
||||||
}
|
}
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final override {
|
||||||
|
return set_best()->parse_string(src, dst);
|
||||||
|
}
|
||||||
simdjson_really_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {}
|
simdjson_really_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {}
|
||||||
private:
|
private:
|
||||||
const implementation *set_best() const noexcept;
|
const implementation *set_best() const noexcept;
|
||||||
@@ -73,6 +82,9 @@ private:
|
|||||||
|
|
||||||
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
|
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
|
||||||
static const std::initializer_list<const implementation *> available_implementation_pointers {
|
static const std::initializer_list<const implementation *> available_implementation_pointers {
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
get_icelake_singleton(),
|
||||||
|
#endif
|
||||||
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
||||||
get_haswell_singleton(),
|
get_haswell_singleton(),
|
||||||
#endif
|
#endif
|
||||||
@@ -115,6 +127,9 @@ public:
|
|||||||
// what are the chances that the programmer has a fallback? Given that *we* provide the
|
// what are the chances that the programmer has a fallback? Given that *we* provide the
|
||||||
// fallback, it implies that the programmer would need a fallback for our fallback.
|
// fallback, it implies that the programmer would need a fallback for our fallback.
|
||||||
}
|
}
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *, uint8_t *) const noexcept final override {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
|
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -179,7 +194,9 @@ simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, s
|
|||||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
|
||||||
return get_active_implementation()->validate_utf8(buf, len);
|
return get_active_implementation()->validate_utf8(buf, len);
|
||||||
}
|
}
|
||||||
|
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) noexcept {
|
||||||
|
return get_active_implementation()->parse_string(src, dst);
|
||||||
|
}
|
||||||
const implementation * builtin_implementation() {
|
const implementation * builtin_implementation() {
|
||||||
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
|
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
|
||||||
assert(builtin_impl);
|
assert(builtin_impl);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
|
#if SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_ICELAKE || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@@ -128,4 +128,4 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256] = {
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
#endif // SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
|
#endif // SIMDJSON_IMPLEMENTATION_ARM64 || SIMDJSON_IMPLEMENTATION_ICELAKE || SIMDJSON_IMPLEMENTATION_HASWELL || SIMDJSON_IMPLEMENTATION_WESTMERE || SIMDJSON_IMPLEMENTATION_PPC64
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ simdjson_really_inline simd8<bool> must_be_2_3_continuation(const simd8<uint8_t>
|
|||||||
//
|
//
|
||||||
// Stage 2
|
// Stage 2
|
||||||
//
|
//
|
||||||
|
#include "generic/stage2/stringparsing.h"
|
||||||
#include "generic/stage2/tape_builder.h"
|
#include "generic/stage2/tape_builder.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -122,6 +122,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
|||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||||
|
return ppc64::stringparsing::parse_string(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
|||||||
#include "fallback/implementation.cpp"
|
#include "fallback/implementation.cpp"
|
||||||
#include "fallback/dom_parser_implementation.cpp"
|
#include "fallback/dom_parser_implementation.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||||
|
#include "icelake/implementation.cpp"
|
||||||
|
#include "icelake/dom_parser_implementation.cpp"
|
||||||
|
#endif
|
||||||
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
||||||
#include "haswell/implementation.cpp"
|
#include "haswell/implementation.cpp"
|
||||||
#include "haswell/dom_parser_implementation.cpp"
|
#include "haswell/dom_parser_implementation.cpp"
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ simdjson_really_inline simd8<bool> must_be_2_3_continuation(const simd8<uint8_t>
|
|||||||
//
|
//
|
||||||
// Stage 2
|
// Stage 2
|
||||||
//
|
//
|
||||||
|
#include "generic/stage2/stringparsing.h"
|
||||||
#include "generic/stage2/tape_builder.h"
|
#include "generic/stage2/tape_builder.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -151,6 +152,10 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
|||||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||||
|
return westmere::stringparsing::parse_string(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {
|
||||||
auto error = stage1(_buf, _len, stage1_mode::regular);
|
auto error = stage1(_buf, _len, stage1_mode::regular);
|
||||||
if (error) { return error; }
|
if (error) { return error; }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace array_error_tests {
|
|||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (auto elem : std::forward<T>(array)) {
|
for (auto elem : std::forward<T>(array)) {
|
||||||
std::cout << "-"; std::cout.flush();
|
std::cout << "-"; std::cout.flush();
|
||||||
V actual;
|
V actual{};
|
||||||
auto actual_error = elem.get(actual);
|
auto actual_error = elem.get(actual);
|
||||||
if (count >= N) {
|
if (count >= N) {
|
||||||
if (count >= (N+N2)) {
|
if (count >= (N+N2)) {
|
||||||
|
|||||||
@@ -5,7 +5,14 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "simdjson.h"
|
#include "simdjson.h"
|
||||||
|
|
||||||
|
|
||||||
|
// We get spurious "maybe used uninitialized" warnings under GCC 12.
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#if __GNUC__ >= 12
|
||||||
|
SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// This ensures the compiler can't rearrange them into the proper order (which causes it to work!)
|
// This ensures the compiler can't rearrange them into the proper order (which causes it to work!)
|
||||||
simdjson_never_inline bool check_point(simdjson_result<ondemand::value> xval, simdjson_result<ondemand::value> yval) {
|
simdjson_never_inline bool check_point(simdjson_result<ondemand::value> xval, simdjson_result<ondemand::value> yval) {
|
||||||
|
|||||||
@@ -6,6 +6,26 @@ using namespace simdjson;
|
|||||||
namespace error_tests {
|
namespace error_tests {
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
bool issue1834() {
|
||||||
|
TEST_START();
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto json = "[[]"_padded;
|
||||||
|
json.data()[json.size()] = ']';
|
||||||
|
auto doc = parser.iterate(json);
|
||||||
|
size_t cnt{};
|
||||||
|
auto error = doc.count_elements().get(cnt);
|
||||||
|
return error != simdjson::SUCCESS;
|
||||||
|
}
|
||||||
|
bool issue1834_2() {
|
||||||
|
TEST_START();
|
||||||
|
ondemand::parser parser;
|
||||||
|
auto json = "{\"a\":{}"_padded;
|
||||||
|
json.data()[json.size()] = '}';
|
||||||
|
auto doc = parser.iterate(json);
|
||||||
|
size_t cnt{};
|
||||||
|
auto error = doc.count_fields().get(cnt);
|
||||||
|
return error != simdjson::SUCCESS;
|
||||||
|
}
|
||||||
bool empty_document_error() {
|
bool empty_document_error() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
ondemand::parser parser;
|
ondemand::parser parser;
|
||||||
@@ -272,6 +292,8 @@ namespace error_tests {
|
|||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
|
issue1834() &&
|
||||||
|
issue1834_2() &&
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
raw_json_string_except() &&
|
raw_json_string_except() &&
|
||||||
raw_json_string_except_with_io() &&
|
raw_json_string_except_with_io() &&
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user