mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8149284602 | |||
| 0e28a8312d | |||
| 04ab4bb4d9 | |||
| 3960880a0d | |||
| e0f906da79 | |||
| 6a054395a6 | |||
| eac04c7324 | |||
| 319b10acad | |||
| d2d15255bc | |||
| 5b7acd2aa7 | |||
| 61ef447595 | |||
| b524e29576 | |||
| a7b7bc2b69 | |||
| 76dd137c87 | |||
| 52b2414281 | |||
| 5d762fb67f | |||
| 9dc70e8d9c | |||
| 589ef23b56 | |||
| 4b1148384e | |||
| 32afd34a90 | |||
| 70674d2dbd | |||
| f594a49a4b | |||
| 54cbebfd29 | |||
| c6e43a631c | |||
| a8635c9b89 | |||
| 075bfb173b | |||
| a88ad515c2 | |||
| 78b4c0aa6e |
@@ -31,7 +31,7 @@ A clear and concise description of any alternative solutions or features you've
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
**Are you willing to contribute code or documentation toward this new feature?**
|
||||
** Are you willing to contribute code or documentation toward this new feature? **
|
||||
If you plan to contribute to simdjson, please read our
|
||||
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
|
||||
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
image: debian:testing
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Doxygen
|
||||
run: sudo apt-get install doxygen graphviz -y
|
||||
- run: mkdir docs
|
||||
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
whitespace:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Remove whitespace and check the diff
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh $CLANGVERSION
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
@@ -31,14 +31,3 @@ jobs:
|
||||
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 .
|
||||
- name: Use cmake (shared)
|
||||
run: |
|
||||
mkdir buildshared &&
|
||||
cd buildshared &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure -LE explicitonly -j &&
|
||||
cmake --install . &&
|
||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||
cd ../tests/installation_tests/find &&
|
||||
mkdir buildshared && cd buildshared && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildshared/destination .. && cmake --build .
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Build on ubuntu-20.04 ppc64le
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
name: Run commands
|
||||
id: runcmd
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Ubuntu riscv64 (GCC 11)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
arch: riscv64
|
||||
distro: ubuntu_latest
|
||||
githubToken: ${{ github.token }}
|
||||
install: |
|
||||
apt-get update -q -y
|
||||
apt-get install -y cmake make g++
|
||||
run: |
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -B build
|
||||
cmake --build build -j=2
|
||||
ctest --output-on-failure --test-dir build
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test
|
||||
id: runcmd
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
CXX: g++-8
|
||||
CC: gcc-8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
@@ -27,11 +27,12 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
- name: Use cmake with undefined sanitizer
|
||||
run: |
|
||||
mkdir builddebugundefsani &&
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,11 +9,13 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Install gcc12
|
||||
run: sudo apt-get install -y g++-12
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Ubuntu 22.04 CI (GCC 13)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
CXX=g++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
|
||||
cmake --build . &&
|
||||
ctest --output-on-failure -LE explicitonly -j
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
- {arch: ARM64}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Use cmake
|
||||
run: |
|
||||
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- 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
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- {gen: Visual Studio 17 2022, arch: x64}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
|
||||
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
name: windows-vs17
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
|
||||
+5
-32
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.6.4
|
||||
VERSION 3.2.3
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,10 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "19.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "19" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
|
||||
set(SIMDJSON_LIB_VERSION "16.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "16" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
@@ -58,17 +56,8 @@ include(cmake/developer-options.cmake)
|
||||
|
||||
# ---- simdjson library ----
|
||||
|
||||
set(SIMDJSON_SOURCES src/simdjson.cpp)
|
||||
|
||||
add_library(simdjson ${SIMDJSON_SOURCES})
|
||||
add_library(simdjson src/simdjson.cpp)
|
||||
add_library(simdjson::simdjson ALIAS simdjson)
|
||||
set(SIMDJSON_LIBRARIES simdjson)
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
add_library(simdjson_static STATIC ${SIMDJSON_SOURCES})
|
||||
add_library(simdjson::simdjson_static ALIAS simdjson_static)
|
||||
list(APPEND SIMDJSON_LIBRARIES simdjson_static)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
simdjson PROPERTIES
|
||||
@@ -128,9 +117,6 @@ if(SIMDJSON_ENABLE_THREADS)
|
||||
endif()
|
||||
|
||||
simdjson_apply_props(simdjson)
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
simdjson_apply_props(simdjson_static)
|
||||
endif()
|
||||
|
||||
# ---- Install rules ----
|
||||
|
||||
@@ -152,6 +138,7 @@ install(
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
|
||||
|
||||
write_basic_package_version_file(
|
||||
@@ -180,20 +167,6 @@ install(
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
|
||||
if(SIMDJSON_BUILD_STATIC_LIB)
|
||||
install(
|
||||
TARGETS simdjson_static
|
||||
EXPORT simdjson_staticTargets
|
||||
ARCHIVE COMPONENT simdjson_Development
|
||||
)
|
||||
install(
|
||||
EXPORT simdjson_staticTargets
|
||||
NAMESPACE simdjson::
|
||||
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
|
||||
COMPONENT simdjson_Development
|
||||
)
|
||||
endif()
|
||||
|
||||
# pkg-config
|
||||
include(cmake/JoinPaths.cmake)
|
||||
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
@@ -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 = "3.6.4"
|
||||
PROJECT_NUMBER = "3.2.3"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
[/badge.svg)](https://simdjson.org/plots.html)
|
||||

|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
|
||||

|
||||
[![][license img]][license]
|
||||
|
||||
[](https://simdjson.github.io/simdjson/)
|
||||
@@ -29,7 +31,6 @@ Table of Contents
|
||||
* [Real-world usage](#real-world-usage)
|
||||
* [Quick Start](#quick-start)
|
||||
* [Documentation](#documentation)
|
||||
* [Godbolt](#godbolt)
|
||||
* [Performance results](#performance-results)
|
||||
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
|
||||
* [About simdjson](#about-simdjson)
|
||||
@@ -41,10 +42,8 @@ Table of Contents
|
||||
Real-world usage
|
||||
----------------
|
||||
|
||||
- [Node.js](https://nodejs.org/)
|
||||
- [ClickHouse](https://github.com/ClickHouse/ClickHouse)
|
||||
- [Meta Velox](https://velox-lib.io)
|
||||
- [Google Pax](https://github.com/google/paxml)
|
||||
- [Facebook/Meta Velox](https://velox-lib.io)
|
||||
- [milvus](https://github.com/milvus-io/milvus)
|
||||
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
|
||||
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
|
||||
@@ -69,9 +68,9 @@ The simdjson library is easily consumable with a single .h and .cpp file.
|
||||
|
||||
0. Prerequisites: `g++` (version 7 or better) or `clang++` (version 6 or better), and a 64-bit
|
||||
system with a command-line shell (e.g., Linux, macOS, freeBSD). We also support programming
|
||||
environments like Visual Studio and Xcode, but different steps are needed. Users of clang++ may need to specify the C++ version (e.g., `c++ -std=c++17`) since clang++ tends to default on C++98.
|
||||
environments like Visual Studio and Xcode, but different steps are needed.
|
||||
1. Pull [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp) into a
|
||||
directory, along with the sample file [twitter.json](jsonexamples/twitter.json). You can download them with the `wget` utility:
|
||||
directory, along with the sample file [twitter.json](jsonexamples/twitter.json).
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.h https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.cpp https://raw.githubusercontent.com/simdjson/simdjson/master/jsonexamples/twitter.json
|
||||
@@ -96,7 +95,6 @@ int main(void) {
|
||||
100 results.
|
||||
```
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
@@ -108,12 +106,11 @@ Usage documentation is available:
|
||||
how you can work with it.
|
||||
* [API](https://simdjson.github.io/simdjson/) contains the automatically generated API documentation.
|
||||
|
||||
Godbolt
|
||||
-------------
|
||||
|
||||
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
|
||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
|
||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
|
||||
|
||||
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn)
|
||||
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
|
||||
|
||||
Performance results
|
||||
-------------------
|
||||
@@ -168,7 +165,6 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
||||
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim json parser based on simdjson bindings.
|
||||
|
||||
About simdjson
|
||||
--------------
|
||||
@@ -177,11 +173,7 @@ The simdjson library takes advantage of modern microarchitectures, parallelizing
|
||||
instructions, reducing branch misprediction, and reducing data dependency to take advantage of each
|
||||
CPU's multiple execution cores.
|
||||
|
||||
Our default front-end is called On Demand, and we wrote a paper about it:
|
||||
|
||||
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
|
||||
|
||||
Some people [enjoy reading the first (2019) simdjson paper](https://arxiv.org/abs/1902.08318): A description of the design
|
||||
Some people [enjoy reading our paper](https://arxiv.org/abs/1902.08318): A description of the design
|
||||
and implementation of simdjson is in our research article:
|
||||
- Geoff Langdale, Daniel Lemire, [Parsing Gigabytes of JSON per Second](https://arxiv.org/abs/1902.08318), VLDB Journal 28 (6), 2019.
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ if (TARGET benchmark::benchmark)
|
||||
if(TARGET nlohmann_json)
|
||||
target_link_libraries(bench_ondemand PRIVATE nlohmann_json)
|
||||
endif()
|
||||
if(TARGET boostjson)
|
||||
target_link_libraries(bench_ondemand PRIVATE boostjson)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -21,10 +21,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
#include <nlohmann/json.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
#include <boost/json.hpp>
|
||||
#endif
|
||||
|
||||
// This has to be last, for reasons I don't yet understand
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
@@ -37,7 +33,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "json2msgpack/sajson.h"
|
||||
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
#include "json2msgpack/nlohmann_json.h"
|
||||
#include "json2msgpack/boostjson.h"
|
||||
|
||||
#include "partial_tweets/simdjson_ondemand.h"
|
||||
#include "partial_tweets/simdjson_dom.h"
|
||||
@@ -53,7 +48,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "partial_tweets/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "partial_tweets/boostjson.h"
|
||||
|
||||
|
||||
#include "distinct_user_id/simdjson_ondemand.h"
|
||||
@@ -72,7 +66,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "distinct_user_id/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "distinct_user_id/boostjson.h"
|
||||
|
||||
#include "find_tweet/simdjson_ondemand.h"
|
||||
#include "find_tweet/simdjson_dom.h"
|
||||
@@ -88,7 +81,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "find_tweet/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "find_tweet/boostjson.h"
|
||||
|
||||
#include "top_tweet/simdjson_ondemand.h"
|
||||
#include "top_tweet/simdjson_dom.h"
|
||||
@@ -104,7 +96,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "top_tweet/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "top_tweet/boostjson.h"
|
||||
|
||||
|
||||
#include "kostya/simdjson_ondemand.h"
|
||||
@@ -121,7 +112,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "kostya/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "kostya/boostjson.h"
|
||||
|
||||
#include "large_random/simdjson_ondemand.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||
@@ -140,7 +130,6 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_SAX
|
||||
#include "large_random/nlohmann_json_sax.h"
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
#include "large_random/boostjson.h"
|
||||
|
||||
#include "amazon_cellphones/simdjson_dom.h"
|
||||
#include "amazon_cellphones/simdjson_ondemand.h"
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
struct boostjson {
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
result.push_back(tweet.at("user").at("id").to_number<uint64_t>());
|
||||
|
||||
if (tweet.as_object().if_contains("retweeted_status")) {
|
||||
result.push_back(tweet.at("retweeted_status").at("user").at("id").to_number<uint64_t>());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "find_tweet.h"
|
||||
|
||||
namespace find_tweet {
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) {
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
if (tweet.at("id") == find_id) {
|
||||
result = tweet.at("text").as_string();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(find_tweet, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace find_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
struct boostjson2msgpack {
|
||||
inline std::string_view to_msgpack(const boost::json::value &root, uint8_t *buf) {
|
||||
buff = buf;
|
||||
recursive_processor(root);
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t *buff{};
|
||||
|
||||
inline void write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
inline void write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
inline void write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
inline void write_string(const std::string & str) {
|
||||
write_byte(0xdb);
|
||||
write_uint32(uint32_t(str.size()));
|
||||
::memcpy(buff, str.data(), str.size());
|
||||
buff += str.size();
|
||||
}
|
||||
|
||||
inline void recursive_processor(const boost::json::value &element) {
|
||||
switch(element.kind()) {
|
||||
case boost::json::kind::array: {
|
||||
write_byte(0xdd);
|
||||
const auto &array = element.as_array();
|
||||
write_uint32(static_cast<uint32_t>(array.size()));
|
||||
for (const auto &child : array) {
|
||||
recursive_processor(child);
|
||||
}
|
||||
} break;
|
||||
|
||||
case boost::json::kind::object: {
|
||||
write_byte(0xdf);
|
||||
const auto &object = element.as_object();
|
||||
write_uint32(static_cast<uint32_t>(object.size()));
|
||||
for (const auto &child : object) {
|
||||
write_string(child.key_c_str());
|
||||
recursive_processor(child.value());
|
||||
}
|
||||
} break;
|
||||
|
||||
case boost::json::kind::int64:
|
||||
case boost::json::kind::uint64:
|
||||
case boost::json::kind::double_:
|
||||
write_double(element.to_number<double>());
|
||||
break;
|
||||
|
||||
case boost::json::kind::string:
|
||||
write_string(element.as_string().c_str());
|
||||
break;
|
||||
|
||||
case boost::json::kind::bool_:
|
||||
write_byte(0xc2 + element.as_bool());
|
||||
break;
|
||||
|
||||
case boost::json::kind::null:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unexpected\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
boostjson2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer, std::string_view &result) {
|
||||
auto root = boost::json::parse(json);
|
||||
result = parser.to_msgpack(root, reinterpret_cast<uint8_t *>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "kostya.h"
|
||||
|
||||
namespace kostya {
|
||||
|
||||
struct boostjson {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &point : root.at("coordinates").as_array()) {
|
||||
result.emplace_back(json_benchmark::point{
|
||||
point.at("x").to_number<double>(),
|
||||
point.at("y").to_number<double>(),
|
||||
point.at("z").to_number<double>()
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(kostya, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace kostya
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
struct boostjson {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &point : root.as_array()) {
|
||||
result.emplace_back(json_benchmark::point{
|
||||
point.at("x").to_number<double>(),
|
||||
point.at("y").to_number<double>(),
|
||||
point.at("z").to_number<double>()
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_random, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<StringType>> &result) {
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
const auto &user = tweet.at("user");
|
||||
|
||||
auto in_reply_to_status_id = tweet.as_object().if_contains("in_reply_to_status_id")
|
||||
? tweet.at("in_reply_to_status_id") : boost::json::value();
|
||||
|
||||
result.emplace_back(partial_tweets::tweet<StringType>{
|
||||
tweet.at("created_at").as_string().c_str(),
|
||||
tweet.at("id").to_number<uint64_t>(),
|
||||
tweet.at("text").as_string().c_str(),
|
||||
in_reply_to_status_id.is_null() ? 0 : in_reply_to_status_id.to_number<uint64_t>(),
|
||||
{
|
||||
user.at("id").to_number<uint64_t>(),
|
||||
user.at("screen_name").as_string().c_str()
|
||||
},
|
||||
tweet.at("retweet_count").to_number<uint64_t>(),
|
||||
tweet.at("favorite_count").to_number<uint64_t>()
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(partial_tweets, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_COMPETITION_BOOSTJSON
|
||||
|
||||
#include "top_tweet.h"
|
||||
|
||||
namespace top_tweet {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct boostjson {
|
||||
using StringType=std::string;
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
boost::json::value top_tweet{};
|
||||
|
||||
auto root = boost::json::parse(json);
|
||||
for (const auto &tweet : root.at("statuses").as_array()) {
|
||||
int64_t retweet_count = tweet.at("retweet_count").as_int64();
|
||||
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
|
||||
result.retweet_count = retweet_count;
|
||||
top_tweet = tweet;
|
||||
}
|
||||
}
|
||||
|
||||
result.text = top_tweet.at("text").as_string();
|
||||
result.screen_name = top_tweet.at("user").at("screen_name").as_string();
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(top_tweet, boostjson)->UseManualTime();
|
||||
|
||||
} // namespace top_tweet
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_BOOSTJSON
|
||||
@@ -114,6 +114,7 @@ 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)
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD ON)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
set(SIMDJSON_STRUCTURAL_INDEXER_STEP CACHE STRING "the SIMDJSON_STRUCTURAL_INDEXER_STEP variable")
|
||||
|
||||
@@ -4,4 +4,3 @@ if("@SIMDJSON_ENABLE_THREADS@")
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/simdjsonTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/simdjson_staticTargets.cmake" OPTIONAL)
|
||||
|
||||
+48
-212
@@ -30,13 +30,11 @@ An overview of what you need to know to use simdjson, with examples.
|
||||
- [Dynamic Number Types](#dynamic-number-types)
|
||||
- [Raw Strings](#raw-strings)
|
||||
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
|
||||
- [Storing Directly into an Existing String Instance](#storing-directly-into-an-existing-string-instance)
|
||||
- [Thread Safety](#thread-safety)
|
||||
- [Standard Compliance](#standard-compliance)
|
||||
- [Backwards Compatibility](#backwards-compatibility)
|
||||
- [Examples](#examples)
|
||||
- [Performance Tips](#performance-tips)
|
||||
- [Further Reading](#further-reading)
|
||||
|
||||
|
||||
Requirements
|
||||
@@ -87,7 +85,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
simdjson
|
||||
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
|
||||
GIT_TAG tags/v3.6.0
|
||||
GIT_TAG tags/v0.9.6
|
||||
GIT_SHALLOW TRUE)
|
||||
|
||||
FetchContent_MakeAvailable(simdjson)
|
||||
@@ -181,8 +179,8 @@ strcpy(json, "[1]");
|
||||
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
|
||||
```
|
||||
|
||||
The simdjson library will also accept `std::string` instances. If the provided
|
||||
reference is non-const, it will allocate padding as needed.
|
||||
The simdjson library will also accept `std::string` instances, as long as the `capacity()` of
|
||||
the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings.
|
||||
|
||||
You can copy your data directly on a `simdjson::padded_string` as follows:
|
||||
|
||||
@@ -220,8 +218,7 @@ This means that while you iterate an array, or search for a field in an object,
|
||||
walking through the original JSON text, merrily reading commas and colons and brackets to make sure
|
||||
you get where you are going. This is the key to On Demand's performance: since it's just an iterator,
|
||||
it lets you parse values as you use them. And particularly, it lets you *skip* values you do not want
|
||||
to use. On Demand is also ideally suited when you want to capture part of the document without parsing it
|
||||
immediately (e.g., see [Raw Strings](#raw-strings)).
|
||||
to use.
|
||||
|
||||
We refer to "On Demand" as a front-end component since it is an interface between the
|
||||
low-level parsing functions and the user. It hides much of the complexity of parsing JSON
|
||||
@@ -256,8 +253,7 @@ copy the data into their own favorite class instances (e.g., alternatives to `st
|
||||
|
||||
A `std::string_view` instance is effectively just a pointer to a region in memory representing
|
||||
a string. In simdjson, we return `std::string_view` instances that either point within the
|
||||
input string you parsed (when using [raw Strings](#raw-strings)), or to a temporary string buffer inside
|
||||
our parser class instances that is valid until the parser object is destroyed or you use it to parse another document.
|
||||
input string you parsed, or to a temporary string buffer inside our parser class instances.
|
||||
When using `std::string_view` instances, it is your responsibility to ensure that
|
||||
`std::string_view` instance does not outlive the pointed-to memory (e.g., either the input
|
||||
buffer or the parser instance). Furthermore, some operations reset the string buffer
|
||||
@@ -265,7 +261,6 @@ inside our parser instances: e.g., when we parse a new document. Thus a `std::st
|
||||
is often best viewed as a temporary string value that is tied to the document you are parsing.
|
||||
At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances:
|
||||
`std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17).
|
||||
For convenience, we also allow [storing an escaped string directly into an existing string instance](#storing-directly-into-an-existing-string-instance).
|
||||
|
||||
The `std::string_view` class has become standard as part of C++17 but it is not always available
|
||||
on compilers which only supports C++11. When we detect that `string_view` is natively
|
||||
@@ -360,7 +355,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
|
||||
scan through the object looking for the field with the matching string, doing a character-by-character
|
||||
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error Handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
|
||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
|
||||
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if(!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
|
||||
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code
|
||||
is in error. Furthermore, you can only consume one field at a time, on the same object. The
|
||||
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
|
||||
@@ -375,11 +370,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> as a key, it will not be recognized. This is not generally a problem. Nevertheless, if you do need
|
||||
> to support escaped keys, the method `unescaped_key()` provides the desired unescaped keys by
|
||||
> parsing and writing out the unescaped keys to a string buffer and returning a `std::string_view`
|
||||
> instance. The `unescaped_key` takes an optional Boolean value: passing it true will decode invalid
|
||||
> Unicode sequences with replacement, meaning that the decoding always succeeds but bogus Unicode
|
||||
> replacement characters are inserted. In general, you should expect a performance penalty
|
||||
> when using `unescaped_key()` compared to `key()` because of the string processing: the `key()`
|
||||
> function just points inside the source JSON document.
|
||||
> instance. You should expect a performance penalty when using `unescaped_key()`.
|
||||
>
|
||||
> ```c++
|
||||
> auto json = R"({"k\u0065y": 1})"_padded;
|
||||
@@ -390,7 +381,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> // parses and writes out the key, after unescaping it,
|
||||
> // to a string buffer. It causes a performance penalty.
|
||||
> std::string_view keyv = field.unescaped_key();
|
||||
> if (keyv == "key") { std::cout << uint64_t(field.value()); }
|
||||
> if(keyv == "key") { std::cout << uint64_t(field.value()); }
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
@@ -423,10 +414,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
step through each value in the JSON array.
|
||||
|
||||
If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`.
|
||||
|
||||
You may also use explicit iterators: `for(auto i = array.begin(); i != array.end(); i++) {}`. You can check that an array is empty with the condition `auto i = array.begin(); if(i == array.end()) {...}`.
|
||||
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`. You may also use explicit iterators : `for(auto i = object.begin(); i != object.end(); i++) { auto field = *i; .... }`. You can check that an object is empty with the condition `auto i = object.begin(); if(i == object.end()) {...}`.
|
||||
- `field.unescaped_key()` will get you the unescaped key string. E.g., the JSON string `"\u00e1"` becomes the Unicode string `á`. Optionally, you pass `true` as a parameter to the `unescaped_key` method if you want invalid escape sequences to be replaced by a default replacement character (e.g., `\ud800\ud801\ud811`): otherwise bad escape sequences lead to an immediate error.
|
||||
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`
|
||||
- `field.unescaped_key()` will get you the unescaped key string.
|
||||
- `field.value()` will get you the value, which you can then use all these other methods on.
|
||||
* **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead,
|
||||
you should iterate through the array and keep an index yourself.
|
||||
@@ -456,7 +445,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> {
|
||||
> ondemand::parser parser;
|
||||
> for (ondemand::object car : parser.iterate(cars_json)) {
|
||||
> if (uint64_t(car["year"]) > 2000) {
|
||||
> if(uint64_t(car["year"]) > 2000) {
|
||||
> arrays.push_back(simdjson::to_json_string(car["tire_pressure"]));
|
||||
> }
|
||||
> }
|
||||
@@ -465,7 +454,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
> std::ostringstream oss;
|
||||
> oss << "[";
|
||||
> for(size_t i = 0; i < arrays.size(); i++) {
|
||||
> if (i>0) { oss << ","; }
|
||||
> if(i>0) { oss << ","; }
|
||||
> oss << arrays[i];
|
||||
> }
|
||||
> oss << "]";
|
||||
@@ -546,7 +535,9 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
|
||||
with a known type, and are trying to generically inspect or walk over JSON elements.
|
||||
You can also represent arbitrary JSON values with
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You can cast a document that is either an array or an object to an `ondemand::value` instance immediately after you create the document instance: you cannot create a `ondemand::value` instance from a document that has already been accessed as it would mean that you would have two instances of the object or array simultaneously (see [rewinding](#rewinding)). You can query the type of a document or a value with the `type()` method. The `type()` method does not consume or validate documents and values, but it tells you whether they are
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
|
||||
You can query the type of a document or a value with the `type()` method.
|
||||
The `type()` method does not consume or validate documents and values, but it tells you whether they are
|
||||
- arrays (`json_type::array`),
|
||||
- objects (`json_type::object`)
|
||||
- numbers (`json_type::number`),
|
||||
@@ -606,7 +597,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
case ondemand::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if (element.is_null()) {
|
||||
if(element.is_null()) {
|
||||
cout << "null";
|
||||
}
|
||||
break;
|
||||
@@ -919,11 +910,11 @@ bool simple_error_example() {
|
||||
ondemand::parser parser;
|
||||
auto json = R"({"bad number":3.14.1 })"_padded;
|
||||
ondemand::document doc;
|
||||
if (parser.iterate(json).get(doc) != SUCCESS) { return false; }
|
||||
if( parser.iterate(json).get(doc) != SUCCESS ) { return false; }
|
||||
double x;
|
||||
auto error = doc["bad number"].get_double().get(x);
|
||||
// returns "simdjson::NUMBER_ERROR"
|
||||
if (error != SUCCESS) {
|
||||
if(error != SUCCESS) {
|
||||
std::cout << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
@@ -985,10 +976,10 @@ it selects the key `"count"` within that object.
|
||||
int main(void) {
|
||||
simdjson::ondemand::parser parser;
|
||||
auto error = padded_string::load("twitter.json").get(json);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
simdjson::ondemand::document tweets;
|
||||
error = parser.iterate(json).get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if( error ) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
simdjson::ondemand::value res;
|
||||
error = tweets["search_metadata"]["count"].get(res);
|
||||
if (error != SUCCESS) {
|
||||
@@ -1019,12 +1010,12 @@ int main(void) {
|
||||
simdjson::ondemand::document tweets;
|
||||
padded_string json;
|
||||
auto error = padded_string::load("twitter.json").get(json);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
error = parser.iterate(json).get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
uint64_t identifier;
|
||||
error = tweets["statuses"].at(0)["id"].get(identifier);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
std::cout << identifier << std::endl;
|
||||
}
|
||||
```
|
||||
@@ -1048,40 +1039,40 @@ bool parse() {
|
||||
|
||||
// Iterating through an array of objects
|
||||
auto error = parser.iterate(cars_json).get(doc);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
ondemand::array cars; // invalid until the get() succeeds
|
||||
error = doc.get_array().get(cars);
|
||||
|
||||
for (auto car_value : cars) {
|
||||
ondemand::object car; // invalid until the get() succeeds
|
||||
error = car_value.get_object().get(car);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
|
||||
// Accessing a field by name
|
||||
std::string_view make;
|
||||
std::string_view model;
|
||||
error = car["make"].get(make);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
error = car["model"].get(model);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
|
||||
cout << "Make/Model: " << make << "/" << model << endl;
|
||||
|
||||
// Casting a JSON element to an integer
|
||||
uint64_t year{};
|
||||
error = car["year"].get(year);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
cout << "- This car is " << 2020 - year << " years old." << endl;
|
||||
|
||||
// Iterating through an array of floats
|
||||
double total_tire_pressure = 0;
|
||||
ondemand::array pressures;
|
||||
error = car["tire_pressure"].get_array().get(pressures);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
for (auto tire_pressure_value : pressures) {
|
||||
double tire_pressure;
|
||||
error = tire_pressure_value.get_double().get(tire_pressure);
|
||||
if (error) { std::cerr << error << std::endl; return false; }
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
total_tire_pressure += tire_pressure;
|
||||
}
|
||||
cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
|
||||
@@ -1097,7 +1088,7 @@ after you have initialized them and checked that there is no error:
|
||||
ondemand::object car; // invalid until the get() succeeds
|
||||
// the `car` instance should not use used before it is initialized
|
||||
error = car_value.get_object().get(car);
|
||||
if (error) {
|
||||
if(error) {
|
||||
// the `car` instance should not use used
|
||||
} else {
|
||||
// the `car` instance can be safely used
|
||||
@@ -1111,20 +1102,20 @@ having to handle exceptions.
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
auto error = parser.iterate(json).get(doc);
|
||||
if (error) { return false; }
|
||||
if(error) { return false; }
|
||||
ondemand::object object; // invalid until the get() succeeds
|
||||
error = doc.get_object().get(object);
|
||||
if (error) { return false; }
|
||||
if(error) { return false; }
|
||||
for(auto field : object) {
|
||||
// We could replace 'field.key() with field.unescaped_key(),
|
||||
// and ondemand::raw_json_string by std::string_view.
|
||||
ondemand::raw_json_string keyv;
|
||||
error = field.key().get(keyv);
|
||||
if (error) { return false; }
|
||||
if (keyv == "key") {
|
||||
if(error) { return false; }
|
||||
if(keyv == "key") {
|
||||
uint64_t intvalue;
|
||||
error = field.value().get(intvalue);
|
||||
if (error) { return false; }
|
||||
if(error) { return false; }
|
||||
std::cout << intvalue;
|
||||
}
|
||||
}
|
||||
@@ -1303,7 +1294,7 @@ content.
|
||||
for (uint64_t values : array) {
|
||||
std::cout << values << std::endl;
|
||||
}
|
||||
if (!doc.at_end()) {
|
||||
if(!doc.at_end()) {
|
||||
// In this instance, we will be left pointing at 'foo' since we have consumed the array [1,2].
|
||||
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||
}
|
||||
@@ -1333,7 +1324,7 @@ before printout the data.
|
||||
|
||||
auto doc = parser.iterate(cars_json);
|
||||
for (simdjson_unused ondemand::object car : doc) {
|
||||
if (car["make"] == "Toyota") { count++; }
|
||||
if(car["make"] == "Toyota") { count++; }
|
||||
}
|
||||
std::cout << "We have " << count << " Toyota cars.\n";
|
||||
doc.rewind(); // requires simdjson 1.0 or better
|
||||
@@ -1401,18 +1392,18 @@ ondemand::parser parser;
|
||||
ondemand::document_stream stream;
|
||||
size_t counter{0};
|
||||
auto error = parser.iterate_many(json, 50).get(stream);
|
||||
if (error) { /* handle the error */ }
|
||||
if( error ) { /* handle the error */ }
|
||||
for (auto doc: stream) {
|
||||
if (counter < 6) {
|
||||
if(counter < 6) {
|
||||
int64_t val;
|
||||
error = doc.at_pointer("/4").get(val);
|
||||
if (error) { /* handle the error */ }
|
||||
if( error ) { /* handle the error */ }
|
||||
std::cout << "5 = " << val << std::endl;
|
||||
} else {
|
||||
ondemand::value val;
|
||||
error = doc.at_pointer("/4").get(val);
|
||||
// error == simdjson::CAPACITY
|
||||
if (error) {
|
||||
if(error) {
|
||||
std::cerr << error << std::endl;
|
||||
// We left 293 bytes unprocessed at the tail end of the input.
|
||||
std::cout << " unprocessed bytes at the end: " << stream.truncated_bytes() << std::endl;
|
||||
@@ -1656,9 +1647,9 @@ JSON string to a user-provided buffer:
|
||||
|
||||
General Direct Access to the Raw JSON String
|
||||
--------------------------------
|
||||
If your value is a string, the `raw_json_string` you with `get_raw_json_string()` gives you direct access to the unprocessed
|
||||
string. But the simdjson library allows you to have access to the raw underlying JSON
|
||||
more generally, not just for strings.
|
||||
If your value is a string, the `raw_json_string` gives you direct access to the unprocess
|
||||
string. The simdjson library allows you to have access to the raw underlying JSON
|
||||
more generally.
|
||||
|
||||
The simdjson library makes explicit assumptions about types. For examples, numbers
|
||||
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
|
||||
@@ -1691,9 +1682,9 @@ string_view token = obj["value"].raw_json_token();
|
||||
|
||||
The `raw_json_token()` should be fast and free of allocation.
|
||||
|
||||
If your value is an array or an object, `raw_json_token()` returns effectively a single
|
||||
If you value is an array or an object, `raw_json_token()` returns effectively a single
|
||||
character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another
|
||||
method called `raw_json()` which consumes (traverses) the array or the object.
|
||||
method called `raw_json()` which consumes (traverse) the array or the object.
|
||||
|
||||
```C++
|
||||
simdjson::ondemand::parser parser;
|
||||
@@ -1725,82 +1716,6 @@ obj.reset(); // revise the object
|
||||
uint64_t x = obj["value"]; // gives me 123
|
||||
```
|
||||
|
||||
You can use `raw_json()` with the values inside an array and object. When
|
||||
calling `raw_json()` on an untyped value, it acts as `raw_json()` when the
|
||||
value is an array or an object. Otherwise, it acts as `raw_json_token()`.
|
||||
It is useful if you do not care for the type of the value and just wants a
|
||||
string representation.
|
||||
|
||||
```C++
|
||||
auto json = R"( [1,2,"fds", {"a":1}, [1,344]] )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
size_t counter = 0;
|
||||
for(auto array: doc) {
|
||||
std::string_view raw = array.raw_json();
|
||||
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
|
||||
}
|
||||
```
|
||||
|
||||
```C++
|
||||
auto json = R"( {"key1":1,"key2":2,"key3":"fds", "key4":{"a":1}, "key5":[1,344]} )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
size_t counter = 0;
|
||||
for(auto key_value: doc.get_object()) {
|
||||
std::string_view raw = key_value.value().raw_json();
|
||||
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Storing Directly into an Existing String Instance
|
||||
-----------------------------------------------------
|
||||
|
||||
The simdjson library favours the use of `std::string_view` instances because
|
||||
it tends to lead to better performance due to causing fewer memory allocations.
|
||||
However, they are cases where you need to store a string result in an `std::string``
|
||||
instance. You can do so with a templated version of the `to_string()` method which takes as
|
||||
a parameter a reference to an `std::string`.
|
||||
|
||||
```C++
|
||||
auto json = R"({
|
||||
"name": "Daniel",
|
||||
"age": 42
|
||||
})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
std::string name;
|
||||
doc["name"].get_string(name);
|
||||
```
|
||||
|
||||
The same routine can be written without exceptions handling:
|
||||
|
||||
```C++
|
||||
std::string name;
|
||||
auto err = doc["name"].get_string(name);
|
||||
if(err) { /* handle error */ }
|
||||
```
|
||||
|
||||
The `std::string` instance, once created, is independent. Unlike our `std::string_view` instances,
|
||||
it does not point at data that is within our `parser` instance. The same caveat applies: you should
|
||||
only consume a JSON string once.
|
||||
|
||||
Because `get_string()` is a template that requires a type that can be assigned an `std::string`, you
|
||||
can use it with features such as `std::optional`:
|
||||
|
||||
```C++
|
||||
auto json = R"({ "foo1": "3.1416" } )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
std::optional<std::string> value;
|
||||
if(doc["foo1"].get_string(value)) { /* error */ }
|
||||
// value was populated with "3.1416"
|
||||
```
|
||||
|
||||
You should be mindful of the trade-off: allocating multiple
|
||||
`std::string` instances can become expensive.
|
||||
|
||||
Thread Safety
|
||||
-------------
|
||||
|
||||
@@ -2029,79 +1944,6 @@ bool example() {
|
||||
}
|
||||
```
|
||||
|
||||
* Example 3: CRT
|
||||
|
||||
```C++
|
||||
|
||||
bool example() {
|
||||
padded_string padded_input_json = R"([
|
||||
{ "monitor": [
|
||||
{ "id": "monitor", "type": "toggle", "label": "monitor" },
|
||||
{ "id": "profile", "type": "selector", "label": "collection" },
|
||||
{ "id": "overlay", "type": "selector", "label": "overlay" },
|
||||
{ "id": "zoom", "type": "toggleSlider", "label": "zoom" }
|
||||
] },
|
||||
|
||||
{ "crt": [
|
||||
{ "id": "system", "type": "multi", "label": "system", "choices": "PAL, NTSC" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "brightness", "type": "slider", "icon": "brightness" },
|
||||
{ "id": "contrast", "type": "slider", "icon": "contrast" },
|
||||
{ "id": "saturation", "type": "slider", "icon": "saturation" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "overscan", "type": "toggleSlider", "label": "overscan" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "emulation", "type": "toggle", "label": "CRT emulation" },
|
||||
{ "type": "spacer" },
|
||||
{ "id": "curve", "type": "toggleSlider", "label": "curve" },
|
||||
{ "id": "bleed", "type": "toggleSlider", "label": "bleed" },
|
||||
{ "id": "vignette", "type": "toggleSlider", "label": "vignette" },
|
||||
{ "id": "scanlines", "type": "toggleSlider", "label": "scanlines" },
|
||||
{ "id": "gridlines", "type": "toggleSlider", "label": "gridlines" },
|
||||
{ "id": "glow", "type": "toggleSlider", "label": "glow" },
|
||||
{ "id": "flicker", "type": "toggleSlider", "label": "flicker" },
|
||||
{ "id": "noise", "type": "toggleSlider", "label": "noise" },
|
||||
{}
|
||||
] }
|
||||
])"_padded;
|
||||
auto parser = ondemand::parser{};
|
||||
auto doc = parser.iterate(padded_input_json);
|
||||
auto root_array = doc.get_array();
|
||||
// the root should be an object, not an array, but that's the JSON we are
|
||||
// given.
|
||||
for (ondemand::object node : root_array) {
|
||||
// We know that we are going to have just one element in the object.
|
||||
for (auto field : node) {
|
||||
std::cout << "\n\ntop level:" << field.key() << std::endl;
|
||||
// You can get a proper std::string_view for the key with:
|
||||
// std::string_view key = field.unescaped_key();
|
||||
// and second for-range loop to get child-elements here
|
||||
for (ondemand::object inner_object : field.value()) {
|
||||
auto i = inner_object.begin();
|
||||
if (i == inner_object.end()) {
|
||||
std::cout << "empty object" << std::endl;
|
||||
continue;
|
||||
} else {
|
||||
for (; i != inner_object.end(); ++i) {
|
||||
auto inner_field = *i;
|
||||
std::cout << '"' << inner_field.key()
|
||||
<< "\" : " << inner_field.value() << ", ";
|
||||
// You can get proper std::string_view for the key and value with:
|
||||
// std::string_view inner_key = field.unescaped_key();
|
||||
// std::string_view value_str = field.value();
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
// You can break here if you only want just the first element.
|
||||
// break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
Performance Tips
|
||||
--------
|
||||
@@ -2127,10 +1969,4 @@ Performance Tips
|
||||
std::string_view year = data["year"];
|
||||
std::string_view rating = data["rating"];
|
||||
```
|
||||
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log's output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
|
||||
|
||||
Further reading
|
||||
--------
|
||||
|
||||
|
||||
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
|
||||
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log's output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
|
||||
+2
-2
@@ -329,10 +329,10 @@ int main(void) {
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element tweets; // invalid until the get() succeeds
|
||||
auto error = parser.load("twitter.json").get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
uint64_t identifier;
|
||||
error = tweets["statuses"].at(0)["id"].get(identifier);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
std::cout << identifier << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -101,8 +101,8 @@ by comparing it with the null pointer.
|
||||
|
||||
```c++
|
||||
auto my_implementation = simdjson::get_available_implementations()["haswell"];
|
||||
if (! my_implementation) { exit(1); }
|
||||
if (! my_implementation->supported_by_runtime_system()) { exit(1); }
|
||||
if(! my_implementation) { exit(1); }
|
||||
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
|
||||
simdjson::get_active_implementation() = my_implementation;
|
||||
```
|
||||
|
||||
@@ -113,7 +113,7 @@ You should call `supported_by_runtime_system()` to compare the processor's featu
|
||||
|
||||
```c++
|
||||
for (auto implementation : simdjson::get_available_implementations()) {
|
||||
if (implementation->supported_by_runtime_system()) {
|
||||
if(implementation->supported_by_runtime_system()) {
|
||||
cout << implementation->name() << ": " << implementation->description() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -196,12 +196,12 @@ Let us illustrate the idea with code:
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document_stream stream;
|
||||
auto error = parser.iterate_many(json).get(stream);
|
||||
if (error) { /* do something */ }
|
||||
if( error ) { /* do something */ }
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
if (!i.error()) {
|
||||
if(!i.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
count++;
|
||||
@@ -237,7 +237,7 @@ Consider the following example where a truncated document (`{"key":"intentionall
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document_stream stream;
|
||||
auto error = parser.iterate_many(json,json.size()).get(stream);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
std::cout << i.source() << std::endl;
|
||||
}
|
||||
@@ -269,7 +269,7 @@ Example:
|
||||
// we pass 'true' to the allow_comma parameter, the batch size will be set to at least
|
||||
// the document size.
|
||||
auto error = parser.iterate_many(json, 32, true).get(doc_stream);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for (auto doc : doc_stream) {
|
||||
std::cout << doc.type() << std::endl;
|
||||
}
|
||||
|
||||
@@ -679,11 +679,11 @@ in production systems:
|
||||
ondemand::object c1 = parent["child1"];
|
||||
// c1 owns the focus
|
||||
//
|
||||
if (std::string_view(c1["name"]) != "John") { ... }
|
||||
if(std::string_view(c1["name"]) != "John") { ... }
|
||||
// c2 attempts to grab the focus from parent but fails
|
||||
ondemand::object c2 = parent["child2"];
|
||||
// c2 is now in an unsafe state and the following line would be unsafe
|
||||
// if (std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
// if(std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
```
|
||||
|
||||
A correct usage is given by the following example:
|
||||
@@ -697,7 +697,7 @@ in production systems:
|
||||
{
|
||||
ondemand::object c1 = parent["child1"];
|
||||
// c1 grabbed the focus from parent
|
||||
if (std::string_view(c1["name"]) != "John") { return false; }
|
||||
if(std::string_view(c1["name"]) != "John") { return false; }
|
||||
}
|
||||
// c1 went out of scope, so its destructor was called and the focus
|
||||
// was handed back to parent.
|
||||
@@ -705,7 +705,7 @@ in production systems:
|
||||
ondemand::object c2 = parent["child2"];
|
||||
// c2 grabbed the focus from parent
|
||||
// the following is safe:
|
||||
if (std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
if(std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+3
-3
@@ -184,12 +184,12 @@ Let us illustrate the idea with code:
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream stream;
|
||||
auto error = parser.parse_many(json).get(stream);
|
||||
if (error) { /* do something */ }
|
||||
if( error ) { /* do something */ }
|
||||
auto i = stream.begin();
|
||||
size_t count{0};
|
||||
for(; i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
if (!doc.error()) {
|
||||
if(!doc.error()) {
|
||||
std::cout << "got full document at " << i.current_index() << std::endl;
|
||||
std::cout << i.source() << std::endl;
|
||||
count++;
|
||||
@@ -225,7 +225,7 @@ Consider the following example where a truncated document (`{"key":"intentionall
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::document_stream stream;
|
||||
auto error = parser.parse_many(json,json.size()).get(stream);
|
||||
if (error) { std::cerr << error << std::endl; return; }
|
||||
if(error) { std::cerr << error << std::endl; return; }
|
||||
for(auto doc : stream) {
|
||||
std::cout << doc << std::endl;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "simdjson/arm64/begin.h"
|
||||
#include "simdjson/generic/amalgamated.h"
|
||||
#include "simdjson/generic/lookup_table.h"
|
||||
#include "simdjson/arm64/end.h"
|
||||
|
||||
#endif // SIMDJSON_ARM64_H
|
||||
@@ -13,12 +13,14 @@ namespace arm64 {
|
||||
|
||||
class implementation;
|
||||
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
template <typename T> struct simd8;
|
||||
template <> struct simd8<bool>;
|
||||
template <> struct simd8<uint8_t>;
|
||||
template <typename T> struct simd8x64;
|
||||
|
||||
} // namespace simd
|
||||
} // unnamed namespace
|
||||
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#define SIMDJSON_IMPLEMENTATION arm64
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#include "simdjson/arm64/bitmanipulation.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#include "simdjson/arm64/numberparsing_defs.h"
|
||||
#include "simdjson/arm64/simd.h"
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
#ifndef SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
#define SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
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
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
_BitScanForward64(&ret, input_num);
|
||||
return (int)ret;
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
return __builtin_ctzll(input_num);
|
||||
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
return input_num & (input_num-1);
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
if (_BitScanReverse64(&leading_zero, input_num))
|
||||
return (int)(63 - leading_zero);
|
||||
else
|
||||
return 64;
|
||||
#else
|
||||
return __builtin_clzll(input_num);
|
||||
#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int count_ones(uint64_t input_num) {
|
||||
return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) // catches clang and gcc
|
||||
/**
|
||||
* ARM has a fast 64-bit "bit reversal function" that is handy. However,
|
||||
* it is not generally available as an intrinsic function under Visual
|
||||
* Studio (though this might be changing). Even under clang/gcc, we
|
||||
* apparently need to invoke inline assembly.
|
||||
*/
|
||||
/*
|
||||
* We use SIMDJSON_PREFER_REVERSE_BITS as a hint that algorithms that
|
||||
* work well with bit reversal may use it.
|
||||
*/
|
||||
#define SIMDJSON_PREFER_REVERSE_BITS 1
|
||||
|
||||
/* reverse the bits */
|
||||
simdjson_inline uint64_t reverse_bits(uint64_t input_num) {
|
||||
uint64_t rev_bits;
|
||||
__asm("rbit %0, %1" : "=r"(rev_bits) : "r"(input_num));
|
||||
return rev_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit at index 63 - lz. Thus if you have 'leading_zeroes' leading zeroes,
|
||||
* then this will set to zero the leading bit. It is possible for leading_zeroes to be
|
||||
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
||||
* of such undefined behavior is never used.
|
||||
**/
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
||||
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
*result = value1 + value2;
|
||||
return *result < value1;
|
||||
#else
|
||||
return __builtin_uaddll_overflow(value1, value2,
|
||||
reinterpret_cast<unsigned long long *>(result));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ARM64_BITMANIPULATION_H
|
||||
@@ -3,11 +3,129 @@
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/intrinsics.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace {
|
||||
namespace bitmask {
|
||||
|
||||
// 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
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
_BitScanForward64(&ret, input_num);
|
||||
return (int)ret;
|
||||
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
return __builtin_ctzll(input_num);
|
||||
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
return input_num & (input_num-1);
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
if (_BitScanReverse64(&leading_zero, input_num))
|
||||
return (int)(63 - leading_zero);
|
||||
else
|
||||
return 64;
|
||||
#else
|
||||
return __builtin_clzll(input_num);
|
||||
#endif// SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int count_ones(uint64_t input_num) {
|
||||
return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) // catches clang and gcc
|
||||
/**
|
||||
* ARM has a fast 64-bit "bit reversal function" that is handy. However,
|
||||
* it is not generally available as an intrinsic function under Visual
|
||||
* Studio (though this might be changing). Even under clang/gcc, we
|
||||
* apparently need to invoke inline assembly.
|
||||
*/
|
||||
/*
|
||||
* We use SIMDJSON_PREFER_REVERSE_BITS as a hint that algorithms that
|
||||
* work well with bit reversal may use it.
|
||||
*/
|
||||
#define SIMDJSON_PREFER_REVERSE_BITS 1
|
||||
|
||||
/* reverse the bits */
|
||||
simdjson_inline uint64_t reverse_bits(uint64_t input_num) {
|
||||
uint64_t rev_bits;
|
||||
__asm("rbit %0, %1" : "=r"(rev_bits) : "r"(input_num));
|
||||
return rev_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips bit at index 63 - lz. Thus if you have 'leading_zeroes' leading zeroes,
|
||||
* then this will set to zero the leading bit. It is possible for leading_zeroes to be
|
||||
* greating or equal to 63 in which case we trigger undefined behavior, but the output
|
||||
* of such undefined behavior is never used.
|
||||
**/
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
|
||||
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
simdjson_inline uint64_t add_carry_out(uint64_t value1, uint64_t value2, bool &carry_out) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint64_t result = value1 + value2;
|
||||
carry_out = result < value1;
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
carry_out = __builtin_uaddll_overflow(value1, value2, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow(uint64_t value1, uint64_t value2, bool &borrow) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
value2 += borrow;
|
||||
uint64_t result = value1 - value2;
|
||||
borrow = value1 > value2;
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
bool borrow1 = __builtin_usubll_overflow(value1, value2, &result);
|
||||
borrow = borrow1 | __builtin_usubll_overflow(result, borrow, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow_out(uint64_t value1, uint64_t value2, bool &borrow_out) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint64_t result = value1 - value2;
|
||||
borrow_out = result > value1;
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
borrow_out = __builtin_usubll_overflow(value1, value2, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
|
||||
|
||||
+287
-97
@@ -3,13 +3,12 @@
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/bitmanipulation.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#include "simdjson/internal/simdprune_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
@@ -17,53 +16,89 @@ namespace {
|
||||
// Start of private section with Visual Studio workaround
|
||||
|
||||
|
||||
#ifndef simdjson_make_uint8x16_t
|
||||
#define simdjson_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
|
||||
x13, x14, x15, x16) \
|
||||
([=]() { \
|
||||
uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
|
||||
x9, x10, x11, x12, x13, x14, x15, x16}; \
|
||||
return vld1q_u8(array); \
|
||||
}())
|
||||
#endif
|
||||
#ifndef simdjson_make_int8x16_t
|
||||
#define simdjson_make_int8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
|
||||
x13, x14, x15, x16) \
|
||||
([=]() { \
|
||||
int8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
|
||||
x9, x10, x11, x12, x13, x14, x15, x16}; \
|
||||
return vld1q_s8(array); \
|
||||
}())
|
||||
#endif
|
||||
/**
|
||||
* make_uint8x16_t initializes a SIMD register (uint8x16_t).
|
||||
* This is needed because, incredibly, the syntax uint8x16_t x = {1,2,3...}
|
||||
* is not recognized under Visual Studio! This is a workaround.
|
||||
* Using a std::initializer_list<uint8_t> as a parameter resulted in
|
||||
* inefficient code. With the current approach, if the parameters are
|
||||
* compile-time constants,
|
||||
* GNU GCC compiles it to ldr, the same as uint8x16_t x = {1,2,3...}.
|
||||
* You should not use this function except for compile-time constants:
|
||||
* it is not efficient.
|
||||
*/
|
||||
simdjson_inline simd_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
|
||||
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8,
|
||||
uint8_t x9, uint8_t x10, uint8_t x11, uint8_t x12,
|
||||
uint8_t x13, uint8_t x14, uint8_t x15, uint8_t x16) {
|
||||
// Doing a load like so end ups generating worse code.
|
||||
// uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8,
|
||||
// x9, x10,x11,x12,x13,x14,x15,x16};
|
||||
// return vld1q_u8(array);
|
||||
simd_t x{};
|
||||
// incredibly, Visual Studio does not allow x[0] = x1
|
||||
x = vsetq_lane_u8(x1, x, 0);
|
||||
x = vsetq_lane_u8(x2, x, 1);
|
||||
x = vsetq_lane_u8(x3, x, 2);
|
||||
x = vsetq_lane_u8(x4, x, 3);
|
||||
x = vsetq_lane_u8(x5, x, 4);
|
||||
x = vsetq_lane_u8(x6, x, 5);
|
||||
x = vsetq_lane_u8(x7, x, 6);
|
||||
x = vsetq_lane_u8(x8, x, 7);
|
||||
x = vsetq_lane_u8(x9, x, 8);
|
||||
x = vsetq_lane_u8(x10, x, 9);
|
||||
x = vsetq_lane_u8(x11, x, 10);
|
||||
x = vsetq_lane_u8(x12, x, 11);
|
||||
x = vsetq_lane_u8(x13, x, 12);
|
||||
x = vsetq_lane_u8(x14, x, 13);
|
||||
x = vsetq_lane_u8(x15, x, 14);
|
||||
x = vsetq_lane_u8(x16, x, 15);
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifndef simdjson_make_uint8x8_t
|
||||
#define simdjson_make_uint8x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
|
||||
([=]() { \
|
||||
uint8_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
|
||||
return vld1_u8(array); \
|
||||
}())
|
||||
#endif
|
||||
#ifndef simdjson_make_int8x8_t
|
||||
#define simdjson_make_int8x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
|
||||
([=]() { \
|
||||
int8_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
|
||||
return vld1_s8(array); \
|
||||
}())
|
||||
#endif
|
||||
#ifndef simdjson_make_uint16x8_t
|
||||
#define simdjson_make_uint16x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
|
||||
([=]() { \
|
||||
uint16_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
|
||||
return vld1q_u16(array); \
|
||||
}())
|
||||
#endif
|
||||
#ifndef simdjson_make_int16x8_t
|
||||
#define simdjson_make_int16x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
|
||||
([=]() { \
|
||||
int16_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
|
||||
return vld1q_s16(array); \
|
||||
}())
|
||||
#endif
|
||||
simdjson_inline uint8x8_t make_uint8x8_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
|
||||
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8) {
|
||||
uint8x8_t x{};
|
||||
x = vset_lane_u8(x1, x, 0);
|
||||
x = vset_lane_u8(x2, x, 1);
|
||||
x = vset_lane_u8(x3, x, 2);
|
||||
x = vset_lane_u8(x4, x, 3);
|
||||
x = vset_lane_u8(x5, x, 4);
|
||||
x = vset_lane_u8(x6, x, 5);
|
||||
x = vset_lane_u8(x7, x, 6);
|
||||
x = vset_lane_u8(x8, x, 7);
|
||||
return x;
|
||||
}
|
||||
|
||||
// We have to do the same work for make_int8x16_t
|
||||
simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int8_t x4,
|
||||
int8_t x5, int8_t x6, int8_t x7, int8_t x8,
|
||||
int8_t x9, int8_t x10, int8_t x11, int8_t x12,
|
||||
int8_t x13, int8_t x14, int8_t x15, int8_t x16) {
|
||||
// Doing a load like so end ups generating worse code.
|
||||
// int8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8,
|
||||
// x9, x10,x11,x12,x13,x14,x15,x16};
|
||||
// return vld1q_s8(array);
|
||||
int8x16_t x{};
|
||||
// incredibly, Visual Studio does not allow x[0] = x1
|
||||
x = vsetq_lane_s8(x1, x, 0);
|
||||
x = vsetq_lane_s8(x2, x, 1);
|
||||
x = vsetq_lane_s8(x3, x, 2);
|
||||
x = vsetq_lane_s8(x4, x, 3);
|
||||
x = vsetq_lane_s8(x5, x, 4);
|
||||
x = vsetq_lane_s8(x6, x, 5);
|
||||
x = vsetq_lane_s8(x7, x, 6);
|
||||
x = vsetq_lane_s8(x8, x, 7);
|
||||
x = vsetq_lane_s8(x9, x, 8);
|
||||
x = vsetq_lane_s8(x10, x, 9);
|
||||
x = vsetq_lane_s8(x11, x, 10);
|
||||
x = vsetq_lane_s8(x12, x, 11);
|
||||
x = vsetq_lane_s8(x13, x, 12);
|
||||
x = vsetq_lane_s8(x14, x, 13);
|
||||
x = vsetq_lane_s8(x15, x, 14);
|
||||
x = vsetq_lane_s8(x16, x, 15);
|
||||
return x;
|
||||
}
|
||||
|
||||
// End of private section with Visual Studio workaround
|
||||
} // namespace
|
||||
@@ -73,18 +108,28 @@ namespace {
|
||||
template<typename T>
|
||||
struct simd8;
|
||||
|
||||
#if !SIMDJSON_IS_ARM && !defined(SIMDJSON_CONDITIONAL_INCLUDE)
|
||||
// Make errors a bit more manageable when editing on non-ARM
|
||||
struct uint8x16_t { uint8_t x[16]; };
|
||||
#endif
|
||||
|
||||
//
|
||||
// Base class of simd8<uint8_t> and simd8<bool>, both of which use uint8x16_t internally.
|
||||
//
|
||||
template<typename T, typename Mask=simd8<bool>>
|
||||
struct base_u8 {
|
||||
uint8x16_t value;
|
||||
static const int SIZE = sizeof(value);
|
||||
/** The actual underlying system SIMD type. */
|
||||
using simd_t = uint8x16_t;
|
||||
static constexpr const int LANES = sizeof(simd_t);
|
||||
using bitmask_t = uint16_t;
|
||||
static_assert(sizeof(bitmask_t)*8 == LANES, "Bitmask type's bits must equal the simd type's bytes");
|
||||
|
||||
simd_t value;
|
||||
|
||||
// Conversion from/to SIMD register
|
||||
simdjson_inline base_u8(const uint8x16_t _value) : value(_value) {}
|
||||
simdjson_inline operator const uint8x16_t&() const { return this->value; }
|
||||
simdjson_inline operator uint8x16_t&() { return this->value; }
|
||||
simdjson_inline base_u8(const simd_t _value) : value(_value) {}
|
||||
simdjson_inline operator const simd_t&() const { return this->value; }
|
||||
simdjson_inline operator simd_t&() { return this->value; }
|
||||
|
||||
// Bit operations
|
||||
simdjson_inline simd8<T> operator|(const simd8<T> other) const { return vorrq_u8(*this, other); }
|
||||
@@ -96,7 +141,8 @@ namespace {
|
||||
simdjson_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
|
||||
simdjson_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
|
||||
|
||||
friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
|
||||
simdjson_inline Mask eq(const simd8<T> rhs) const { return vceqq_u8(*this, rhs); }
|
||||
friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return lhs.eq(rhs); }
|
||||
|
||||
template<int N=1>
|
||||
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||
@@ -112,7 +158,7 @@ namespace {
|
||||
|
||||
static simdjson_inline simd8<bool> splat(bool _value) { return vmovq_n_u8(uint8_t(-(!!_value))); }
|
||||
|
||||
simdjson_inline simd8(const uint8x16_t _value) : base_u8<bool>(_value) {}
|
||||
simdjson_inline simd8(const simd_t _value) : base_u8<bool>(_value) {}
|
||||
// False constructor
|
||||
simdjson_inline simd8() : simd8(vdupq_n_u8(0)) {}
|
||||
// Splat constructor
|
||||
@@ -122,14 +168,14 @@ namespace {
|
||||
// purposes (cutting it down to uint16_t costs performance in some compilers).
|
||||
simdjson_inline uint32_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
const simd_t bit_mask = make_simd_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
|
||||
#else
|
||||
const uint8x16_t bit_mask = {0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
const simd_t bit_mask = {0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
|
||||
#endif
|
||||
auto minput = *this & bit_mask;
|
||||
uint8x16_t tmp = vpaddq_u8(minput, minput);
|
||||
simd_t tmp = vpaddq_u8(minput, minput);
|
||||
tmp = vpaddq_u8(tmp, tmp);
|
||||
tmp = vpaddq_u8(tmp, tmp);
|
||||
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
|
||||
@@ -140,11 +186,14 @@ namespace {
|
||||
// Unsigned bytes
|
||||
template<>
|
||||
struct simd8<uint8_t>: base_u8<uint8_t> {
|
||||
static simdjson_inline uint8x16_t splat(uint8_t _value) { return vmovq_n_u8(_value); }
|
||||
static simdjson_inline uint8x16_t zero() { return vdupq_n_u8(0); }
|
||||
static simdjson_inline uint8x16_t load(const uint8_t* values) { return vld1q_u8(values); }
|
||||
using typename base_u8<uint8_t>::simd_t;
|
||||
using base_u8<uint8_t>::LANES;
|
||||
|
||||
simdjson_inline simd8(const uint8x16_t _value) : base_u8<uint8_t>(_value) {}
|
||||
static simdjson_inline simd_t splat(uint8_t _value) { return vmovq_n_u8(_value); }
|
||||
static simdjson_inline simd_t zero() { return vdupq_n_u8(0); }
|
||||
static simdjson_inline simd_t load(const uint8_t* values) { return vld1q_u8(values); }
|
||||
|
||||
simdjson_inline simd8(const simd_t _value) : base_u8<uint8_t>(_value) {}
|
||||
// Zero constructor
|
||||
simdjson_inline simd8() : simd8(zero()) {}
|
||||
// Array constructor
|
||||
@@ -156,7 +205,7 @@ namespace {
|
||||
simdjson_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
|
||||
) : simd8(simdjson_make_uint8x16_t(
|
||||
) : simd8(make_uint8x16_t(
|
||||
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||
v8, v9, v10,v11,v12,v13,v14,v15
|
||||
)) {}
|
||||
@@ -164,7 +213,7 @@ namespace {
|
||||
simdjson_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
|
||||
) : simd8(uint8x16_t{
|
||||
) : simd8(simd_t{
|
||||
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||
v8, v9, v10,v11,v12,v13,v14,v15
|
||||
}) {}
|
||||
@@ -218,15 +267,20 @@ namespace {
|
||||
simdjson_inline simd8<uint8_t> shl() const { return vshlq_n_u8(*this, N); }
|
||||
|
||||
// Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||
simdjson_inline simd8<uint8_t> lookup_16(simd8<uint8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this);
|
||||
}
|
||||
|
||||
// Perform a lookup based on the lower 4 bits of each lane. (Platform-dependent behavior for
|
||||
// non-ASCII values--may look up the lower 4 bits on some platforms, and return 0 on others.)
|
||||
simdjson_inline simd8<uint8_t> lookup_low_nibble_ascii(simd8<uint8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this & 0b10001111);
|
||||
}
|
||||
|
||||
|
||||
// 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 16 - count_ones(mask) bytes of the result are significant but 16 bytes
|
||||
// Only the first 16 - bitmask::count_ones(mask) bytes of the result are significant but 16 bytes
|
||||
// get written.
|
||||
// Design consideration: it seems like a function with the
|
||||
// signature simd8<L> compress(uint16_t mask) would be
|
||||
@@ -244,16 +298,16 @@ namespace {
|
||||
// thintable_epi8[mask2] into a 128-bit register, using only
|
||||
// two instructions on most compilers.
|
||||
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
|
||||
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
simd_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
simd_t inc = make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
simd_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
#endif
|
||||
shufmask = vaddq_u8(shufmask, inc);
|
||||
// this is the version "nearly pruned"
|
||||
uint8x16_t pruned = vqtbl1q_u8(*this, shufmask);
|
||||
simd_t pruned = vqtbl1q_u8(*this, shufmask);
|
||||
// we still need to put the two halves together.
|
||||
// we compute the popcount of the first half:
|
||||
int pop1 = BitsSetTable256mul2[mask1];
|
||||
@@ -261,8 +315,8 @@ namespace {
|
||||
// only the first pop1 bytes from the first 8 bytes, and then
|
||||
// it fills in with the bytes from the second 8 bytes + some filling
|
||||
// at the end.
|
||||
uint8x16_t compactmask = vld1q_u8(reinterpret_cast<const uint8_t *>(pshufb_combine_table + pop1 * 8));
|
||||
uint8x16_t answer = vqtbl1q_u8(pruned, compactmask);
|
||||
simd_t compactmask = vld1q_u8(reinterpret_cast<const uint8_t *>(pshufb_combine_table + pop1 * 8));
|
||||
simd_t answer = vqtbl1q_u8(pruned, compactmask);
|
||||
vst1q_u8(reinterpret_cast<uint8_t*>(output), answer);
|
||||
}
|
||||
|
||||
@@ -277,7 +331,7 @@ namespace {
|
||||
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
uint8x8_t inc = make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
#endif
|
||||
@@ -287,20 +341,6 @@ namespace {
|
||||
vst1_u8((uint8_t*)output2, vqtbl1_u8(*this, compactmask2));
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
simdjson_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
|
||||
));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
simdjson_inline simd8<uint8_t> apply_lookup_16_to(const simd8<T> original) {
|
||||
return vqtbl1q_u8(*this, simd8<uint8_t>(original));
|
||||
@@ -332,7 +372,7 @@ namespace {
|
||||
simdjson_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
|
||||
) : simd8(simdjson_make_int8x16_t(
|
||||
) : simd8(make_int8x16_t(
|
||||
v0, v1, v2, v3, v4, v5, v6, v7,
|
||||
v8, v9, v10,v11,v12,v13,v14,v15
|
||||
)) {}
|
||||
@@ -365,7 +405,7 @@ namespace {
|
||||
// In theory, we could check this occurrence with std::same_as and std::enabled_if but it is C++14
|
||||
// and relatively ugly and hard to read.
|
||||
#ifndef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline explicit simd8(const uint8x16_t other): simd8(vreinterpretq_s8_u8(other)) {}
|
||||
simdjson_inline explicit simd8(const simd_t other): simd8(vreinterpretq_s8_u8(other)) {}
|
||||
#endif
|
||||
simdjson_inline explicit operator simd8<uint8_t>() const { return vreinterpretq_u8_s8(this->value); }
|
||||
|
||||
@@ -388,10 +428,13 @@ namespace {
|
||||
}
|
||||
|
||||
// Perform a lookup assuming no value is larger than 16
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||
simdjson_inline simd8<int8_t> lookup_16(simd8<int8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this);
|
||||
}
|
||||
// Perform a lookup based on the lower 4 bits of each lane, returning 0 for values with a high bit of 1.
|
||||
simdjson_inline simd8<int8_t> lookup_low_nibble_ascii(simd8<int8_t> lookup_table) const {
|
||||
return lookup_table.apply_lookup_16_to(*this & 0b10001111);
|
||||
}
|
||||
template<typename L>
|
||||
simdjson_inline simd8<L> lookup_16(
|
||||
L replace0, L replace1, L replace2, L replace3,
|
||||
@@ -424,6 +467,8 @@ namespace {
|
||||
|
||||
simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
|
||||
simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
|
||||
simdjson_inline simd8x64(simd8x64<T>&& o) noexcept = default;
|
||||
simdjson_inline simd8x64<T>& operator=(simd8x64<T>&& other) noexcept = default;
|
||||
|
||||
simdjson_inline void store(T ptr[64]) const {
|
||||
this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
|
||||
@@ -450,19 +495,19 @@ namespace {
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
|
||||
const simd_t bit_mask = make_uint8x16_t(
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
);
|
||||
#else
|
||||
const uint8x16_t bit_mask = {
|
||||
const simd_t bit_mask = {
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
};
|
||||
#endif
|
||||
// Add each of the elements next to each other, successively, to stuff each 8 byte mask into one.
|
||||
uint8x16_t sum0 = vpaddq_u8(this->chunks[0] & bit_mask, this->chunks[1] & bit_mask);
|
||||
uint8x16_t sum1 = vpaddq_u8(this->chunks[2] & bit_mask, this->chunks[3] & bit_mask);
|
||||
simd_t sum0 = vpaddq_u8(this->chunks[0] & bit_mask, this->chunks[1] & bit_mask);
|
||||
simd_t sum1 = vpaddq_u8(this->chunks[2] & bit_mask, this->chunks[3] & bit_mask);
|
||||
sum0 = vpaddq_u8(sum0, sum1);
|
||||
sum0 = vpaddq_u8(sum0, sum0);
|
||||
return vgetq_lane_u64(vreinterpretq_u64_u8(sum0), 0);
|
||||
@@ -478,6 +523,24 @@ namespace {
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_16(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_16(lookup_table),
|
||||
this->chunks[1].lookup_16(lookup_table),
|
||||
this->chunks[2].lookup_16(lookup_table),
|
||||
this->chunks[3].lookup_16(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_low_nibble_ascii(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[1].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[2].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[3].lookup_low_nibble_ascii(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t lteq(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return simd8x64<bool>(
|
||||
@@ -487,10 +550,137 @@ namespace {
|
||||
this->chunks[3] <= mask
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other.chunks[0],
|
||||
this->chunks[1] & other.chunks[1],
|
||||
this->chunks[2] & other.chunks[2],
|
||||
this->chunks[3] & other.chunks[3]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other,
|
||||
this->chunks[1] & other,
|
||||
this->chunks[2] & other,
|
||||
this->chunks[3] & other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other.chunks[0],
|
||||
this->chunks[1] | other.chunks[1],
|
||||
this->chunks[2] | other.chunks[2],
|
||||
this->chunks[3] | other.chunks[3]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other,
|
||||
this->chunks[1] | other,
|
||||
this->chunks[2] | other,
|
||||
this->chunks[3] | other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other.chunks[0],
|
||||
this->chunks[1] ^ other.chunks[1],
|
||||
this->chunks[2] ^ other.chunks[2],
|
||||
this->chunks[3] ^ other.chunks[3]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other,
|
||||
this->chunks[1] ^ other,
|
||||
this->chunks[2] ^ other,
|
||||
this->chunks[3] ^ other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other.chunks[0]),
|
||||
this->chunks[1].bit_andnot(other.chunks[1]),
|
||||
this->chunks[2].bit_andnot(other.chunks[2]),
|
||||
this->chunks[3].bit_andnot(other.chunks[3])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other),
|
||||
this->chunks[1].bit_andnot(other),
|
||||
this->chunks[2].bit_andnot(other),
|
||||
this->chunks[3].bit_andnot(other)
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shr() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shr<N>(),
|
||||
this->chunks[1].template shr<N>(),
|
||||
this->chunks[2].template shr<N>(),
|
||||
this->chunks[3].template shr<N>()
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shl() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shl<N>(),
|
||||
this->chunks[1].template shl<N>(),
|
||||
this->chunks[2].template shl<N>(),
|
||||
this->chunks[3].template shl<N>()
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits),
|
||||
this->chunks[1].any_bits_set(bits),
|
||||
this->chunks[2].any_bits_set(bits),
|
||||
this->chunks[3].any_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits.chunks[0]),
|
||||
this->chunks[1].any_bits_set(bits.chunks[1]),
|
||||
this->chunks[2].any_bits_set(bits.chunks[2]),
|
||||
this->chunks[3].any_bits_set(bits.chunks[3])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits),
|
||||
this->chunks[1].no_bits_set(bits),
|
||||
this->chunks[2].no_bits_set(bits),
|
||||
this->chunks[3].no_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits.chunks[0]),
|
||||
this->chunks[1].no_bits_set(bits.chunks[1]),
|
||||
this->chunks[2].no_bits_set(bits.chunks[2]),
|
||||
this->chunks[3].no_bits_set(bits.chunks[3])
|
||||
};
|
||||
}
|
||||
}; // struct simd8x64<T>
|
||||
|
||||
} // namespace simd
|
||||
} // unnamed namespace
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/arm64/base.h"
|
||||
#include "simdjson/arm64/simd.h"
|
||||
#include "simdjson/arm64/bitmanipulation.h"
|
||||
#include "simdjson/arm64/bitmask.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
|
||||
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
|
||||
simdjson_inline bool has_backslash() { return bs_bits != 0; }
|
||||
simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
|
||||
simdjson_inline int quote_index() { return bitmask::trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return bitmask::trailing_zeroes(bs_bits); }
|
||||
|
||||
uint32_t bs_bits;
|
||||
uint32_t quote_bits;
|
||||
|
||||
@@ -167,6 +167,41 @@ double from_chars(const char *first, const char* end) noexcept;
|
||||
#define simdjson_inline simdjson_really_inline
|
||||
#endif
|
||||
|
||||
#ifndef simdjson_constexpr
|
||||
#if __cpp_constexpr
|
||||
#define simdjson_constexpr constexpr simdjson_inline
|
||||
#else
|
||||
#define simdjson_constexpr simdjson_inline
|
||||
#endif
|
||||
#endif
|
||||
// simdjson_constexpr
|
||||
|
||||
#ifndef simdjson_consteval
|
||||
#if __cpp_consteval
|
||||
#define simdjson_consteval consteval simdjson_inline
|
||||
#else
|
||||
#define simdjson_consteval simdjson_constexpr
|
||||
#endif
|
||||
#endif // simdjson_consteval
|
||||
|
||||
#ifndef simdjson_constinit
|
||||
#if __cpp_constinit
|
||||
#define simdjson_constinit constinit
|
||||
#elif __cpp_consteval
|
||||
#define simdjson_constinit consteval
|
||||
#else
|
||||
#define simdjson_constinit constexpr
|
||||
#endif
|
||||
#endif // simdjson_constinit
|
||||
|
||||
#ifndef simdjson_if_constexpr
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
#define simdjson_if_constexpr constexpr
|
||||
#else
|
||||
#define simdjson_if_constexpr
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SIMDJSON_VISUAL_STUDIO
|
||||
/**
|
||||
* Windows users need to do some extra work when building
|
||||
|
||||
@@ -224,7 +224,8 @@ private:
|
||||
* Parse the next document found in the buffer previously given to document_stream.
|
||||
*
|
||||
* The content should be a valid JSON document encoded as UTF-8. If there is a
|
||||
* UTF-8 BOM, the parser skips it.
|
||||
* UTF-8 BOM, the caller is responsible for omitting it, UTF-8 BOM are
|
||||
* discouraged.
|
||||
*
|
||||
* You do NOT need to pre-allocate a parser. This function takes care of
|
||||
* pre-allocating a capacity defined by the batch_size defined when creating the
|
||||
|
||||
@@ -410,12 +410,6 @@ inline simdjson_result<element> element::at_key(std::string_view key) const noex
|
||||
inline simdjson_result<element> element::at_key_case_insensitive(std::string_view key) const noexcept {
|
||||
return get<object>().at_key_case_insensitive(key);
|
||||
}
|
||||
inline bool element::operator<(const element &other) const noexcept {
|
||||
return tape.json_index < other.tape.json_index;
|
||||
}
|
||||
inline bool element::operator==(const element &other) const noexcept {
|
||||
return tape.json_index == other.tape.json_index;
|
||||
}
|
||||
|
||||
inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
|
||||
@@ -211,11 +211,7 @@ public:
|
||||
inline simdjson_result<T> get() const noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are Boolean (bool), numbers (double, uint64_t, int64_t), "
|
||||
"strings (std::string_view, const char *), arrays (dom::array) and objects (dom::object). "
|
||||
"We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
"get_object(), get_array() or get_string() instead of the get template.");
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,22 +451,6 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> at_key_case_insensitive(std::string_view key) const noexcept;
|
||||
|
||||
/**
|
||||
* operator< defines a total order for element allowing to use them in
|
||||
* ordered C++ STL containers
|
||||
*
|
||||
* @return TRUE if the key appears before the other one in the tape
|
||||
*/
|
||||
inline bool operator<(const element &other) const noexcept;
|
||||
|
||||
/**
|
||||
* operator== allows to verify if two element values reference the
|
||||
* same JSON item
|
||||
*
|
||||
* @return TRUE if the two values references the same JSON element
|
||||
*/
|
||||
inline bool operator==(const element &other) const noexcept;
|
||||
|
||||
/** @private for debugging. Prints out the root element. */
|
||||
inline bool dump_raw_tape(std::ostream &out) const noexcept;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "simdjson/dom/element-inl.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstring> /* memcmp */
|
||||
|
||||
namespace simdjson {
|
||||
namespace dom {
|
||||
@@ -92,14 +91,10 @@ inline simdjson_result<size_t> parser::read_file(const std::string &path) noexce
|
||||
}
|
||||
|
||||
inline simdjson_result<element> parser::load(const std::string &path) & noexcept {
|
||||
return load_into_document(doc, path);
|
||||
}
|
||||
|
||||
inline simdjson_result<element> parser::load_into_document(document& provided_doc, const std::string &path) & noexcept {
|
||||
size_t len;
|
||||
auto _error = read_file(path).get(len);
|
||||
if (_error) { return _error; }
|
||||
return parse_into_document(provided_doc, loaded_bytes.get(), len, false);
|
||||
return parse(loaded_bytes.get(), len, false);
|
||||
}
|
||||
|
||||
inline simdjson_result<document_stream> parser::load_many(const std::string &path, size_t batch_size) noexcept {
|
||||
@@ -125,14 +120,8 @@ inline simdjson_result<element> parser::parse_into_document(document& provided_d
|
||||
_loaded_bytes_capacity = len;
|
||||
}
|
||||
std::memcpy(static_cast<void *>(loaded_bytes.get()), buf, len);
|
||||
buf = reinterpret_cast<const uint8_t*>(loaded_bytes.get());
|
||||
}
|
||||
|
||||
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
|
||||
buf += 3;
|
||||
len -= 3;
|
||||
}
|
||||
_error = implementation->parse(buf, len, provided_doc);
|
||||
_error = implementation->parse(realloc_if_needed ? reinterpret_cast<const uint8_t*>(loaded_bytes.get()): buf, len, provided_doc);
|
||||
|
||||
if (_error) { return _error; }
|
||||
|
||||
@@ -169,10 +158,6 @@ simdjson_inline simdjson_result<element> parser::parse(const padded_string_view
|
||||
|
||||
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
|
||||
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
||||
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
|
||||
buf += 3;
|
||||
len -= 3;
|
||||
}
|
||||
return document_stream(*this, buf, len, batch_size);
|
||||
}
|
||||
inline simdjson_result<document_stream> parser::parse_many(const char *buf, size_t len, size_t batch_size) noexcept {
|
||||
|
||||
@@ -95,53 +95,6 @@ public:
|
||||
*/
|
||||
inline simdjson_result<element> load(const std::string &path) & noexcept;
|
||||
inline simdjson_result<element> load(const std::string &path) && = delete ;
|
||||
|
||||
/**
|
||||
* Load a JSON document from a file into a provide document instance and return a temporary reference to it.
|
||||
* It is similar to the function `load` except that instead of parsing into the internal
|
||||
* `document` instance associated with the parser, it allows the user to provide a document
|
||||
* instance.
|
||||
*
|
||||
* dom::parser parser;
|
||||
* dom::document doc;
|
||||
* element doc_root = parser.load_into_document(doc, "jsonexamples/twitter.json");
|
||||
*
|
||||
* The function is eager: the file's content is loaded in memory inside the parser instance
|
||||
* and immediately parsed. The file can be deleted after the `parser.load_into_document` call.
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* After the call to load_into_document, the parser is no longer needed.
|
||||
*
|
||||
* The JSON document lives in the document instance: you must keep the document
|
||||
* instance alive while you navigate through it (i.e., used the returned value from
|
||||
* load_into_document). You are encourage to reuse the document instance
|
||||
* many times with new data to avoid reallocations:
|
||||
*
|
||||
* dom::document doc;
|
||||
* element doc_root1 = parser.load_into_document(doc, "jsonexamples/twitter.json");
|
||||
* //... doc_root1 is a pointer inside doc
|
||||
* element doc_root2 = parser.load_into_document(doc, "jsonexamples/twitter.json");
|
||||
* //... doc_root2 is a pointer inside doc
|
||||
* // at this point doc_root1 is no longer safe
|
||||
*
|
||||
* Moving the document instance is safe, but it invalidates the element instances. After
|
||||
* moving a document, you can recover safe access to the document root with its `root()` method.
|
||||
*
|
||||
* @param doc The document instance where the parsed data will be stored (on success).
|
||||
* @param path The path to load.
|
||||
* @return The document, or an error:
|
||||
* - IO_ERROR if there was an error opening or reading the file.
|
||||
* Be mindful that on some 32-bit systems,
|
||||
* the file size might be limited to 2 GB.
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails.
|
||||
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
|
||||
* - other json errors if parsing fails. You should not rely on these errors to always the same for the
|
||||
* same document: they may vary under runtime dispatch (so they may vary depending on your system and hardware).
|
||||
*/
|
||||
inline simdjson_result<element> load_into_document(document& doc, const std::string &path) & noexcept;
|
||||
inline simdjson_result<element> load_into_document(document& doc, const std::string &path) && =delete;
|
||||
|
||||
/**
|
||||
* Parse a JSON document and return a temporary reference to it.
|
||||
*
|
||||
@@ -301,8 +254,6 @@ public:
|
||||
* And, possibly, no document many have been parsed when the `parser.load_many(path)` function
|
||||
* returned.
|
||||
*
|
||||
* If there is a UTF-8 BOM, the parser skips it.
|
||||
*
|
||||
* ### Format
|
||||
*
|
||||
* The file must contain a series of one or more JSON documents, concatenated into a single
|
||||
@@ -395,8 +346,6 @@ public:
|
||||
* cout << std::string(doc["title"]) << endl;
|
||||
* }
|
||||
*
|
||||
* If there is a UTF-8 BOM, the parser skips it.
|
||||
*
|
||||
* ### Format
|
||||
*
|
||||
* The buffer must contain a series of one or more JSON documents, concatenated into a single
|
||||
|
||||
@@ -42,7 +42,7 @@ enum error_code {
|
||||
INVALID_URI_FRAGMENT, ///< Invalid URI fragment
|
||||
UNEXPECTED_ERROR, ///< indicative of a bug in simdjson
|
||||
PARSER_IN_USE, ///< parser is already in use.
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order
|
||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||
@@ -51,13 +51,6 @@ enum error_code {
|
||||
NUM_ERROR_CODES
|
||||
};
|
||||
|
||||
/**
|
||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||
* that was written while breaking some simdjson::ondemand requirement. They should not occur in released
|
||||
* code after these issues were fixed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the error message for the given error code.
|
||||
*
|
||||
@@ -217,11 +210,11 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
||||
*/
|
||||
simdjson_inline simdjson_result() noexcept;
|
||||
/**
|
||||
* @private Create a new successful result.
|
||||
* @private Create a new error result.
|
||||
*/
|
||||
simdjson_inline simdjson_result(T &&value) noexcept;
|
||||
/**
|
||||
* @private Create a new error result.
|
||||
* @private Create a new successful result.
|
||||
*/
|
||||
simdjson_inline simdjson_result(error_code error_code) noexcept;
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define SIMDJSON_IMPLEMENTATION fallback
|
||||
#include "simdjson/fallback/base.h"
|
||||
#include "simdjson/fallback/bitmanipulation.h"
|
||||
#include "simdjson/fallback/bitmask.h"
|
||||
#include "simdjson/fallback/stringparsing_defs.h"
|
||||
#include "simdjson/fallback/numberparsing_defs.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SIMDJSON_FALLBACK_BITMANIPULATION_H
|
||||
#define SIMDJSON_FALLBACK_BITMANIPULATION_H
|
||||
#ifndef SIMDJSON_FALLBACK_BITMASK_H
|
||||
#define SIMDJSON_FALLBACK_BITMASK_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/fallback/base.h"
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace simdjson {
|
||||
namespace fallback {
|
||||
namespace {
|
||||
namespace bitmask {
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_M_ARM64) && !defined(_M_X64)
|
||||
static inline unsigned char _BitScanForward64(unsigned long* ret, uint64_t x) {
|
||||
@@ -0,0 +1,303 @@
|
||||
#ifndef SIMDJSON_GENERIC_SIMD_LOOKUP_TABLE_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_SIMD_LOOKUP_TABLE_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace simd {
|
||||
|
||||
template <typename T = uint8_t>
|
||||
struct simd8_buffer {
|
||||
T buf[simd8<T>::LANES] = {0};
|
||||
simdjson_consteval T& operator[](size_t i) noexcept { return buf[i]; }
|
||||
simdjson_consteval T operator[](size_t i) const noexcept { return buf[i]; }
|
||||
simdjson_inline operator simd8<T>() const noexcept { return buf; }
|
||||
};
|
||||
|
||||
|
||||
struct nibble_range;
|
||||
|
||||
struct byte_range {
|
||||
struct _exclusive{};
|
||||
static simdjson_constinit _exclusive exclusive{};
|
||||
|
||||
simdjson_consteval byte_range(uint8_t start, uint16_t end, const _exclusive&) noexcept : _start{start}, _end{end} {
|
||||
SIMDJSON_ASSUME(start < end && end <= 256);
|
||||
}
|
||||
simdjson_consteval byte_range(uint8_t first, uint8_t last) noexcept : byte_range(first, static_cast<uint16_t>(last+1), exclusive) {}
|
||||
simdjson_consteval byte_range(uint8_t first) noexcept : byte_range(first, first) {}
|
||||
|
||||
simdjson_consteval size_t size() const noexcept { return static_cast<size_t>(_end - _start); }
|
||||
simdjson_consteval byte_range operator|(const byte_range& other) const noexcept {
|
||||
SIMDJSON_ASSUME((_end + 1 >= other._start) || (other._end + 1 >= _start));
|
||||
return {std::min(_start, other._start), std::max(_end, other._end), exclusive};
|
||||
}
|
||||
|
||||
simdjson_consteval bool includes(uint8_t byte) const noexcept { return _start <= byte && byte < _end; }
|
||||
|
||||
struct nibble_iter {
|
||||
int nibble;
|
||||
const int last_nibble;
|
||||
simdjson_consteval nibble_iter& operator++() noexcept {
|
||||
if (nibble == last_nibble) {
|
||||
nibble = -1;
|
||||
} else {
|
||||
++nibble;
|
||||
nibble %= 16;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
simdjson_consteval nibble_iter operator++(int) noexcept { auto copy = *this; ++*this; return copy; }
|
||||
simdjson_consteval bool operator==(const nibble_iter& other) const noexcept { return nibble == other.nibble; }
|
||||
simdjson_consteval bool operator!=(const nibble_iter& other) const noexcept { return nibble != other.nibble; }
|
||||
simdjson_consteval uint8_t operator*() const noexcept { return static_cast<uint8_t>(nibble); }
|
||||
simdjson_consteval nibble_iter begin() const noexcept { return *this; }
|
||||
simdjson_consteval nibble_iter end() const noexcept { return {-1, last_nibble}; }
|
||||
};
|
||||
|
||||
simdjson_consteval nibble_iter nibble(int shift) const noexcept {
|
||||
SIMDJSON_ASSUME(_start < _end);
|
||||
auto first_nibble = _start >> shift;
|
||||
auto last_nibble = (_end-1) >> shift;
|
||||
if ((last_nibble - first_nibble) >= 16) { return {0x00, 0x0F}; }
|
||||
return {static_cast<uint8_t>(first_nibble & 0x0F), static_cast<uint8_t>(last_nibble & 0x0F)};
|
||||
}
|
||||
|
||||
struct _iter {
|
||||
uint16_t value;
|
||||
simdjson_consteval _iter& operator++() noexcept { ++value; return *this; }
|
||||
simdjson_consteval _iter operator++(int) noexcept { auto copy = *this; ++*this; return copy; }
|
||||
simdjson_consteval bool operator==(const _iter& other) const noexcept { return value == other.value; }
|
||||
simdjson_consteval bool operator!=(const _iter& other) const noexcept { return value != other.value; }
|
||||
simdjson_consteval uint8_t operator*() const noexcept { return static_cast<uint8_t>(value); }
|
||||
};
|
||||
|
||||
simdjson_consteval _iter begin() const noexcept { return _iter{_start}; }
|
||||
simdjson_consteval _iter end() const noexcept { return _iter{_end}; }
|
||||
|
||||
uint8_t _start;
|
||||
const uint16_t _end;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
struct _lookup_entry_range;
|
||||
|
||||
struct _lookup_entry : byte_range {
|
||||
const uint8_t value;
|
||||
|
||||
simdjson_consteval _lookup_entry(const byte_range& bytes, uint8_t value) noexcept
|
||||
: byte_range{bytes}, value{value} {}
|
||||
};
|
||||
|
||||
simdjson_consteval simd8_buffer<uint8_t> _make_nibble_lookup_table(
|
||||
std::initializer_list<_lookup_entry> entries, int shift) noexcept {
|
||||
// Make the buffer
|
||||
simd8_buffer<uint8_t> buf;
|
||||
for (auto entry : entries) {
|
||||
for (auto key : entry.nibble(shift)) {
|
||||
// Repeat the value over and over for longer simd types.
|
||||
for (uint8_t k = key; k < sizeof(buf); k += 16) { buf[k] |= entry.value; }
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
/**
|
||||
* Byte lookup table where the key is the high 4 bits of the input, and the value is an
|
||||
* arbitrary byte.
|
||||
*
|
||||
* - Unmatched values yield 0.
|
||||
* - Multiple keys may yield the same value.
|
||||
* - Multiple bytes with the same high 4 bits may NOT yield different values.
|
||||
*
|
||||
* ```
|
||||
* enum ops_t : uint8_t {
|
||||
* COMMA = 1,
|
||||
* COLON = 2,
|
||||
* BRACKET = 3,
|
||||
* CURLY = 4
|
||||
* };
|
||||
* static constinit const high_nibble_lookup OPS(
|
||||
* {',', COMMA},
|
||||
* {':', COLON},
|
||||
* {'[', BRACKET},
|
||||
* {']', BRACKET},
|
||||
* {'{', CURLY},
|
||||
* {'}', CURLY}
|
||||
* );
|
||||
* simd8<uint8_t> lookup_ops(simd8<uint8_t>& operators) { return OPS[operators]; }
|
||||
* ```
|
||||
*/
|
||||
struct high_nibble_lookup {
|
||||
const simd8_buffer<uint8_t> table;
|
||||
|
||||
/**
|
||||
* Construct a nibble lookup table from the high bits of the input to the output.
|
||||
*
|
||||
* @param entries A list of {key, value} pairs (e.g. {'a', 10}).
|
||||
* @error asserts if multiple keys have the same high 4 bits but different values.
|
||||
*/
|
||||
simdjson_consteval high_nibble_lookup(std::initializer_list<_lookup_entry> entries) noexcept
|
||||
: table{_make_nibble_lookup_table(entries, 4)} {}
|
||||
simdjson_consteval high_nibble_lookup(const simd8_buffer<uint8_t>& table) noexcept : table(table) {}
|
||||
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> operator[](const simd8<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> lookup(const simd8<uint8_t>& keys) const noexcept { return lookup_low(keys.shr<4>()); }
|
||||
/**
|
||||
* Look up the value in the table assuming the high 4 key bits are stored in the lower 4 bits.
|
||||
* @pre all indexes be less than 16.
|
||||
*/
|
||||
simdjson_inline simd8<uint8_t> lookup_low(const simd8<uint8_t>& shifted_keys) const noexcept {
|
||||
return shifted_keys.lookup_16(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the value in the table assuming the high 4 key bits are stored in the lower 4 bits.
|
||||
* @pre all indexes be less than 16.
|
||||
*/
|
||||
simdjson_inline simd8x64<uint8_t> lookup_low(const simd8x64<uint8_t>& shifted_keys) const noexcept {
|
||||
return shifted_keys.lookup_16(table);
|
||||
}
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> lookup(const simd8x64<uint8_t>& keys) const noexcept { return lookup_low(keys.shr<4>()); }
|
||||
/** Look up the value corresponding the higher 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> operator[](const simd8x64<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
|
||||
simdjson_consteval uint8_t operator[](uint8_t key) const noexcept { return lookup(key); }
|
||||
simdjson_consteval uint8_t lookup(uint8_t key) const noexcept { return table[key >> 4]; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte lookup table where the key is the low 4 bits of the input, and the value is an
|
||||
* arbitrary byte.
|
||||
*
|
||||
* - Unmatched values yield 0.
|
||||
* - Multiple keys may yield the same value.
|
||||
* - Multiple bytes with the same low 4 bits may NOT yield different values.
|
||||
*
|
||||
* ```
|
||||
* enum ops_t : uint8_t {
|
||||
* COMMA = 1,
|
||||
* COLON = 2,
|
||||
* BRACKET = 3,
|
||||
* CURLY = 4
|
||||
* };
|
||||
* static constinit const high_nibble_lookup OPS(
|
||||
* {',', COMMA},
|
||||
* {':', COLON},
|
||||
* {'[', BRACKET},
|
||||
* {']', BRACKET},
|
||||
* {'{', CURLY},
|
||||
* {'}', CURLY}
|
||||
* );
|
||||
* simd8<uint8_t> lookup_ops(simd8<uint8_t>& operators) { return OPS[operators]; }
|
||||
* ```
|
||||
*/
|
||||
struct low_nibble_lookup {
|
||||
const simd8_buffer<uint8_t> table;
|
||||
|
||||
/**
|
||||
* Construct a nibble lookup table from the low bits of the input to the output.
|
||||
*
|
||||
* @param entries A list of {key, value} pairs (e.g. {'a', 0}).
|
||||
* @error asserts if multiple keys have the same low 4 bits but different values.
|
||||
*/
|
||||
simdjson_consteval low_nibble_lookup(std::initializer_list<_lookup_entry> entries) noexcept
|
||||
: table{_make_nibble_lookup_table(entries, 0)} {}
|
||||
simdjson_consteval low_nibble_lookup(const simd8_buffer<uint8_t>& table) noexcept : table(table) {}
|
||||
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> operator[](const simd8<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8<uint8_t> lookup(const simd8<uint8_t>& keys) const noexcept {
|
||||
return keys.lookup_low_nibble_ascii(table);
|
||||
}
|
||||
/**
|
||||
* Look up the value in the table. Behavior is system-dependent for indexes greater than 16.
|
||||
*
|
||||
* - On some platforms like arm64, indexes greater than 16 will not match anything in the table.
|
||||
* - On platforms like Intel, index bits 4-6 will be ignored, but if the high bit is set, it
|
||||
* will not match anything in the table. greater than 16 will be ignored, *except* if the high bit is 1,
|
||||
*/
|
||||
simdjson_inline simd8<uint8_t> lookup_unsafe(const simd8<uint8_t>& keys) const noexcept {
|
||||
return keys.lookup_16(table);
|
||||
}
|
||||
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> operator[](const simd8x64<uint8_t>& keys) const noexcept { return lookup(keys); }
|
||||
/** Look up the value corresponding the lower 4 bits of each input byte, and return it. */
|
||||
simdjson_inline simd8x64<uint8_t> lookup(const simd8x64<uint8_t>& keys) const noexcept {
|
||||
return keys.lookup_low_nibble_ascii(table);
|
||||
}
|
||||
/**
|
||||
* Look up the value in the table. Behavior is system-dependent for indexes greater than 16.
|
||||
*
|
||||
* - On some platforms like arm64, indexes greater than 16 will not match anything in the table.
|
||||
* - On platforms like Intel, index bits 4-6 will be ignored, but if the high bit is set, it
|
||||
* will not match anything in the table. greater than 16 will be ignored, *except* if the high bit is 1,
|
||||
*/
|
||||
simdjson_inline simd8x64<uint8_t> lookup_unsafe(const simd8x64<uint8_t>& low_keys) const noexcept {
|
||||
return low_keys.lookup_16(table);
|
||||
}
|
||||
|
||||
simdjson_consteval uint8_t operator[](uint8_t key) const noexcept { return lookup(key); }
|
||||
simdjson_consteval uint8_t lookup(uint8_t key) const noexcept { return table[key & 0x0F]; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Classifies bytes by looking up their lower 4 bits, then their high 4 bits, and &'ing the
|
||||
* results together.
|
||||
*
|
||||
* Pass the bytes you want to match, and the classifications you want for them.
|
||||
*/
|
||||
struct byte_classifier {
|
||||
const low_nibble_lookup low;
|
||||
const high_nibble_lookup high;
|
||||
simdjson_consteval byte_classifier(std::initializer_list<_lookup_entry> entries)
|
||||
: low{entries}, high{entries} {}
|
||||
|
||||
simdjson_inline simd8<uint8_t> classify(const simd8<uint8_t>& bytes) const noexcept {
|
||||
return low.lookup(bytes) & high.lookup(bytes);
|
||||
}
|
||||
simdjson_inline simd8x64<uint8_t> classify(const simd8x64<uint8_t>& bytes) const noexcept {
|
||||
auto low_lookup = low.lookup(bytes); // 3 (+simd:N)
|
||||
auto high_lookup = high.lookup(bytes); // 6 (+simd:2N)
|
||||
return low_lookup & high_lookup; // 3 (+simd:N)
|
||||
// critical path: 9 (+simd:4N)
|
||||
}
|
||||
simdjson_consteval uint8_t classify(uint8_t byte) const noexcept {
|
||||
return low.lookup(byte) & high.lookup(byte);
|
||||
}
|
||||
|
||||
simdjson_inline simd8<uint8_t> operator[](const simd8<uint8_t>& bytes) const noexcept { return classify(bytes); }
|
||||
simdjson_inline simd8x64<uint8_t> operator[](const simd8x64<uint8_t>& bytes) const noexcept { return classify(bytes); }
|
||||
simdjson_consteval uint8_t operator[](uint8_t byte) const noexcept { return classify(byte); }
|
||||
|
||||
simdjson_inline bool matches_correctly(std::initializer_list<_lookup_entry> entries) const noexcept {
|
||||
uint8_t expected_output[256] = {};
|
||||
for (auto entry : entries) {
|
||||
for (uint8_t byte : entry) {
|
||||
expected_output[byte] |= entry.value;
|
||||
}
|
||||
}
|
||||
for (uint8_t byte = 0; byte <= 0xFF; byte++) {
|
||||
if (expected_output[byte] != classify(byte)) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace simd
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SIMD_LOOKUP_TABLE_H
|
||||
@@ -143,7 +143,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
|
||||
|
||||
// We want the most significant bit of i to be 1. Shift if needed.
|
||||
int lz = leading_zeroes(i);
|
||||
int lz = bitmask::leading_zeroes(i);
|
||||
i <<= lz;
|
||||
|
||||
|
||||
@@ -186,7 +186,8 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// power_of_five_128[index]. Usually, that's good enough to approximate i * 5^q
|
||||
// to the desired approximation using one multiplication. Sometimes it does not suffice.
|
||||
// Then we store the next most significant 64 bits in power_of_five_128[index + 1], and
|
||||
// then we get a better approximation to i * 5^q.
|
||||
// then we get a better approximation to i * 5^q. In very rare cases, even that
|
||||
// will not suffice, though it is seemingly very hard to find such a scenario.
|
||||
//
|
||||
// That's for when q>=0. The logic for q<0 is somewhat similar but it is somewhat
|
||||
// more complicated.
|
||||
@@ -201,9 +202,12 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
simdjson::internal::value128 secondproduct = full_multiplication(i, simdjson::internal::power_of_five_128[index + 1]);
|
||||
firstproduct.low += secondproduct.high;
|
||||
if(secondproduct.high > firstproduct.low) { firstproduct.high++; }
|
||||
// As it has been proven by Noble Mushtak and Daniel Lemire in "Fast Number Parsing Without
|
||||
// Fallback" (https://arxiv.org/abs/2212.06644), at this point we are sure that the product
|
||||
// is sufficiently accurate, and more computation is not needed.
|
||||
// At this point, we might need to add at most one to firstproduct, but this
|
||||
// can only change the value of firstproduct.high if firstproduct.low is maximal.
|
||||
if(simdjson_unlikely(firstproduct.low == 0xFFFFFFFFFFFFFFFF)) {
|
||||
// This is very unlikely, but if so, we need to do much more work!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint64_t lower = firstproduct.low;
|
||||
uint64_t upper = firstproduct.high;
|
||||
@@ -446,8 +450,11 @@ simdjson_inline size_t significant_digits(const uint8_t * start_digits, size_t d
|
||||
} // unnamed namespace
|
||||
|
||||
/** @private */
|
||||
static error_code slow_float_parsing(simdjson_unused const uint8_t * src, double* answer) {
|
||||
if (parse_float_fallback(src, answer)) {
|
||||
template<typename W>
|
||||
error_code slow_float_parsing(simdjson_unused const uint8_t * src, W writer) {
|
||||
double d;
|
||||
if (parse_float_fallback(src, &d)) {
|
||||
writer.append_double(d);
|
||||
return SUCCESS;
|
||||
}
|
||||
return INVALID_NUMBER(src);
|
||||
@@ -471,13 +478,13 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative,
|
||||
// 10000000000000000000000000000000000000000000e+308
|
||||
// 3.1415926535897932384626433832795028841971693993751
|
||||
//
|
||||
// NOTE: We do not pass a reference to the to slow_float_parsing. If we passed our writer
|
||||
// reference to it, it would force it to be stored in memory, preventing the compiler from
|
||||
// picking it apart and putting into registers. i.e. if we pass it as reference,
|
||||
// it gets slow.
|
||||
double d;
|
||||
error_code error = slow_float_parsing(src, &d);
|
||||
writer.append_double(d);
|
||||
// NOTE: This makes a *copy* of the writer and passes it to slow_float_parsing. This happens
|
||||
// because slow_float_parsing is a non-inlined function. If we passed our writer reference to
|
||||
// it, it would force it to be stored in memory, preventing the compiler from picking it apart
|
||||
// and putting into registers. i.e. if we pass it as reference, it gets slow.
|
||||
// This is what forces the skip_double, as well.
|
||||
error_code error = slow_float_parsing(src, writer);
|
||||
writer.skip_double();
|
||||
return error;
|
||||
}
|
||||
// NOTE: it's weird that the simdjson_unlikely() only wraps half the if, but it seems to get slower any other
|
||||
@@ -1001,7 +1008,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
|
||||
// Skip leading 0.00000 and see if it still overflows
|
||||
const uint8_t *start_digits = src + 2;
|
||||
while (*start_digits == '0') { start_digits++; }
|
||||
overflow = p-start_digits > 19;
|
||||
overflow = start_digits-src > 19;
|
||||
}
|
||||
} else {
|
||||
overflow = p-src > 19;
|
||||
@@ -1200,7 +1207,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
|
||||
// Skip leading 0.00000 and see if it still overflows
|
||||
const uint8_t *start_digits = src + 2;
|
||||
while (*start_digits == '0') { start_digits++; }
|
||||
overflow = p-start_digits > 19;
|
||||
overflow = start_digits-src > 19;
|
||||
}
|
||||
} else {
|
||||
overflow = p-src > 19;
|
||||
|
||||
@@ -68,17 +68,7 @@ simdjson_inline simdjson_result<object> document::start_or_resume_object() noexc
|
||||
simdjson_inline simdjson_result<value> document::get_value() noexcept {
|
||||
// Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
|
||||
// gets called.
|
||||
|
||||
// It is the convention throughout the code that the macro `SIMDJSON_DEVELOPMENT_CHECKS` determines whether
|
||||
// we check for OUT_OF_ORDER_ITERATION. Proper on::demand code should never trigger this error.
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
if (!iter.at_root()) { return OUT_OF_ORDER_ITERATION; }
|
||||
#endif
|
||||
// assert_at_root() serves two purposes: in Debug mode, whether or not
|
||||
// SIMDJSON_DEVELOPMENT_CHECKS is set or not, it checks that we are at the root of
|
||||
// the document (this will typically be redundant). In release mode, it generates
|
||||
// SIMDJSON_ASSUME statements to allow the compiler to make assumptions.
|
||||
iter.assert_at_root();
|
||||
iter.assert_at_document_depth();
|
||||
switch (*iter.peek()) {
|
||||
case '[': {
|
||||
// The following lines check that the document ends with ].
|
||||
@@ -138,10 +128,6 @@ simdjson_inline simdjson_result<double> document::get_double_in_string() noexcep
|
||||
simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
|
||||
return get_root_value_iterator().get_root_string(true, allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
|
||||
return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
|
||||
return get_root_value_iterator().get_root_wobbly_string(true);
|
||||
}
|
||||
@@ -411,11 +397,6 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(receiver, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_wobbly_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_wobbly_string();
|
||||
@@ -602,8 +583,6 @@ simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string
|
||||
simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||
simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
|
||||
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
|
||||
@@ -740,11 +719,6 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(receiver, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_wobbly_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_wobbly_string();
|
||||
|
||||
@@ -100,21 +100,6 @@ public:
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
/**
|
||||
* Attempts to fill the provided std::string reference with the parsed value of the current string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8.
|
||||
*
|
||||
* Important: a value should be consumed once. Calling get_string() twice on the same value
|
||||
* is an error.
|
||||
*
|
||||
* Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
|
||||
* We recommend you avoid allocating an std::string unless you need to.
|
||||
*
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
|
||||
*/
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
@@ -146,12 +131,6 @@ public:
|
||||
/**
|
||||
* Cast this JSON value to a value when the document is an object or an array.
|
||||
*
|
||||
* You must not have begun iterating through the object or array. When
|
||||
* SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode
|
||||
* by default), and you have already begun iterating,
|
||||
* you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
|
||||
* rewind() to reset the document to its initial state before calling this method.
|
||||
*
|
||||
* @returns A value if a JSON array or object cannot be found.
|
||||
* @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
|
||||
*/
|
||||
@@ -181,19 +160,13 @@ public:
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template.");
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
/** @overload template<typename T> simdjson_result<T> get() & noexcept */
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template.");
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,15 +247,10 @@ public:
|
||||
*/
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a value when the document is an object or an array.
|
||||
* Cast this JSON value to a value.
|
||||
*
|
||||
* You must not have begun iterating through the object or array. When
|
||||
* SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating,
|
||||
* you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use
|
||||
* rewind() to reset the document to its initial state before calling this method.
|
||||
*
|
||||
* @returns A value value if a JSON array or object cannot be found.
|
||||
* @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
|
||||
* @returns A value value.
|
||||
* @exception if a JSON value cannot be found
|
||||
*/
|
||||
simdjson_inline operator value() noexcept(false);
|
||||
#endif
|
||||
@@ -650,8 +618,6 @@ public:
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
@@ -721,8 +687,6 @@ public:
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
@@ -795,8 +759,6 @@ public:
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
|
||||
@@ -241,7 +241,8 @@ private:
|
||||
* Parse the next document found in the buffer previously given to document_stream.
|
||||
*
|
||||
* The content should be a valid JSON document encoded as UTF-8. If there is a
|
||||
* UTF-8 BOM, the parser skips it.
|
||||
* UTF-8 BOM, the caller is responsible for omitting it, UTF-8 BOM are
|
||||
* discouraged.
|
||||
*
|
||||
* You do NOT need to pre-allocate a parser. This function takes care of
|
||||
* pre-allocating a capacity defined by the batch_size defined when creating the
|
||||
|
||||
@@ -101,10 +101,6 @@ simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_
|
||||
case '[': case '{': case ':':
|
||||
logger::log_start_value(*this, "skip");
|
||||
break;
|
||||
// If there is a comma, we have just finished a value in an array/object, and need to get back in
|
||||
case ',':
|
||||
logger::log_value(*this, "skip");
|
||||
break;
|
||||
// ] or } means we just finished a value and need to jump out of the array/object
|
||||
case ']': case '}':
|
||||
logger::log_end_value(*this, "skip");
|
||||
|
||||
@@ -254,7 +254,6 @@ public:
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
|
||||
|
||||
simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
|
||||
|
||||
simdjson_inline error_code consume_character(char c) noexcept;
|
||||
|
||||
@@ -92,6 +92,8 @@ protected:
|
||||
*/
|
||||
friend class value_iterator;
|
||||
template<typename W>
|
||||
friend error_code numberparsing::slow_float_parsing(simdjson_unused const uint8_t * src, W writer);
|
||||
template<typename W>
|
||||
friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
|
||||
template<typename W>
|
||||
friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
|
||||
|
||||
@@ -46,8 +46,6 @@ simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capa
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
|
||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
||||
|
||||
json.remove_utf8_bom();
|
||||
|
||||
// Allocate if needed
|
||||
if (capacity() < json.length() || !string_buf) {
|
||||
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
|
||||
@@ -70,13 +68,6 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(s
|
||||
return iterate(padded_string_view(json, allocated));
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
|
||||
if(json.capacity() - json.size() < SIMDJSON_PADDING) {
|
||||
json.reserve(json.size() + SIMDJSON_PADDING);
|
||||
}
|
||||
return iterate(padded_string_view(json));
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
|
||||
return iterate(padded_string_view(json));
|
||||
}
|
||||
@@ -98,8 +89,6 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(c
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
|
||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
||||
|
||||
json.remove_utf8_bom();
|
||||
|
||||
// Allocate if needed
|
||||
if (capacity() < json.length()) {
|
||||
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
|
||||
@@ -112,10 +101,6 @@ simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iter
|
||||
|
||||
inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
|
||||
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
||||
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
|
||||
buf += 3;
|
||||
len -= 3;
|
||||
}
|
||||
if(allow_comma_separated && batch_size < len) { batch_size = len; }
|
||||
return document_stream(*this, buf, len, batch_size, allow_comma_separated);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
|
||||
* Otherwise the iterate method may return an error. In particular, the whole input should be
|
||||
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
|
||||
* document. If there is a UTF-8 BOM, the parser skips it.
|
||||
* document.
|
||||
*
|
||||
* ### IMPORTANT: Validate what you use
|
||||
*
|
||||
@@ -107,8 +107,6 @@ public:
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(std::string &json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
|
||||
@@ -188,7 +186,6 @@ public:
|
||||
* arrays or objects) MUST be separated with ASCII whitespace.
|
||||
*
|
||||
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
|
||||
* If there is a UTF-8 BOM, the parser skips it.
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||
|
||||
@@ -47,10 +47,6 @@ simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() no
|
||||
simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
|
||||
return iter.get_string(allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
|
||||
return iter.get_string(receiver, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
|
||||
return iter.get_wobbly_string();
|
||||
}
|
||||
@@ -197,26 +193,6 @@ simdjson_inline std::string_view value::raw_json_token() noexcept {
|
||||
return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> value::raw_json() noexcept {
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
switch (t)
|
||||
{
|
||||
case json_type::array: {
|
||||
ondemand::array array;
|
||||
SIMDJSON_TRY(get_array().get(array));
|
||||
return array.raw_json();
|
||||
}
|
||||
case json_type::object: {
|
||||
ondemand::object object;
|
||||
SIMDJSON_TRY(get_object().get(object));
|
||||
return object.raw_json();
|
||||
}
|
||||
default:
|
||||
return raw_json_token();
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
|
||||
return iter.json_iter().current_location();
|
||||
}
|
||||
@@ -343,11 +319,6 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(receiver, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_wobbly_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_wobbly_string();
|
||||
@@ -448,11 +419,6 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
|
||||
return first.raw_json_token();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::raw_json() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_location() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_location();
|
||||
|
||||
@@ -38,10 +38,7 @@ public:
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template.");
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,21 +132,6 @@ public:
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
|
||||
/**
|
||||
* Attempts to fill the provided std::string reference with the parsed value of the current string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8.
|
||||
*
|
||||
* Important: a value should be consumed once. Calling get_string() twice on the same value
|
||||
* is an error.
|
||||
*
|
||||
* Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory.
|
||||
* We recommend you avoid allocating an std::string unless you need to.
|
||||
*
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
|
||||
*/
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a "wobbly" string.
|
||||
@@ -493,21 +475,9 @@ public:
|
||||
* - true
|
||||
* - false
|
||||
* - null
|
||||
*
|
||||
* See also value::raw_json().
|
||||
*/
|
||||
simdjson_inline std::string_view raw_json_token() noexcept;
|
||||
|
||||
/**
|
||||
* Get a string_view pointing at this value in the JSON document.
|
||||
* If this element is an array or an object, it consumes the array or the object
|
||||
* and returns a string_view instance corresponding to the
|
||||
* array as represented in JSON. It points inside the original document.
|
||||
* If this element is a scalar (string, number, Boolean, null), it returns what
|
||||
* raw_json_token() would return.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current location in the document if in bounds.
|
||||
*/
|
||||
@@ -632,8 +602,6 @@ public:
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
template <typename string_type>
|
||||
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
@@ -726,7 +694,6 @@ public:
|
||||
|
||||
/** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
@@ -97,16 +97,12 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_n
|
||||
|
||||
// It's illegal to call this unless there are more tokens: anything that ends in } or ] is
|
||||
// obligated to verify there are more tokens if they are not the top level.
|
||||
switch (*_json_iter->return_current_and_advance()) {
|
||||
case '}':
|
||||
logger::log_end_value(*_json_iter, "object");
|
||||
SIMDJSON_TRY( end_container() );
|
||||
return false;
|
||||
case ',':
|
||||
return true;
|
||||
default:
|
||||
return report_error(TAPE_ERROR, "Missing comma between object fields");
|
||||
if (_json_iter->consume_character('}')) {
|
||||
logger::log_end_value(*_json_iter, "object");
|
||||
SIMDJSON_TRY( end_container() );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
|
||||
@@ -483,16 +479,13 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::has_n
|
||||
assert_at_next();
|
||||
|
||||
logger::log_event(*this, "has_next_element");
|
||||
switch (*_json_iter->return_current_and_advance()) {
|
||||
case ']':
|
||||
if (_json_iter->consume_character(']')) {
|
||||
logger::log_end_value(*_json_iter, "array");
|
||||
SIMDJSON_TRY( end_container() );
|
||||
return false;
|
||||
case ',':
|
||||
_json_iter->descend_to(depth()+1);
|
||||
return true;
|
||||
default:
|
||||
return report_error(TAPE_ERROR, "Missing comma between array elements");
|
||||
} else {
|
||||
_json_iter->descend_to(depth()+1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,14 +506,6 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
|
||||
return get_raw_json_string().unescape(json_iter(), allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
|
||||
std::string_view content;
|
||||
auto err = get_string(allow_replacement).get(content);
|
||||
if (err) { return err; }
|
||||
receiver = content;
|
||||
return SUCCESS;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
|
||||
return get_raw_json_string().unescape_wobbly(json_iter());
|
||||
}
|
||||
@@ -644,14 +629,6 @@ simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool che
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
|
||||
return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
|
||||
}
|
||||
template <typename string_type>
|
||||
simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
|
||||
std::string_view content;
|
||||
auto err = get_root_string(check_trailing, allow_replacement).get(content);
|
||||
if (err) { return err; }
|
||||
receiver = content;
|
||||
return SUCCESS;
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
|
||||
return get_root_raw_json_string(check_trailing).unescape_wobbly(json_iter());
|
||||
}
|
||||
|
||||
@@ -296,8 +296,6 @@ public:
|
||||
*/
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
|
||||
template <typename string_type>
|
||||
simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
@@ -314,9 +312,7 @@ public:
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
|
||||
template <typename string_type>
|
||||
simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "simdjson/haswell/begin.h"
|
||||
#include "simdjson/generic/amalgamated.h"
|
||||
#include "simdjson/generic/lookup_table.h"
|
||||
#include "simdjson/haswell/end.h"
|
||||
|
||||
#endif // SIMDJSON_HASWELL_H
|
||||
@@ -14,12 +14,14 @@ namespace haswell {
|
||||
|
||||
class implementation;
|
||||
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
template <typename T> struct simd8;
|
||||
template <> struct simd8<bool>;
|
||||
template <> struct simd8<uint8_t>;
|
||||
template <typename T> struct simd8x64;
|
||||
|
||||
} // namespace simd
|
||||
} // unnamed namespace
|
||||
|
||||
} // namespace haswell
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
|
||||
#endif
|
||||
|
||||
#include "simdjson/haswell/bitmanipulation.h"
|
||||
#include "simdjson/haswell/bitmask.h"
|
||||
#include "simdjson/haswell/bitmask.h"
|
||||
#include "simdjson/haswell/numberparsing_defs.h"
|
||||
#include "simdjson/haswell/simd.h"
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#ifndef SIMDJSON_HASWELL_BITMANIPULATION_H
|
||||
#define SIMDJSON_HASWELL_BITMANIPULATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/haswell/base.h"
|
||||
#include "simdjson/haswell/intrinsics.h"
|
||||
#include "simdjson/haswell/bitmask.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace haswell {
|
||||
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
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#if 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_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_inline int leading_zeroes(uint64_t input_num) {
|
||||
return int(_lzcnt_u64(input_num));
|
||||
}
|
||||
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||
// note: we do not support legacy 32-bit Windows in this kernel
|
||||
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||
}
|
||||
#else
|
||||
simdjson_inline long long int count_ones(uint64_t input_num) {
|
||||
return _popcnt64(input_num);
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||
uint64_t *result) {
|
||||
#if 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 haswell
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_HASWELL_BITMANIPULATION_H
|
||||
@@ -8,14 +8,99 @@
|
||||
|
||||
namespace simdjson {
|
||||
namespace haswell {
|
||||
namespace {
|
||||
namespace bitmask {
|
||||
|
||||
simdjson_constinit uint64_t ALL = 0xFFFFFFFFFFFFFFFF;
|
||||
simdjson_constinit uint64_t NONE = 0xFFFFFFFFFFFFFFFF;
|
||||
simdjson_constinit uint64_t EVEN = 0x5555555555555555;
|
||||
simdjson_constinit uint64_t ODD = 0xAAAAAAAAAAAAAAAA;
|
||||
|
||||
// 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
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#if 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_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_inline int leading_zeroes(uint64_t input_num) {
|
||||
return int(_lzcnt_u64(input_num));
|
||||
}
|
||||
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) {
|
||||
// note: we do not support legacy 32-bit Windows in this kernel
|
||||
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||
}
|
||||
#else
|
||||
simdjson_inline long long int count_ones(uint64_t input_num) {
|
||||
return _popcnt64(input_num);
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline uint64_t add_carry_out(const uint64_t value1, const uint64_t value2, bool& carry_out) noexcept {
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned __int64 result;
|
||||
carry_out = _addcarry_u64(0, value1, value2, &result);
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
carry_out = __builtin_uaddll_overflow(value1, value2, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow(const uint64_t value1, const uint64_t value2, bool& borrow) noexcept {
|
||||
// TODO only do this on GCC, not clang
|
||||
// #if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
// unsigned __int64 result;
|
||||
// borrow = _subborrow_u64(borrow, value1, value2, &result);
|
||||
// return result;
|
||||
// #else
|
||||
unsigned long long result;
|
||||
bool borrow1 = __builtin_usubll_overflow(value1, value2, &result);
|
||||
borrow = borrow1 | __builtin_usubll_overflow(result, borrow, &result);
|
||||
return result;
|
||||
// #endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow_out(const uint64_t value1, const int64_t value2, bool& borrow_out) noexcept {
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned __int64 result;
|
||||
borrow_out = _subborrow_u64(0, value1, value2, &result);
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
borrow_out = __builtin_usubll_overflow(value1, value2, &result); // 2 (one to set )
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
|
||||
//
|
||||
// For example, prefix_xor(00100100) == 00011100
|
||||
//
|
||||
simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
|
||||
simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) noexcept {
|
||||
// There should be no such thing with a processor supporting avx2
|
||||
// but not clmul.
|
||||
__m128i all_ones = _mm_set1_epi8('\xFF');
|
||||
@@ -23,7 +108,7 @@ simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
|
||||
return _mm_cvtsi128_si64(result);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace bitmask
|
||||
} // namespace haswell
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+157
-57
@@ -4,29 +4,30 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/haswell/base.h"
|
||||
#include "simdjson/haswell/intrinsics.h"
|
||||
#include "simdjson/haswell/bitmanipulation.h"
|
||||
#include "simdjson/haswell/bitmask.h"
|
||||
#include "simdjson/internal/simdprune_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace haswell {
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
// Forward-declared so they can be used by splat and friends.
|
||||
template<typename Child>
|
||||
struct base {
|
||||
__m256i value;
|
||||
/** The actual underlying system SIMD type. */
|
||||
using simd_t = __m256i;
|
||||
simd_t value;
|
||||
|
||||
// Zero constructor
|
||||
simdjson_inline base() : value{__m256i()} {}
|
||||
simdjson_inline base() : value{simd_t()} {}
|
||||
|
||||
// Conversion from SIMD register
|
||||
simdjson_inline base(const __m256i _value) : value(_value) {}
|
||||
simdjson_inline base(const simd_t _value) : value(_value) {}
|
||||
|
||||
// Conversion to SIMD register
|
||||
simdjson_inline operator const __m256i&() const { return this->value; }
|
||||
simdjson_inline operator __m256i&() { return this->value; }
|
||||
simdjson_inline operator const simd_t&() const { return this->value; }
|
||||
simdjson_inline operator simd_t&() { return this->value; }
|
||||
|
||||
// Bit operations
|
||||
simdjson_inline Child operator|(const Child other) const { return _mm256_or_si256(*this, other); }
|
||||
@@ -44,15 +45,16 @@ namespace simd {
|
||||
|
||||
template<typename T, typename Mask=simd8<bool>>
|
||||
struct base8: base<simd8<T>> {
|
||||
typedef uint32_t bitmask_t;
|
||||
typedef uint64_t bitmask2_t;
|
||||
using typename base<simd8<T>>::simd_t;
|
||||
static constexpr const int LANES = sizeof(simd_t);
|
||||
using bitmask_t = uint32_t;
|
||||
static_assert(sizeof(bitmask_t)*8 == LANES, "Bitmask type's bits must equal the simd type's bytes");
|
||||
|
||||
simdjson_inline base8() : base<simd8<T>>() {}
|
||||
simdjson_inline base8(const __m256i _value) : base<simd8<T>>(_value) {}
|
||||
simdjson_inline base8(const simd_t _value) : base<simd8<T>>(_value) {}
|
||||
|
||||
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return _mm256_cmpeq_epi8(lhs, rhs); }
|
||||
|
||||
static const int SIZE = sizeof(base<T>::value);
|
||||
simdjson_inline Mask eq(const simd8<T> rhs) const { return _mm256_cmpeq_epi8(*this, rhs); }
|
||||
friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return lhs.eq(rhs); }
|
||||
|
||||
template<int N=1>
|
||||
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||
@@ -66,7 +68,7 @@ namespace simd {
|
||||
static simdjson_inline simd8<bool> splat(bool _value) { return _mm256_set1_epi8(uint8_t(-(!!_value))); }
|
||||
|
||||
simdjson_inline simd8<bool>() : base8() {}
|
||||
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
|
||||
simdjson_inline simd8<bool>(const simd_t _value) : base8<bool>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
|
||||
|
||||
@@ -77,10 +79,12 @@ namespace simd {
|
||||
|
||||
template<typename T>
|
||||
struct base8_numeric: base8<T> {
|
||||
using typename base8<T>::simd_t;
|
||||
using base8<T>::LANES;
|
||||
static simdjson_inline simd8<T> splat(T _value) { return _mm256_set1_epi8(_value); }
|
||||
static simdjson_inline simd8<T> zero() { return _mm256_setzero_si256(); }
|
||||
static simdjson_inline simd8<T> load(const T values[32]) {
|
||||
return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(values));
|
||||
return _mm256_loadu_si256(reinterpret_cast<const simd_t *>(values));
|
||||
}
|
||||
// Repeat 16 values as many times as necessary (usually for lookup tables)
|
||||
static simdjson_inline simd8<T> repeat_16(
|
||||
@@ -96,10 +100,10 @@ namespace simd {
|
||||
}
|
||||
|
||||
simdjson_inline base8_numeric() : base8<T>() {}
|
||||
simdjson_inline base8_numeric(const __m256i _value) : base8<T>(_value) {}
|
||||
simdjson_inline base8_numeric(const simd_t _value) : base8<T>(_value) {}
|
||||
|
||||
// Store to array
|
||||
simdjson_inline void store(T dst[32]) const { return _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst), *this); }
|
||||
simdjson_inline void store(T dst[32]) const { return _mm256_storeu_si256(reinterpret_cast<simd_t *>(dst), *this); }
|
||||
|
||||
// Addition/subtraction are the same for signed and unsigned
|
||||
simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm256_add_epi8(*this, other); }
|
||||
@@ -111,14 +115,18 @@ namespace simd {
|
||||
simdjson_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_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||
simdjson_inline simd8<T> lookup_16(const simd8<T>& lookup_table) const {
|
||||
return _mm256_shuffle_epi8(lookup_table, *this);
|
||||
}
|
||||
// Perform a lookup based on the lower 4 bits of each lane. (Platform-dependent behavior for
|
||||
// non-ASCII values--may look up the lower 4 bits on some platforms, and return 0 on others.)
|
||||
simdjson_inline simd8<T> lookup_low_nibble_ascii(const simd8<T>& lookup_table) const {
|
||||
return lookup_16(lookup_table);
|
||||
}
|
||||
|
||||
// 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
|
||||
// Only the first 32 - bitmask::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
|
||||
@@ -137,14 +145,14 @@ namespace simd {
|
||||
// next line just loads the 64-bit values thintable_epi8[mask1] and
|
||||
// thintable_epi8[mask2] into a 128-bit register, using only
|
||||
// two instructions on most compilers.
|
||||
__m256i shufmask = _mm256_set_epi64x(thintable_epi8[mask4], thintable_epi8[mask3],
|
||||
simd_t shufmask = _mm256_set_epi64x(thintable_epi8[mask4], thintable_epi8[mask3],
|
||||
thintable_epi8[mask2], thintable_epi8[mask1]);
|
||||
// we increment by 0x08 the second half of the mask and so forth
|
||||
shufmask =
|
||||
_mm256_add_epi8(shufmask, _mm256_set_epi32(0x18181818, 0x18181818,
|
||||
0x10101010, 0x10101010, 0x08080808, 0x08080808, 0, 0));
|
||||
// this is the version "nearly pruned"
|
||||
__m256i pruned = _mm256_shuffle_epi8(*this, shufmask);
|
||||
simd_t pruned = _mm256_shuffle_epi8(*this, shufmask);
|
||||
// we still need to put the pieces back together.
|
||||
// we compute the popcount of the first words:
|
||||
int pop1 = BitsSetTable256mul2[mask1];
|
||||
@@ -152,35 +160,20 @@ namespace simd {
|
||||
|
||||
// then load the corresponding mask
|
||||
// could be done with _mm256_loadu2_m128i but many standard libraries omit this intrinsic.
|
||||
__m256i v256 = _mm256_castsi128_si256(
|
||||
simd_t v256 = _mm256_castsi128_si256(
|
||||
_mm_loadu_si128(reinterpret_cast<const __m128i *>(pshufb_combine_table + pop1 * 8)));
|
||||
__m256i compactmask = _mm256_insertf128_si256(v256,
|
||||
simd_t compactmask = _mm256_insertf128_si256(v256,
|
||||
_mm_loadu_si128(reinterpret_cast<const __m128i *>(pshufb_combine_table + pop3 * 8)), 1);
|
||||
__m256i almostthere = _mm256_shuffle_epi8(pruned, compactmask);
|
||||
simd_t almostthere = _mm256_shuffle_epi8(pruned, compactmask);
|
||||
// We just need to write out the result.
|
||||
// This is the tricky bit that is hard to do
|
||||
// if we want to return a SIMD register, since there
|
||||
// is no single-instruction approach to recombine
|
||||
// the two 128-bit lanes with an offset.
|
||||
__m128i v128;
|
||||
v128 = _mm256_castsi256_si128(almostthere);
|
||||
__m128i v128 = _mm256_castsi256_si128(almostthere);
|
||||
_mm_storeu_si128( reinterpret_cast<__m128i *>(output), v128);
|
||||
v128 = _mm256_extractf128_si256(almostthere, 1);
|
||||
_mm_storeu_si128( reinterpret_cast<__m128i *>(output + 16 - count_ones(mask & 0xFFFF)), v128);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
simdjson_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
|
||||
));
|
||||
_mm_storeu_si128( reinterpret_cast<__m128i *>(output + 16 - bitmask::count_ones(mask & 0xFFFF)), v128);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -188,7 +181,7 @@ namespace simd {
|
||||
template<>
|
||||
struct simd8<int8_t> : base8_numeric<int8_t> {
|
||||
simdjson_inline simd8() : base8_numeric<int8_t>() {}
|
||||
simdjson_inline simd8(const __m256i _value) : base8_numeric<int8_t>(_value) {}
|
||||
simdjson_inline simd8(const simd_t _value) : base8_numeric<int8_t>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
|
||||
// Array constructor
|
||||
@@ -229,7 +222,7 @@ namespace simd {
|
||||
template<>
|
||||
struct simd8<uint8_t>: base8_numeric<uint8_t> {
|
||||
simdjson_inline simd8() : base8_numeric<uint8_t>() {}
|
||||
simdjson_inline simd8(const __m256i _value) : base8_numeric<uint8_t>(_value) {}
|
||||
simdjson_inline simd8(const simd_t _value) : base8_numeric<uint8_t>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
|
||||
// Array constructor
|
||||
@@ -307,13 +300,15 @@ namespace simd {
|
||||
|
||||
simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
|
||||
simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+32)} {}
|
||||
simdjson_inline simd8x64(simd8x64<T>&& o) noexcept = default;
|
||||
simdjson_inline simd8x64<T>& operator=(simd8x64<T>&& other) noexcept = default;
|
||||
|
||||
simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
|
||||
uint32_t mask1 = uint32_t(mask);
|
||||
uint32_t mask2 = uint32_t(mask >> 32);
|
||||
this->chunks[0].compress(mask1, output);
|
||||
this->chunks[1].compress(mask2, output + 32 - count_ones(mask1));
|
||||
return 64 - count_ones(mask);
|
||||
this->chunks[1].compress(mask2, output + 32 - bitmask::count_ones(mask1));
|
||||
return 64 - bitmask::count_ones(mask);
|
||||
}
|
||||
|
||||
simdjson_inline void store(T ptr[64]) const {
|
||||
@@ -323,7 +318,7 @@ namespace simd {
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const {
|
||||
uint64_t r_lo = uint32_t(this->chunks[0].to_bitmask());
|
||||
uint64_t r_hi = this->chunks[1].to_bitmask();
|
||||
uint64_t r_hi = this->chunks[1].to_bitmask();
|
||||
return r_lo | (r_hi << 32);
|
||||
}
|
||||
|
||||
@@ -331,14 +326,6 @@ namespace simd {
|
||||
return this->chunks[0] | this->chunks[1];
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_or(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return simd8x64<T>(
|
||||
this->chunks[0] | mask,
|
||||
this->chunks[1] | mask
|
||||
);
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t eq(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return simd8x64<bool>(
|
||||
@@ -347,13 +334,27 @@ namespace simd {
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
|
||||
simdjson_inline uint64_t eq(const simd8x64<T> &other) const {
|
||||
return simd8x64<bool>(
|
||||
this->chunks[0] == other.chunks[0],
|
||||
this->chunks[1] == other.chunks[1]
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_16(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_16(lookup_table),
|
||||
this->chunks[1].lookup_16(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_low_nibble_ascii(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_low_nibble_ascii(lookup_table),
|
||||
this->chunks[1].lookup_low_nibble_ascii(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t lteq(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return simd8x64<bool>(
|
||||
@@ -361,11 +362,110 @@ namespace simd {
|
||||
this->chunks[1] <= mask
|
||||
).to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other.chunks[0],
|
||||
this->chunks[1] & other.chunks[1]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other,
|
||||
this->chunks[1] & other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other.chunks[0],
|
||||
this->chunks[1] | other.chunks[1]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other,
|
||||
this->chunks[1] | other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other.chunks[0],
|
||||
this->chunks[1] ^ other.chunks[1]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other,
|
||||
this->chunks[1] ^ other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other.chunks[0]),
|
||||
this->chunks[1].bit_andnot(other.chunks[1])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other),
|
||||
this->chunks[1].bit_andnot(other),
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shr() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shr<N>(),
|
||||
this->chunks[1].template shr<N>()
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shl() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shl<N>(),
|
||||
this->chunks[1].template shl<N>()
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits),
|
||||
this->chunks[1].any_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits.chunks[0]),
|
||||
this->chunks[1].any_bits_set(bits.chunks[1])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits),
|
||||
this->chunks[1].no_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits.chunks[0]),
|
||||
this->chunks[1].no_bits_set(bits.chunks[1])
|
||||
};
|
||||
}
|
||||
}; // struct simd8x64<T>
|
||||
|
||||
} // namespace simd
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace haswell
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/haswell/base.h"
|
||||
#include "simdjson/haswell/simd.h"
|
||||
#include "simdjson/haswell/bitmanipulation.h"
|
||||
#include "simdjson/haswell/bitmask.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
|
||||
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
|
||||
simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
|
||||
simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
|
||||
simdjson_inline int quote_index() { return bitmask::trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return bitmask::trailing_zeroes(bs_bits); }
|
||||
|
||||
uint32_t bs_bits;
|
||||
uint32_t quote_bits;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "simdjson/icelake/begin.h"
|
||||
#include "simdjson/generic/amalgamated.h"
|
||||
#include "simdjson/generic/lookup_table.h"
|
||||
#include "simdjson/icelake/end.h"
|
||||
|
||||
#endif // SIMDJSON_ICELAKE_H
|
||||
@@ -14,6 +14,15 @@ namespace icelake {
|
||||
|
||||
class implementation;
|
||||
|
||||
namespace simd {
|
||||
|
||||
template <typename T> struct simd8;
|
||||
template <> struct simd8<bool>;
|
||||
template <> struct simd8<uint8_t>;
|
||||
template <typename T> struct simd8x64;
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
} // namespace icelake
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
SIMDJSON_TARGET_REGION("avx512f,avx512dq,avx512cd,avx512bw,avx512vbmi,avx512vbmi2,avx512vl,avx2,bmi,pclmul,lzcnt,popcnt")
|
||||
#endif
|
||||
|
||||
#include "simdjson/icelake/bitmanipulation.h"
|
||||
#include "simdjson/icelake/bitmask.h"
|
||||
#include "simdjson/icelake/simd.h"
|
||||
#include "simdjson/icelake/stringparsing_defs.h"
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#ifndef SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||
#define SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/icelake/base.h"
|
||||
#include "simdjson/icelake/intrinsics.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace icelake {
|
||||
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
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#if 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_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_inline int leading_zeroes(uint64_t input_num) {
|
||||
return int(_lzcnt_u64(input_num));
|
||||
}
|
||||
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_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_inline long long int count_ones(uint64_t input_num) {
|
||||
return _popcnt64(input_num);
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2,
|
||||
uint64_t *result) {
|
||||
#if 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 icelake
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ICELAKE_BITMANIPULATION_H
|
||||
@@ -8,14 +8,99 @@
|
||||
|
||||
namespace simdjson {
|
||||
namespace icelake {
|
||||
namespace {
|
||||
namespace bitmask {
|
||||
|
||||
simdjson_constinit uint64_t ALL = 0xFFFFFFFFFFFFFFFF;
|
||||
simdjson_constinit uint64_t NONE = 0xFFFFFFFFFFFFFFFF;
|
||||
simdjson_constinit uint64_t EVEN = 0x5555555555555555;
|
||||
simdjson_constinit uint64_t ODD = 0xAAAAAAAAAAAAAAAA;
|
||||
|
||||
// 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
|
||||
// This function can be used safely even if not all bytes have been
|
||||
// initialized.
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(const uint64_t input_num) noexcept {
|
||||
#if 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_inline uint64_t clear_lowest_bit(const uint64_t input_num) noexcept {
|
||||
return _blsr_u64(input_num);
|
||||
}
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) noexcept {
|
||||
return int(_lzcnt_u64(input_num));
|
||||
}
|
||||
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline unsigned __int64 count_ones(uint64_t input_num) noexcept {
|
||||
// note: we do not support legacy 32-bit Windows
|
||||
return __popcnt64(input_num);// Visual Studio wants two underscores
|
||||
}
|
||||
#else
|
||||
simdjson_inline long long int count_ones(const uint64_t input_num) noexcept {
|
||||
return _popcnt64(input_num);
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline uint64_t add_carry_out(const uint64_t value1, const uint64_t value2, bool& carry_out) noexcept {
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned __int64 result;
|
||||
carry_out = _addcarry_u64(0, value1, value2, &result);
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
carry_out = __builtin_uaddll_overflow(value1, value2, &result);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow(const uint64_t value1, const uint64_t value2, bool& borrow) noexcept {
|
||||
// TODO only do this on GCC, not clang
|
||||
// #if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
// unsigned __int64 result;
|
||||
// borrow = _subborrow_u64(borrow, value1, value2, &result);
|
||||
// return result;
|
||||
// #else
|
||||
unsigned long long result;
|
||||
bool borrow1 = __builtin_usubll_overflow(value1, value2, &result);
|
||||
borrow = borrow1 | __builtin_usubll_overflow(result, borrow, &result);
|
||||
return result;
|
||||
// #endif
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t subtract_borrow_out(const uint64_t value1, const int64_t value2, bool& borrow_out) noexcept {
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned __int64 result;
|
||||
borrow_out = _subborrow_u64(0, value1, value2, &result);
|
||||
return result;
|
||||
#else
|
||||
unsigned long long result;
|
||||
borrow_out = __builtin_usubll_overflow(value1, value2, &result); // 2 (one to set )
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Perform a "cumulative bitwise xor," flipping bits each time a 1 is encountered.
|
||||
//
|
||||
// For example, prefix_xor(00100100) == 00011100
|
||||
//
|
||||
simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
|
||||
simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) noexcept {
|
||||
// There should be no such thing with a processor supporting avx2
|
||||
// but not clmul.
|
||||
__m128i all_ones = _mm_set1_epi8('\xFF');
|
||||
@@ -23,7 +108,7 @@ simdjson_inline uint64_t prefix_xor(const uint64_t bitmask) {
|
||||
return _mm_cvtsi128_si64(result);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace bitmask
|
||||
} // namespace icelake
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+138
-49
@@ -4,7 +4,7 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/icelake/base.h"
|
||||
#include "simdjson/icelake/intrinsics.h"
|
||||
#include "simdjson/icelake/bitmanipulation.h"
|
||||
#include "simdjson/icelake/bitmask.h"
|
||||
#include "simdjson/internal/simdprune_tables.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
/**
|
||||
* GCC 8 fails to provide _mm512_set_epi8. We roll our own.
|
||||
*/
|
||||
inline __m512i _mm512_set_epi8(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6, uint8_t a7, uint8_t a8, uint8_t a9, uint8_t a10, uint8_t a11, uint8_t a12, uint8_t a13, uint8_t a14, uint8_t a15, uint8_t a16, uint8_t a17, uint8_t a18, uint8_t a19, uint8_t a20, uint8_t a21, uint8_t a22, uint8_t a23, uint8_t a24, uint8_t a25, uint8_t a26, uint8_t a27, uint8_t a28, uint8_t a29, uint8_t a30, uint8_t a31, uint8_t a32, uint8_t a33, uint8_t a34, uint8_t a35, uint8_t a36, uint8_t a37, uint8_t a38, uint8_t a39, uint8_t a40, uint8_t a41, uint8_t a42, uint8_t a43, uint8_t a44, uint8_t a45, uint8_t a46, uint8_t a47, uint8_t a48, uint8_t a49, uint8_t a50, uint8_t a51, uint8_t a52, uint8_t a53, uint8_t a54, uint8_t a55, uint8_t a56, uint8_t a57, uint8_t a58, uint8_t a59, uint8_t a60, uint8_t a61, uint8_t a62, uint8_t a63) {
|
||||
inline simd_t _mm512_set_epi8(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6, uint8_t a7, uint8_t a8, uint8_t a9, uint8_t a10, uint8_t a11, uint8_t a12, uint8_t a13, uint8_t a14, uint8_t a15, uint8_t a16, uint8_t a17, uint8_t a18, uint8_t a19, uint8_t a20, uint8_t a21, uint8_t a22, uint8_t a23, uint8_t a24, uint8_t a25, uint8_t a26, uint8_t a27, uint8_t a28, uint8_t a29, uint8_t a30, uint8_t a31, uint8_t a32, uint8_t a33, uint8_t a34, uint8_t a35, uint8_t a36, uint8_t a37, uint8_t a38, uint8_t a39, uint8_t a40, uint8_t a41, uint8_t a42, uint8_t a43, uint8_t a44, uint8_t a45, uint8_t a46, uint8_t a47, uint8_t a48, uint8_t a49, uint8_t a50, uint8_t a51, uint8_t a52, uint8_t a53, uint8_t a54, uint8_t a55, uint8_t a56, uint8_t a57, uint8_t a58, uint8_t a59, uint8_t a60, uint8_t a61, uint8_t a62, uint8_t a63) {
|
||||
return _mm512_set_epi64(uint64_t(a7) + (uint64_t(a6) << 8) + (uint64_t(a5) << 16) + (uint64_t(a4) << 24) + (uint64_t(a3) << 32) + (uint64_t(a2) << 40) + (uint64_t(a1) << 48) + (uint64_t(a0) << 56),
|
||||
uint64_t(a15) + (uint64_t(a14) << 8) + (uint64_t(a13) << 16) + (uint64_t(a12) << 24) + (uint64_t(a11) << 32) + (uint64_t(a10) << 40) + (uint64_t(a9) << 48) + (uint64_t(a8) << 56),
|
||||
uint64_t(a23) + (uint64_t(a22) << 8) + (uint64_t(a21) << 16) + (uint64_t(a20) << 24) + (uint64_t(a19) << 32) + (uint64_t(a18) << 40) + (uint64_t(a17) << 48) + (uint64_t(a16) << 56),
|
||||
@@ -34,23 +34,23 @@ inline __m512i _mm512_set_epi8(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3, u
|
||||
|
||||
namespace simdjson {
|
||||
namespace icelake {
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
// Forward-declared so they can be used by splat and friends.
|
||||
template<typename Child>
|
||||
struct base {
|
||||
__m512i value;
|
||||
using simd_t = __m512i;
|
||||
simd_t value;
|
||||
|
||||
// Zero constructor
|
||||
simdjson_inline base() : value{__m512i()} {}
|
||||
simdjson_inline base() : value{simd_t()} {}
|
||||
|
||||
// Conversion from SIMD register
|
||||
simdjson_inline base(const __m512i _value) : value(_value) {}
|
||||
simdjson_inline base(const simd_t _value) : value(_value) {}
|
||||
|
||||
// Conversion to SIMD register
|
||||
simdjson_inline operator const __m512i&() const { return this->value; }
|
||||
simdjson_inline operator __m512i&() { return this->value; }
|
||||
simdjson_inline operator const simd_t&() const { return this->value; }
|
||||
simdjson_inline operator simd_t&() { return this->value; }
|
||||
|
||||
// Bit operations
|
||||
simdjson_inline Child operator|(const Child other) const { return _mm512_or_si512(*this, other); }
|
||||
@@ -68,17 +68,16 @@ namespace simd {
|
||||
|
||||
template<typename T, typename Mask=simd8<bool>>
|
||||
struct base8: base<simd8<T>> {
|
||||
typedef uint32_t bitmask_t;
|
||||
typedef uint64_t bitmask2_t;
|
||||
using typename base<simd8<T>>::simd_t;
|
||||
static constexpr const int LANES = sizeof(simd_t);
|
||||
using bitmask_t = uint64_t;
|
||||
static_assert(sizeof(bitmask_t)*8 == LANES, "Bitmask type's bits must equal the simd type's bytes");
|
||||
|
||||
simdjson_inline base8() : base<simd8<T>>() {}
|
||||
simdjson_inline base8(const __m512i _value) : base<simd8<T>>(_value) {}
|
||||
simdjson_inline base8(const simd_t _value) : base<simd8<T>>(_value) {}
|
||||
|
||||
friend simdjson_really_inline uint64_t operator==(const simd8<T> lhs, const simd8<T> rhs) {
|
||||
return _mm512_cmpeq_epi8_mask(lhs, rhs);
|
||||
}
|
||||
|
||||
static const int SIZE = sizeof(base<T>::value);
|
||||
simdjson_inline uint64_t eq(const simd8<T> rhs) const { return _mm512_cmpeq_epi8_mask(*this, rhs); }
|
||||
friend simdjson_inline uint64_t operator==(const simd8<T> lhs, const simd8<T> rhs) { return lhs.eq(rhs); }
|
||||
|
||||
template<int N=1>
|
||||
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
|
||||
@@ -94,19 +93,24 @@ namespace simd {
|
||||
static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
|
||||
|
||||
simdjson_inline simd8<bool>() : base8() {}
|
||||
simdjson_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
|
||||
simdjson_inline simd8<bool>(const simd_t _value) : base8<bool>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
|
||||
simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
|
||||
simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const noexcept { return _mm512_movepi8_mask(*this); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct base8_numeric: base8<T> {
|
||||
using typename base8<T>::simd_t;
|
||||
using base8<T>::LANES;
|
||||
|
||||
static simdjson_inline simd8<T> splat(T _value) { return _mm512_set1_epi8(_value); }
|
||||
static simdjson_inline simd8<T> zero() { return _mm512_setzero_si512(); }
|
||||
static simdjson_inline simd8<T> load(const T values[64]) {
|
||||
return _mm512_loadu_si512(reinterpret_cast<const __m512i *>(values));
|
||||
return _mm512_loadu_si512(reinterpret_cast<const simd_t *>(values));
|
||||
}
|
||||
// Repeat 16 values as many times as necessary (usually for lookup tables)
|
||||
static simdjson_inline simd8<T> repeat_16(
|
||||
@@ -126,10 +130,10 @@ namespace simd {
|
||||
}
|
||||
|
||||
simdjson_inline base8_numeric() : base8<T>() {}
|
||||
simdjson_inline base8_numeric(const __m512i _value) : base8<T>(_value) {}
|
||||
simdjson_inline base8_numeric(const simd_t _value) : base8<T>(_value) {}
|
||||
|
||||
// Store to array
|
||||
simdjson_inline void store(T dst[64]) const { return _mm512_storeu_si512(reinterpret_cast<__m512i *>(dst), *this); }
|
||||
simdjson_inline void store(T dst[64]) const { return _mm512_storeu_si512(reinterpret_cast<simd_t *>(dst), *this); }
|
||||
|
||||
// Addition/subtraction are the same for signed and unsigned
|
||||
simdjson_inline simd8<T> operator+(const simd8<T> other) const { return _mm512_add_epi8(*this, other); }
|
||||
@@ -141,14 +145,18 @@ namespace simd {
|
||||
simdjson_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_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
|
||||
simdjson_inline simd8<T> lookup_16(const simd8<T>& lookup_table) const {
|
||||
return _mm512_shuffle_epi8(lookup_table, *this);
|
||||
}
|
||||
// Perform a lookup based on the lower 4 bits of each lane. (Platform-dependent behavior for
|
||||
// non-ASCII values--may look up the lower 4 bits on some platforms, and return 0 on others.)
|
||||
simdjson_inline simd8<T> lookup_low_nibble_ascii(const simd8<T>& lookup_table) const {
|
||||
return lookup_16(lookup_table);
|
||||
}
|
||||
|
||||
// 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
|
||||
// Only the first 32 - bitmask::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
|
||||
@@ -157,27 +165,13 @@ namespace simd {
|
||||
simdjson_inline void compress(uint64_t mask, L * output) const {
|
||||
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
simdjson_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_inline simd8() : base8_numeric<int8_t>() {}
|
||||
simdjson_inline simd8(const __m512i _value) : base8_numeric<int8_t>(_value) {}
|
||||
simdjson_inline simd8(const simd_t _value) : base8_numeric<int8_t>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
|
||||
// Array constructor
|
||||
@@ -232,7 +226,7 @@ namespace simd {
|
||||
template<>
|
||||
struct simd8<uint8_t>: base8_numeric<uint8_t> {
|
||||
simdjson_inline simd8() : base8_numeric<uint8_t>() {}
|
||||
simdjson_inline simd8(const __m512i _value) : base8_numeric<uint8_t>(_value) {}
|
||||
simdjson_inline simd8(const simd_t _value) : base8_numeric<uint8_t>(_value) {}
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
|
||||
// Array constructor
|
||||
@@ -327,10 +321,16 @@ namespace simd {
|
||||
simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1) : chunks{chunk0, chunk1} {}
|
||||
simdjson_inline simd8x64(const simd8<T> chunk0) : chunks{chunk0} {}
|
||||
simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr)} {}
|
||||
simdjson_inline simd8x64(simd8x64<T>&& o) noexcept = default;
|
||||
simdjson_inline simd8x64<T>& operator=(simd8x64<T>&& other) noexcept = default;
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const noexcept {
|
||||
return this->chunks[0].to_bitmask();
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
|
||||
this->chunks[0].compress(mask, output);
|
||||
return 64 - count_ones(mask);
|
||||
return 64 - bitmask::count_ones(mask);
|
||||
}
|
||||
|
||||
simdjson_inline void store(T ptr[64]) const {
|
||||
@@ -341,31 +341,120 @@ namespace simd {
|
||||
return this->chunks[0];
|
||||
}
|
||||
|
||||
simdjson_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_inline uint64_t eq(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return this->chunks[0] == mask;
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t eq(const simd8x64<uint8_t> &other) const {
|
||||
simdjson_inline uint64_t eq(const simd8x64<T> &other) const {
|
||||
return this->chunks[0] == other.chunks[0];
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_16(const simd8<T>& lookup_table) const {
|
||||
return { this->chunks[0].lookup_16(lookup_table) };
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> lookup_low_nibble_ascii(const simd8<T>& lookup_table) const {
|
||||
return {
|
||||
this->chunks[0].lookup_low_nibble_ascii(lookup_table)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline uint64_t lteq(const T m) const {
|
||||
const simd8<T> mask = simd8<T>::splat(m);
|
||||
return this->chunks[0] <= mask;
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other.chunks[0]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator&(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] & other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other.chunks[0]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator|(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] | other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other.chunks[0]
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> operator^(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0] ^ other
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8x64<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other.chunks[0])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<T> bit_andnot(const simd8<T>& other) const {
|
||||
return {
|
||||
this->chunks[0].bit_andnot(other)
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shr() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shr<N>()
|
||||
};
|
||||
}
|
||||
|
||||
template <int N>
|
||||
simdjson_inline simd8x64<T> shl() const noexcept {
|
||||
return {
|
||||
this->chunks[0].template shl<N>()
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> any_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].any_bits_set(bits.chunks[0])
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits)
|
||||
};
|
||||
}
|
||||
|
||||
simdjson_inline simd8x64<bool> no_bits_set(const simd8x64<T>& bits) const {
|
||||
return {
|
||||
this->chunks[0].no_bits_set(bits.chunks[0])
|
||||
};
|
||||
}
|
||||
}; // struct simd8x64<T>
|
||||
|
||||
} // namespace simd
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace icelake
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#include "simdjson/icelake/base.h"
|
||||
#include "simdjson/icelake/simd.h"
|
||||
#include "simdjson/icelake/bitmanipulation.h"
|
||||
#include "simdjson/icelake/bitmask.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
|
||||
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
|
||||
simdjson_inline bool has_backslash() { return ((quote_bits - 1) & bs_bits) != 0; }
|
||||
simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
|
||||
simdjson_inline int quote_index() { return bitmask::trailing_zeroes(quote_bits); }
|
||||
simdjson_inline int backslash_index() { return bitmask::trailing_zeroes(bs_bits); }
|
||||
|
||||
uint64_t bs_bits;
|
||||
uint64_t quote_bits;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// #pragma once // We remove #pragma once here as it generates a warning in some cases. We rely on the include guard.
|
||||
#pragma once
|
||||
|
||||
#ifndef NONSTD_SV_LITE_H_INCLUDED
|
||||
#define NONSTD_SV_LITE_H_INCLUDED
|
||||
@@ -69,10 +69,6 @@
|
||||
# define nssv_CONFIG_NO_STREAM_INSERTION 0
|
||||
#endif
|
||||
|
||||
#ifndef nssv_CONFIG_CONSTEXPR11_STD_SEARCH
|
||||
# define nssv_CONFIG_CONSTEXPR11_STD_SEARCH 1
|
||||
#endif
|
||||
|
||||
// Control presence of exception handling (try and auto discover):
|
||||
|
||||
#ifndef nssv_CONFIG_NO_EXCEPTIONS
|
||||
@@ -271,7 +267,7 @@ using std::operator<<;
|
||||
# define nssv_HAS_CPP0X 0
|
||||
#endif
|
||||
|
||||
// Unless defined otherwise below, consider VC14 as C++11 for string-view-lite:
|
||||
// Unless defined otherwise below, consider VC14 as C++11 for variant-lite:
|
||||
|
||||
#if nssv_COMPILER_MSVC_VER >= 1900
|
||||
# undef nssv_CPP11_OR_GREATER
|
||||
@@ -438,9 +434,9 @@ using std::operator<<;
|
||||
# pragma clang diagnostic ignored "-Wreserved-user-defined-literal"
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wuser-defined-literals"
|
||||
#elif nssv_COMPILER_GNUC_VERSION >= 480
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wliteral-suffix"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wliteral-suffix"
|
||||
#endif // __clang__
|
||||
|
||||
#if nssv_COMPILER_MSVC_VERSION >= 140
|
||||
@@ -455,8 +451,8 @@ using std::operator<<;
|
||||
|
||||
#if defined(__clang__)
|
||||
# define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
|
||||
#elif nssv_COMPILER_GNUC_VERSION >= 480
|
||||
# define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
|
||||
#elif defined(__GNUC__)
|
||||
# define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
|
||||
#elif nssv_COMPILER_MSVC_VERSION >= 140
|
||||
# define nssv_RESTORE_WARNINGS() __pragma(warning(pop ))
|
||||
#else
|
||||
@@ -571,31 +567,12 @@ constexpr const CharT* search( basic_string_view<CharT, Traits> haystack, basic_
|
||||
|
||||
// non-recursive:
|
||||
|
||||
#if nssv_CONFIG_CONSTEXPR11_STD_SEARCH
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT> >
|
||||
constexpr const CharT* search( basic_string_view<CharT, Traits> haystack, basic_string_view<CharT, Traits> needle )
|
||||
{
|
||||
return std::search( haystack.begin(), haystack.end(), needle.begin(), needle.end() );
|
||||
}
|
||||
|
||||
#else // nssv_CONFIG_CONSTEXPR11_STD_SEARCH
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT> >
|
||||
nssv_constexpr14 const CharT* search( basic_string_view<CharT, Traits> haystack, basic_string_view<CharT, Traits> needle )
|
||||
{
|
||||
while ( needle.size() <= haystack.size() )
|
||||
{
|
||||
if ( haystack.starts_with(needle) )
|
||||
{
|
||||
return haystack.cbegin();
|
||||
}
|
||||
haystack = basic_string_view<CharT, Traits>{ haystack.begin() + 1, haystack.size() - 1U };
|
||||
}
|
||||
return haystack.cend();
|
||||
}
|
||||
#endif // nssv_CONFIG_CONSTEXPR11_STD_SEARCH
|
||||
|
||||
#endif // OPTIMIZE
|
||||
#endif // nssv_CPP11_OR_GREATER && ! nssv_CPP17_OR_GREATER
|
||||
|
||||
@@ -868,7 +845,7 @@ public:
|
||||
|
||||
// find(), 4x:
|
||||
|
||||
nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
|
||||
nssv_constexpr size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept // (1)
|
||||
{
|
||||
return assert( v.size() == 0 || v.data() != nssv_nullptr )
|
||||
, pos >= size()
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
#define SIMDJSON_PADDED_STRING_VIEW_INL_H
|
||||
|
||||
#include "simdjson/padded_string_view.h"
|
||||
#include "simdjson/error-inl.h"
|
||||
|
||||
#include <cstring> /* memcmp */
|
||||
#include "simdjson/error-inl.h"
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
@@ -32,16 +31,6 @@ inline size_t padded_string_view::capacity() const noexcept { return _capacity;
|
||||
|
||||
inline size_t padded_string_view::padding() const noexcept { return capacity() - length(); }
|
||||
|
||||
inline bool padded_string_view::remove_utf8_bom() noexcept {
|
||||
if(length() < 3) { return false; }
|
||||
if (std::memcmp(data(), "\xEF\xBB\xBF", 3) == 0) {
|
||||
remove_prefix(3);
|
||||
_capacity -= 3;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
|
||||
#endif
|
||||
|
||||
@@ -54,13 +54,6 @@ public:
|
||||
/** The number of allocated bytes. */
|
||||
inline size_t capacity() const noexcept;
|
||||
|
||||
/**
|
||||
* Remove the UTF-8 Byte Order Mark (BOM) if it exists.
|
||||
*
|
||||
* @return whether a BOM was found and removed
|
||||
*/
|
||||
inline bool remove_utf8_bom() noexcept;
|
||||
|
||||
/** The amount of padding on the string (capacity() - length()) */
|
||||
inline size_t padding() const noexcept;
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
#define SIMDJSON_IS_X86_64 1
|
||||
#elif defined(__aarch64__) || defined(_M_ARM64)
|
||||
#define SIMDJSON_IS_ARM64 1
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#define SIMDJSON_IS_RISCV64 1
|
||||
#elif defined(__PPC64__) || defined(_M_PPC64)
|
||||
#if defined(__ALTIVEC__)
|
||||
#define SIMDJSON_IS_PPC64_VMX 1
|
||||
@@ -60,8 +58,11 @@
|
||||
|
||||
#if SIMDJSON_IS_32BITS
|
||||
#ifndef SIMDJSON_NO_PORTABILITY_WARNING
|
||||
// In the future, we should allow programmers
|
||||
// to get warning.
|
||||
#pragma message("The simdjson library is designed \
|
||||
for 64-bit processors and it seems that you are not \
|
||||
compiling for a known 64-bit platform. All fast kernels \
|
||||
will be disabled and performance may be poor. Please \
|
||||
use a 64-bit target such as x64, 64-bit ARM or 64-bit PPC.")
|
||||
#endif // SIMDJSON_NO_PORTABILITY_WARNING
|
||||
#endif // SIMDJSON_IS_32BITS
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user