Compare commits

...

31 Commits

Author SHA1 Message Date
Daniel Lemire 3620e9d151 version bump 2024-06-11 15:37:22 -04:00
Daniel Lemire d017cd7ca4 Merge branch 'master' of github.com:simdjson/simdjson 2024-06-11 14:08:20 -04:00
Daniel Lemire d9d1ff5856 chore: remove unneeded gcc13 ci tests 2024-06-11 14:07:56 -04:00
Daniel Lemire eb8f2bce14 fix: add test for issue 2199 (#2200)
* fix: add test for issue 2199

* added ubuntu 24 workflow + silencing a warning
2024-06-11 13:55:55 -04:00
Dirk Stolle 2a4ff73468 update string_view lite to version 1.8.0 (#2197)
This is the header as seen for the tag v1.8.0,
commit a47222b9855dd6e6d1eac38acaa495822e2caa69, on
<https://github.com/martinmoene/string-view-lite>.
2024-06-10 10:29:25 -04:00
Daniel Lemire 77fc2b8447 doc: explaining the page trick (#2196)
* doc: explaining the page trick

* simplify

* did as john said

* trying something else

* flipping order

* trying some other order

* hmmm
2024-06-07 22:12:08 -04:00
Daniel Lemire ba8b66a633 Update basics.md 2024-06-07 12:49:32 -04:00
Daniel Lemire 66eec5feaf Update basics.md 2024-06-05 08:55:12 -04:00
Janeczko Jakub 3964f3e5d2 pull size_t from the std namespace (#2191) 2024-06-03 14:08:23 -04:00
Daniel Lemire ee8515122d version bump 2024-05-30 10:53:40 -04:00
halx99 5d35e7ca1f Fix compile error on llvm-19 (#2187) 2024-05-30 10:52:38 -04:00
spershin deefc88b9c Adding path for parsing incomplete json. (#2189)
1. Allows processing inclomplete, damaged, corrupted json to some extent.
2. Pariity with the Presto Java functionality.
3. Protected with SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON define.
4. Does not interfere with the normal path (can co-exist).
5. Tested in production forkflow.
2024-05-30 10:52:09 -04:00
Yuriy Chernyshov c80dda7c58 Fix building simdjson against libc++ with _LIBCPP_REMOVE_TRANSITIVE_INCLUDES defined (#2184)
```
src/implementation.cpp:193:20: error: no template named 'is_trivially_destructible' in namespace 'std'; did you mean 'is_trivially_move_constructible'?
static_assert(std::is_trivially_destructible<detect_best_supported_implementation_on_first_use>::value, "detect_best_supported_implementation_on_first_use should be trivially destructible");
              ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
                   is_trivially_move_constructible
```
2024-05-23 16:54:23 -04:00
Daniel Lemire d2954ef68b Update ubuntu22-gcc13.yml 2024-05-23 16:53:48 -04:00
Daniel Lemire ac719827ff fix: solve issue 2181 (#2182) 2024-05-11 20:44:38 -04:00
Daniel Lemire 6ea77392a7 Update basics.md 2024-05-10 12:21:26 -04:00
pnck e2f879751c fix: issue #2154 (#2178) 2024-05-10 00:33:09 -04:00
Daniel Lemire bf7834179c version bump 2024-05-07 19:15:43 -04:00
Daniel Lemire 69ab8848bf fix: satisfy a C++20 compiler warning (#2177) 2024-05-07 18:04:59 -04:00
Daniel Lemire 7288323e36 Update basics.md 2024-05-06 21:09:56 -04:00
Daniel Lemire 3f381cf3ee Update README.md 2024-05-06 11:11:34 -04:00
Daniel Lemire 52406402ed fix: replace vm*vq_u8 by vm*vq_u32 for better performance under some systems. 2024-05-01 14:53:48 -04:00
Daniel Lemire 799d8e3fc9 fix ref 2024-04-26 14:09:42 -04:00
Daniel Lemire 6c647d9f3b Update README.md 2024-04-24 16:23:45 -04:00
Daniel Lemire 8519e24f12 issue 2170 (#2172) 2024-04-24 01:41:40 -04:00
Daniel Lemire fffb62743c removing power fuzzer. 2024-04-23 23:50:49 -04:00
Daniel Lemire c888075f8d makes implementations trivially destructible (#2171) 2024-04-23 23:49:20 -04:00
Daniel Lemire 9b8aac5f22 [skip ci] updating documentation 2024-04-22 09:18:49 -04:00
Javier Blazquez 40b414d184 add Windows ARM64EC build and CI support (#2168)
* add Windows ARM64EC support

* add ARM64EC to vs17-arm-ci workflow
2024-04-09 14:56:58 -04:00
Daniel Lemire c85e8a7db1 version bump 2024-04-05 15:19:02 -04:00
Daniel Lemire 83f390f8e7 fix: adopt recommendation from issue 2163 (#2164) 2024-04-05 15:17:57 -04:00
48 changed files with 1629 additions and 440 deletions
-71
View File
@@ -1,71 +0,0 @@
name: short fuzz on the power arch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
armv7_job:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
# The host should always be Linux
runs-on: ubuntu-20.04
name: Build on ubuntu-20.04 ppc64le
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2.0.5
name: Run commands
id: runcmd
env:
DEBIAN_FRONTEND: noninteractive
with:
arch: ppc64le
distro: buster
# Not required, but speeds up builds by storing container images in
# a GitHub package registry.
githubToken: ${{ github.token }}
run: |
export CLANGSUFFIX="-7"
apt-get -qq update
apt-get install -q -y clang-7 libfuzzer-7-dev git wget zip ninja-build gnupg software-properties-common
wget -q -O - "https://raw.githubusercontent.com/simdjson/debian-ppa/master/key.gpg" | apt-key add -
apt-add-repository "deb https://raw.githubusercontent.com/simdjson/debian-ppa/master simdjson main"
apt-get -qq update
apt-get purge cmake cmake-data
apt-get -t simdjson -y install cmake
mkdir -p build ; cd build
cmake .. -GNinja \
-DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX \
-DCMAKE_C_COMPILER=clang$CLANGSUFFIX \
-DBUILD_SHARED_LIBS=OFF \
-DSIMDJSON_DEVELOPER_MODE=ON \
-DSIMDJSON_ENABLE_FUZZING=On \
-DSIMDJSON_COMPETITION=OFF \
-DSIMDJSON_GOOGLE_BENCHMARKS=OFF \
-DSIMDJSON_DISABLE_DEPRECATED_API=On \
-DSIMDJSON_FUZZ_LDFLAGS=-lFuzzer \
-DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=" \
-DCMAKE_C_FLAGS="-fsanitize=fuzzer-no-link" \
-DCMAKE_BUILD_TYPE=Release \
-DSIMDJSON_FUZZ_LINKMAIN=Off
cd ..
builddir=build
cmake --build $builddir
wget -O corpus.tar.gz https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson
tar xf corpus.tar.gz
fuzzernames=$(cmake --build $builddir --target print_all_fuzzernames |tail -n1)
for fuzzer in $fuzzernames ; do
exe=$builddir/fuzz/$fuzzer
shortname=$(echo $fuzzer |cut -f2- -d_)
echo found fuzzer $shortname with executable $exe
mkdir -p out/$shortname
others=$(find out -type d -not -name $shortname -not -name out -not -name cmin)
$exe -max_total_time=20 -max_len=4000 out/$shortname $others
echo "*************************************************************************"
done
echo "all is good, no errors found in any of these fuzzers: $fuzzernames"
-23
View File
@@ -1,23 +0,0 @@
name: Ubuntu 22.04 CI (GCC 13)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
CXX=g++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . &&
ctest --output-on-failure -LE explicitonly -j
+24
View File
@@ -0,0 +1,24 @@
name: Ubuntu 24.04 CI
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-24.04
strategy:
matrix:
shared: [ON, OFF]
cxx: [g++-13, clang++-16]
sanitizer: [ON, OFF]
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Prepare
run: cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE=${{matrix.sanitizer}} -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
env:
CXX: ${{matrix.cxx}}
- name: Build
run: cmake --build build -j=2
- name: Test
run: ctest --output-on-failure --test-dir build
+2 -1
View File
@@ -12,10 +12,11 @@ jobs:
include:
- {arch: ARM}
- {arch: ARM64}
- {arch: ARM64EC}
steps:
- name: checkout
uses: actions/checkout@v4
- name: Use cmake
run: |
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
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
+1 -1
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.9.0
VERSION 3.9.4
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
+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.9.0"
PROJECT_NUMBER = "3.9.4"
# 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
+2 -1
View File
@@ -59,6 +59,7 @@ Real-world usage
- [vast](https://github.com/tenzir/vast)
- [ada-url](https://github.com/ada-url/ada)
- [fastgron](https://github.com/adamritter/fastgron)
- [WasmEdge](https://wasmedge.org)
If you are planning to use simdjson in a product, please work from one of our releases.
@@ -180,7 +181,7 @@ CPU's multiple execution cores.
Our default front-end is called On Demand, and we wrote a paper about it:
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience 54 (6), 2024.
Some people [enjoy reading the first (2019) simdjson paper](https://arxiv.org/abs/1902.08318): A description of the design
and implementation of simdjson is in our research article:
+101 -67
View File
@@ -9,36 +9,37 @@ An overview of what you need to know to use simdjson, with examples.
- [Using simdjson with package managers](#using-simdjson-with-package-managers)
- [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
- [Versions](#versions)
- [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
- [Documents are Iterators](#documents-are-iterators)
- [Parser, Document and JSON Scope](#parser-document-and-json-scope)
- [The basics: loading and parsing JSON documents](#the-basics-loading-and-parsing-json-documents)
- [Documents are iterators](#documents-are-iterators)
- [Parser, document and JSON scope](#parser-document-and-json-scope)
- [string_view](#string_view)
- [Using the Parsed JSON](#using-the-parsed-json)
- [Using the Parsed JSON: Additional examples](#using-the-parsed-json-additional-examples)
- [Avoiding pitfalls: enable development checks](#avoiding-pitfalls-enable-development-checks)
- [Using the parsed JSON](#using-the-parsed-json)
- [Using the parsed JSON: additional examples](#using-the-parsed-json-additional-examples)
- [Adding support for custom types](#adding-support-for-custom-types)
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
- [UTF-8 validation (alone)](#utf-8-validation-alone)
- [JSON Pointer](#json-pointer)
- [JSONPath](#json-path)
- [Error Handling](#error-handling)
- [Error Handling Examples without Exceptions](#error-handling-examples-without-exceptions)
- [Disabling Exceptions](#disabling-exceptions)
- [JSONPath](#jsonpath)
- [Error handling](#error-handling)
- [Error handling examples without exceptions](#error-handling-examples-without-exceptions)
- [Disabling exceptions](#disabling-exceptions)
- [Exceptions](#exceptions)
- [Current location in document](#current-location-in-document)
- [Checking for trailing content](#checking-for-trailing-content)
- [Rewinding](#rewinding)
- [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
- [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
- [Parsing numbers inside strings](#parsing-numbers-inside-strings)
- [Dynamic Number Types](#dynamic-number-types)
- [Raw Strings From Keys](#raw-strings-from-keys)
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
- [Storing Directly into an Existing String Instance](#storing-directly-into-an-existing-string-instance)
- [Thread Safety](#thread-safety)
- [Standard Compliance](#standard-compliance)
- [Backwards Compatibility](#backwards-compatibility)
- [Raw strings from keys](#raw-strings-from-keys)
- [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string)
- [Storing directly into an existing string instance](#storing-directly-into-an-existing-string-instance)
- [Thread safety](#thread-safety)
- [Standard compliance](#standard-compliance)
- [Backwards compatibility](#backwards-compatibility)
- [Examples](#examples)
- [Performance Tips](#performance-tips)
- [Further Reading](#further-reading)
- [Performance tips](#performance-tips)
- [Further reading](#further-reading)
Requirements
@@ -50,7 +51,7 @@ Requirements
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better, AMD Zen 4 or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler.
We test the library on a big-endian system (IBM s390x with Linux) .
We test the library on a big-endian system (IBM s390x with Linux).
Including simdjson
------------------
@@ -63,20 +64,25 @@ into your project. Then include it in your project with:
using namespace simdjson; // optional
```
You can compile with:
Under most systems, you can compile with:
```
c++ myproject.cpp simdjson.cpp
```
Note:
- We recommend that you use simdjson by copying the single-header `simdjson.h` file along with the source file `simdjson.cpp` directly in your project, as they are part of [every release](https://github.com/simdjson/simdjson/releases) as assets. In this manner, you only have to compile `simdjson.cpp` as any other source file: it works well in every development environment. However, you may also use simdjson as a git submodule ([example](https://github.com/simdjson/cmakedemo)), using FetchContent ([example](https://github.com/simdjson/cmake_demo_single_file)), with ExternalProject_Add ([example](https://github.com/simdjson/cmakedemo_externalproject)) or with CPM ([example](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples/simdjson)).
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`).
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`) if you want your binaries to run everywhere.
Using simdjson with package managers
------------------
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
You can install the simdjson library on your system or in your project using multiple package managers such as MSYS2, the conan package manager, vcpkg, brew, the apt package manager (debian-based Linux systems), the FreeBSD package manager (FreeBSD), and so on. E.g., [we provide an complete example with vcpkg](https://github.com/simdjson/simdjson-vcpkg) that works under Windows. [Visit our wiki for more details](https://github.com/simdjson/simdjson/wiki/Installing-simdjson-with-a-package-manager).
The following Linux distributions provide simdjson packages: Alpine, RedHat, Rocky Linux, Debian, Fedora, and Ubuntu.
Using simdjson as a CMake dependency
------------------
@@ -141,7 +147,7 @@ https://github.com/simdjson/simdjson/blob/vx.y.z/doc/basics.md
where `x.y.z` should correspond to the version number you have
chosen.
The Basics: Loading and Parsing JSON Documents
The basics: loading and parsing JSON documents
----------------------------------------------
The simdjson library allows you to navigate and validate JSON documents ([RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html)).
@@ -153,7 +159,8 @@ For efficiency reasons, simdjson requires a string with a few bytes (`simdjson::
at the end, these bytes may be read but their content does not affect the parsing. In practice,
it means that the JSON inputs should be stored in a memory region with `simdjson::SIMDJSON_PADDING`
extra bytes at the end. You do not have to set these bytes to specific values though you may
want to if you want to avoid runtime warnings with some sanitizers.
want to if you want to avoid runtime warnings with some sanitizers. Advanced users may want to
read the section Free Padding in [our performance notes](performance.md).
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
@@ -204,7 +211,7 @@ simdjson::padded_string my_padded_data(data); // copies to a padded buffer
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.
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error Handling](#error-handling) for details.
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error handling](#error-handling) for details.
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
@@ -219,7 +226,7 @@ Further, they may use the AreFileApisANSI function to determine whether
the filename is interpreted using the ANSI or the system default OEM
codepage, and they may call SetFileApisToOEM accordingly.
Documents are Iterators
Documents are iterators
-----------------------
The simdjson library relies on an approach to parsing JSON that we call "On Demand".
@@ -229,13 +236,13 @@ walking through the original JSON text, merrily reading commas and colons and br
you get where you are going. This is the key to On Demand's performance: since it's just an iterator,
it lets you parse values as you use them. And particularly, it lets you *skip* values you do not want
to use. On Demand is also ideally suited when you want to capture part of the document without parsing it
immediately (e.g., see [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)).
immediately (e.g., see [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string)).
We refer to "On Demand" as a front-end component since it is an interface between the
low-level parsing functions and the user. It hides much of the complexity of parsing JSON
documents.
### Parser, Document and JSON Scope
### Parser, document and JSON scope
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:
@@ -264,7 +271,7 @@ copy the data into their own favorite class instances (e.g., alternatives to `st
A `std::string_view` instance is effectively just a pointer to a region in memory representing
a string. In simdjson, we return `std::string_view` instances that either point within the
input string you parsed (see [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)), or to a temporary string buffer inside
input string you parsed (see [General direct access to the raw JSON string](#general-direct-access-to-the-raw-json-string)), or to a temporary string buffer inside
our parser class instances that is valid until the parser object is destroyed or you use it to parse another document.
When using `std::string_view` instances, it is your responsibility to ensure that
`std::string_view` instance does not outlive the pointed-to memory (e.g., either the input
@@ -289,23 +296,31 @@ Some users prefer to use non-JSON native encoding formats such as UTF-16 or UTF-
transcode the UTF-8 strings produced by the simdjson library to other formats. See the
[simdutf library](https://github.com/simdutf/simdutf), for example.
Using the Parsed JSON
---------------------
Avoiding pitfalls: enable development checks
--------------------
We recommend that you first compile and run your code in Debug mode: under Visual Studio,
it means having the `_DEBUG` macro defined, and, for other compilers, it means leaving
the `__OPTIMIZE__` macro undefined. The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1`.
We recommend that you first compile and run your code in Debug mode:
- under Visual Studio, it means having the `_DEBUG` macro defined,
- for other compilers, it means leaving the `__OPTIMIZE__` macro undefined.
The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1` in debug mode.
Alternatively, you can set the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
the `simdjson.h` header to enable these additional checks: just make sure you remove the
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
simdjson library runs additional (expensive) tests on your code to help ensure that you are
using the library in a safe manner. Once your code has been tested, you can then run it in
using the library in a safe manner.
Once your code has been tested, you can then run it in
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
disable these checks by setting `SIMDJSON_DEVELOPMENT_CHECKS` to 0. Once your code is tested, we
further encourage you to define `NDEBUG` in your Release builds to disable additional runtime
testing and get the best performance.
Using the parsed JSON
---------------------
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
idiomatic C++ iterators, operators and casts. Besides the document instances and
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
@@ -349,7 +364,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
`get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for `ondemand::object` and `ondemand::array`. An exception may be thrown if
the cast is not possible: there error code is `simdjson::INCORRECT_TYPE` (see [Error Handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
the cast is not possible: there error code is `simdjson::INCORRECT_TYPE` (see [Error handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content.
The `get_string()` returns a valid UTF-8 string, after
@@ -365,17 +380,40 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. This will
step through each value in the JSON array.
To iterate through an array, you should be at the beginning
of the array: to warn you, an OUT_OF_ORDER_ITERATION error is generated [when development checks](#avoiding-pitfalls-enable-development-checks) are active. If you need to access an array more
than once, you may call `reset()` on it although we discourage this practice. Keep in mind that
you should consume each value at most once.
If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`.
You may also use explicit iterators: `for(auto i = array.begin(); i != array.end(); i++) {}`. You can check that an array is empty with the condition `auto i = array.begin(); if (i == array.end()) {...}`.
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`. You may also use explicit iterators : `for(auto i = object.begin(); i != object.end(); i++) { auto field = *i; .... }`. You can check that an object is empty with the condition `auto i = object.begin(); if (i == object.end()) {...}`.
- `field.unescaped_key()` will get you the unescaped key string as a `std::string_view` instance. E.g., the JSON string `"\u00e1"` becomes the Unicode string `á`. Optionally, you pass `true` as a parameter to the `unescaped_key` method if you want invalid escape sequences to be replaced by a default replacement character (e.g., `\ud800\ud801\ud811`): otherwise bad escape sequences lead to an immediate error.
- `field.escaped_key()` will get you the key string as as a `std::string_view` instance, but unlike `unescaped_key()`, the key is not processed, so no unescaping is done. E.g., the JSON string `"\u00e1"` becomes the Unicode string `\u00e1`. We expect that `escaped_key()` is faster than `field.unescaped_key()`.
- `field.value()` will get you the value, which you can then use all these other methods on.
To iterate through an object, you should be at the beginning
of the object: to warn you, an OUT_OF_ORDER_ITERATION error is generated [when development checks](#avoiding-pitfalls-enable-development-checks) are active. If you need to access an object more
than once, you may call `reset()` on it although we discourage this practice. Keep in mind that
you should consume each value at most once.
* **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead,
you should iterate through the array and keep an index yourself. Exceptionally, if need a single value
out of the array, you may use an array access (e.g., `array[1]`).
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
scan through the object looking for the field with the matching string, doing a character-by-character
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error Handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Generally, you should not mix and match iterating through an object (`for(auto field : object) {...}`) and key accesses (`object["foo"]`): if you need to iterate through an object after a key access, you need to call `reset()` on the object. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code
is in error. Furthermore, you can only consume one field at a time, on the same object. The
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
If you have retrieved `content["bids"].get_array()` and you later call
`content["asks"].get_array()`, then the first array should no longer be accessed: it would be
unsafe to do so. You can detect such mistakes by first compiling and running the code in
Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
unsafe to do so. You can detect such mistakes by first compiling and running the code [with development checks](#avoiding-pitfalls-enable-development-checks): an OUT_OF_ORDER_ITERATION error is generated.
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching.
@@ -432,18 +470,6 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> double y = doc["y"]; // The cursor is now after the 2 (at })
> double x = doc["x"]; // Success: [] loops back around to find "x"
> ```
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. This will
step through each value in the JSON array.
If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`.
You may also use explicit iterators: `for(auto i = array.begin(); i != array.end(); i++) {}`. You can check that an array is empty with the condition `auto i = array.begin(); if (i == array.end()) {...}`.
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`. You may also use explicit iterators : `for(auto i = object.begin(); i != object.end(); i++) { auto field = *i; .... }`. You can check that an object is empty with the condition `auto i = object.begin(); if (i == object.end()) {...}`.
- `field.unescaped_key()` will get you the unescaped key string as a `std::string_view` instance. E.g., the JSON string `"\u00e1"` becomes the Unicode string `á`. Optionally, you pass `true` as a parameter to the `unescaped_key` method if you want invalid escape sequences to be replaced by a default replacement character (e.g., `\ud800\ud801\ud811`): otherwise bad escape sequences lead to an immediate error.
- `field.escaped_key()` will get you the key string as as a `std::string_view` instance, but unlike `unescaped_key()`, the key is not processed, so no unescaping is done. E.g., the JSON string `"\u00e1"` becomes the Unicode string `\u00e1`. We expect that `escaped_key()` is faster than `field.unescaped_key()`.
- `field.value()` will get you the value, which you can then use all these other methods on.
* **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead,
you should iterate through the array and keep an index yourself.
* **Output to strings:** Given a document, a value, an array or an object in a JSON document, you can output a JSON string version suitable to be parsed again as JSON content: `simdjson::to_json_string(element)`. A call to `to_json_string` consumes fully the element: if you apply it on a document, the JSON pointer is advanced to the end of the document. The `simdjson::to_json_string` does not allocate memory. The `to_json_string` function should not be confused with retrieving the value of a string instance which are escaped and represented using a lightweight `std::string_view` instance pointing at an internal string buffer inside the parser instance. To illustrate, the first of the following two code segments will print the unescaped string `"test"` complete with the quote whereas the second one will print the escaped content of the string (without the quotes).
> ```C++
> // serialize a JSON to an escaped std::string instance so that it can be parsed again as JSON
@@ -545,7 +571,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
auto json = R"( { "test":{ "val1":1, "val2":2 } } )"_padded;
auto doc = parser.iterate(json);
size_t count = doc.count_fields(); // requires simdjson 1.0 or better
std::cout << "Number of fields: " << new_count << std::endl; // Prints "Number of fields: 1"
std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 1"
```
Similarly to `count_elements`, you should not let an object instance go out of scope before consuming it after calling
the `count_fields` method. If you access an object inside a document, you can use the `count_fields` method as follow.
@@ -643,7 +669,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
}
```
### Using the Parsed JSON: Additional examples
### Using the parsed JSON: additional examples
Let us review these concepts with some additional examples. For simplicity, we omit the include clauses (`#include "simdjson.h"`) as well as namespace-using clauses (`using namespace simdjson;`).
@@ -815,7 +841,7 @@ simdjson::ondemand::value::get() noexcept {
}
```
We may then provide support for our `Car`` struct:
We may then provide support for our `Car` struct:
```C++
template <>
@@ -1241,7 +1267,7 @@ doc.at_path(".\\u00E9") == 123; // true
doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD)
```
Error Handling
Error handling
--------------
Error handing with exception and a single try/catch clause makes the code simple, but it gives you little control over errors. For easier debugging or more robust error handling, you may want to consider our exception-free approach.
@@ -1391,9 +1417,9 @@ int main(void) {
The `at` method can only be called once on an array. It cannot be used
to iterate through the values of an array.
### Error Handling Examples without Exceptions
### Error handling examples without exceptions
This is how the example in "Using the Parsed JSON" could be written using only error code checking (without exceptions):
This is how the example in "Using the parsed JSON" could be written using only error code checking (without exceptions):
```c++
bool parse() {
@@ -1489,7 +1515,7 @@ having to handle exceptions.
}
```
### Disabling Exceptions
### Disabling exceptions
The simdjson can be build with exceptions entirely disabled. It checks the `__cpp_exceptions` macro at compile time. Even if exceptions are enabled in your compiler, you may still disable exceptions specifically for simdjson, by setting `SIMDJSON_EXCEPTIONS` to `0` (false) at compile-time when building the simdjson library. If you are building with CMake, to ensure you don't write any code that uses exceptions, you compile with `SIMDJSON_EXCEPTIONS=OFF`. For example, if including the project via cmake:
@@ -1800,7 +1826,7 @@ If your documents are large (e.g., larger than a megabyte), then the `iterate_ma
We also provide some support for comma-separated documents and other advanced features.
See [iterate_many.md](iterate_many.md) for detailed information and design.
Parsing Numbers Inside Strings
Parsing numbers inside strings
------------------------------
Though the JSON specification allows for numbers and string values, many engineers choose to integrate the numbers inside strings, e.g., they prefer `{"a":"1.9"}` to`{"a":1.9}`.
@@ -2030,7 +2056,7 @@ This code prints the following:
'99999999999999999999999 '
```
Raw Strings From Keys
Raw strings from keys
-----------
It is sometimes useful to have access to a raw (unescaped) string: we make available a
@@ -2082,7 +2108,7 @@ begins with `"name"` and may containing trailing white-space characters.
```
General Direct Access to the Raw JSON String
General direct access to the raw JSON string
--------------------------------
If your value is a string, the `raw_json_string` you get with `get_raw_json_string()` gives you direct access to the unprocessed
string. But the simdjson library allows you to have access to the raw underlying JSON
@@ -2189,7 +2215,7 @@ string representation.
```
Storing Directly into an Existing String Instance
Storing directly into an existing string instance
-----------------------------------------------------
The simdjson library favours the use of `std::string_view` instances because
@@ -2236,7 +2262,7 @@ can use it with features such as `std::optional`:
You should be mindful of the trade-off: allocating multiple
`std::string` instances can become expensive.
Thread Safety
Thread safety
-------------
We built simdjson with thread safety in mind.
@@ -2249,10 +2275,15 @@ acts as an iterator (and is therefore not thread safe).
The CPU detection, which runs the first time parsing is attempted and switches to the fastest
parser for your CPU, is transparent and thread-safe.
Our runtime dispatching is based on global objects that are instantiated at the beginning of the
main thread and may be discarded at the end of the main thread. If you have multiple threads running
and some threads use the library while the main thread is cleaning up ressources, you may encounter
issues. If you expect such problems, you may consider using [std::quick_exit](https://en.cppreference.com/w/cpp/utility/program/quick_exit).
In a threaded environment, stack space is often limited. Running code like simdjson in debug mode may require hundreds of kilobytes of stack memory. Thus stack overflows are a possibility. We recommend you turn on optimization when working in an environment where stack space is limited. If you must run your code in debug mode, we recommend you configure your system to have more stack space. We discourage you from running production code based on a debug build.
Standard Compliance
Standard compliance
--------------------
The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification.
@@ -2270,7 +2301,7 @@ The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.o
- The specification states that an implementation may set limits on the maximum depth of nesting. By default, the simdjson will refuse to parse documents with a depth exceeding 1024.
Backwards Compatibility
Backwards compatibility
-----------------------
The only header file supported by simdjson is `simdjson.h`. Older versions of simdjson published a
@@ -2565,10 +2596,11 @@ int main(void) {
}
```
Performance Tips
Performance tips
--------
- Read [our performance notes](performance.md) for advanced topics.
- The On Demand front-end works best when doing a single pass over the input: avoid calling `count_elements`, `rewind` and similar methods.
- If you are familiar with assembly language, you may use the online tool godbolt to explore the compiled code. The following example may work: [https://godbolt.org/z/xE4GWs573](https://godbolt.org/z/xE4GWs573).
- Given a field `field` in an object, calling `field.key()` is often faster than `field.unescaped_key()` so if you do not need an unescaped `std::string_view` instance, prefer `field.key()`. Similarly, we expect `field.escaped_key()` to be faster than `field.unescaped_key()` even though both return a `std::string_view` instance.
@@ -2591,8 +2623,10 @@ Performance Tips
```
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log's output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
Further reading
--------
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience 54 (6), 2024
+108
View File
@@ -14,6 +14,7 @@ testing and get the best performance.
* [Number parsing](#number-parsing)
* [Visual Studio](#visual-studio)
* [Power Usage and Downclocking](#power-usage-and-downclocking)
* [Free Padding](#free-padding)
NDEBUG directive
@@ -179,3 +180,110 @@ The simdjson library does not generally make use of heavy 256-bit instructions.
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
Free Padding
-------
For performance reasons, the simdjson library requires that the JSON input contain at least
`simdjson::SIMDJSON_PADDING` bytes at the end of the stream. The value `simdjson::SIMDJSON_PADDING` is
small (e.g., 64 bytes). On modern systems, you can safely read beyond an allocated buffers,
as long as you remain within an allocated page. Pages on modern systems span at least 4 kilobytes,
but can be significantly larger. E.g., Apple systems favour pages spanning 16 kilobytes.
In effect, it means that you can almost always read a few bytes beyond your current buffer---without
allocating extra memory. However, tools such as valgrind or memory sanitizers will flag such behavior as unsafe.
Nevertheless, you can still make sure of this capability in your code if you are an expert
programmer and you are willing to silence sanitizer warnings. The following code provides
a portable example.
The conditional compilation checks for the `_MSC_VER` macro (indicating Microsoft Visual Studio)
and includes platform-specific headers accordingly.
The `page_size()` function determines the default size of a memory page in bytes on the system.
On Windows (when `_WIN32` is defined), it uses `GetSystemInfo()` to retrieve system information and obtain the page size.
On other platforms (non-Windows), it uses `sysconf(_SC_PAGESIZE)` to get the page size.
The function returns the page size.
The `need_allocation()` function checks whether the buffer (given by `buf`) plus the specified length (`len`) is near a page boundary.
If the buffer extends beyond the current page when padded by `simdjson::SIMDJSON_PADDING`, it returns true, indicating that reallocation is needed.
Otherwise, it returns false.
The `get_padded_string_view()` creates a `padded_string_view` from the input buffer.
If reallocation is needed (unlikely case), it allocates a new padded_string and assigns it to `jsonbuffer`.
Otherwise (very likely), it creates a `padded_string_view` directly from the buffer.
The `simdjson::SIMDJSON_PADDING` ensures that there is additional padding for parsing efficiency.
The calling code just needs to provide `jsonbuffer` (an instance of `simdjson::padded_string`)
and pass `get_padded_string_view(buf, len, jsonbuffer)` to `parser.iterate`. Most of the time,
this code will not allocate new memory.
```cpp
#ifdef _WIN32
#include <windows.h>
#include <sysinfoapi.h>
#else
#include <unistd.h>
#endif
#include "simdjson.h"
#include <cstdio>
// Returns the default size of the page in bytes on this system.
long page_size() {
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
long pagesize = sysInfo.dwPageSize;
#else
long pagesize = sysconf(_SC_PAGESIZE);
#endif
return pagesize;
}
// 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);
}
simdjson::padded_string_view
get_padded_string_view(const char *buf, size_t len,
simdjson::padded_string &jsonbuffer) {
if (need_allocation(buf, len)) { // unlikely case
jsonbuffer = simdjson::padded_string(buf, len);
return jsonbuffer;
} else { // no reallcation needed (very likely)
return simdjson::padded_string_view(buf, len,
len + simdjson::SIMDJSON_PADDING);
}
}
int main() {
printf("page_size: %ld\n", page_size());
const char *jsonpoiner = R"(
{
"key": "value"
}
)";
size_t len = strlen(jsonpoiner);
simdjson::padded_string jsonbuffer; // only allocate if needed
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
simdjson::error_code error =
parser.iterate(get_padded_string_view(jsonpoiner, len, jsonbuffer))
.get(doc);
if (error) {
printf("error: %s\n", simdjson::error_message(error));
return EXIT_FAILURE;
}
std::string_view value;
error = doc["key"].get_string().get(value);
if (error) {
return EXIT_FAILURE;
}
printf("Value: \"%.*s\"\n", (int)value.size(), value.data());
if (value != "value") {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
```
+4 -4
View File
@@ -9,10 +9,10 @@
#include <cstring>
#if _M_ARM64
#if SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
// __umulh requires intrin.h
#include <intrin.h>
#endif // _M_ARM64
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
namespace simdjson {
namespace arm64 {
@@ -32,13 +32,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
+1 -1
View File
@@ -134,7 +134,7 @@ namespace {
tmp = vpaddq_u8(tmp, tmp);
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
}
simdjson_inline bool any() const { return vmaxvq_u8(*this) != 0; }
simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; }
};
// Unsigned bytes
+5 -1
View File
@@ -223,7 +223,11 @@ simdjson_inline std::string_view document_stream::iterator::source() const noexc
return std::string_view(start, next_doc_index - current_index() + 1);
} else {
size_t next_doc_index = stream->batch_start + stream->parser->implementation->structural_indexes[stream->parser->implementation->next_structural_index];
return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), next_doc_index - current_index() - 1);
size_t svlen = next_doc_index - current_index();
while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
svlen--;
}
return std::string_view(start, svlen);
}
}
+21 -1
View File
@@ -375,6 +375,23 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
return at_key(key);
}
inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
if (simdjson_unlikely(json_pointer[0] != '/')) {
return false;
}
size_t escape = json_pointer.find('~');
if (escape == std::string_view::npos) {
return true;
}
if (escape == json_pointer.size() - 1) {
return false;
}
if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
return false;
}
return true;
}
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
@@ -383,7 +400,10 @@ inline simdjson_result<element> element::at_pointer(std::string_view json_pointe
case internal::tape_type::START_ARRAY:
return array(tape).at_pointer(json_pointer);
default: {
if(!json_pointer.empty()) { // a non-empty string is invalid on an atom
if (!json_pointer.empty()) { // a non-empty string can be invalid, or accessing a primitive (issue 2154)
if (is_pointer_well_formed(json_pointer)) {
return NO_SUCH_FIELD;
}
return INVALID_JSON_POINTER;
}
// an empty string means that we return the current node
+3 -3
View File
@@ -57,15 +57,15 @@ public:
simdjson_inline void one_char(char c);
simdjson_inline void call_print_newline() {
this->print_newline();
static_cast<formatter*>(this)->print_newline();
}
simdjson_inline void call_print_indents(size_t depth) {
this->print_indents(depth);
static_cast<formatter*>(this)->print_indents(depth);
}
simdjson_inline void call_print_space() {
this->print_space();
static_cast<formatter*>(this)->print_space();
}
protected:
+1 -1
View File
@@ -39,7 +39,7 @@ enum error_code {
INDEX_OUT_OF_BOUNDS, ///< JSON array index too large
NO_SUCH_FIELD, ///< JSON field not found in object
IO_ERROR, ///< Error reading a file
INVALID_JSON_POINTER, ///< Invalid JSON pointer reference
INVALID_JSON_POINTER, ///< Invalid JSON pointer syntax
INVALID_URI_FRAGMENT, ///< Invalid URI fragment
UNEXPECTED_ERROR, ///< indicative of a bug in simdjson
PARSER_IN_USE, ///< parser is already in use.
@@ -56,13 +56,13 @@ static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi)
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -342,9 +342,18 @@ simdjson_inline std::string_view document_stream::iterator::source() const noexc
depth--;
break;
default: // Scalar value document
// TODO: Remove any trailing whitespaces
// TODO: We could remove trailing whitespaces
// This returns a string spanning from start of value to the beginning of the next document (excluded)
return std::string_view(reinterpret_cast<const char*>(stream->buf) + current_index(), stream->parser->implementation->structural_indexes[++cur_struct_index] - current_index() - 1);
{
auto next_index = stream->parser->implementation->structural_indexes[++cur_struct_index];
// normally the length would be next_index - current_index() - 1, except for the last document
size_t svlen = next_index - current_index();
const char *start = reinterpret_cast<const char*>(stream->buf) + current_index();
while(svlen > 1 && (std::isspace(start[svlen-1]) || start[svlen-1] == '\0')) {
svlen--;
}
return std::string_view(start, svlen);
}
}
cur_struct_index++;
}
@@ -54,6 +54,23 @@ simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parse
#endif
}
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
simdjson_inline json_iterator::json_iterator(const uint8_t *buf, ondemand::parser *_parser, bool streaming) noexcept
: token(buf, &_parser->implementation->structural_indexes[0]),
parser{_parser},
_string_buf_loc{parser->string_buf.get()},
_depth{1},
_root{parser->implementation->structural_indexes.get()},
_streaming{streaming}
{
logger::log_headers();
#if SIMDJSON_CHECK_EOF
assert_more_tokens();
#endif
}
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
inline void json_iterator::rewind() noexcept {
token.set_position( root_position() );
logger::log_headers(); // We start again
@@ -293,6 +293,9 @@ public:
inline bool balanced() const noexcept;
protected:
simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser) noexcept;
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
simdjson_inline json_iterator(const uint8_t *buf, ondemand::parser *parser, bool streaming) noexcept;
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
/// The last token before the end
simdjson_inline token_position last_position() const noexcept;
/// The token *at* the end. This points at gibberish and should only be used for comparison.
@@ -58,6 +58,27 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(p
return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
}
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
json.remove_utf8_bom();
// Allocate if needed
if (capacity() < json.length() || !string_buf) {
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
}
// Run stage 1.
const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
if (err) {
if (err != UNCLOSED_STRING)
return err;
}
return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
}
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
return iterate(padded_string_view(json, len, allocated));
}
@@ -98,6 +98,9 @@ public:
* - UNCLOSED_STRING if there is an unclosed string in the document.
*/
simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
simdjson_warn_unused simdjson_result<document> iterate_allow_incomplete_json(padded_string_view json) & noexcept;
#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
@@ -239,6 +239,26 @@ simdjson_inline int32_t value::current_depth() const noexcept{
return iter.json_iter().depth();
}
inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept {
if (simdjson_unlikely(json_pointer.empty())) { // can't be
return false;
}
if (simdjson_unlikely(json_pointer[0] != '/')) {
return false;
}
size_t escape = json_pointer.find('~');
if (escape == std::string_view::npos) {
return true;
}
if (escape == json_pointer.size() - 1) {
return false;
}
if (json_pointer[escape + 1] != '0' && json_pointer[escape + 1] != '1') {
return false;
}
return true;
}
simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
json_type t;
SIMDJSON_TRY(type().get(t));
@@ -249,6 +269,10 @@ simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_p
case json_type::object:
return (*this).get_object().at_pointer(json_pointer);
default:
// a non-empty string can be invalid, or accessing a primitive (issue 2154)
if (is_pointer_well_formed(json_pointer)) {
return NO_SUCH_FIELD;
}
return INVALID_JSON_POINTER;
}
}
@@ -37,13 +37,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
+3 -3
View File
@@ -65,10 +65,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm256_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm256_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm256_testz_si256(*this, *this); }
@@ -33,13 +33,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
+3 -3
View File
@@ -93,10 +93,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m512i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
};
+6 -5
View File
@@ -53,7 +53,7 @@ public:
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64".
*/
virtual const std::string &name() const { return _name; }
virtual std::string name() const { return std::string(_name); }
/**
* The description of this implementation.
@@ -63,7 +63,7 @@ public:
*
* @return the description of the implementation, e.g. "Intel/AMD AVX2", "Intel/AMD SSE4.2", "ARM NEON".
*/
virtual const std::string &description() const { return _description; }
virtual std::string description() const { return std::string(_description); }
/**
* The instruction sets this implementation is compiled against
@@ -139,18 +139,19 @@ protected:
_required_instruction_sets(required_instruction_sets)
{
}
virtual ~implementation()=default;
protected:
~implementation() = default;
private:
/**
* The name of this implementation.
*/
const std::string _name;
std::string_view _name;
/**
* The description of this implementation.
*/
const std::string _description;
std::string_view _description;
/**
* Instruction sets required for this implementation.
+43 -7
View File
@@ -26,7 +26,11 @@
#ifndef SIMDJSON_IMPLEMENTATION_ARM64
#define SIMDJSON_IMPLEMENTATION_ARM64 (SIMDJSON_IS_ARM64)
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
#if SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 0
#endif
// Default Icelake to on if this is x86-64. Even if we're not compiled for it, it could be selected
// at runtime.
@@ -37,9 +41,20 @@
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#if ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 0
#endif
#else
#if ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 0
#endif
#endif
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
@@ -55,9 +70,20 @@
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
#if ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 0
#endif
#else
#if ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 0
#endif
#endif
// Default Westmere to on if this is x86-64.
@@ -69,12 +95,22 @@
#define SIMDJSON_IMPLEMENTATION_WESTMERE SIMDJSON_IS_X86_64
#endif
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
#if (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE 0
#endif
#ifndef SIMDJSON_IMPLEMENTATION_PPC64
#define SIMDJSON_IMPLEMENTATION_PPC64 (SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX)
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX
#if SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 0
#endif
#ifndef SIMDJSON_IMPLEMENTATION_LASX
#define SIMDJSON_IMPLEMENTATION_LASX (SIMDJSON_IS_LOONGARCH64 && __loongarch_asx)
+3 -3
View File
@@ -67,10 +67,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return __lasx_xvreplgr2vr_b(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const {
__m256i mask = __lasx_xvmskltz_b(*this);
+3 -3
View File
@@ -65,10 +65,10 @@ namespace simd {
return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
}
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
+4 -2
View File
@@ -6,13 +6,13 @@
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// #pragma once // We remove #pragma once here as it generates a warning in some cases. We rely on the include guard.
#pragma once
#ifndef NONSTD_SV_LITE_H_INCLUDED
#define NONSTD_SV_LITE_H_INCLUDED
#define string_view_lite_MAJOR 1
#define string_view_lite_MINOR 7
#define string_view_lite_MINOR 8
#define string_view_lite_PATCH 0
#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH)
@@ -134,6 +134,8 @@
#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
#include <string>
namespace nonstd {
template< class CharT, class Traits, class Allocator = std::allocator<CharT> >
+5 -2
View File
@@ -11,6 +11,9 @@
#include <strings.h>
#endif
// We are using size_t without namespace std:: throughout the project
using std::size_t;
#ifdef _MSC_VER
#define SIMDJSON_VISUAL_STUDIO 1
/**
@@ -32,9 +35,9 @@
#endif // __clang__
#endif // _MSC_VER
#if defined(__x86_64__) || defined(_M_AMD64)
#if (defined(__x86_64__) || defined(_M_AMD64)) && !defined(_M_ARM64EC)
#define SIMDJSON_IS_X86_64 1
#elif defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#define SIMDJSON_IS_ARM64 1
#elif defined(__riscv) && __riscv_xlen == 64
#define SIMDJSON_IS_RISCV64 1
+2 -2
View File
@@ -41,13 +41,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
+3 -3
View File
@@ -96,11 +96,11 @@ template <> struct simd8<bool> : base8<bool> {
return (__m128i)vec_splats((unsigned char)(-(!!_value)));
}
simdjson_inline simd8<bool>() : base8<bool>() {}
simdjson_inline simd8<bool>(const __m128i _value)
simdjson_inline simd8() : base8<bool>() {}
simdjson_inline simd8(const __m128i _value)
: base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value)
simdjson_inline simd8(bool _value)
: base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const {
+2 -2
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.9.0"
#define SIMDJSON_VERSION "3.9.4"
namespace simdjson {
enum {
@@ -19,7 +19,7 @@ enum {
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 0
SIMDJSON_VERSION_REVISION = 4
};
} // namespace simdjson
@@ -35,13 +35,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
+3 -3
View File
@@ -59,10 +59,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
+140 -93
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-04-04 12:24:07 -0400. Do not edit! */
/* auto-generated on 2024-06-11 14:08:20 -0400. Do not edit! */
/* including simdjson.cpp: */
/* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP
@@ -84,6 +84,9 @@
#include <strings.h>
#endif
// We are using size_t without namespace std:: throughout the project
using std::size_t;
#ifdef _MSC_VER
#define SIMDJSON_VISUAL_STUDIO 1
/**
@@ -105,9 +108,9 @@
#endif // __clang__
#endif // _MSC_VER
#if defined(__x86_64__) || defined(_M_AMD64)
#if (defined(__x86_64__) || defined(_M_AMD64)) && !defined(_M_ARM64EC)
#define SIMDJSON_IS_X86_64 1
#elif defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#define SIMDJSON_IS_ARM64 1
#elif defined(__riscv) && __riscv_xlen == 64
#define SIMDJSON_IS_RISCV64 1
@@ -527,13 +530,13 @@ 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 // We remove #pragma once here as it generates a warning in some cases. We rely on the include guard.
#pragma once
#ifndef NONSTD_SV_LITE_H_INCLUDED
#define NONSTD_SV_LITE_H_INCLUDED
#define string_view_lite_MAJOR 1
#define string_view_lite_MINOR 7
#define string_view_lite_MINOR 8
#define string_view_lite_PATCH 0
#define string_view_lite_VERSION nssv_STRINGIFY(string_view_lite_MAJOR) "." nssv_STRINGIFY(string_view_lite_MINOR) "." nssv_STRINGIFY(string_view_lite_PATCH)
@@ -655,6 +658,8 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
#include <string>
namespace nonstd {
template< class CharT, class Traits, class Allocator = std::allocator<CharT> >
@@ -2359,7 +2364,7 @@ enum error_code {
INDEX_OUT_OF_BOUNDS, ///< JSON array index too large
NO_SUCH_FIELD, ///< JSON field not found in object
IO_ERROR, ///< Error reading a file
INVALID_JSON_POINTER, ///< Invalid JSON pointer reference
INVALID_JSON_POINTER, ///< Invalid JSON pointer syntax
INVALID_URI_FRAGMENT, ///< Invalid URI fragment
UNEXPECTED_ERROR, ///< indicative of a bug in simdjson
PARSER_IN_USE, ///< parser is already in use.
@@ -5505,7 +5510,11 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]=
#ifndef SIMDJSON_IMPLEMENTATION_ARM64
#define SIMDJSON_IMPLEMENTATION_ARM64 (SIMDJSON_IS_ARM64)
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
#if SIMDJSON_IMPLEMENTATION_ARM64 && SIMDJSON_IS_ARM64
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ARM64 0
#endif
// Default Icelake to on if this is x86-64. Even if we're not compiled for it, it could be selected
// at runtime.
@@ -5516,9 +5525,20 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]=
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#if ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 0
#endif
#else
#if ((SIMDJSON_IMPLEMENTATION_ICELAKE) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__) && (__AVX512F__) && (__AVX512DQ__) && (__AVX512CD__) && (__AVX512BW__) && (__AVX512VL__) && (__AVX512VBMI2__))
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_ICELAKE 0
#endif
#endif
// Default Haswell to on if this is x86-64. Even if we're not compiled for it, it could be selected
@@ -5534,9 +5554,20 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]=
#ifdef _MSC_VER
// To see why (__BMI__) && (__PCLMUL__) && (__LZCNT__) are not part of this next line, see
// https://github.com/simdjson/simdjson/issues/1247
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
#if ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__))
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 0
#endif
#else
#if ((SIMDJSON_IMPLEMENTATION_HASWELL) && (SIMDJSON_IS_X86_64) && (__AVX2__) && (__BMI__) && (__PCLMUL__) && (__LZCNT__))
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_HASWELL 0
#endif
#endif
// Default Westmere to on if this is x86-64.
@@ -5548,12 +5579,22 @@ SIMDJSON_DLLIMPORTEXPORT const uint64_t simdjson::internal::power_of_five_128[]=
#define SIMDJSON_IMPLEMENTATION_WESTMERE SIMDJSON_IS_X86_64
#endif
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
#if (SIMDJSON_IMPLEMENTATION_WESTMERE && SIMDJSON_IS_X86_64 && __SSE4_2__ && __PCLMUL__)
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_WESTMERE 0
#endif
#ifndef SIMDJSON_IMPLEMENTATION_PPC64
#define SIMDJSON_IMPLEMENTATION_PPC64 (SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX)
#endif
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX
#if SIMDJSON_IMPLEMENTATION_PPC64 && SIMDJSON_IS_PPC64 && SIMDJSON_IS_PPC64_VMX
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 1
#else
#define SIMDJSON_CAN_ALWAYS_RUN_PPC64 0
#endif
#ifndef SIMDJSON_IMPLEMENTATION_LASX
#define SIMDJSON_IMPLEMENTATION_LASX (SIMDJSON_IS_LOONGARCH64 && __loongarch_asx)
@@ -6103,7 +6144,7 @@ public:
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64".
*/
virtual const std::string &name() const { return _name; }
virtual std::string name() const { return std::string(_name); }
/**
* The description of this implementation.
@@ -6113,7 +6154,7 @@ public:
*
* @return the description of the implementation, e.g. "Intel/AMD AVX2", "Intel/AMD SSE4.2", "ARM NEON".
*/
virtual const std::string &description() const { return _description; }
virtual std::string description() const { return std::string(_description); }
/**
* The instruction sets this implementation is compiled against
@@ -6189,18 +6230,19 @@ protected:
_required_instruction_sets(required_instruction_sets)
{
}
virtual ~implementation()=default;
protected:
~implementation() = default;
private:
/**
* The name of this implementation.
*/
const std::string _name;
std::string_view _name;
/**
* The description of this implementation.
*/
const std::string _description;
std::string_view _description;
/**
* Instruction sets required for this implementation.
@@ -6676,7 +6718,7 @@ static inline uint32_t detect_supported_architectures() {
return instruction_set::ALTIVEC;
}
#elif defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
static inline uint32_t detect_supported_architectures() {
return instruction_set::NEON;
@@ -6859,6 +6901,7 @@ static inline uint32_t detect_supported_architectures() {
/* end file internal/isadetection.h */
#include <initializer_list>
#include <type_traits>
namespace simdjson {
@@ -7310,8 +7353,8 @@ namespace internal {
*/
class detect_best_supported_implementation_on_first_use final : public implementation {
public:
const std::string &name() const noexcept final { return set_best()->name(); }
const std::string &description() const noexcept final { return set_best()->description(); }
std::string name() const noexcept final { return set_best()->name(); }
std::string description() const noexcept final { return set_best()->description(); }
uint32_t required_instruction_sets() const noexcept final { return set_best()->required_instruction_sets(); }
simdjson_warn_unused error_code create_dom_parser_implementation(
size_t capacity,
@@ -7331,6 +7374,8 @@ private:
const implementation *set_best() const noexcept;
};
static_assert(std::is_trivially_destructible<detect_best_supported_implementation_on_first_use>::value, "detect_best_supported_implementation_on_first_use should be trivially destructible");
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
static const std::initializer_list<const implementation *> available_implementation_pointers {
#if SIMDJSON_IMPLEMENTATION_ICELAKE
@@ -7387,6 +7432,8 @@ public:
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
};
static_assert(std::is_trivially_destructible<unsupported_implementation>::value, "unsupported_singleton should be trivially destructible");
const unsupported_implementation* get_unsupported_singleton() {
static const unsupported_implementation unsupported_singleton{};
return &unsupported_singleton;
@@ -7703,10 +7750,10 @@ simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
#include <cstring>
#if _M_ARM64
#if SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
// __umulh requires intrin.h
#include <intrin.h>
#endif // _M_ARM64
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
namespace simdjson {
namespace arm64 {
@@ -7726,13 +7773,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -7887,7 +7934,7 @@ namespace {
tmp = vpaddq_u8(tmp, tmp);
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
}
simdjson_inline bool any() const { return vmaxvq_u8(*this) != 0; }
simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; }
};
// Unsigned bytes
@@ -10459,10 +10506,10 @@ simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
#include <cstring>
#if _M_ARM64
#if SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
// __umulh requires intrin.h
#include <intrin.h>
#endif // _M_ARM64
#endif // SIMDJSON_REGULAR_VISUAL_STUDIO && SIMDJSON_IS_ARM64
namespace simdjson {
namespace arm64 {
@@ -10482,13 +10529,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -10643,7 +10690,7 @@ namespace {
tmp = vpaddq_u8(tmp, tmp);
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
}
simdjson_inline bool any() const { return vmaxvq_u8(*this) != 0; }
simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; }
};
// Unsigned bytes
@@ -14200,13 +14247,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -14292,10 +14339,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm256_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm256_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm256_testz_si256(*this, *this); }
@@ -16833,13 +16880,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -16925,10 +16972,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm256_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm256_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm256_testz_si256(*this, *this); }
@@ -20474,10 +20521,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m512i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
};
@@ -20840,13 +20887,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -23105,10 +23152,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm512_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m512i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m512i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline bool any() const { return !!_mm512_test_epi8_mask (*this, *this); }
simdjson_inline simd8<bool> operator~() const { return *this ^ true; }
};
@@ -23471,13 +23518,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -26665,13 +26712,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -26788,11 +26835,11 @@ template <> struct simd8<bool> : base8<bool> {
return (__m128i)vec_splats((unsigned char)(-(!!_value)));
}
simdjson_inline simd8<bool>() : base8<bool>() {}
simdjson_inline simd8<bool>(const __m128i _value)
simdjson_inline simd8() : base8<bool>() {}
simdjson_inline simd8(const __m128i _value)
: base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value)
simdjson_inline simd8(bool _value)
: base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const {
@@ -29409,13 +29456,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -29532,11 +29579,11 @@ template <> struct simd8<bool> : base8<bool> {
return (__m128i)vec_splats((unsigned char)(-(!!_value)));
}
simdjson_inline simd8<bool>() : base8<bool>() {}
simdjson_inline simd8<bool>(const __m128i _value)
simdjson_inline simd8() : base8<bool>() {}
simdjson_inline simd8(const __m128i _value)
: base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value)
simdjson_inline simd8(bool _value)
: base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const {
@@ -33134,13 +33181,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -33220,10 +33267,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
@@ -33648,10 +33695,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
@@ -36199,13 +36246,13 @@ static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -36285,10 +36332,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
@@ -36713,10 +36760,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return _mm_set1_epi8(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return _mm_movemask_epi8(*this); }
simdjson_inline bool any() const { return !_mm_testz_si128(*this, *this); }
@@ -40183,10 +40230,10 @@ namespace simd {
return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
}
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
@@ -42712,10 +42759,10 @@ namespace simd {
return __lsx_vreplgr2vr_b(uint8_t(-(!!_value)));
}
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m128i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m128i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const { return __lsx_vpickve2gr_w(__lsx_vmskltz_b(*this), 0); }
simdjson_inline bool any() const { return 0 == __lsx_vpickve2gr_hu(__lsx_vmsknz_b(*this), 0); }
@@ -46168,10 +46215,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return __lasx_xvreplgr2vr_b(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const {
__m256i mask = __lasx_xvmskltz_b(*this);
@@ -48713,10 +48760,10 @@ namespace simd {
struct simd8<bool>: base8<bool> {
static simdjson_inline simd8<bool> splat(bool _value) { return __lasx_xvreplgr2vr_b(uint8_t(-(!!_value))); }
simdjson_inline simd8<bool>() : base8() {}
simdjson_inline simd8<bool>(const __m256i _value) : base8<bool>(_value) {}
simdjson_inline simd8() : base8() {}
simdjson_inline simd8(const __m256i _value) : base8<bool>(_value) {}
// Splat constructor
simdjson_inline simd8<bool>(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline simd8(bool _value) : base8<bool>(splat(_value)) {}
simdjson_inline int to_bitmask() const {
__m256i mask = __lasx_xvmskltz_b(*this);
@@ -52103,13 +52150,13 @@ static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi)
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
@@ -54237,13 +54284,13 @@ static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi)
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
#if SIMDJSON_IS_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#endif // SIMDJSON_IS_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
+795 -113
View File
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -7,6 +7,7 @@
#include <internal/isadetection.h>
#include <initializer_list>
#include <type_traits>
namespace simdjson {
@@ -169,8 +170,8 @@ namespace internal {
*/
class detect_best_supported_implementation_on_first_use final : public implementation {
public:
const std::string &name() const noexcept final { return set_best()->name(); }
const std::string &description() const noexcept final { return set_best()->description(); }
std::string name() const noexcept final { return set_best()->name(); }
std::string description() const noexcept final { return set_best()->description(); }
uint32_t required_instruction_sets() const noexcept final { return set_best()->required_instruction_sets(); }
simdjson_warn_unused error_code create_dom_parser_implementation(
size_t capacity,
@@ -190,6 +191,8 @@ private:
const implementation *set_best() const noexcept;
};
static_assert(std::is_trivially_destructible<detect_best_supported_implementation_on_first_use>::value, "detect_best_supported_implementation_on_first_use should be trivially destructible");
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
static const std::initializer_list<const implementation *> available_implementation_pointers {
#if SIMDJSON_IMPLEMENTATION_ICELAKE
@@ -246,6 +249,8 @@ public:
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
};
static_assert(std::is_trivially_destructible<unsupported_implementation>::value, "unsupported_singleton should be trivially destructible");
const unsupported_implementation* get_unsupported_singleton() {
static const unsupported_implementation unsupported_singleton{};
return &unsupported_singleton;
+1 -1
View File
@@ -65,7 +65,7 @@ static inline uint32_t detect_supported_architectures() {
return instruction_set::ALTIVEC;
}
#elif defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
static inline uint32_t detect_supported_architectures() {
return instruction_set::NEON;
+46 -1
View File
@@ -227,6 +227,49 @@ namespace document_stream_tests {
return true;
}
bool issue2170() {
TEST_START();
auto json = R"(1 2 3)"_padded;
simdjson::dom::parser parser;
simdjson::dom::document_stream stream;
ASSERT_SUCCESS(parser.parse_many(json).get(stream));
auto i = stream.begin();
size_t count{0};
std::vector<size_t> indexes = { 0, 2, 4 };
std::vector<std::string_view> expected = { "1", "2", "3" };
for(; i != stream.end(); ++i) {
auto doc = *i;
ASSERT_SUCCESS(doc);
ASSERT_TRUE(count < 3);
ASSERT_EQUAL(i.current_index(), indexes[count]);
ASSERT_EQUAL(i.source(), expected[count]);
count++;
}
TEST_SUCCEED();
}
bool issue2181() {
TEST_START();
auto json = R"(1 2 34)"_padded;
simdjson::dom::parser parser;
simdjson::dom::document_stream stream;
ASSERT_SUCCESS(parser.parse_many(json).get(stream));
auto i = stream.begin();
size_t count{0};
std::vector<size_t> indexes = { 0, 2, 4 };
std::vector<std::string_view> expected = { "1", "2", "34" };
for(; i != stream.end(); ++i) {
auto doc = *i;
ASSERT_SUCCESS(doc);
ASSERT_TRUE(count < 3);
ASSERT_EQUAL(i.current_index(), indexes[count]);
ASSERT_EQUAL(i.source(), expected[count]);
count++;
}
TEST_SUCCEED();
}
bool issue1310() {
std::cout << "Running " << __func__ << std::endl;
// hex : 20 20 5B 20 33 2C 31 5D 20 22 22 22 22 22 22 22 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
@@ -941,7 +984,9 @@ namespace document_stream_tests {
}
bool run() {
return skipbom() &&
return issue2181() &&
issue2170() &&
skipbom() &&
fuzzaccess() &&
baby_fuzzer() &&
issue1649() &&
+30
View File
@@ -191,10 +191,40 @@ bool issue1142() {
return true;
}
bool issue2154() { // mistakenly taking value as path should not raise INVALID_JSON_POINTER
#if SIMDJSON_EXCEPTIONS
std::cout << "issue 2154" << std::endl;
auto example_json = R"__(
{
"obj": {
"s": "42",
"n": 42,
"f": 4.2
}
}
)__"_padded;
dom::parser parser;
dom::element example = parser.parse(example_json);
std::string_view sfield = example.at_pointer("/obj/s");
ASSERT_EQUAL(sfield, "42");
int64_t nfield = example.at_pointer("/obj/n");
ASSERT_EQUAL(nfield, 42);
ASSERT_ERROR(example.at_pointer("/obj/X/42").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_pointer("/obj/s/42").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_pointer("/obj/n/42").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_pointer("/obj/f/4.2").error(), NO_SUCH_FIELD);
ASSERT_ERROR(example.at_pointer("/obj/f/4~").error(), INVALID_JSON_POINTER);
ASSERT_ERROR(example.at_pointer("/obj/f/~").error(), INVALID_JSON_POINTER);
ASSERT_ERROR(example.at_pointer("/obj/f/~1").error(), NO_SUCH_FIELD);
#endif
return true;
}
int main() {
if (true
&& demo()
&& issue1142()
&& issue2154()
#ifdef SIMDJSON_ENABLE_DEPRECATED_API
&& legacy_support()
#endif
+3
View File
@@ -28,6 +28,9 @@ add_cpp_test(ondemand_to_string LABELS ondemand acceptance per_impl
add_cpp_test(ondemand_twitter_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_wrong_type_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_iterate_many_csv LABELS ondemand acceptance per_implementation)
if(NOT SIMDJSON_SANITIZE)
add_cpp_test(ondemand_cacheline LABELS ondemand acceptance per_implementation)
endif()
if(HAVE_POSIX_FORK AND HAVE_POSIX_WAIT) # assert tests use fork and wait, which aren't on MSVC
add_cpp_test(ondemand_assert_out_of_order_values LABELS assert per_implementation explicitonly ondemand)
+68
View File
@@ -0,0 +1,68 @@
#ifdef _WIN32
#include <windows.h>
#include <sysinfoapi.h>
#else
#include <unistd.h>
#endif
#include "simdjson.h"
#include <cstdio>
// Returns the default size of the page in bytes on this system.
long page_size() {
#ifdef _WIN32
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
long pagesize = sysInfo.dwPageSize;
#else
long pagesize = sysconf(_SC_PAGESIZE);
#endif
return pagesize;
}
// 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);
}
simdjson::padded_string_view
get_padded_string_view(const char *buf, size_t len,
simdjson::padded_string &jsonbuffer) {
if (need_allocation(buf, len)) { // unlikely case
jsonbuffer = simdjson::padded_string(buf, len);
return jsonbuffer;
} else { // no reallcation needed (very likely)
return simdjson::padded_string_view(buf, len,
len + simdjson::SIMDJSON_PADDING);
}
}
int main() {
printf("page_size: %ld\n", page_size());
const char *jsonpoiner = R"(
{
"key": "value"
}
)";
size_t len = strlen(jsonpoiner);
simdjson::padded_string jsonbuffer; // only allocate if needed
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
simdjson::error_code error =
parser.iterate(get_padded_string_view(jsonpoiner, len, jsonbuffer))
.get(doc);
if (error) {
printf("error: %s\n", simdjson::error_message(error));
return EXIT_FAILURE;
}
std::string_view value;
error = doc["key"].get_string().get(value);
if (error) {
return EXIT_FAILURE;
}
printf("Value: \"%.*s\"\n", (int)value.size(), value.data());
if (value != "value") {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
@@ -196,6 +196,48 @@ namespace document_stream_tests {
TEST_SUCCEED();
}
bool issue2170() {
TEST_START();
auto json = R"(1 2 3)"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
auto i = stream.begin();
size_t count{0};
std::vector<size_t> indexes = { 0, 2, 4 };
std::vector<std::string_view> expected = { "1", "2", "3" };
for(; i != stream.end(); ++i) {
ASSERT_SUCCESS(i.error());
ASSERT_TRUE(count < 3);
ASSERT_EQUAL(i.current_index(), indexes[count]);
ASSERT_EQUAL(i.source(), expected[count]);
count++;
}
TEST_SUCCEED();
}
bool issue2181() {
TEST_START();
auto json = R"(1 2 34)"_padded;
ondemand::parser parser;
ondemand::document_stream stream;
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
auto i = stream.begin();
size_t count{0};
std::vector<size_t> indexes = { 0, 2, 4 };
std::vector<std::string_view> expected = { "1", "2", "34" };
for(; i != stream.end(); ++i) {
ASSERT_SUCCESS(i.error());
ASSERT_TRUE(count < 3);
ASSERT_EQUAL(i.current_index(), indexes[count]);
ASSERT_EQUAL(i.source(), expected[count]);
count++;
}
TEST_SUCCEED();
}
bool issue1977() {
TEST_START();
std::string json = R"( 1111 })";
@@ -881,6 +923,8 @@ namespace document_stream_tests {
bool run() {
return
issue2181() &&
issue2170() &&
issue2137() &&
skipbom() &&
issue1977() &&
@@ -385,8 +385,38 @@ namespace json_pointer_tests {
TEST_SUCCEED();
}
#endif
bool issue2154() { // mistakenly taking value as path should not raise INVALID_JSON_POINTER
#if SIMDJSON_EXCEPTIONS
std::cout << "issue 2154" << std::endl;
auto example_json = R"__({
"obj": {
"s": "42",
"n": 42,
"f": 4.2
}
})__"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(example_json).get(doc));
std::string_view sfield = doc.at_pointer("/obj/s");
ASSERT_EQUAL(sfield, "42");
int64_t nfield = doc.at_pointer("/obj/n");
ASSERT_EQUAL(nfield, 42);
ASSERT_ERROR(doc.at_pointer("/obj/X/42").error(), NO_SUCH_FIELD);
ASSERT_ERROR(doc.at_pointer("/obj/s/42").error(), NO_SUCH_FIELD);
ASSERT_ERROR(doc.at_pointer("/obj/n/42").error(), NO_SUCH_FIELD);
ASSERT_ERROR(doc.at_pointer("/obj/f/4.2").error(), NO_SUCH_FIELD);
ASSERT_ERROR(doc.at_pointer("/obj/f/4~").error(), INVALID_JSON_POINTER);
ASSERT_ERROR(doc.at_pointer("/obj/f/~").error(), INVALID_JSON_POINTER);
ASSERT_ERROR(doc.at_pointer("/obj/f/~1").error(), NO_SUCH_FIELD);
#endif
return true;
}
bool run() {
return
issue2154() &&
#if SIMDJSON_EXCEPTIONS
json_pointer_invalidation_exceptions() &&
#endif
+24 -6
View File
@@ -5,6 +5,22 @@ using namespace simdjson;
namespace misc_tests {
using namespace std;
#if SIMDJSON_EXCEPTIONS
// user reported an asan error:
bool issue2199() {
TEST_START();
static constexpr std::string_view kJsonString = R"( { "name": "name", "version": 100, } )";
try {
simdjson::padded_string buffer{kJsonString};
simdjson::ondemand::parser parser;
simdjson::ondemand::document document = parser.iterate(buffer);
(void)document;
} catch (simdjson::simdjson_error& /*error*/) {
std::cerr << "Caught simdjson_error" << std::endl;
}
TEST_SUCCEED();
}
#endif
bool issue1981_success() {
auto error_phrase = R"(false)"_padded;
TEST_START();
@@ -532,7 +548,7 @@ namespace misc_tests {
string_view token;
ASSERT_SUCCESS(o["value"].raw_json_token().get(token));
ASSERT_EQUAL(token, "12321323213213213213213213213211223");
return true;
TEST_SUCCEED();
}
simdjson_warn_unused bool big_integer_in_string() {
TEST_START();
@@ -545,7 +561,7 @@ namespace misc_tests {
string_view token;
ASSERT_SUCCESS(o["value"].raw_json_token().get(token));
ASSERT_EQUAL(token, "\"12321323213213213213213213213211223\"");
return true;
TEST_SUCCEED();
}
simdjson_warn_unused bool test_raw_json_token(string_view json, string_view expected_token, int expected_start_index = 0) {
string title("'");
@@ -558,7 +574,7 @@ namespace misc_tests {
ASSERT_EQUAL( token, expected_token );
// Validate the text is inside the original buffer
ASSERT_EQUAL( reinterpret_cast<const void*>(token.data()), reinterpret_cast<const void*>(&json_padded.data()[expected_start_index]));
return true;
TEST_SUCCEED();
}));
// Test values
@@ -576,10 +592,9 @@ namespace misc_tests {
// Validate the text is inside the original buffer
// Adjust for the {"a":
ASSERT_EQUAL( reinterpret_cast<const void*>(token.data()), reinterpret_cast<const void*>(&json_padded.data()[5+expected_start_index]));
return true;
TEST_SUCCEED();
}));
return true;
TEST_SUCCEED();
}
bool raw_json_token() {
@@ -605,6 +620,9 @@ namespace misc_tests {
bool run() {
return
#if SIMDJSON_EXCEPTIONS
issue2199() &&
#endif
skipbom() &&
issue1981_success() &&
issue1981_failure() &&