Compare commits

..

38 Commits

Author SHA1 Message Date
Daniel Lemire 6bbcbfbb95 version 3.11.1 2024-12-07 11:13:00 -05:00
Valery Mironov e6578fea39 Fix missing override (#2305) 2024-12-07 11:12:25 -05:00
Joyee Cheung 6fb050d04e fix: fix deprecation from -Wdeprecated-literal-operator (#2307)
Otherwise simdjson doesn't build with V8's Node.js fork, which
uses -Werror,-Wdeprecated-literal-operator and latest version
of clang.
2024-12-07 11:12:14 -05:00
Daniel Lemire b4242d3b4f release candidate (#2304) 2024-12-05 22:05:39 -05:00
Daniel Lemire cbfe2d4a21 Update vs17-arm-ci.yml 2024-12-02 20:24:24 -05:00
halx99 79126ca323 fix: processor checks inconsistently problem (#2299) 2024-12-02 20:23:28 -05:00
Daniel Lemire 3f87f958d7 documentation 2024-12-02 00:06:20 -05:00
Daniel Lemire cab383e1de Update README.md 2024-11-30 20:43:20 -05:00
Daniel Lemire 9b314922a1 additional documentation 2024-11-08 11:53:34 -05:00
Daniel Lemire 587beae307 prevent int to pointer implicit conversion for operator[](const char *) (#2286) 2024-11-01 18:11:43 -04:00
Daniel Lemire f53981d945 Update dom.md 2024-11-01 12:23:35 -04:00
Daniel Lemire 41b4ffd6aa Update basics.md 2024-11-01 12:15:40 -04:00
Daniel Lemire 6cd8a6d776 adding pad function (#2283) 2024-10-29 21:26:01 -04:00
Daniel Lemire 3c0d032ded Candidate for C++20 deserialization features (#2276)
* tag_invoke based custom types (#2219)

* tag_invoke based custom types

Now you can use tag_invoke to add a custom type or a group of custom types.

* Fixing macro usage + Fixing noexcept

* Fixing the usage of #include

We don't need <concepts> at all seems like it

* Fixing tag_invoke impl for MSVC

* Making `tag_invoke` to support `ondemand::document` as well + docs (#2228)

* Making `tag_invoke` to support `ondemand::document` as well + docs

* Fix typos and doc update by @lemire

Co-authored-by: Daniel Lemire <daniel@lemire.me>

* Better docs by @lemire

Co-authored-by: Daniel Lemire <daniel@lemire.me>

* Preserving the old, disallowing in the new

I'm disabling `document::get() &&` if the user has provided a `tag_invoke`d version; otherwise, we retain the compatibility.

---------

Co-authored-by: Daniel Lemire <daniel@lemire.me>

* fix: correct small issues with deserialize (#2232)

* Extending the deserialization code with more defaults + docs (#2233)

* Make custom types easier with some predefined cases + docs

* missing include

* adding Ubuntu 24 CXX 20

* using concepts all the way

* minor tweak

* tiny tweak

* tweaks

* more tweaking

* saving

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>

* Making `tag_invoke` a "put" as opposed to a "get" (#2256)

* fix: add tests related to issue 2227 (#2229)

* fix: add tests related to issue 2227

* avoiding name clash

* pedantic fix

* deprecate rvalue get on document

* selectively deprecating

* Fix ndjson spec link (#2234)

* fix ndjson spec link

The link in the readme of parse_many links to a casino spam site

* fix link

* [no-ci] Update README.md

* Make simdjson compile again

* Enable SIMDJSON_SINGLEHEADER=OFF in VS Code

With singleheader on, clangd can't find the right
include files.

* Add missing include directives to static build targets of simdjson. (#2240)

* adding a warning

* adding warning regarding SIMDJSON_BUILD_STATIC_LIB

* release candidate

* pedantic viable size

* Making tag_invoke a feeder instead of a producer

* adding missing undef silencer (#2253)

* Ignore pragma once when amalgamating source files (#2248)

With gcc it causes an error in `simdjson.cpp`:
```
simdjson.cpp:548:9: warning: #pragma once in main file
  548 | #pragma once
      |         ^~~~
```

It had previously been commented out in:
https://github.com/simdjson/simdjson/commit/6ef555e6fb79363fae057a9a46b52cd208d9e305

However, this was lost in an upgrade:
https://github.com/simdjson/simdjson/commit/2a4ff7346813b120f2b5b40e95d69352b593cc9c

* Update CI (#2254)

* adding missing undef silencer

* Updating CI

* more fixes

* fix

* big endian fix

* Moving to the new tag_invoke signature

* Fix nlohmann ambiguity on C++23-enabled clang

* Revert "Merge branch 'master' of https://github.com/simdjson/simdjson into builder_development_branch_extra"

This reverts commit 3eeecbab34, reversing
changes made to 6858b208b4.

---------

Co-authored-by: Daniel Lemire <daniel@lemire.me>
Co-authored-by: Sasha Lopoukhine <superlopuh@gmail.com>
Co-authored-by: John Keiser <john@johnkeiser.com>
Co-authored-by: Tan Li Boon <undisputed-seraphim@users.noreply.github.com>
Co-authored-by: tobil4sk <tobil4sk@outlook.com>

* update CI on the builder_development_branch (no code change) (#2262)

* typo

* General madness simpler, no simpler!!! (#2267)

* Minimal tag_invokes for STL types

* simpler madness

* adding a comment

* missing file

* minor tweaks to style

* fixing incorrect max/min usage

* updating single

* simplify

* validating the idea

* putting back the concept

* moving the include

* guarding

* Cheap General Madness (#2268)

* Some General Concepts and their deserializations

* Resolving ambiguity

* Add missing #include

* C++20 custom deserializer: better documentation (#2269)

* mostly a documentation update.

* missing cpp

* [no-ci] fix comment

* various minor fixes

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>

---------

Co-authored-by: M. Bahoosh <12122474+the-moisrex@users.noreply.github.com>
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
Co-authored-by: M. Bahoosh <moisrex@gmail.com>

* minor update

* More documentation regarding builder (#2270)

* minor update

* more improvment to our documentation (builder branch)

* putting back missing functions

* merge candidate

---------

Co-authored-by: M. Bahoosh <moisrex@gmail.com>
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
Co-authored-by: Sasha Lopoukhine <superlopuh@gmail.com>
Co-authored-by: John Keiser <john@johnkeiser.com>
Co-authored-by: Tan Li Boon <undisputed-seraphim@users.noreply.github.com>
Co-authored-by: tobil4sk <tobil4sk@outlook.com>
Co-authored-by: M. Bahoosh <12122474+the-moisrex@users.noreply.github.com>
2024-10-18 20:37:38 -04:00
Daniel Lemire 36f5dbcb75 documentation for threading... (#2277)
* documentation for threading...

* remove const

* doc
2024-10-11 12:34:11 -04:00
Daniel Lemire 49901fb254 doc 2024-10-10 21:32:51 -04:00
Daniel Lemire c066b5421b Jsonpath (#2272)
* Add support for JSONPath with '$' prefix and integrate into dom::at_path (#2266)

- Updated `json_path_to_pointer_conversion` to support JSONPath starting with the '$' prefix, while maintaining compatibility with the existing implementation.
- Moved `json_path_to_pointer_conversion` to a separate header file for better modularity and to support JSONPath queries in `dom` mode.
- Implemented `at_path` functionality in `dom` mode to enable querying JSON using JSONPath.
- Added unit tests to validate the new JSONPath support in `dom` mode and ensure compatibility with both standard and existing JSONPath formats.

* two minor fixes

* more tests and documentation

* damn compiler warnings

* more documentation fixes

---------

Co-authored-by: Zhengguo Yang <yangzhgg@gmail.com>
2024-10-08 10:37:59 -04:00
Daniel Lemire ec7550a70e fixes issue 2271 (#2273) 2024-10-08 10:36:12 -04:00
Daniel Lemire 3ef3078e51 documentation for issue 2259 (clarifying) (#2260) 2024-09-21 09:10:35 -04:00
tobil4sk fd06782c97 Make document::is_null behavior consistent with documentation (#2258)
* Make null-like value test consistent with docs

According to the docs: `INCORRECT_TYPE If the JSON value begins with 'n'
and is not 'null'.`

* Match document::is_null behavior to documentation

* Test other token beginning with n with is_null
2024-09-20 20:58:41 -04:00
Daniel Lemire 9303efbd0c [no-ci] Update basics.md 2024-09-20 20:56:11 -04:00
Daniel Lemire 6c979f15cc deps: switch to CPM (#2257)
* deps: switch to CPM

* missing file

* setting the dependencies on URL download

* using fixed version of cxxopts
2024-09-20 13:29:47 -04:00
Daniel Lemire 09ccabbe6c enable BMI, but only when LLVM is the compiler (#2255) 2024-09-20 10:59:54 -04:00
Daniel Lemire e00cc8c6dc Update CI (#2254)
* adding missing undef silencer

* Updating CI

* more fixes

* fix

* big endian fix
2024-09-18 09:09:11 -04:00
tobil4sk c10b32d463 Ignore pragma once when amalgamating source files (#2248)
With gcc it causes an error in `simdjson.cpp`:
```
simdjson.cpp:548:9: warning: #pragma once in main file
  548 | #pragma once
      |         ^~~~
```

It had previously been commented out in:
https://github.com/simdjson/simdjson/commit/6ef555e6fb79363fae057a9a46b52cd208d9e305

However, this was lost in an upgrade:
https://github.com/simdjson/simdjson/commit/2a4ff7346813b120f2b5b40e95d69352b593cc9c
2024-09-17 15:41:12 -04:00
Daniel Lemire 025a44348a adding missing undef silencer (#2253) 2024-09-16 21:04:09 -04:00
Daniel Lemire 70a68da941 pedantic viable size 2024-09-06 01:19:47 -04:00
Daniel Lemire e341c8b438 release candidate 2024-08-26 09:37:33 -04:00
Daniel Lemire 0ac0a80e28 Merge branch 'master' of github.com:simdjson/simdjson 2024-08-26 09:37:03 -04:00
Daniel Lemire 6b9117c029 adding warning regarding SIMDJSON_BUILD_STATIC_LIB 2024-08-26 09:36:44 -04:00
Daniel Lemire dd92151971 adding a warning 2024-08-26 09:34:39 -04:00
Tan Li Boon 0679c247f4 Add missing include directives to static build targets of simdjson. (#2240) 2024-08-26 09:24:01 -04:00
John Keiser 615218a3ad Merge pull request #2237 from simdjson/jkeiser/simdjson-vscode
Reduce errors in vscode
2024-08-18 22:04:20 -07:00
John Keiser 4c1b0a41d8 Enable SIMDJSON_SINGLEHEADER=OFF in VS Code
With singleheader on, clangd can't find the right
include files.
2024-08-18 14:21:00 -07:00
John Keiser ef563a4b09 Make simdjson compile again 2024-08-18 11:21:26 -07:00
Daniel Lemire 7a9ff93388 [no-ci] Update README.md 2024-08-15 12:52:47 -04:00
Sasha Lopoukhine fc61d7c7ba Fix ndjson spec link (#2234)
* fix ndjson spec link

The link in the readme of parse_many links to a casino spam site

* fix link
2024-08-10 10:11:05 -04:00
Daniel Lemire d506af0a79 fix: add tests related to issue 2227 (#2229)
* fix: add tests related to issue 2227

* avoiding name clash

* pedantic fix

* deprecate rvalue get on document

* selectively deprecating
2024-08-07 20:15:06 -04:00
66 changed files with 2470 additions and 944 deletions
+1
View File
@@ -25,6 +25,7 @@ CompileFlags:
Diagnostics:
Suppress:
- pp_including_mainfile_in_preamble
- unused-includes
---
# Amalgamated files that require or partly define an implementation
If:
+2 -3
View File
@@ -1,9 +1,8 @@
name: Doxygen GitHub Pages
on:
push:
branches:
- master
release:
types: [created]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
+1 -2
View File
@@ -10,7 +10,6 @@ jobs:
fail-fast: false
matrix:
include:
- {arch: ARM}
- {arch: ARM64}
- {arch: ARM64EC}
steps:
@@ -19,4 +18,4 @@ jobs:
- name: Use cmake
run: |
cmake -A ${{ matrix.arch }} -DCMAKE_SYSTEM_VERSION="10.0.22621.0" -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
cmake --build build --verbose
cmake --build build --verbose
+20 -10
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 3.10.0
VERSION 3.11.1
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -20,10 +20,14 @@ string(
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "23.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "23" CACHE STRING "simdjson library soversion")
set(SIMDJSON_LIB_VERSION "24.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "24" CACHE STRING "simdjson library soversion")
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
message(WARNING "SIMDJSON_BUILD_STATIC_LIB only makes sense if BUILD_SHARED_LIBS is set to ON")
message(WARNING "You might be building and installing a two identical static libraries.")
endif()
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
@@ -51,6 +55,7 @@ endif()
if(is_top_project)
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
option(SIMDJSON_SINGLEHEADER "Disable singleheader generation" ON)
endif()
include(cmake/handle-deprecations.cmake)
@@ -155,11 +160,13 @@ endif()
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
install(
FILES singleheader/simdjson.h
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT simdjson_Development
)
if(SIMDJSON_SINGLEHEADER)
install(
FILES singleheader/simdjson.h
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT simdjson_Development
)
endif()
install(
TARGETS simdjson
@@ -203,6 +210,7 @@ if(SIMDJSON_BUILD_STATIC_LIB)
TARGETS simdjson_static
EXPORT simdjson_staticTargets
ARCHIVE COMPONENT simdjson_Development
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(
EXPORT simdjson_staticTargets
@@ -279,6 +287,7 @@ enable_testing()
add_custom_target(all_tests)
add_subdirectory(windows)
include(cmake/CPM.cmake)
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
@@ -286,8 +295,9 @@ add_subdirectory(tools) ## This needs to be before tests because of cxxopts
# most of the data has been moved to https://github.com/simdjson/simdjson-data
add_subdirectory(jsonexamples)
if(SIMDJSON_SINGLEHEADER)
add_subdirectory(singleheader)
endif()
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "3.10.0"
PROJECT_NUMBER = "3.11.1"
# 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
+6 -2
View File
@@ -31,6 +31,7 @@ Table of Contents
* [Documentation](#documentation)
* [Godbolt](#godbolt)
* [Performance results](#performance-results)
* [Packages](#packages)
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
* [About simdjson](#about-simdjson)
* [Funding](#funding)
@@ -143,6 +144,9 @@ speed for [synthetic files over various sizes generated with a script](https://g
For NDJSON files, we can exceed 3 GB/s with [our multithreaded parsing functions](https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md).
Packages
------------------------------
[![Packaging status](https://repology.org/badge/vertical-allrepos/simdjson.svg)](https://repology.org/project/simdjson/versions)
Bindings and Ports of simdjson
@@ -201,8 +205,8 @@ For the video inclined, <br />
Funding
-------
The work is supported by the Natural Sciences and Engineering Research Council of Canada under grant
number RGPIN-2017-03910.
The work is supported by the Natural Sciences and Engineering Research Council of Canada under grants
RGPIN-2017-03910 and RGPIN-2024-03787.
[license]: LICENSE
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg
+24
View File
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.40.2)
set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})
+76 -37
View File
@@ -1,5 +1,4 @@
include(CMakeDependentOption)
include(import.cmake)
option(SIMDJSON_ALLOW_DOWNLOADS
"Allow dependencies to be downloaded during configure time"
@@ -11,17 +10,21 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
SIMDJSON_ALLOW_DOWNLOADS OFF)
if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_TESTING)
set_off(BENCHMARK_ENABLE_INSTALL)
set_off(BENCHMARK_ENABLE_WERROR)
import_dependency(google_benchmarks google/benchmark v1.7.1)
add_dependency(google_benchmarks)
CPMAddPackage(
NAME google_benchmarks
URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.zip
OPTIONS
"BENCHMARK_ENABLE_TESTING OFF"
"BENCHMARK_ENABLE_INSTALL OFF"
"BENCHMARK_ENABLE_WERROR OFF"
)
endif()
# The bulk of our benchmarking and testing data has been moved simdjson/simdjson-data
import_dependency(simdjson-data simdjson/simdjson-data a5b13babe65c1bba7186b41b43d4cbdc20a5c470)
add_dependency(simdjson-data)
CPMAddPackage(
NAME simdjson-data
URL https://github.com/simdjson/simdjson-data/archive/a5b13babe65c1bba7186b41b43d4cbdc20a5c470.zip
)
option(SIMDJSON_USE_BOOST_JSON "Try to include BOOST_JSON, this may break your binaries under some systems." OFF)
# This prevents variables declared with set() from unnecessarily escaping and
# should not be called more than once
@@ -38,20 +41,30 @@ function(competition_scope_)
int main() {}
]] SIMDJSON_FOUND_STRING_VIEW)
if(SIMDJSON_FOUND_STRING_VIEW AND SIMDJSON_USE_BOOST_JSON)
import_dependency(boostjson boostorg/json ee8d72d)
CPMAddPackage(
NAME boostjson
URL https://github.com/boostorg/json/archive/ee8d72d8502b409b5561200299cad30ccdb91415.zip
)
add_library(boostjson STATIC "${boostjson_SOURCE_DIR}/src/src.cpp")
target_compile_definitions(boostjson PUBLIC BOOST_JSON_STANDALONE)
target_include_directories(boostjson SYSTEM PUBLIC
"${boostjson_SOURCE_DIR}/include")
target_compile_definitions(boostjson INTERFACE SIMDJSON_COMPETITION_BOOSTJSON)
endif()
import_dependency(cjson DaveGamble/cJSON c69134d)
CPMAddPackage(
NAME cjson
URL https://github.com/DaveGamble/cJSON/archive/c69134d01746dcf551dd7724b4edb12f922eb0d1.zip
DOWNLOAD_ONLY YES
)
add_library(cjson STATIC "${cjson_SOURCE_DIR}/cJSON.c")
target_include_directories(cjson SYSTEM PUBLIC "${cjson_SOURCE_DIR}")
target_compile_definitions(cjson INTERFACE SIMDJSON_COMPETITION_CJSON)
import_dependency(fastjson mikeando/fastjson 485f994)
CPMAddPackage(
NAME fastjson
URL https://github.com/mikeando/fastjson/archive/485f994a61a64ac73fa6a40d4d639b99b463563b.zip
DOWNLOAD_ONLY YES
)
add_library(fastjson STATIC
"${fastjson_SOURCE_DIR}/src/fastjson.cpp"
"${fastjson_SOURCE_DIR}/src/fastjson2.cpp"
@@ -60,28 +73,36 @@ int main() {}
"${fastjson_SOURCE_DIR}/include")
target_compile_definitions(fastjson INTERFACE SIMDJSON_COMPETITION_FASTJSON)
import_dependency(gason vivkin/gason 7aee524)
CPMAddPackage(
NAME gason
URL https://github.com/vivkin/gason/archive/7aee524189da1c1ecd19f67981e3d903dae25470.zip
DOWNLOAD_ONLY YES
)
add_library(gason STATIC "${gason_SOURCE_DIR}/src/gason.cpp")
target_include_directories(gason SYSTEM PUBLIC "${gason_SOURCE_DIR}/src")
target_compile_definitions(gason INTERFACE SIMDJSON_COMPETITION_GASON)
import_dependency(jsmn zserge/jsmn 18e9fe4)
CPMAddPackage(
NAME jsmn
URL https://github.com/zserge/jsmn/archive/18e9fe42cbfe21d65076f5c77ae2be379ad1270f.zip
DOWNLOAD_ONLY YES
)
add_library(jsmn STATIC "${jsmn_SOURCE_DIR}/jsmn.c")
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
message(STATUS "Importing json (nlohmann/json@v3.10.5)")
set(nlohmann_json_SOURCE_DIR "${dep_root}/json")
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}")
file(DOWNLOAD
"https://github.com/nlohmann/json/releases/download/v3.10.5/json.hpp"
"${nlohmann_json_SOURCE_DIR}/nlohmann/json.hpp")
endif()
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json SYSTEM INTERFACE "${nlohmann_json_SOURCE_DIR}")
target_compile_definitions(nlohmann_json INTERFACE SIMDJSON_COMPETITION_NLOHMANN_JSON)
CPMAddPackage(
NAME nlohmann_json
URL https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip
)
import_dependency(json11 dropbox/json11 ec4e452)
set_property(TARGET nlohmann_json APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS SIMDJSON_COMPETITION_NLOHMANN_JSON)
CPMAddPackage(
NAME json11
URL https://github.com/dropbox/json11/archive/ec4e45219af1d7cde3d58b49ed762376fccf1ace.zip
DOWNLOAD_ONLY YES
)
add_library(json11 STATIC "${json11_SOURCE_DIR}/json11.cpp")
target_include_directories(json11 SYSTEM PUBLIC "${json11_SOURCE_DIR}")
target_compile_definitions(json11 INTERFACE SIMDJSON_COMPETITION_JSON11)
@@ -91,7 +112,11 @@ int main() {}
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
import_dependency(rapidjson Tencent/rapidjson f54b0e4)
CPMAddPackage(
NAME rapidjson
URL https://github.com/Tencent/rapidjson/archive/f54b0e47a08782a6131cc3d60f94d038fa6e0a51.zip
DOWNLOAD_ONLY YES
)
add_library(rapidjson INTERFACE)
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
include (TestBigEndian)
@@ -110,14 +135,22 @@ int main() {}
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
endif()
import_dependency(sajson chadaustin/sajson 2dcfd35)
CPMAddPackage(
NAME sajson
URL https://github.com/chadaustin/sajson/archive/2dcfd350586375f9910f74821d4f07d67ae455ba.zip
DOWNLOAD_ONLY YES
)
add_library(sajson INTERFACE)
target_compile_definitions(sajson INTERFACE SAJSON_UNSORTED_OBJECT_KEYS)
target_include_directories(sajson SYSTEM INTERFACE
"${sajson_SOURCE_DIR}/include")
target_compile_definitions(sajson INTERFACE SIMDJSON_COMPETITION_SAJSON)
import_dependency(ujson4c esnme/ujson4c e14f3fd)
CPMAddPackage(
NAME ujson4c
URL https://github.com/esnme/ujson4c/archive/e14f3fd5207fe30d1bdea723f260609e69d1abfa.zip
DOWNLOAD_ONLY YES
)
add_library(ujson4c STATIC
"${ujson4c_SOURCE_DIR}/src/ujdecode.c"
"${ujson4c_SOURCE_DIR}/3rdparty/ultrajsondec.c")
@@ -126,7 +159,11 @@ int main() {}
"${ujson4c_SOURCE_DIR}/3rdparty")
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
import_dependency(yyjson ibireme/yyjson c385651)
CPMAddPackage(
NAME yyjson
URL https://github.com/ibireme/yyjson/archive/c3856514de0a67d7b66939bf3ed491a2d6e61277.zip
DOWNLOAD_ONLY YES
)
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
@@ -151,10 +188,12 @@ cmake_dependent_option(SIMDJSON_CXXOPTS "Download cxxopts (necessary for tools)"
SIMDJSON_ALLOW_DOWNLOADS OFF)
if(SIMDJSON_CXXOPTS)
set_off(CXXOPTS_BUILD_EXAMPLES)
set_off(CXXOPTS_BUILD_TESTS)
set_off(CXXOPTS_ENABLE_INSTALL)
import_dependency(cxxopts jarro2783/cxxopts 5965670)
add_dependency(cxxopts)
CPMAddPackage(
NAME cxxopts
URL https://github.com/jarro2783/cxxopts/archive/59656709c0c58fcd0ed18b38e02938dbe05284c5.zip
OPTIONS
"CXXOPTS_BUILD_EXAMPLES OFF"
"CXXOPTS_BUILD_TESTS OFF"
"CXXOPTS_ENABLE_INSTALL OFF"
)
endif()
-48
View File
@@ -1,48 +0,0 @@
set(dep_root "${simdjson_SOURCE_DIR}/dependencies/.cache")
if(DEFINED ENV{simdjson_DEPENDENCY_CACHE_DIR})
set(dep_root "$ENV{simdjson_DEPENDENCY_CACHE_DIR}")
endif()
function(import_dependency NAME GITHUB_REPO COMMIT)
message(STATUS "Importing ${NAME} (${GITHUB_REPO}@${COMMIT})")
set(target "${dep_root}/${NAME}")
# If the folder exists in the cache, then we assume that everything is as
# should be and do nothing
if(EXISTS "${target}")
set("${NAME}_SOURCE_DIR" "${target}" PARENT_SCOPE)
return()
endif()
set(zip_url "https://github.com/${GITHUB_REPO}/archive/${COMMIT}.zip")
set(archive "${dep_root}/archive.zip")
set(dest "${dep_root}/_extract")
file(DOWNLOAD "${zip_url}" "${archive}")
file(MAKE_DIRECTORY "${dest}")
execute_process(
WORKING_DIRECTORY "${dest}"
COMMAND "${CMAKE_COMMAND}" -E tar xf "${archive}")
file(REMOVE "${archive}")
# GitHub archives only ever have one folder component at the root, so this
# will always match that single folder
file(GLOB dir LIST_DIRECTORIES YES "${dest}/*")
file(RENAME "${dir}" "${target}")
set("${NAME}_SOURCE_DIR" "${target}" PARENT_SCOPE)
endfunction()
# Delegates to the dependency
macro(add_dependency NAME)
if(NOT DEFINED "${NAME}_SOURCE_DIR")
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
endif()
add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}" EXCLUDE_FROM_ALL)
endmacro()
function(set_off NAME)
set("${NAME}" OFF CACHE INTERNAL "")
endfunction()
+38 -4
View File
@@ -209,6 +209,25 @@ std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
```
You can then parse the JSON data from the `simdjson::padded_string` instance:
```c++
ondemand::document doc = parser.iterate(my_padded_data);
```
Whenever you pass an `std::string` reference to `parser::iterate`,
the parser will access the bytes beyond the end of
the string but before the end of the allocated memory (`std::string::capacity()`).
If you are using a sanitizer that checks for reading uninitialized bytes or `std::string`'s
container-overflow checks, you may encounter sanitizer warnings.
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
```c++
std::string json = "[1]";
ondemand::document doc = parser.iterate(simdjson::pad(json));
```
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
Consider reusing the same buffers and limiting memory allocations.
@@ -249,7 +268,7 @@ documents.
For code safety, you should keep (1) the `parser` instance, (2) the input string and (3) the document instance alive throughout your parsing. Additionally, you should follow the following rules:
- A `parser` may have at most one document open at a time, since it holds allocated memory used for the parsing.
- By design, you should only have one `document` instance per JSON document. Thus, if you must pass a document instance to a function, you should avoid passing it by value: choose to pass it by reference instance to avoid the copy. (We also provide a `document_reference` class if you need to pass by value.)
- By design, you should only have one `document` instance per JSON document. Thus, if you must pass a document instance to a function, you should avoid passing it by value: choose to pass it by reference instance to avoid the copy. In any case, the `document` class does not have a copy constructor.
During the `iterate` call, the original JSON text is never modified--only read. After you are done
with the document, the source (whether file or string) can be safely discarded.
@@ -538,7 +557,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
For this purpose, `array` instances have a `count_elements` method. Users should be
aware that the `count_elements` method can be costly since it requires scanning the
whole array. You should only call `count_elements` as a last resort as it may
require scanning the document twice or more. You may use it as follows if your document is itself an array:
require scanning the document twice or more. In the spirit of On-Demand, the `count_elements` function does not validate the values in the array. You may use it as follows if your document is itself an array:
```C++
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
@@ -1428,9 +1447,11 @@ be represented as `value` instances. You can check that a document is a scalar w
JSONPath
------------
The simdjson library now supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
The simdjson library supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_path`.
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of
[`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects
and arrays: make sure to consume the values between each call to `at_path`.
Consider the following example:
@@ -1471,6 +1492,18 @@ doc.at_path(".\\u00E9") == 123; // true
doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD)
```
We also support the `$` prefix. When you start a JSONPath expression with $, you are indicating that the path starts from the root of the JSON document. E.g.,
```c++
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object obj = doc.get_object();
int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
x = obj.at_path("$.d.foo2.a.2"); // 30
```
Error handling
--------------
@@ -2876,6 +2909,7 @@ Performance tips
std::string_view year = data["year"];
std::string_view rating = data["rating"];
```
- You will get better performance if you seek the keys in the order in which they appear in the document. So if processing `{"a":1, "b":2, "c":3}`, do `value1 = data["a"]; value2 = data["b"]; value3 data["c"];` and not `value2 = data["b"]; value1 = data["a"]; value3 data["c"];`. Of course, it is not always possible to know for sure in which order the keys appear.
+64
View File
@@ -8,6 +8,7 @@ An overview of what you need to know to use simdjson, with examples.
* [Using the Parsed JSON](#using-the-parsed-json)
* [C++17 Support](#c17-support)
* [JSON Pointer](#json-pointer)
* [JSONPath](#jsonpath)
* [Error Handling](#error-handling)
* [Error Handling Example](#error-handling-example)
* [Exceptions](#exceptions)
@@ -59,6 +60,26 @@ std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
```
You can then parse the JSON document from the `simdjson::padded_string` instance:
```cpp
simdjson::dom::parser parser;
simdjson::dom::element doc = parser.parse(my_padded_data);
```
Whenever you pass an `std::string` reference to `parser::parse`,
the parser will access the bytes beyond the end of
the string but before the end of the allocated memory (`std::string::capacity()`).
If you are using a sanitizer that checks for reading uninitialized bytes or `std::string`'s
container-overflow checks, you may encounter sanitizer warnings.
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
```c++
std::string json = "[1]";
dom::element doc = parser.parse(simdjson::pad(json));
```
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
You cannot copy a `parser` instance, you may only move it.
@@ -257,6 +278,49 @@ for (dom::element car_element : cars) {
}
```
JSONPath
------------
The simdjson library supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
Consider the following example:
```c++
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(cars_json).get(doc);
if(error) { /*won't happen*/ }
double p;
error = doc.at_path("[0].tire_pressure[1]").get(p);
if(error) { /*won't happen*/ }
cout << p << endl; // Prints 39.9
```
We also support the `$` prefix. When you start a JSONPath expression with $, you are indicating that the path starts from the root of the JSON document. E.g.,
```c++
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(json).get(doc);
if(error) { /*won't happen*/ }
dom::object obj;
error = doc.get_object().get(obj);
if(error) { /*won't happen*/ }
int64_t x;
error = obj.at_path("$[3].foo.a[1]").get(x);
if(error) { /*won't happen*/ }
if(x != 20) { /*won't happen*/ }
x = obj.at_path("$.d.foo2.a.2");
if(error) { /*won't happen*/ }
```
Error Handling
+6 -1
View File
@@ -103,7 +103,12 @@ remove almost entirely its cost and replaces it by the overhead of a thread, whi
cheaper. Ain't that awesome!
Thread support is only active if thread supported is detected in which case the macro
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
SIMDJSON_THREADS_ENABLED is set. You can also manually pass `SIMDJSON_THREADS_ENABLED=1` flag
to the library. Otherwise the library runs in single-thread mode.
You should be consistent. If you link against the simdjson library built for multithreading
(i.e., with `SIMDJSON_THREADS_ENABLED`), then you should build your application with multithreading
system (setting `SIMDJSON_THREADS_ENABLED=1` and linking against a thread library).
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
+7 -2
View File
@@ -103,7 +103,12 @@ cases, remove almost entirely its cost and replaces it by the overhead of a thre
of magnitude cheaper. Ain't that awesome!
Thread support is only active if thread supported is detected in which case the macro
SIMDJSON_THREADS_ENABLED is set. Otherwise the library runs in single-thread mode.
SIMDJSON_THREADS_ENABLED is set. You can also manually pass `SIMDJSON_THREADS_ENABLED=1` flag
to the library. Otherwise the library runs in single-thread mode.
You should be consistent. If you link against the simdjson library built for multithreading
(i.e., with `SIMDJSON_THREADS_ENABLED`), then you should build your application with multithreading
system (setting `SIMDJSON_THREADS_ENABLED=1` and linking against a thread library).
A `document_stream` instance uses at most two threads: there is a main thread and a worker thread.
You should expect the main thread to be fully occupied while the worker thread is partially busy
@@ -125,7 +130,7 @@ Whitespace Characters:
- **Nothing**
Some official formats **(non-exhaustive list)**:
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
- [Newline-Delimited JSON (NDJSON)](https://github.com/ndjson/ndjson-spec)
- [JSON lines (JSONL)](http://jsonlines.org/)
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream!
- [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
+2 -2
View File
@@ -241,8 +241,8 @@ long page_size() {
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
// page boundary.
bool need_allocation(const char *buf, size_t len) {
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
simdjson::SIMDJSON_PADDING);
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
+ simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
}
simdjson::padded_string_view
+9 -3
View File
@@ -19,7 +19,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// 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
#if 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).
@@ -35,9 +35,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
// We sometimes call leading_zeroes 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.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if 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).
@@ -90,7 +96,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
#else
@@ -51,6 +51,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
+7 -7
View File
@@ -12,7 +12,7 @@ namespace arm64 {
namespace {
namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace {
// Start of private section with Visual Studio workaround
@@ -121,7 +121,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else
@@ -152,7 +152,7 @@ namespace {
// Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
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
@@ -246,7 +246,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if 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);
#else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -276,7 +276,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -328,7 +328,7 @@ namespace {
// Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
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
@@ -449,7 +449,7 @@ namespace {
}
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
+4
View File
@@ -50,6 +50,8 @@ double from_chars(const char *first, const char* end) noexcept;
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
#if SIMDJSON_REGULAR_VISUAL_STUDIO
// We could use [[deprecated]] but it requires C++14
#define simdjson_deprecated __declspec(deprecated)
#define simdjson_really_inline __forceinline
#define simdjson_never_inline __declspec(noinline)
@@ -88,6 +90,8 @@ double from_chars(const char *first, const char* end) noexcept;
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
// We could use [[deprecated]] but it requires C++14
#define simdjson_deprecated __attribute__((deprecated))
#define simdjson_really_inline inline __attribute__((always_inline))
#define simdjson_never_inline inline __attribute__((noinline))
+14
View File
@@ -7,6 +7,7 @@
#include "simdjson/dom/array.h"
#include "simdjson/dom/element.h"
#include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include "simdjson/internal/tape_ref-inl.h"
#include <limits>
@@ -44,6 +45,13 @@ inline simdjson_result<dom::element> simdjson_result<dom::array>::at_pointer(std
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::array>::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::array>::at(size_t index) const noexcept {
if (error()) { return error(); }
return first.at(index);
@@ -113,6 +121,12 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
return child;
}
inline simdjson_result<element> array::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0;
+16
View File
@@ -108,6 +108,21 @@ public:
*/
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
/**
* Get the value at the given index. This function has linear-time complexity and
* is equivalent to the following:
@@ -152,6 +167,7 @@ public:
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at(size_t index) const noexcept;
#if SIMDJSON_EXCEPTIONS
+11
View File
@@ -9,6 +9,7 @@
#include "simdjson/dom/object-inl.h"
#include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include <ostream>
#include <limits>
@@ -122,6 +123,11 @@ simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_path(const std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
@@ -412,6 +418,11 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
}
}
}
inline simdjson_result<element> element::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
inline simdjson_result<element> element::at(std::string_view json_pointer) const noexcept {
+19
View File
@@ -372,6 +372,8 @@ public:
* - INCORRECT_TYPE if this is not an object
*/
inline simdjson_result<element> operator[](const char *key) const noexcept;
simdjson_result<element> operator[](int) const noexcept = delete;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -397,6 +399,21 @@ public:
*/
inline simdjson_result<element> at_pointer(const std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
/**
*
@@ -525,7 +542,9 @@ public:
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_result<dom::element> operator[](int) const noexcept = delete;
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept;
+12
View File
@@ -7,6 +7,7 @@
#include "simdjson/dom/element-inl.h"
#include "simdjson/error-inl.h"
#include "simdjson/jsonpathutil.h"
#include <cstring>
@@ -34,6 +35,11 @@ inline simdjson_result<dom::element> simdjson_result<dom::object>::at_pointer(st
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<dom::element> simdjson_result<dom::object>::at_key(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
@@ -131,6 +137,12 @@ inline simdjson_result<element> object::at_pointer(std::string_view json_pointer
return child;
}
inline simdjson_result<element> object::at_path(std::string_view json_path) const noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
return at_pointer(json_pointer);
}
inline simdjson_result<element> object::at_key(std::string_view key) const noexcept {
iterator end_field = end();
for (iterator field = begin(); field != end_field; ++field) {
+18
View File
@@ -145,6 +145,7 @@ public:
* - INCORRECT_TYPE if this is not an object
*/
inline simdjson_result<element> operator[](const char *key) const noexcept;
simdjson_result<element> operator[](int) const noexcept = delete;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
@@ -171,6 +172,21 @@ public:
*/
inline simdjson_result<element> at_pointer(std::string_view json_pointer) const noexcept;
/**
* Get the value associated with the given JSONPath expression. We only support
* JSONPath queries that trivially convertible to JSON Pointer queries: key
* names and array indices.
*
* https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00
*
* @return The value associated with the given JSONPath expression, or:
* - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails
* - NO_SUCH_FIELD if a field does not exist in an object
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
* - INCORRECT_TYPE if a non-integer is used to access an array
*/
inline simdjson_result<element> at_path(std::string_view json_path) const noexcept;
/**
* Get the value associated with the given key.
*
@@ -243,7 +259,9 @@ public:
inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_result<dom::element> operator[](int) const noexcept = delete;
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
+22 -1
View File
@@ -202,6 +202,22 @@ public:
* simdjson::dom::parser parser;
* simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
*
* ### std::string references
*
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
*
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
* the string but before the end of the allocated memory (std::string::capacity()).
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
* container-overflow checks, you may encounter sanitizer warnings.
* You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
* string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
* which can be be passed to the parser's parse function:
*
* std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
* element doc = parser.parse(simdjson::pad(json));
*
* ### Parser Capacity
*
* If the parser's current capacity is less than len, it will allocate enough capacity
@@ -549,9 +565,14 @@ public:
/**
* The parser instance can use threads when they are available to speed up some
* operations. It is enabled by default. Changing this attribute will change the
* behavior of the parser for future operations.
* behavior of the parser for future operations. Set to true by default.
*/
bool threaded{true};
#else
/**
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
*/
bool threaded{false};
#endif
/** @private Use the new DOM API instead */
class Iterator;
+1 -1
View File
@@ -86,7 +86,7 @@ struct simdjson_error : public std::exception {
*/
simdjson_error(error_code error) noexcept : _error{error} { }
/** The error message */
const char *what() const noexcept { return error_message(error()); }
const char *what() const noexcept override { return error_message(error()); }
/** The error code */
error_code error() const noexcept { return _error; }
private:
@@ -75,6 +75,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
-1
View File
@@ -574,7 +574,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
+1 -47
View File
@@ -2,6 +2,7 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_ARRAY_INL_H
#include "simdjson/jsonpathutil.h"
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/array.h"
#include "simdjson/generic/ondemand/array_iterator-inl.h"
@@ -163,53 +164,6 @@ inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) n
return child;
}
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
if (json_path.empty() || (json_path.front() != '.' &&
json_path.front() != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
size_t i = 0;
while (i < json_path.length()) {
if (json_path[i] == '.') {
result += '/';
} else if (json_path[i] == '[') {
result += '/';
++i; // Move past the '['
while (i < json_path.length() && json_path[i] != ']') {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
++i;
}
if (i == json_path.length() || json_path[i] != ']') {
return "-1"; // Using sentinel value that will be handled as an error by the caller.
}
} else {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
}
++i;
}
return result;
}
inline simdjson_result<value> array::at_path(std::string_view json_path) noexcept {
auto json_pointer = json_path_to_pointer_conversion(json_path);
if (json_pointer == "-1") { return INVALID_JSON_POINTER; }
+2 -1
View File
@@ -44,7 +44,8 @@ public:
* calling this function, if successful, the array is 'rewinded' at its
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
* safe to continue. Note that count_elements() does not validate the JSON values,
* only the structure of the array.
*
* To check that an array is empty, it is more performant to use
* the is_empty() method.
@@ -13,5 +13,6 @@
#include "simdjson/padded_string.h"
#include "simdjson/padded_string_view.h"
#include "simdjson/internal/dom_parser_implementation.h"
#include "simdjson/jsonpathutil.h"
#endif // SIMDJSON_GENERIC_ONDEMAND_DEPENDENCIES_H
@@ -3,17 +3,15 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_INL_H
#include "simdjson/generic/ondemand/base.h"
#include "simdjson/generic/ondemand/array-inl.h"
#include "simdjson/generic/ondemand/array_iterator.h"
#include "simdjson/generic/ondemand/document.h"
#include "simdjson/generic/ondemand/json_iterator-inl.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion-inl.h"
#include "simdjson/generic/ondemand/json_type.h"
#include "simdjson/generic/ondemand/object-inl.h"
#include "simdjson/generic/ondemand/raw_json_string.h"
#include "simdjson/generic/ondemand/value.h"
#include "simdjson/generic/ondemand/value-inl.h"
#include "simdjson/generic/ondemand/array-inl.h"
#include "simdjson/generic/ondemand/json_iterator-inl.h"
#include "simdjson/generic/ondemand/object-inl.h"
#include "simdjson/generic/ondemand/value_iterator-inl.h"
#include "simdjson/generic/ondemand/deserialize.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
@@ -179,10 +177,19 @@ template<> simdjson_inline error_code document::get(int64_t& out) & noexcept { r
template<> simdjson_inline error_code document::get(bool& out) & noexcept { return get_bool().get(out); }
template<> simdjson_inline error_code document::get(value& out) & noexcept { return get_value().get(out); }
template<> simdjson_deprecated simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
template<> simdjson_deprecated simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
template<> simdjson_deprecated simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
#if SIMDJSON_EXCEPTIONS
template <class T>
simdjson_inline document::operator T() noexcept(false) { return get<T>(); }
simdjson_deprecated simdjson_inline document::operator T() && noexcept(false) { return get<T>(); }
template <class T>
simdjson_inline document::operator T() & noexcept(false) { return get<T>(); }
simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
@@ -469,7 +476,7 @@ simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::onde
return first.get<T>();
}
template<typename T>
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get() && noexcept {
simdjson_deprecated simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first).get<T>();
}
@@ -485,7 +492,7 @@ simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::do
}
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() & noexcept = delete;
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() && noexcept {
template<> simdjson_deprecated simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get<SIMDJSON_IMPLEMENTATION::ondemand::document>() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::document>(first);
}
+17 -4
View File
@@ -254,7 +254,7 @@ public:
#endif
}
/** @overload template<typename T> error_code get(T &out) & noexcept */
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
#if SIMDJSON_EXCEPTIONS
/**
@@ -267,7 +267,10 @@ public:
* @returns An instance of type T
*/
template <class T>
explicit simdjson_inline operator T() noexcept(false);
explicit simdjson_inline operator T() & noexcept(false);
template <class T>
explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false);
/**
* Cast this JSON value to an array.
*
@@ -351,7 +354,8 @@ public:
* calling this function, if successful, the array is 'rewinded' at its
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
* safe to continue. Note that count_elements() does not validate the JSON values,
* only the structure of the array.
*/
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
/**
@@ -463,6 +467,7 @@ public:
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
simdjson_result<value> operator[](int) & noexcept = delete;
/**
* Get the type of this JSON value. It does not validate or consume the value.
@@ -731,6 +736,11 @@ protected:
/**
* A document_reference is a thin wrapper around a document reference instance.
* The document_reference instances are used primarily/solely for streams of JSON
* documents. They differ from document instances when parsing a scalar value
* (a document that is not an array or an object). In the case of a document,
* we expect the document to be fully consumed. In the case of a document_reference,
* we allow trailing content.
*/
class document_reference {
public:
@@ -844,6 +854,7 @@ public:
simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
simdjson_result<value> operator[](int) & noexcept = delete;
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
@@ -896,7 +907,7 @@ public:
simdjson_inline simdjson_result<bool> is_null() noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
template<typename T> simdjson_deprecated simdjson_inline simdjson_result<T> get() && noexcept;
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
@@ -922,6 +933,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) & noexcept = delete;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
@@ -999,6 +1011,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) & noexcept = delete;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
@@ -316,7 +316,7 @@ private:
friend class document;
friend class json_iterator;
friend struct simdjson_result<ondemand::document_stream>;
friend struct internal::simdjson_result_base<ondemand::document_stream>;
friend struct simdjson::internal::simdjson_result_base<ondemand::document_stream>;
}; // document_stream
} // namespace ondemand
@@ -1,67 +0,0 @@
#pragma once
#ifndef SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
#define SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_GENERIC_ONDEMAND_JSON_PATH_TO_POINTER_CONVERSION_INL_H
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {}
namespace ondemand {
simdjson_inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
if (json_path.empty() || (json_path.front() != '.' && json_path.front() != '[') {
return "-1"; // Sentinel value to be handled as an error by the caller.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
// Skip the initial '.' as it's assumed every path starts with it.
size_t i = 0;
while (i < json_path.length()) {
if (json_path[i] == '.') {
result += '/';
} else if (json_path[i] == '[') {
result += '/';
++i; // Move past the '['
while (i < json_path.length() && json_path[i] != ']') {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
++i;
}
if (i == json_path.length() || json_path[i] != ']') {
return "-1"; // Returning sentinel value that will be handled as an error by the caller
}
} else {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
}
++i;
}
return simdjson_result<std::string>(result);
}
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_INL_H
@@ -1,22 +0,0 @@
#pragma once
#ifndef SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_H
#define SIMDJSON_ONDEMAND_GENERIC_JSON_PATH_TO_POINTER_CONVERSION_H
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace internal {
/**
* Converts JSONPath to JSON Pointer.
* @param json_path The JSONPath string to be converted.
* @return A string containing the equivalent JSON Pointer.
* @throws simdjson_error If the conversion fails.
*/
simdjson_inline std::string json_path_to_pointer_conversion(std::string_view json_path);
} // namespace internal
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#endif // SIMDJSON_JSON_PATH_TO_POINTER_CONVERSION_H
+22 -2
View File
@@ -84,6 +84,22 @@ public:
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
* SIMDJSON_PADDING bytes to avoid runtime warnings.
*
* ### std::string references
*
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
*
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
* the string but before the end of the allocated memory (std::string::capacity()).
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
* container-overflow checks, you may encounter sanitizer warnings.
* You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
* string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
* which can be be passed to the parser's iterate function:
*
* std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
* document doc = parser.iterate(simdjson::pad(json));
*
* @param json The JSON to parse.
* @param len The length of the JSON.
* @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
@@ -278,8 +294,12 @@ public:
* behavior of the parser for future operations.
*/
bool threaded{true};
#else
/**
* When SIMDJSON_THREADS_ENABLED is not defined, the parser instance cannot use threads.
*/
bool threaded{false};
#endif
/**
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
* The result must be valid UTF-8.
@@ -340,7 +360,7 @@ public:
private:
/** @private [for benchmarking access] The implementation to use */
std::unique_ptr<internal::dom_parser_implementation> implementation{};
std::unique_ptr<simdjson::internal::dom_parser_implementation> implementation{};
size_t _capacity{0};
size_t _max_capacity;
size_t _max_depth{DEFAULT_MAX_DEPTH};
@@ -6,8 +6,6 @@
#include "simdjson/generic/ondemand/array.h"
#include "simdjson/generic/ondemand/array_iterator.h"
#include "simdjson/generic/ondemand/json_iterator.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion.h"
#include "simdjson/generic/ondemand/json_path_to_pointer_conversion-inl.h"
#include "simdjson/generic/ondemand/json_type.h"
#include "simdjson/generic/ondemand/object.h"
#include "simdjson/generic/ondemand/raw_json_string.h"
+13
View File
@@ -163,6 +163,17 @@ public:
* Important: a value should be consumed once. Calling get_string() twice on the same value
* is an error.
*
* In some instances, you may want to allow replacement of invalid Unicode sequences.
* You may do so by passing the allow_replacement parameter as true. In the following
* example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
* to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
* replacement character (U+FFFD).
*
* simdjson::ondemand::parser parser;
* auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
* simdjson::ondemand::document doc = parser.iterate(json);
* auto view = doc["deviceId"].get_string(true);
*
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
* time it parses a document or when it is destroyed.
* @returns INCORRECT_TYPE if the JSON value is not a string.
@@ -414,6 +425,7 @@ public:
simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
simdjson_result<value> operator[](int) noexcept = delete;
/**
* Get the type of this JSON value. It does not validate or consume the value.
@@ -781,6 +793,7 @@ public:
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) noexcept;
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) noexcept;
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) noexcept = delete;
/**
* Get the type of this JSON value.
@@ -6,9 +6,9 @@
#include "simdjson/generic/atomparsing.h"
#include "simdjson/generic/numberparsing.h"
#include "simdjson/generic/ondemand/json_iterator.h"
#include "simdjson/generic/ondemand/value_iterator.h"
#include "simdjson/generic/ondemand/json_type-inl.h"
#include "simdjson/generic/ondemand/raw_json_string-inl.h"
#include "simdjson/generic/ondemand/value_iterator.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
@@ -799,6 +799,8 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_tr
if(result) { // we have something that looks like a null.
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("null");
} else if (json[0] == 'n') {
return incorrect_type_error("Not a null but starts with n");
}
return result;
}
+6
View File
@@ -4,8 +4,14 @@
#include "simdjson/haswell/intrinsics.h"
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif
#endif
#include "simdjson/haswell/bitmanipulation.h"
#include "simdjson/haswell/bitmask.h"
+64
View File
@@ -0,0 +1,64 @@
#ifndef SIMDJSON_JSONPATHUTIL_H
#define SIMDJSON_JSONPATHUTIL_H
#include <string>
#include <string_view>
namespace simdjson {
/**
* Converts JSONPath to JSON Pointer.
* @param json_path The JSONPath string to be converted.
* @return A string containing the equivalent JSON Pointer.
*/
inline std::string json_path_to_pointer_conversion(std::string_view json_path) {
size_t i = 0;
// if JSONPath starts with $, skip it
if (!json_path.empty() && json_path.front() == '$') {
i = 1;
}
if (json_path.empty() || (json_path[i] != '.' &&
json_path[i] != '[')) {
return "-1"; // This is just a sentinel value, the caller should check for this and return an error.
}
std::string result;
// Reserve space to reduce allocations, adjusting for potential increases due
// to escaping.
result.reserve(json_path.size() * 2);
while (i < json_path.length()) {
if (json_path[i] == '.') {
result += '/';
} else if (json_path[i] == '[') {
result += '/';
++i; // Move past the '['
while (i < json_path.length() && json_path[i] != ']') {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
++i;
}
if (i == json_path.length() || json_path[i] != ']') {
return "-1"; // Using sentinel value that will be handled as an error by the caller.
}
} else {
if (json_path[i] == '~') {
result += "~0";
} else if (json_path[i] == '/') {
result += "~1";
} else {
result += json_path[i];
}
}
++i;
}
return result;
}
} // namespace simdjson
#endif // SIMDJSON_JSONPATHUTIL_H
@@ -36,6 +36,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
@@ -36,6 +36,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
+11 -3
View File
@@ -53,6 +53,9 @@ inline padded_string::padded_string(const char *data, size_t length) noexcept
if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, data, length);
}
if (data_ptr == nullptr) {
viable_size = 0;
}
}
#ifdef __cpp_char8_t
inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
@@ -60,12 +63,17 @@ inline padded_string::padded_string(const char8_t *data, size_t length) noexcept
if ((data != nullptr) && (data_ptr != nullptr)) {
std::memcpy(data_ptr, reinterpret_cast<const char *>(data), length);
}
if (data_ptr == nullptr) {
viable_size = 0;
}
}
#endif
// note: do not pass std::string arguments by value
inline padded_string::padded_string(const std::string & str_ ) noexcept
: viable_size(str_.size()), data_ptr(internal::allocate_padded_buffer(str_.size())) {
if (data_ptr != nullptr) {
if (data_ptr == nullptr) {
viable_size = 0;
} else {
std::memcpy(data_ptr, str_.data(), str_.size());
}
}
@@ -179,11 +187,11 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
} // namespace simdjson
inline simdjson::padded_string operator "" _padded(const char *str, size_t len) {
inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
return simdjson::padded_string(str, len);
}
#ifdef __cpp_char8_t
inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len) {
inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len) {
return simdjson::padded_string(reinterpret_cast<const char8_t *>(str), len);
}
#endif
+2 -2
View File
@@ -161,9 +161,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
} // namespace simdjson
// This is deliberately outside of simdjson so that people get it without having to use the namespace
inline simdjson::padded_string operator "" _padded(const char *str, size_t len);
inline simdjson::padded_string operator ""_padded(const char *str, size_t len);
#ifdef __cpp_char8_t
inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len);
inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len);
#endif
namespace simdjson {
@@ -53,6 +53,11 @@ inline bool padded_string_view::remove_utf8_bom() noexcept {
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
#endif
inline padded_string_view pad(std::string& s) noexcept {
const auto len = s.size();
s.append(SIMDJSON_PADDING, ' ');
return padded_string_view(s.data(), len, s.size());
}
} // namespace simdjson
+9
View File
@@ -83,6 +83,15 @@ public:
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false);
#endif
/**
* Create a padded_string_view from a string. The string will be padded with SIMDJSON_PADDING
* space characters. The resulting padded_string_view will have a length equal to the original
* string.
*
* @param s The string.
* @return The padded string.
*/
inline padded_string_view pad(std::string& s) noexcept;
} // namespace simdjson
#endif // SIMDJSON_PADDED_STRING_VIEW_H
+39
View File
@@ -201,4 +201,43 @@ using std::size_t;
#endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H
@@ -60,6 +60,12 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
+3 -3
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.10.0"
#define SIMDJSON_VERSION "3.11.1"
namespace simdjson {
enum {
@@ -15,11 +15,11 @@ enum {
/**
* The minor version (major.MINOR.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MINOR = 10,
SIMDJSON_VERSION_MINOR = 11,
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 0
SIMDJSON_VERSION_REVISION = 1
};
} // namespace simdjson
+4
View File
@@ -323,6 +323,10 @@ class Amalgamator:
for line in fid2:
line = line.rstrip('\n')
# Ignore #pragma once, it causes warnings if it ends up in a .cpp file
if re.search(r'^#pragma once$', line):
continue
# Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE
if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file!"
+149 -31
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-09-30 10:57:33 -0400. Do not edit! */
/* auto-generated on 2024-12-07 11:12:25 -0500. Do not edit! */
/* including simdjson.cpp: */
/* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP
@@ -296,6 +296,45 @@ using std::size_t;
#endif
#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#elif defined _WIN32
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#elif defined(__MVS__)
#include <sys/endian.h>
#else
#ifdef __has_include
#if __has_include(<endian.h>)
#include <endian.h>
#endif //__has_include(<endian.h>)
#endif //__has_include
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define SIMDJSON_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define SIMDJSON_IS_BIG_ENDIAN 0
#else
#define SIMDJSON_IS_BIG_ENDIAN 1
#endif
#endif
#endif // SIMDJSON_PORTABILITY_H
/* end file simdjson/portability.h */
@@ -344,6 +383,8 @@ double from_chars(const char *first, const char* end) noexcept;
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
#if SIMDJSON_REGULAR_VISUAL_STUDIO
// We could use [[deprecated]] but it requires C++14
#define simdjson_deprecated __declspec(deprecated)
#define simdjson_really_inline __forceinline
#define simdjson_never_inline __declspec(noinline)
@@ -382,6 +423,8 @@ double from_chars(const char *first, const char* end) noexcept;
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
#else // SIMDJSON_REGULAR_VISUAL_STUDIO
// We could use [[deprecated]] but it requires C++14
#define simdjson_deprecated __attribute__((deprecated))
#define simdjson_really_inline inline __attribute__((always_inline))
#define simdjson_never_inline inline __attribute__((noinline))
@@ -557,7 +600,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
// 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
#ifndef NONSTD_SV_LITE_H_INCLUDED
#define NONSTD_SV_LITE_H_INCLUDED
@@ -2438,7 +2480,7 @@ struct simdjson_error : public std::exception {
*/
simdjson_error(error_code error) noexcept : _error{error} { }
/** The error message */
const char *what() const noexcept { return error_message(error()); }
const char *what() const noexcept override { return error_message(error()); }
/** The error code */
error_code error() const noexcept { return _error; }
private:
@@ -7746,7 +7788,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// 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
#if 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).
@@ -7762,9 +7804,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
// We sometimes call leading_zeroes 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.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if 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).
@@ -7817,7 +7865,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
#else
@@ -7934,7 +7982,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */
@@ -7954,7 +8008,7 @@ namespace arm64 {
namespace {
namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace {
// Start of private section with Visual Studio workaround
@@ -8063,7 +8117,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else
@@ -8094,7 +8148,7 @@ namespace {
// Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
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
@@ -8188,7 +8242,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if 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);
#else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8218,7 +8272,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -8270,7 +8324,7 @@ namespace {
// Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
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
@@ -8391,7 +8445,7 @@ namespace {
}
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -9551,7 +9605,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -10502,7 +10555,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
// 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
#if 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).
@@ -10518,9 +10571,15 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
// We sometimes call leading_zeroes 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.
// Applies only when SIMDJSON_PREFER_REVERSE_BITS is defined and true.
// (See below.)
SIMDJSON_NO_SANITIZE_UNDEFINED
/* result might be undefined when input_num is zero */
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if 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).
@@ -10573,7 +10632,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
#endif
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
#else
@@ -10690,7 +10749,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace arm64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
/* end file simdjson/arm64/numberparsing_defs.h */
@@ -10710,7 +10775,7 @@ namespace arm64 {
namespace {
namespace simd {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
namespace {
// Start of private section with Visual Studio workaround
@@ -10819,7 +10884,7 @@ namespace {
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else
@@ -10850,7 +10915,7 @@ namespace {
// Splat constructor
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
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
@@ -10944,7 +11009,7 @@ namespace {
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if 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);
#else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -10974,7 +11039,7 @@ namespace {
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
@@ -11026,7 +11091,7 @@ namespace {
// Array constructor
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
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
@@ -11147,7 +11212,7 @@ namespace {
}
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
#if SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
@@ -14238,8 +14303,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
/* end file simdjson/haswell/intrinsics.h */
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif
#endif
/* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
/* begin file simdjson/haswell/bitmanipulation.h */
@@ -15893,7 +15964,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -16871,8 +16941,14 @@ static_assert(sizeof(__m256i) <= simdjson::SIMDJSON_PADDING, "insufficient paddi
/* end file simdjson/haswell/intrinsics.h */
#if !SIMDJSON_CAN_ALWAYS_RUN_HASWELL
// We enable bmi2 only if LLVM/clang is used, because GCC may not
// make good use of it. See https://github.com/simdjson/simdjson/pull/2243
#if defined(__clang__)
SIMDJSON_TARGET_REGION("avx2,bmi,bmi2,pclmul,lzcnt,popcnt")
#else
SIMDJSON_TARGET_REGION("avx2,bmi,pclmul,lzcnt,popcnt")
#endif
#endif
/* including simdjson/haswell/bitmanipulation.h: #include "simdjson/haswell/bitmanipulation.h" */
/* begin file simdjson/haswell/bitmanipulation.h */
@@ -22107,7 +22183,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -26873,7 +26948,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */
@@ -28477,7 +28558,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -29617,7 +29697,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace ppc64
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_PPC64_NUMBERPARSING_DEFS_H
/* end file simdjson/ppc64/numberparsing_defs.h */
@@ -35213,7 +35299,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -40299,7 +40384,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */
@@ -41773,7 +41864,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -42828,7 +42918,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lsx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LSX_NUMBERPARSING_DEFS_H
/* end file simdjson/lsx/numberparsing_defs.h */
@@ -46282,7 +46378,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */
@@ -47772,7 +47874,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -48827,7 +48928,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace lasx
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_LASX_NUMBERPARSING_DEFS_H
/* end file simdjson/lasx/numberparsing_defs.h */
@@ -52311,7 +52418,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */
@@ -53370,7 +53483,6 @@ simdjson_unused simdjson_inline simdjson_result<number_type> get_number_type(con
// Our objective is accurate parsing (ULP of 0) at high speed.
template<typename W>
simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
//
// Check for minus sign
//
@@ -54445,7 +54557,13 @@ simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t
} // namespace fallback
} // namespace simdjson
#ifndef SIMDJSON_SWAR_NUMBER_PARSING
#if SIMDJSON_IS_BIG_ENDIAN
#define SIMDJSON_SWAR_NUMBER_PARSING 0
#else
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif
#endif
#endif // SIMDJSON_FALLBACK_NUMBERPARSING_DEFS_H
/* end file simdjson/fallback/numberparsing_defs.h */
+1102 -616
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -12,6 +12,7 @@ add_cpp_test(errortests LABELS dom acceptance per_implementation
add_cpp_test(extracting_values_example LABELS dom acceptance per_implementation)
add_cpp_test(integer_tests LABELS dom acceptance per_implementation)
add_cpp_test(jsoncheck LABELS dom acceptance per_implementation)
add_cpp_test(json_path_tests LABELS dom acceptance per_implementation)
add_cpp_test(minefieldcheck LABELS dom acceptance per_implementation)
add_cpp_test(numberparsingcheck LABELS dom acceptance per_implementation) # https://tools.ietf.org/html/rfc6901
add_cpp_test(parse_many_test LABELS dom acceptance per_implementation)
+350
View File
@@ -0,0 +1,350 @@
/**
* refer to pathcheck.cpp
*/
#include <iostream>
#include <string>
using namespace std::string_literals;
#include "simdjson.h"
#include "test_macros.h"
// we define our own asserts to get around NDEBUG
#ifndef ASSERT
#define ASSERT(x) \
{ \
if (!(x)) { \
std::cerr << "Failed assertion " << #x << std::endl; \
return false; \
} \
}
#endif
using namespace simdjson;
bool demo() {
#if SIMDJSON_EXCEPTIONS
std::cout << "demo test" << std::endl;
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars = parser.parse(cars_json);
double x = cars.at_path("$[0].tire_pressure[1]");
if (x != 39.9)
return false;
// Iterating through an array of objects
std::vector<double> measured;
for (dom::element car_element : cars) {
dom::object car;
simdjson::error_code error;
if ((error = car_element.get(car))) {
std::cerr << error << std::endl;
return false;
}
double x3 = car.at_path("$.tire_pressure[1]");
measured.push_back(x3);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
#endif
return true;
}
const padded_string TEST_JSON = R"(
{
"/~01abc": [
0,
{
"\\\" 0": [
"value0",
"value1"
]
}
],
"0": "0 ok",
"01": "01 ok",
"": "empty ok",
"arr": []
}
)"_padded;
const padded_string TEST_RFC_JSON = R"(
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
)"_padded;
bool run_success_test(const padded_string &source, const char *json_path,
std::string_view expected_value) {
std::cout << "Running successful JSONPath test '" << json_path << "' ..."
<< std::endl;
dom::parser parser;
dom::element doc;
auto error = parser.parse(source).get(doc);
if (error) {
std::cerr << "cannot parse: " << error << std::endl;
return false;
}
dom::element answer;
error = doc.at_path(json_path).get(answer);
if (error) {
std::cerr << "cannot access pointer: " << error << std::endl;
return false;
}
std::string str_answer = simdjson::minify(answer);
if (str_answer != expected_value) {
std::cerr << "They differ!!!" << std::endl;
std::cerr << " found '" << str_answer << "'" << std::endl;
std::cerr << " expected '" << expected_value << "'" << std::endl;
}
ASSERT_EQUAL(str_answer, expected_value);
return true;
}
bool run_failure_test(const padded_string &source, const char *json_path,
error_code expected_error) {
std::cout << "Running invalid JSONPath test '" << json_path << "' ..."
<< std::endl;
dom::parser parser;
ASSERT_ERROR(parser.parse(source).at_path(json_path).error(), expected_error);
return true;
}
bool demo_relative_path() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
auto error = parser.parse(cars_json).get(cars);
if (error) {
std::cerr << "cannot parse: " << error << std::endl;
return false;
}
dom::array cars_array;
error = cars.get(cars_array);
if (error) {
std::cerr << "cannot get array: " << error << std::endl;
return false;
}
for (auto car_element : cars_array) {
double x;
ASSERT_SUCCESS(car_element.at_path(".tire_pressure[1]").get(x));
measured.push_back(x);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
TEST_SUCCEED();
}
bool many_json_paths() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
ASSERT_SUCCESS(parser.parse(cars_json).get(cars));
for (int i = 0; i < 3; i++) {
double x;
std::string json_path = std::string("$[") + std::to_string(i) +
std::string("].tire_pressure[1]");
ASSERT_SUCCESS(cars.at_path(json_path).get(x));
measured.push_back(x);
}
std::vector<double> expected = {39.9, 31, 30};
if (measured != expected) {
return false;
}
TEST_SUCCEED();
}
bool many_json_paths_object_array() {
TEST_START();
auto dogcatpotato =
R"( { "dog" : [1,2,3], "cat" : [5, 6, 7], "potato" : [1234]})"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(dogcatpotato).get(doc));
dom::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.dog[1]").get(x));
ASSERT_EQUAL(x, 2);
ASSERT_SUCCESS(obj.at_path("$.potato[0]").get(x));
ASSERT_EQUAL(x, 1234);
TEST_SUCCEED();
}
bool many_json_paths_object() {
TEST_START();
auto cfoofoo2 =
R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(cfoofoo2).get(doc));
dom::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.c.foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
ASSERT_SUCCESS(obj.at_path("$.d.foo2.a.2").get(x));
ASSERT_EQUAL(x, 30);
ASSERT_SUCCESS(obj.at_path("$.e").get(x));
ASSERT_EQUAL(x, 120);
TEST_SUCCEED();
}
bool many_json_paths_array() {
TEST_START();
auto cfoofoo2 =
R"( [ 111, 2, 3, { "foo": { "a": [ 10, 20, 33 ] }}, { "foo2": { "a": [ 10, 20, 30 ] }}, 1001 ])"_padded;
dom::parser parser;
dom::element doc;
ASSERT_SUCCESS(parser.parse(cfoofoo2).get(doc));
dom::array arr;
ASSERT_SUCCESS(doc.get_array().get(arr));
int64_t x;
ASSERT_SUCCESS(arr.at_path("$[3].foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
TEST_SUCCEED();
}
struct car_type {
std::string make;
std::string model;
uint64_t year;
std::vector<double> tire_pressure;
car_type(std::string_view _make, std::string_view _model, uint64_t _year,
std::vector<double> &&_tire_pressure)
: make{_make}, model{_model}, year(_year), tire_pressure(_tire_pressure) {
}
};
bool json_path_invalidation() {
TEST_START();
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element cars;
std::vector<double> measured;
ASSERT_SUCCESS(parser.parse(cars_json).get(cars));
std::vector<car_type> content;
for (int i = 0; i < 3; i++) {
dom::object obj;
std::string json_path =
std::string("$[") + std::to_string(i) + std::string("]");
// Each successive at_path call invalidates
// previously parsed values, strings, objects and array.
ASSERT_SUCCESS(cars.at_path(json_path).get(obj));
// We materialize the object.
std::string_view make;
ASSERT_SUCCESS(obj["make"].get(make));
std::string_view model;
ASSERT_SUCCESS(obj["model"].get(model));
uint64_t year;
ASSERT_SUCCESS(obj["year"].get(year));
// We materialize the array.
dom::array arr;
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
std::vector<double> values;
for (auto x : arr) {
double value_double;
ASSERT_SUCCESS(x.get(value_double));
values.push_back(value_double);
}
content.emplace_back(make, model, year, std::move(values));
}
std::string expected[] = {"Toyota", "Kia", "Toyota"};
int i = 0;
for (car_type c : content) {
std::cout << c.make << " " << c.model << " " << c.year << "\n";
ASSERT_EQUAL(expected[i++], c.make);
}
TEST_SUCCEED();
}
// for 0.5 version and following (standard compliant)
bool modern_support() {
#if SIMDJSON_EXCEPTIONS
std::cout << "modern test" << std::endl;
auto example_json = R"({"key": "value", "array": [0, 1, 2]})"_padded;
dom::parser parser;
dom::element example = parser.parse(example_json);
std::string_view value_str = example.at_path("$.key");
ASSERT_EQUAL(value_str, "value");
int64_t array0 = example.at_path("$.array[0]");
ASSERT_EQUAL(array0, 0);
array0 = example.at_path("$.array").at_path("$[0]");
ASSERT_EQUAL(array0, 0);
ASSERT_ERROR(example.at_path("$.no_such_key").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_path("$.array[9]").error(), INDEX_OUT_OF_BOUNDS);
ASSERT_ERROR(example.at_path("$.array.not_a_num").error(), INCORRECT_TYPE);
ASSERT_ERROR(example.at_path("$.array.").error(), INVALID_JSON_POINTER);
#endif
return true;
}
int main() {
if (true && demo() && modern_support() &&
run_success_test(TEST_RFC_JSON, "$.foo", "[\"bar\",\"baz\"]") &&
run_success_test(TEST_RFC_JSON, "$.foo[0]", "\"bar\"") &&
run_success_test(TEST_RFC_JSON, "$.", "0") &&
run_success_test(TEST_RFC_JSON, "$.a/b", "1") &&
run_success_test(TEST_RFC_JSON, "$.c%d", "2") &&
run_success_test(TEST_RFC_JSON, "$.e^f", "3") &&
run_success_test(TEST_RFC_JSON, "$.g|h", "4") &&
run_success_test(TEST_RFC_JSON, "$.i\\j", "5") &&
run_success_test(TEST_RFC_JSON, "$.k\"l", "6") &&
run_success_test(TEST_RFC_JSON, "$. ", "7") &&
run_success_test(TEST_RFC_JSON, "$.m~n", "8") &&
run_success_test(TEST_JSON, "$./~01abc",
R"([0,{"\\\" 0":["value0","value1"]}])") &&
run_success_test(TEST_JSON, "$./~01abc[1]",
R"({"\\\" 0":["value0","value1"]})") &&
run_success_test(TEST_JSON, "$./~01abc[1].\\\" 0",
R"(["value0","value1"])") &&
run_success_test(TEST_JSON, "$.arr", R"([])") // get array
&&
run_failure_test(TEST_JSON, R"($./~01abc[1].\\\" 0[2])", NO_SUCH_FIELD) &&
run_failure_test(TEST_JSON, "$.arr[0]", INDEX_OUT_OF_BOUNDS) &&
run_failure_test(TEST_JSON, "/~01abc", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, ".~1abc", NO_SUCH_FIELD) &&
run_failure_test(TEST_JSON, "./~01abc.01", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, "./~01abc.", INVALID_JSON_POINTER) &&
run_failure_test(TEST_JSON, "./~01abc.-", INDEX_OUT_OF_BOUNDS)) {
std::cout << "Success!" << std::endl;
return 0;
} else {
std::cerr << "Failed!" << std::endl;
return 1;
}
}
+45
View File
@@ -461,7 +461,52 @@ void parse_documentation_lowlevel() {
(void)element;
}
void simplepad() {
std::string json = "[1]";
dom::parser parser;
dom::element doc;
auto error = parser.parse(simdjson::pad(json)).get(doc);
if(error) { exit(-1); }
}
void jsondollar() {
dom::parser parser;
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
dom::element doc;
auto error = parser.parse(json).get(doc);
if(error) { exit(-1); }
dom::object obj;
error = doc.get_object().get(obj);
if(error) { exit(-1); }
int64_t x = 0; // initialization to silence unwarranted compiler warning
error = obj.at_path("$[3].foo.a[1]").get(x);
if(error) { exit(-1); }
if(x != 20) { exit(-1); }
x = obj.at_path("$.d.foo2.a.2");
if(x != 30) { exit(-1); }
if(error) { exit(-1); }
}
void jsonpath() {
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::element doc;
auto error = parser.parse(cars_json).get(doc);
if(error) { exit(-1); }
double p = 0.0; // initialization to silence unwarranted compiler warning
error = doc.at_path("[0].tire_pressure[1]").get(p);
if(error) { exit(-1); }
if(p != 39.9) { exit(-1); }
}
int main() {
simplepad();
jsonpath();
jsondollar();
basics_dom_1();
basics_dom_2();
basics_dom_3();
@@ -13,7 +13,8 @@ function(add_dual_compile_test TEST_NAME)
target_compile_definitions(${TEST_NAME}_should_not_compile PRIVATE COMPILATION_TEST_USE_FAILING_CODE=1)
endfunction(add_dual_compile_test)
add_dual_compile_test(iterate_object)
add_dual_compile_test(iterate_array)
add_dual_compile_test(iterate_char_star)
add_dual_compile_test(iterate_string_view)
add_dual_compile_test(iterate_temporary_buffer)
@@ -0,0 +1,34 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main() {
auto json = "[1]"_padded;
ondemand::parser parser;
auto f = [](ondemand::parser& p, simdjson::padded_string& jsons) -> ondemand::document {
ondemand::document doc;
auto error = p.iterate(jsons).get(doc);
if(error) { std::abort(); }
return doc;
};
ondemand::array arrayv;
#if COMPILATION_TEST_USE_FAILING_CODE
// Not allowed as this would be unsafe, the document must remain alive.
auto error = f(parser).get_array().get(arrayv);
#else
ondemand::document doc = f(parser, json);
auto error = doc.get_array().get(arrayv);
#endif
if(error) {
std::cout << "Failure" << std::endl;
}
int64_t a = 0;
error = arrayv.at(0).get_int64().get(a);
if(error) {
std::cout << "failure" << std::endl;
}
printf("a = %d\n", (int)a);
return EXIT_SUCCESS;
}
@@ -0,0 +1,34 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main() {
auto json = "{\"a\":1}"_padded;
ondemand::parser parser;
auto f = [](ondemand::parser& p, simdjson::padded_string& jsons) -> ondemand::document {
ondemand::document doc;
auto error = p.iterate(jsons).get(doc);
if(error) { std::abort(); }
return doc;
};
ondemand::object objv;
#if COMPILATION_TEST_USE_FAILING_CODE
// Not allowed as this would be unsafe, the document must remain alive.
auto error = f(parser).get_object().get(objv);
#else
ondemand::document doc = f(parser, json);
auto error = doc.get_object().get(objv);
#endif
if(error) {
std::cout << "Failure" << std::endl;
}
int64_t a = 0;
error = objv["a"].get_int64().get(a);
if(error) {
std::cout << "failure" << std::endl;
}
printf("a = %d\n", (int)a);
return EXIT_SUCCESS;
}
+22 -2
View File
@@ -21,8 +21,24 @@ long page_size() {
// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the
// page boundary.
bool need_allocation(const char *buf, size_t len) {
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size()) <
simdjson::SIMDJSON_PADDING);
return ((reinterpret_cast<uintptr_t>(buf + len - 1) % page_size())
+ simdjson::SIMDJSON_PADDING > static_cast<uintptr_t>(page_size()));
}
bool check_need_allocation() {
long ps = page_size();
std::vector<std::tuple<uintptr_t,size_t,bool>> test_cases = {
{2*ps, 5, false}, {2*ps, ps, true}, {2*ps, 100, false},
};
for(auto t : test_cases) {
uintptr_t buf = std::get<0>(t);
size_t len = std::get<1>(t);
bool expected = std::get<2>(t);
if(need_allocation(reinterpret_cast<const char *>(buf), len) != expected) {
return false;
}
}
return true;
}
simdjson::padded_string_view
@@ -39,6 +55,10 @@ get_padded_string_view(const char *buf, size_t len,
int main() {
printf("page_size: %ld\n", page_size());
if(!check_need_allocation()) {
printf("Bug in the need_allocation function.\n");
return EXIT_FAILURE;
}
const char *jsonpoiner = R"(
{
"key": "value"
@@ -59,6 +59,22 @@ void compilation_test_3() {
}
}
}
// Do not run this, it is only meant to compile
void compilation_test_4() {
const padded_string bogus = ""_padded;
ondemand::parser parser;
int64_t x1 = (int64_t)parser.iterate(bogus);
double x2 = (double)parser.iterate(bogus);
std::string_view x = (std::string_view)parser.iterate(bogus);
uint64_t x3 = (uint64_t)parser.iterate(bogus);
bool x4 = (bool)parser.iterate(bogus);
(void) x1;
(void) x2;
(void) x3;
(void) x4;
(void) x;
}
#endif // SIMDJSON_EXCEPTIONS
int main(void) {
@@ -346,6 +346,54 @@ namespace json_path_tests {
TEST_SUCCEED();
}
bool many_json_paths_with_prefix() {
TEST_START();
// object
{
auto cfoofoo2 = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(cfoofoo2).get(doc));
ondemand::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.c.foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
ASSERT_SUCCESS(obj.at_path("$.d.foo2.a.2").get(x));
ASSERT_EQUAL(x, 30);
ASSERT_SUCCESS(obj.at_path("$.e").get(x));
ASSERT_EQUAL(x, 120);
}
// array
{
auto cfoofoo2 = R"( [ 111, 2, 3, { "foo": { "a": [ 10, 20, 33 ] }}, { "foo2": { "a": [ 10, 20, 30 ] }}, 1001 ])"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(cfoofoo2).get(doc));
ondemand::array arr;
ASSERT_SUCCESS(doc.get_array().get(arr));
int64_t x;
ASSERT_SUCCESS(arr.at_path("$[3].foo.a[1]").get(x));
ASSERT_EQUAL(x, 20);
}
// onject array
{
auto dogcatpotato = R"( { "dog" : [1,2,3], "cat" : [5, 6, 7], "potato" : [1234]})"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(dogcatpotato).get(doc));
ondemand::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
int64_t x;
ASSERT_SUCCESS(obj.at_path("$.dog[1]").get(x));
ASSERT_EQUAL(x, 2);
ASSERT_SUCCESS(obj.at_path("$.potato[0]").get(x));
ASSERT_EQUAL(x, 1234);
}
TEST_SUCCEED();
}
#if SIMDJSON_EXCEPTIONS
bool json_path_invalidation_exceptions() {
TEST_START();
@@ -392,6 +440,7 @@ namespace json_path_tests {
many_json_paths_array() &&
many_json_paths_object() &&
many_json_paths_object_array() &&
many_json_paths_with_prefix() &&
run_broken_tests() &&
json_path_invalidation() &&
demo_test() &&
@@ -164,8 +164,7 @@ namespace json_pointer_tests {
ASSERT_TRUE(is_scalar);
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
std::cout << " checking true"<< std::endl;
ASSERT_SUCCESS(parser.iterate(true_json).get(doc));
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
ASSERT_SUCCESS(parser.iterate(true_json).is_scalar().get(is_scalar));
ASSERT_TRUE(is_scalar);
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
std::cout << " checking object"<< std::endl;
+24 -1
View File
@@ -8,7 +8,15 @@
#endif
using namespace std;
using namespace simdjson;
using error_code=simdjson::error_code;
using error_code = simdjson::error_code;
bool simplepad() {
std::string json = "[1]";
ondemand::parser parser;
ondemand::document doc;
auto error = parser.iterate(simdjson::pad(json)).get(doc);
return error == SUCCESS;
}
bool string1() {
const char * data = "my data"; // 7 bytes
@@ -221,6 +229,19 @@ bool gen_raw2() {
TEST_SUCCEED();
}
bool jsondollar() {
TEST_START();
auto json = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object obj = doc.get_object();
int64_t x = obj.at_path("$.c.foo.a[1]"); // 20
ASSERT_EQUAL(x, 20);
x = obj.at_path("$.d.foo2.a.2"); // 30
ASSERT_EQUAL(x, 30);
TEST_SUCCEED();
}
bool gen_raw3() {
TEST_START();
simdjson::ondemand::parser parser;
@@ -1876,6 +1897,7 @@ bool run() {
#if SIMDJSON_CPLUSPLUS17
&& big_int_array()
#endif // SIMDJSON_CPLUSPLUS17
&& jsondollar()
&& big_int_array_as_double()
&& key_raw_json_token()
&& to_optional()
@@ -1904,6 +1926,7 @@ bool run() {
&& using_the_parsed_json_4()
&& using_the_parsed_json_5()
#endif
&& simplepad()
&& using_the_parsed_json_6()
&& json_pointer_simple()
&& json_pointer_unicode()
+12 -3
View File
@@ -369,15 +369,24 @@ namespace scalar_tests {
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
bool x;
ASSERT_SUCCESS(doc.is_null().get(x));
ASSERT_TRUE(!x);
ASSERT_ERROR(doc.is_null(), INCORRECT_TYPE);
TEST_SUCCEED();
}
bool nul() {
TEST_START();
auto json = R"( nul )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.is_null(), INCORRECT_TYPE);
TEST_SUCCEED();
}
bool run() {
return
nully() &&
nul() &&
string_with_trailing() &&
uint64_with_trailing() &&
int64_with_trailing() &&