mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 751d41ab1e | |||
| 25d8709b18 | |||
| 33b014dd23 | |||
| c8f5f376a0 | |||
| 2e51e7bb8d | |||
| 4037b48e6a | |||
| c3954b1fb8 | |||
| ce74ece545 | |||
| dd4dce848e | |||
| e8f370b085 | |||
| 645033a8c8 | |||
| 3b5ceeb80d | |||
| 82433a67f9 | |||
| 8c1bfe782b | |||
| 730939f01c | |||
| b169dc2ea7 |
+8
-4
@@ -8,7 +8,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
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
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -19,6 +19,7 @@ steps:
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- 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=westmere 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
|
||||
CXX: clang++-6.0
|
||||
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
|
||||
commands:
|
||||
- mkdir build
|
||||
@@ -43,6 +44,7 @@ steps:
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- 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=westmere ctest $CTEST_FLAGS -L per_implementation
|
||||
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
|
||||
@@ -100,7 +102,7 @@ steps:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
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
|
||||
commands:
|
||||
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
|
||||
@@ -111,6 +113,7 @@ steps:
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- 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=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
|
||||
@@ -126,7 +129,7 @@ steps:
|
||||
environment:
|
||||
CC: 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
|
||||
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
|
||||
commands:
|
||||
@@ -135,6 +138,7 @@ steps:
|
||||
- cmake $CMAKE_FLAGS ..
|
||||
- cmake --build . $BUILD_FLAGS
|
||||
- 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=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
|
||||
|
||||
@@ -38,6 +38,6 @@ jobs:
|
||||
run: |
|
||||
mkdir 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
|
||||
ctest -j4 --output-on-failure -LE explicitonly
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Ubuntu 22.04 CI (GCC 12, CXX 20)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -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 &&
|
||||
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -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 .
|
||||
@@ -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@v2
|
||||
- uses: actions/cache@v2
|
||||
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 .
|
||||
@@ -0,0 +1,44 @@
|
||||
name: VS17-CI CXX20
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
name: windows-vs17
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -DSIMDJSON_CXX_STANDARD=20 -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||
- name: Build Debug
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
run: cmake --build build --config Release --verbose
|
||||
- name: Run Release tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Release -LE explicitonly --output-on-failure
|
||||
- name: Run Debug tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Debug -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config Release
|
||||
- name: Test Installation
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||
cmake --build build_install_test --config Release
|
||||
@@ -13,16 +13,16 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, static: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, static: OFF}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, static: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, static: OFF}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Configure
|
||||
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
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
|
||||
@@ -9,23 +9,33 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
name: windows-vs17
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {gen: Visual Studio 17 2022, arch: x64}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: 'Run CMake with VS17 Clang'
|
||||
uses: lukka/run-cmake@v3
|
||||
with:
|
||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
|
||||
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
|
||||
cmakeBuildType: Release
|
||||
buildWithCMake: true
|
||||
cmakeAppendedArgs: -T ClangCL -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: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
- name: Build Debug
|
||||
run: cmake --build build --config Debug --verbose
|
||||
- name: Build Release
|
||||
run: cmake --build build --config Release --verbose
|
||||
- name: Run Release tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Release -LE explicitonly --output-on-failure
|
||||
- name: Run Debug tests
|
||||
run: |
|
||||
cd build
|
||||
ctest -C Debug -LE explicitonly --output-on-failure
|
||||
- name: Install
|
||||
run: |
|
||||
cmake --install build --config Release
|
||||
- name: Test Installation
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
|
||||
cmake --build build_install_test --config Release
|
||||
@@ -1,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'
|
||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 1.0.2
|
||||
VERSION 2.0.0
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,8 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "9.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "9" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "11.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "11" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
|
||||
+4
-1
@@ -38,5 +38,8 @@ Brendan Knapp
|
||||
Danila Kutenin
|
||||
Pavel Pavlov
|
||||
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!
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "1.0.2"
|
||||
PROJECT_NUMBER = "2.0.0"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[/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
|
||||
===============================================
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace amazon_cellphones {
|
||||
|
||||
const bool UNTHREADED = false;
|
||||
const bool THREADED = true;
|
||||
|
||||
using namespace json_benchmark;
|
||||
|
||||
struct brand {
|
||||
@@ -59,10 +63,11 @@ struct runner : public file_runner<I> {
|
||||
}
|
||||
};
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_dom;
|
||||
|
||||
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
|
||||
@@ -8,12 +8,16 @@ namespace amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_dom {
|
||||
using StringType = std::string;
|
||||
|
||||
dom::parser parser{};
|
||||
|
||||
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 i = stream.begin();
|
||||
++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
|
||||
|
||||
|
||||
@@ -8,12 +8,16 @@ namespace amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string;
|
||||
|
||||
ondemand::parser parser{};
|
||||
|
||||
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::iterator i = stream.begin();
|
||||
++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
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define __BENCHMARKER_H
|
||||
|
||||
#include "event_counter.h"
|
||||
#include "simdjson.h" // For SIMDJSON_DISABLE_DEPRECATED_WARNINGS
|
||||
#include "simdjson.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
|
||||
@@ -50,9 +50,9 @@ simdjson_really_inline void simdjson_process_atom(stat_t &s,
|
||||
} else if(element.is<double>()) {
|
||||
s.float_count++;
|
||||
} else if (element.is<bool>()) {
|
||||
simdjson::error_code err;
|
||||
bool v;
|
||||
err = element.get(v);
|
||||
simdjson::error_code error;
|
||||
if ((error = element.get(v))) { std::cerr << error << std::endl; abort(); }
|
||||
if (v) {
|
||||
s.true_count++;
|
||||
} else {
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
namespace large_amazon_cellphones {
|
||||
|
||||
const bool UNTHREADED = false;
|
||||
const bool THREADED = true;
|
||||
|
||||
static const simdjson::padded_string &get_built_json();
|
||||
|
||||
using namespace json_benchmark;
|
||||
@@ -81,11 +84,11 @@ static const simdjson::padded_string &get_built_json() {
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_dom;
|
||||
|
||||
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
|
||||
@@ -9,12 +9,16 @@ namespace large_amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_dom {
|
||||
using StringType = std::string;
|
||||
|
||||
dom::parser parser{};
|
||||
|
||||
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 i = stream.begin();
|
||||
++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
|
||||
|
||||
|
||||
@@ -8,12 +8,16 @@ namespace large_amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string;
|
||||
|
||||
ondemand::parser parser{};
|
||||
|
||||
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::iterator i = stream.begin();
|
||||
++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
|
||||
|
||||
|
||||
@@ -91,7 +91,8 @@ endif()
|
||||
|
||||
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a
|
||||
# target.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(SIMDJSON_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for simdjson")
|
||||
set(CMAKE_CXX_STANDARD ${SIMDJSON_CXX_STANDARD})
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
@@ -175,6 +176,18 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
|
||||
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)
|
||||
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
|
||||
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Implementation selection
|
||||
#
|
||||
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell arm64 ppc64)
|
||||
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64)
|
||||
|
||||
set(
|
||||
SIMDJSON_IMPLEMENTATION ""
|
||||
@@ -15,7 +15,7 @@ set(
|
||||
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
|
||||
CACHE STRING "\
|
||||
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 \
|
||||
runtime."
|
||||
)
|
||||
|
||||
+1
-7
@@ -1401,10 +1401,6 @@ You must check the type before accessing the value: it is an error to call `get_
|
||||
|
||||
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
|
||||
|
||||
If you only need to compute `v.get_number().get_number_type()` on
|
||||
a `document` or `value` instance, you should call directly the faster method
|
||||
`v.get_number_type()` which does not generate an
|
||||
intermediate `number` instance.
|
||||
|
||||
Consider the following example:
|
||||
```C++
|
||||
@@ -1417,9 +1413,7 @@ Consider the following example:
|
||||
std::cout << "negative: " << val.is_negative() << " ";
|
||||
std::cout << "is_integer: " << val.is_integer() << " ";
|
||||
ondemand::number num = val.get_number();
|
||||
// direct computation without materializing the number:
|
||||
ondemand::number_type dt = val.get_number_type();
|
||||
if(t != dt) { throw std::runtime_error("bug"); }
|
||||
ondemand::number_type t = num.get_number_type();
|
||||
switch(t) {
|
||||
case ondemand::number_type::signed_integer:
|
||||
std::cout << "integer: " << int64_t(num) << " ";
|
||||
|
||||
+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 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.
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
// Determine the best 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
|
||||
#elif SIMDJSON_CAN_ALWAYS_RUN_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")
|
||||
// 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 \
|
||||
SIMDJSON_DISABLE_GCC_WARNING(-Weffc++) \
|
||||
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(-Wunused-parameter) \
|
||||
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_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
|
||||
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
|
||||
|
||||
@@ -1067,6 +1067,11 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
|
||||
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
|
||||
if ( p == src ) { return NUMBER_ERROR; }
|
||||
if (jsoncharutils::is_structural_or_whitespace(*p)) {
|
||||
// We have an integer.
|
||||
// If the number is negative and valid, it must be a signed integer.
|
||||
if(negative) { return ondemand::number_type::signed_integer; }
|
||||
// We want values larger or equal to 9223372036854775808 to be unsigned
|
||||
// integers, and the other values to be signed integers.
|
||||
int digit_count = int(p - src);
|
||||
if(digit_count >= 19) {
|
||||
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
|
||||
@@ -1076,6 +1081,7 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
|
||||
}
|
||||
return ondemand::number_type::signed_integer;
|
||||
}
|
||||
// Hopefully, we have 'e' or 'E' or '.'.
|
||||
return ondemand::number_type::floating_point_number;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ inline simdjson_result<const char *> document::current_location() noexcept {
|
||||
return iter.current_location();
|
||||
}
|
||||
|
||||
inline int32_t document::current_depth() const noexcept {
|
||||
return iter.depth();
|
||||
}
|
||||
|
||||
inline bool document::is_alive() noexcept {
|
||||
return iter.is_alive();
|
||||
}
|
||||
@@ -471,6 +475,11 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_depth() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_depth();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::raw_json_token() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json_token();
|
||||
@@ -528,6 +537,7 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
|
||||
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
|
||||
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
||||
simdjson_really_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
|
||||
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
||||
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
|
||||
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
|
||||
|
||||
@@ -399,7 +399,14 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
/**
|
||||
* Determine the number type (integer or floating-point number).
|
||||
* Determine the number type (integer or floating-point number) as quickly
|
||||
* as possible. This function does not fully validate the input. It is
|
||||
* useful when you only need to classify the numbers, without parsing them.
|
||||
*
|
||||
* If you are planning to retrieve the value or you need full validation,
|
||||
* consider using the get_number() method instead: it will fully parse
|
||||
* and validate the input, and give you access to the type:
|
||||
* get_number().get_number_type().
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
@@ -407,8 +414,7 @@ public:
|
||||
* integer that is less than 9223372036854775808
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
*
|
||||
* This function req
|
||||
* uires processing the number string, but it is expected
|
||||
* This function requires processing the number string, but it is expected
|
||||
* to be faster than get_number().get_number_type() because it is does not
|
||||
* parse the number value.
|
||||
*
|
||||
@@ -489,6 +495,17 @@ public:
|
||||
*/
|
||||
inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current depth in the document if in bounds.
|
||||
*
|
||||
* E.g.,
|
||||
* 0 = finished with document
|
||||
* 1 = document root value (could be [ or {, not yet known)
|
||||
* 2 = , or } inside root array/object
|
||||
* 3 = key or value inside root array/object.
|
||||
*/
|
||||
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard.
|
||||
@@ -609,6 +626,7 @@ public:
|
||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||
simdjson_really_inline bool is_negative() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
@@ -675,6 +693,7 @@ public:
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||
simdjson_really_inline bool is_negative() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||
@@ -735,6 +754,7 @@ public:
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||
simdjson_really_inline bool is_negative() noexcept;
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
* 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
|
||||
* safe to derefence this pointer.
|
||||
* safe to dereference this pointer.
|
||||
*/
|
||||
simdjson_really_inline const uint8_t *unsafe_pointer() const noexcept;
|
||||
/**
|
||||
|
||||
@@ -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 start/end array or object I am skipping'\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("#\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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
@@ -181,6 +181,10 @@ simdjson_really_inline simdjson_result<const char *> value::current_location() n
|
||||
return iter.json_iter().current_location();
|
||||
}
|
||||
|
||||
simdjson_really_inline int32_t value::current_depth() const noexcept{
|
||||
return iter.json_iter().depth();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
@@ -400,6 +404,11 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_depth();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
|
||||
@@ -369,7 +369,14 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
|
||||
/**
|
||||
* Determine the number type (integer or floating-point number).
|
||||
* Determine the number type (integer or floating-point number) as quickly
|
||||
* as possible. This function does not fully validate the input. It is
|
||||
* useful when you only need to classify the numbers, without parsing them.
|
||||
*
|
||||
* If you are planning to retrieve the value or you need full validation,
|
||||
* consider using the get_number() method instead: it will fully parse
|
||||
* and validate the input, and give you access to the type:
|
||||
* get_number().get_number_type().
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
@@ -448,6 +455,17 @@ public:
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current depth in the document if in bounds.
|
||||
*
|
||||
* E.g.,
|
||||
* 0 = finished with document
|
||||
* 1 = document root value (could be [ or {, not yet known)
|
||||
* 2 = , or } inside root array/object
|
||||
* 3 = key or value inside root array/object.
|
||||
*/
|
||||
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard.
|
||||
@@ -479,7 +497,7 @@ public:
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
||||
@@ -650,7 +668,8 @@ public:
|
||||
|
||||
/** @copydoc simdjson_really_inline simdjson_result<const char *> current_location() noexcept */
|
||||
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
/** @copydoc simdjson_really_inline int32_t current_depth() const noexcept */
|
||||
simdjson_really_inline int32_t current_depth() const noexcept;
|
||||
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
/**
|
||||
* Get the depth of this value.
|
||||
*/
|
||||
simdjson_really_inline depth_t depth() const noexcept;
|
||||
simdjson_really_inline int32_t depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the JSON type of this value.
|
||||
|
||||
@@ -41,11 +41,7 @@
|
||||
// has it as a macro.
|
||||
#ifndef _blsr_u64
|
||||
// we roll our own
|
||||
SIMDJSON_TARGET_HASWELL
|
||||
static simdjson_really_inline uint64_t _blsr_u64(uint64_t n) {
|
||||
return (n - 1) & n;
|
||||
}
|
||||
SIMDJSON_UNTARGET_HASWELL
|
||||
#define _blsr_u64(n) ((n - 1) & n)
|
||||
#endif // _blsr_u64
|
||||
#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,31 @@
|
||||
#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;
|
||||
};
|
||||
|
||||
} // 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,339 @@
|
||||
#ifndef SIMDJSON_ICELAKE_SIMD_H
|
||||
#define SIMDJSON_ICELAKE_SIMD_H
|
||||
|
||||
#include "simdjson/internal/simdprune_tables.h"
|
||||
|
||||
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) {}
|
||||
|
||||
simdjson_really_inline uint64_t operator==(const simd8<T> other) const { return _mm512_cmpeq_epi8_mask(*this, other); }
|
||||
|
||||
static const int SIZE = sizeof(base<T>::value);
|
||||
|
||||
template<int N=1>
|
||||
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||
return _mm512_alignr_epi8(*this, _mm512_permutex2var_epi64(prev_chunk, _mm512_set_epi64(13, 12, 11, 10, 9, 8, 7, 6), *this), 16 - N);
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
@@ -13,10 +13,37 @@
|
||||
#endif
|
||||
#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
|
||||
|
||||
// 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
|
||||
// at runtime.
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_HASWELL
|
||||
#define SIMDJSON_IMPLEMENTATION_HASWELL (SIMDJSON_IS_X86_64)
|
||||
#define SIMDJSON_IMPLEMENTATION_HASWELL SIMDJSON_IS_X86_64
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
|
||||
@@ -26,7 +53,7 @@
|
||||
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
|
||||
#endif
|
||||
|
||||
// Default Westmere to on if this is x86-64, unless we'll always select Haswell.
|
||||
// Default Westmere to on if this is x86-64. Note that the macro SIMDJSON_REQUIRES_HASWELL appears unused.
|
||||
#ifndef SIMDJSON_IMPLEMENTATION_WESTMERE
|
||||
#define SIMDJSON_IMPLEMENTATION_WESTMERE (SIMDJSON_IS_X86_64 && !SIMDJSON_REQUIRES_HASWELL)
|
||||
#endif
|
||||
@@ -49,6 +76,7 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||
// Implementations
|
||||
#include "simdjson/arm64.h"
|
||||
#include "simdjson/fallback.h"
|
||||
#include "simdjson/icelake.h"
|
||||
#include "simdjson/haswell.h"
|
||||
#include "simdjson/ppc64.h"
|
||||
#include "simdjson/westmere.h"
|
||||
|
||||
@@ -66,7 +66,16 @@ enum instruction_set {
|
||||
PCLMULQDQ = 0x10,
|
||||
BMI1 = 0x20,
|
||||
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__)
|
||||
@@ -96,11 +105,20 @@ static inline uint32_t detect_supported_architectures() {
|
||||
|
||||
namespace {
|
||||
// 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_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_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
|
||||
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_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7
|
||||
constexpr uint32_t cpuid_avx512f_bit = 1 << 16; ///< @private bit 16 of EBX for EAX=0x7
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
eax = 0x1;
|
||||
cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION 1.0.2
|
||||
#define SIMDJSON_VERSION 2.0.0
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -19,7 +19,7 @@ enum {
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 2
|
||||
SIMDJSON_VERSION_REVISION = 0
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import subprocess
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import datetime
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
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)
|
||||
file = os.path.join(prepath, filename)
|
||||
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.
|
||||
print(f"/* begin file {RELFILE} */", file=fid)
|
||||
print(f"/* begin file {OSRELFILE} */", file=fid)
|
||||
includepattern = re.compile('^#include "(.*)"')
|
||||
redefines_simdjson_implementation = re.compile('^#define\s+SIMDJSON_IMPLEMENTATION\s+(.*)')
|
||||
undefines_simdjson_implementation = re.compile('^#undef\s+SIMDJSON_IMPLEMENTATION\s*$')
|
||||
@@ -113,7 +116,7 @@ def dofile(fid, prepath, filename):
|
||||
else:
|
||||
# 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(f"/* end file {RELFILE} */", file=fid)
|
||||
print(f"/* end file {OSRELFILE} */", file=fid)
|
||||
|
||||
|
||||
# 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.
|
||||
# Forcing it to be UTC is difficult, because it needs to be portable
|
||||
# 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()
|
||||
except:
|
||||
print("git not found, timestamp based on current time")
|
||||
timestamp = str(datetime.datetime.now())
|
||||
print(f"timestamp is {timestamp}")
|
||||
|
||||
os.makedirs(AMALGAMATE_OUTPUT_PATH, exist_ok=True)
|
||||
|
||||
+2358
-15
File diff suppressed because it is too large
Load Diff
+2516
-29
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,12 @@ public:
|
||||
// base_ptr[base] incrementing base as we go
|
||||
// will potentially store extra values beyond end of valid bits, so base_ptr
|
||||
// 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) {
|
||||
// In some instances, the next branch is expensive because it is mispredicted.
|
||||
// Unfortunately, in other cases,
|
||||
@@ -117,6 +123,8 @@ public:
|
||||
this->tail += cnt;
|
||||
#endif
|
||||
}
|
||||
#endif // SIMDJSON_CUSTOM_BIT_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) {
|
||||
// If the previous input's last 3 bytes match this, they're too short (they ended at EOF):
|
||||
// ... 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] = {
|
||||
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
|
||||
};
|
||||
#endif
|
||||
const simd8<uint8_t> max_value(&max_array[sizeof(max_array)-sizeof(simd8<uint8_t>)]);
|
||||
return input.gt_bits(max_value);
|
||||
}
|
||||
@@ -154,9 +167,13 @@ using namespace simd;
|
||||
this->error |= this->prev_incomplete;
|
||||
} else {
|
||||
// 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),
|
||||
"We support either two or four chunks per 64-byte block.");
|
||||
if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
|
||||
static_assert((simd8x64<uint8_t>::NUM_CHUNKS == 1)
|
||||
||(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[1], input.chunks[0]);
|
||||
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
#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/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 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"
|
||||
|
||||
@@ -14,6 +14,12 @@ namespace internal {
|
||||
// Static array of known implementations. We're hoping these get baked into the executable
|
||||
// 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
|
||||
static const haswell::implementation* get_haswell_singleton() {
|
||||
static const haswell::implementation haswell_singleton{};
|
||||
@@ -73,6 +79,9 @@ private:
|
||||
|
||||
static const std::initializer_list<const implementation *>& get_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
|
||||
get_haswell_singleton(),
|
||||
#endif
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -128,4 +128,4 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t thintable_epi8[256] = {
|
||||
} // namespace internal
|
||||
} // 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
|
||||
|
||||
@@ -19,6 +19,10 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
||||
#include "fallback/implementation.cpp"
|
||||
#include "fallback/dom_parser_implementation.cpp"
|
||||
#endif
|
||||
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
||||
#include "icelake/implementation.cpp"
|
||||
#include "icelake/dom_parser_implementation.cpp"
|
||||
#endif
|
||||
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
||||
#include "haswell/implementation.cpp"
|
||||
#include "haswell/dom_parser_implementation.cpp"
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace array_error_tests {
|
||||
size_t count = 0;
|
||||
for (auto elem : std::forward<T>(array)) {
|
||||
std::cout << "-"; std::cout.flush();
|
||||
V actual;
|
||||
V actual{};
|
||||
auto actual_error = elem.get(actual);
|
||||
if (count >= N) {
|
||||
if (count >= (N+N2)) {
|
||||
|
||||
@@ -10,7 +10,7 @@ using namespace simdjson;
|
||||
// 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) {
|
||||
// Verify the expected release behavior
|
||||
uint64_t x, y;
|
||||
uint64_t x{}, y{};
|
||||
if (!xval.get(x)) { return false; }
|
||||
if (!yval.get(y)) { return false; }
|
||||
std::cout << x << "," << y << std::endl;
|
||||
|
||||
@@ -197,16 +197,18 @@ namespace number_tests {
|
||||
bool get_number_tests() {
|
||||
TEST_START();
|
||||
ondemand::parser parser;
|
||||
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999])"_padded;
|
||||
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999,-9223372036854775807,-9223372036854775808])"_padded;
|
||||
ondemand::number_type expectedtypes[] = {ondemand::number_type::floating_point_number,
|
||||
ondemand::number_type::signed_integer,
|
||||
ondemand::number_type::signed_integer,
|
||||
ondemand::number_type::floating_point_number,
|
||||
ondemand::number_type::signed_integer,
|
||||
ondemand::number_type::unsigned_integer
|
||||
ondemand::number_type::unsigned_integer,
|
||||
ondemand::number_type::signed_integer,
|
||||
ondemand::number_type::signed_integer
|
||||
};
|
||||
bool is_negative[] = {false, false, false, false, true, false};
|
||||
bool is_integer[] = {false, true, true, false, true, true};
|
||||
bool is_negative[] = {false, false, false, false, true, false, true, true};
|
||||
bool is_integer[] = {false, true, true, false, true, true, true, true};
|
||||
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
|
||||
@@ -109,6 +109,85 @@ bool basics_treewalk() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_depth_space(ondemand::value element) {
|
||||
for(auto i = 0; i < element.current_depth(); i++) {
|
||||
cout << " ";
|
||||
}
|
||||
}
|
||||
|
||||
void recursive_print_json_breakline(ondemand::value element) {
|
||||
bool add_comma;
|
||||
switch (element.type()) {
|
||||
case ondemand::json_type::array:
|
||||
cout << endl;
|
||||
print_depth_space(element);
|
||||
cout << "[";
|
||||
add_comma = false;
|
||||
for (auto child : element.get_array()) {
|
||||
if (add_comma) {
|
||||
print_depth_space(element);
|
||||
cout << ",";
|
||||
}
|
||||
// We need the call to value() to get
|
||||
// an ondemand::value type.
|
||||
recursive_print_json_breakline(child.value());
|
||||
add_comma = true;
|
||||
}
|
||||
cout << "]";
|
||||
break;
|
||||
case ondemand::json_type::object:
|
||||
cout << endl;
|
||||
print_depth_space(element);
|
||||
cout << "{";
|
||||
add_comma = false;
|
||||
for (auto field : element.get_object()) {
|
||||
if (add_comma) {
|
||||
print_depth_space(element);
|
||||
cout << ",";
|
||||
}
|
||||
// key() returns the key as it appears in the raw
|
||||
// JSON document, if we want the unescaped key,
|
||||
// we should do field.unescaped_key().
|
||||
cout << "\"" << field.key() << "\": ";
|
||||
recursive_print_json_breakline(field.value());
|
||||
add_comma = true;
|
||||
}
|
||||
cout << "}\n";
|
||||
break;
|
||||
case ondemand::json_type::number:
|
||||
// assume it fits in a double
|
||||
cout << element.get_double();
|
||||
break;
|
||||
case ondemand::json_type::string:
|
||||
// get_string() would return escaped string, but
|
||||
// we are happy with unescaped string.
|
||||
cout << "\"" << element.get_raw_json_string() << "\"";
|
||||
break;
|
||||
case ondemand::json_type::boolean:
|
||||
cout << element.get_bool();
|
||||
break;
|
||||
case ondemand::json_type::null:
|
||||
cout << "null";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool basics_treewalk_breakline() {
|
||||
padded_string json[3] = {R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded, R"( {"key":"value"} )"_padded, "[12,3]"_padded};
|
||||
ondemand::parser parser;
|
||||
for(size_t i = 0 ; i < 3; i++) {
|
||||
ondemand::document doc = parser.iterate(json[i]);
|
||||
ondemand::value val = doc;
|
||||
recursive_print_json_breakline(val);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basics_1() {
|
||||
TEST_START();
|
||||
|
||||
@@ -673,7 +752,7 @@ bool stream_capacity_example() {
|
||||
if( error ) { /* handle the error */ }
|
||||
for (auto doc: stream) {
|
||||
if(counter < 6) {
|
||||
int64_t val;
|
||||
int64_t val{};
|
||||
error = doc.at_pointer("/4").get(val);
|
||||
if( error ) { /* handle the error */ }
|
||||
std::cout << "5 = " << val << std::endl;
|
||||
@@ -882,6 +961,7 @@ bool current_location_no_error() {
|
||||
int main() {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
basics_treewalk();
|
||||
basics_treewalk_breakline();
|
||||
#endif
|
||||
if (
|
||||
true
|
||||
|
||||
+30
-1
@@ -1,3 +1,4 @@
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#if (!(_MSC_VER) && !(__MINGW32__) && !(__MINGW64__))
|
||||
#include <dirent.h>
|
||||
@@ -38,6 +39,7 @@ int main(int argc, const char *argv[]) {
|
||||
}
|
||||
options.add_options()
|
||||
("a,arch", ss.str(), cxxopts::value<std::string>())
|
||||
("t,timing", "Report only timing.")
|
||||
("f,file", "File name.", cxxopts::value<std::string>())
|
||||
("h,help", "Print usage.")
|
||||
;
|
||||
@@ -79,7 +81,34 @@ int main(int argc, const char *argv[]) {
|
||||
size_t copy_len;
|
||||
error = simdjson::get_active_implementation()->minify((const uint8_t*)p.data(), p.length(), (uint8_t*)copy.data(), copy_len);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
printf("%s", copy.data());
|
||||
/**
|
||||
* If a user only wants to time the required time, we do not output
|
||||
* the result and we simply do the processing in a tight loop.
|
||||
* At this point in time, we can assume that the processing will
|
||||
* succeed.
|
||||
*/
|
||||
if(result.count("timing")) {
|
||||
uint64_t beforens = std::chrono::duration_cast<::std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count();
|
||||
error = simdjson::get_active_implementation()->minify((const uint8_t*)p.data(), p.length(), (uint8_t*)copy.data(), copy_len);
|
||||
uint64_t afterns = std::chrono::duration_cast<::std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count();
|
||||
size_t times = 1;
|
||||
while(afterns - beforens < 1000000000) {
|
||||
error = simdjson::get_active_implementation()->minify((const uint8_t*)p.data(), p.length(), (uint8_t*)copy.data(), copy_len);
|
||||
afterns = std::chrono::duration_cast<::std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count();
|
||||
times += 1;
|
||||
}
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
printf("%.3f GB/s\n", double(p.length() * times) / double(afterns - beforens));
|
||||
} else {
|
||||
// This is the expected path:
|
||||
printf("%s", copy.data());
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
#ifdef __cpp_exceptions
|
||||
} catch (const cxxopts::OptionException& e) {
|
||||
|
||||
Reference in New Issue
Block a user