mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7382dc2be8 | |||
| 8c14e0c56f | |||
| a9a62feb75 | |||
| b9228b4d3c | |||
| 726c3eb611 | |||
| 4cdc4f18ef | |||
| f3b034ac38 | |||
| 9c2e8a8f39 | |||
| dfa43f6cdd | |||
| 797e61742c | |||
| f289412e0a | |||
| 7bd79b4445 | |||
| 078e2c9073 | |||
| d7b6b20511 | |||
| dbea3bbd62 | |||
| e422933414 | |||
| de4d69b367 | |||
| b8675a7f7b | |||
| 5642bb93a4 | |||
| 1b23a77e03 | |||
| 57699bfed8 | |||
| 648303b26a | |||
| 9008960e36 | |||
| 8a9e8a1792 | |||
| ba33e9e78f | |||
| d98b351eef | |||
| 5488dca126 | |||
| 7712ecf164 | |||
| 2803ca3093 | |||
| e7f2463920 | |||
| 5bfa0b098c | |||
| f7ba9cb11b | |||
| d4bf0cc7ec | |||
| 2fbbea0b15 | |||
| c16486f702 | |||
| f615112093 | |||
| 6bbcbfbb95 | |||
| e6578fea39 | |||
| 6fb050d04e | |||
| b4242d3b4f | |||
| cbfe2d4a21 | |||
| 79126ca323 | |||
| 3f87f958d7 | |||
| cab383e1de | |||
| 9b314922a1 | |||
| 587beae307 | |||
| f53981d945 | |||
| 41b4ffd6aa | |||
| 6cd8a6d776 |
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
name: Doxygen GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
release:
|
||||
types: [created]
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
implementations: haswell westmere fallback
|
||||
UBSAN_OPTIONS: halt_on_error=1
|
||||
MAXLEN: -max_len=4000
|
||||
CLANGVERSION: 15
|
||||
CLANGVERSION: 19
|
||||
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
|
||||
OPTLEVEL: -O3
|
||||
|
||||
@@ -125,7 +125,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Save the corpus as a github artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: corpus
|
||||
path: corpus.tar
|
||||
@@ -148,7 +148,7 @@ jobs:
|
||||
run: tar cf valgrind.tar valgrind-*.txt
|
||||
|
||||
- name: Save valgrind output as a github artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: valgrindresults
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Archive any crashes as an artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: crashes
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: Debug
|
||||
- msystem: "MINGW64"
|
||||
- msystem: "MINGW64"
|
||||
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
|
||||
type: RelWithDebInfo
|
||||
env:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
- uses: uraimo/run-on-arch-action@v3
|
||||
name: Test
|
||||
id: runcmd
|
||||
with:
|
||||
|
||||
@@ -18,4 +18,4 @@ jobs:
|
||||
- name: Use cmake
|
||||
run: |
|
||||
cmake -A ${{ matrix.arch }} -DCMAKE_SYSTEM_VERSION="10.0.22621.0" -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
|
||||
cmake --build build --verbose
|
||||
cmake --build build --verbose
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 3.10.1
|
||||
VERSION 3.12.3
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,8 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "23.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "23" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "25.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "25" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson (only makes sense if BUILD_SHARED_LIBS=ON)" OFF)
|
||||
if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ We welcome contributions from women and less represented groups. If you need hel
|
||||
|
||||
Consider the following points when engaging with the project:
|
||||
|
||||
- We discourage arguments from authority: ideas are discusssed on their own merits and not based on who stated it.
|
||||
- We discourage arguments from authority: ideas are discussed on their own merits and not based on who stated it.
|
||||
- Be mindful that what you may view as an aggression is maybe merely a difference of opinion or a misunderstanding.
|
||||
- Be mindful that a collection of small aggressions, even if mild in isolation, can become harmful.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "3.10.1"
|
||||
PROJECT_NUMBER = "3.12.3"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018-2023 The simdjson authors
|
||||
Copyright 2018-2025 The simdjson authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
Copyright 2018-2025 The simdjson authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
[/badge.svg)](https://simdjson.org/plots.html)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
|
||||
[![][license img]][license]
|
||||
[![][license img]][license] [![][licensemit img]][licensemit]
|
||||
|
||||
|
||||
[](https://simdjson.github.io/simdjson/)
|
||||
|
||||
@@ -31,6 +31,7 @@ Table of Contents
|
||||
* [Documentation](#documentation)
|
||||
* [Godbolt](#godbolt)
|
||||
* [Performance results](#performance-results)
|
||||
* [Packages](#packages)
|
||||
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
|
||||
* [About simdjson](#about-simdjson)
|
||||
* [Funding](#funding)
|
||||
@@ -61,6 +62,8 @@ Real-world usage
|
||||
- [ada-url](https://github.com/ada-url/ada)
|
||||
- [fastgron](https://github.com/adamritter/fastgron)
|
||||
- [WasmEdge](https://wasmedge.org)
|
||||
- [RonDB](https://github.com/logicalclocks/rondb)
|
||||
|
||||
|
||||
If you are planning to use simdjson in a product, please work from one of our releases.
|
||||
|
||||
@@ -143,6 +146,9 @@ speed for [synthetic files over various sizes generated with a script](https://g
|
||||
For NDJSON files, we can exceed 3 GB/s with [our multithreaded parsing functions](https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md).
|
||||
|
||||
|
||||
Packages
|
||||
------------------------------
|
||||
[](https://repology.org/project/simdjson/versions)
|
||||
|
||||
|
||||
Bindings and Ports of simdjson
|
||||
@@ -167,7 +173,8 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
|
||||
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
|
||||
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
|
||||
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
|
||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
|
||||
- [zimdjson](https://github.com/EzequielRamis/zimdjson): Zig port.
|
||||
- [simdjzon](https://github.com/travisstaloch/simdjzon): Zig port.
|
||||
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
|
||||
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
|
||||
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
|
||||
@@ -207,6 +214,11 @@ RGPIN-2017-03910 and RGPIN-2024-03787.
|
||||
[license]: LICENSE
|
||||
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg
|
||||
|
||||
|
||||
[licensemit]: LICENSE-MIT
|
||||
[licensemit img]: https://img.shields.io/badge/License-MIT-blue.svg
|
||||
|
||||
|
||||
Contributing to simdjson
|
||||
------------------------
|
||||
|
||||
@@ -216,7 +228,7 @@ Head over to [CONTRIBUTING.md](CONTRIBUTING.md) for information on contributing
|
||||
License
|
||||
-------
|
||||
|
||||
This code is made available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).
|
||||
This code is made available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) as well as under the MIT License. As a user, you can pick the license you prefer.
|
||||
|
||||
Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it is under the liberal (business-friendly) MIT license.
|
||||
|
||||
|
||||
+80
-10
@@ -48,7 +48,7 @@ Requirements
|
||||
------------------
|
||||
|
||||
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
|
||||
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64 or ARM64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
|
||||
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64 or ARM64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clang-cl) as well as as the regular Visual Studio compiler. For better release performance (both compile time and execution time), we recommend Visual Studio users adopt LLVM (clang-cl). We also support MinGW 64-bit under Windows.
|
||||
|
||||
|
||||
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.
|
||||
@@ -209,6 +209,25 @@ std::string data = "my data";
|
||||
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||
```
|
||||
|
||||
You can then parse the JSON data from the `simdjson::padded_string` instance:
|
||||
|
||||
|
||||
```c++
|
||||
ondemand::document doc = parser.iterate(my_padded_data);
|
||||
```
|
||||
|
||||
Whenever you pass an `std::string` reference to `parser::iterate`,
|
||||
the parser will access the bytes beyond the end of
|
||||
the string but before the end of the allocated memory (`std::string::capacity()`).
|
||||
If you are using a sanitizer that checks for reading uninitialized bytes or `std::string`'s
|
||||
container-overflow checks, you may encounter sanitizer warnings.
|
||||
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
|
||||
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
|
||||
|
||||
```c++
|
||||
std::string json = "[1]";
|
||||
ondemand::document doc = parser.iterate(simdjson::pad(json));
|
||||
```
|
||||
|
||||
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
|
||||
Consider reusing the same buffers and limiting memory allocations.
|
||||
@@ -403,9 +422,13 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
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.
|
||||
|
||||
When you are iterating through an object, you are advancing through its keys and values. You should not also access the object or other objects. E.g. within a loop over `myobject`, you should not be accessing `myobject`. The following is an anti-pattern: `for(auto value: myobject) {myobject["mykey"]}`.
|
||||
|
||||
You should never reset an object as you are iterating through it. The following is an anti-pattern: `for(auto value: myobject) {myobject.reset()}`.
|
||||
* **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]`).
|
||||
out of the array, you may use an array access (e.g., `array[1]`). You should never reset an array as you are iterating through it. The following is an anti-pattern: `for(auto value: myarray) {myarray.reset()}`.
|
||||
* **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
|
||||
@@ -538,7 +561,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
For this purpose, `array` instances have a `count_elements` method. Users should be
|
||||
aware that the `count_elements` method can be costly since it requires scanning the
|
||||
whole array. You should only call `count_elements` as a last resort as it may
|
||||
require scanning the document twice or more. You may use it as follows if your document is itself an array:
|
||||
require scanning the document twice or more. You should never use the `count_elements` as part of an attempt to iterate through the array: use a `for` loop to iterate through arrays. In the spirit of On-Demand, the `count_elements` function does not validate the values in the array: they are validated when they are consumed. You may use it as follows if your document is itself an array:
|
||||
|
||||
```C++
|
||||
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
|
||||
@@ -1220,7 +1243,6 @@ int main() {
|
||||
You may also conditionally fill in `std::optional` values.
|
||||
|
||||
```C++
|
||||
|
||||
padded_string json =
|
||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] }
|
||||
@@ -1235,6 +1257,23 @@ You may also conditionally fill in `std::optional` values.
|
||||
// error is simdjson::SUCCESS
|
||||
```
|
||||
|
||||
You can also deserialized to map-like types with keys that can be constructed
|
||||
from `std::string_view` instances:
|
||||
|
||||
|
||||
```C++
|
||||
padded_string json =
|
||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] }
|
||||
})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
std:map<std::string,Car> cars;
|
||||
error = doc.get<std:map<std::string,Car>>().get(cars);
|
||||
// car has value car1->Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}}
|
||||
// error is simdjson::SUCCESS
|
||||
```
|
||||
|
||||
And so forth.
|
||||
|
||||
Advanced users may want to overwrite the defaults provided by the simdjson library.
|
||||
@@ -1508,7 +1547,20 @@ Some errors are recoverable:
|
||||
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
|
||||
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
|
||||
|
||||
Other errors (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`) may indicate a fatal error and often follow from the fact that the document is not valid JSON. In which case, it is no longer possible to continue accessing the document: calling the method `is_alive()` on the document instance returns false. All following accesses will keep returning the same fatal error (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`).
|
||||
Other errors (`simdjson::INCOMPLETE_ARRAY_OR_OBJECT` and `simdjson::TAPE_ERROR`) indicate a fatal error and follow from the fact that the document is not valid JSON. These errors are not recoverable: you cannot continue. In which case, it is no longer safe to continue accessing the document: calling the method `is_alive()` on the document instance returns false. It is your responsibility as a user to stop using the simdjson
|
||||
document after encountering these fatal errors. Consider the following example, after
|
||||
the fatal error, the document instance cannot be used. Observe how the JSON input is invalid.
|
||||
```cpp
|
||||
simdjson::padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc;
|
||||
auto errordoc = parser.iterate(badjson).get(doc);
|
||||
// errordoc == simdjson::SUCCESS
|
||||
simdjson::ondemand::value v;
|
||||
auto error = doc.get_object()["year"].get(v);
|
||||
// simdjson::is_fatal(error)) is true!
|
||||
// doc.is_alive() is false
|
||||
```
|
||||
|
||||
When you use the code without exceptions, it is your responsibility to check for error before using the
|
||||
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
|
||||
@@ -1606,7 +1658,7 @@ The following is a similar example where one wants to get the id of the first tw
|
||||
triggering exceptions. To do this, we use `["statuses"].at(0)["id"]`. We break that expression down:
|
||||
|
||||
- Get the list of tweets (the `"statuses"` key of the document) using `["statuses"]`). The result is expected to be an array.
|
||||
- Get the first tweet using `.at(0)`. The result is expected to be an object.
|
||||
- Get the first tweet using `.at(0)`. The result is expected to be an object. Observe that the `at` method can only be called once on an array (it cannot be used for iteration).
|
||||
- Get the id of the tweet using ["id"]. We expect the value to be a non-negative integer.
|
||||
|
||||
Observe how we use the `at` method when querying an index into an array, and not the bracket operator.
|
||||
@@ -1631,8 +1683,8 @@ 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.
|
||||
*Important remark*: The `at` method can only be called once on an array. It cannot be used
|
||||
to iterate through the values of an array. We deliberately forbid this usage to avoid performance antipatterns. If you need to iterate through the values of an array, you should use a `for` loop.
|
||||
|
||||
### Error handling examples without exceptions
|
||||
|
||||
@@ -1897,6 +1949,8 @@ conclude that you have trailing content and that your document is not valid JSON
|
||||
You may then use `doc.current_location()` to obtain a pointer to the start of the trailing
|
||||
content.
|
||||
|
||||
Example 1.
|
||||
|
||||
```C++
|
||||
auto json = R"([1, 2] foo ])"_padded;
|
||||
ondemand::parser parser;
|
||||
@@ -1911,6 +1965,21 @@ content.
|
||||
}
|
||||
```
|
||||
|
||||
Example 2.
|
||||
|
||||
```cpp
|
||||
auto json = R"(["extra close"]])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
ondemand::array array = doc.get_array();
|
||||
for (std::string_view values : array) {
|
||||
std::cout << values << std::endl;
|
||||
}
|
||||
if(!doc.at_end()) {
|
||||
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
The `at_end()` method is equivalent to `doc.current_location().error() == simdjson::SUCCESS` but
|
||||
more convenient.
|
||||
|
||||
@@ -1951,6 +2020,7 @@ to the document `rewind()` method, except that it does not rewind the
|
||||
internal string buffer. Thus you should consume values only once
|
||||
even if you can iterate through the array or object more than once.
|
||||
If you unescape a string within an array more than once, you have unsafe code.
|
||||
You must not call `reset()` on an object or an array as you are iterating through it.
|
||||
|
||||
|
||||
Newline-Delimited JSON (ndjson) and JSON lines
|
||||
@@ -1962,7 +2032,7 @@ serialize data into streams of multiple JSON documents. That is, instead of one
|
||||
write out multiple records as independent JSON documents, to be read one-by-one.
|
||||
|
||||
The simdjson library also supports multithreaded JSON streaming through a large file
|
||||
containing many smaller JSON documents in either [ndjson](http://ndjson.org)
|
||||
containing many smaller JSON documents in either [ndjson](https://github.com/ndjson/ndjson-spec)
|
||||
or [JSON lines](http://jsonlines.org) format. If your JSON documents all contain arrays
|
||||
or objects, we even support direct file concatenation without whitespace. However, if there
|
||||
is content between your JSON documents, it should be exclusively ASCII white-space characters.
|
||||
@@ -2521,7 +2591,7 @@ The CPU detection, which runs the first time parsing is attempted and switches t
|
||||
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
|
||||
and some threads use the library while the main thread is cleaning up resources, 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.
|
||||
|
||||
+21
-1
@@ -60,6 +60,26 @@ std::string data = "my data";
|
||||
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||
```
|
||||
|
||||
You can then parse the JSON document from the `simdjson::padded_string` instance:
|
||||
|
||||
```cpp
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element doc = parser.parse(my_padded_data);
|
||||
```
|
||||
|
||||
Whenever you pass an `std::string` reference to `parser::parse`,
|
||||
the parser will access the bytes beyond the end of
|
||||
the string but before the end of the allocated memory (`std::string::capacity()`).
|
||||
If you are using a sanitizer that checks for reading uninitialized bytes or `std::string`'s
|
||||
container-overflow checks, you may encounter sanitizer warnings.
|
||||
You can safely ignore these warnings. Or you can call `simdjson::pad(std::string&)` to pad the
|
||||
string with `SIMDJSON_PADDING` spaces: this function returns a `simdjson::padding_string_view` which can be be passed to the parser's iterator function:
|
||||
|
||||
```c++
|
||||
std::string json = "[1]";
|
||||
dom::element doc = parser.parse(simdjson::pad(json));
|
||||
```
|
||||
|
||||
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
|
||||
You cannot copy a `parser` instance, you may only move it.
|
||||
|
||||
@@ -713,5 +733,5 @@ Setting the `realloc_if_needed` parameter `false` in this manner may lead to bet
|
||||
Performance Tips
|
||||
---------------------
|
||||
|
||||
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directrive, you must set it manually (e.g., `-DNDEBUG`).
|
||||
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`).
|
||||
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
|
||||
|
||||
+2
-2
@@ -130,7 +130,7 @@ If your documents are all objects or arrays, then you may even have nothing betw
|
||||
E.g., `[1,2]{"32":1}` is recognized as two documents.
|
||||
|
||||
Some official formats **(non-exhaustive list)**:
|
||||
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
|
||||
- [Newline-Delimited JSON (NDJSON)](https://github.com/ndjson/ndjson-spec/)
|
||||
- [JSON lines (JSONL)](http://jsonlines.org/)
|
||||
- [Record separator-delimited JSON (RFC 7464)](https://tools.ietf.org/html/rfc7464) <- Not supported by JsonStream!
|
||||
- [More on Wikipedia...](https://en.wikipedia.org/wiki/JSON_streaming)
|
||||
@@ -367,7 +367,7 @@ Please see our main documentation (`basics.md`) under
|
||||
"Use `tag_invoke` for custom types (C++20)" for details about
|
||||
tag_invoke functions.
|
||||
|
||||
Given a stream of JSON documents, you can add them to a data struture
|
||||
Given a stream of JSON documents, you can add them to a data structure
|
||||
such as a `std::vector<Car>` like so if you support exceptions:
|
||||
|
||||
```C++
|
||||
|
||||
@@ -102,7 +102,7 @@ or indexing (`object["key"]`). In some cases, the values are even deserialized d
|
||||
maps.
|
||||
|
||||
The DOM approach is conceptually simple and "programmer friendly". Using the
|
||||
DOM tree is often easy enough that many users use the DOM as-is instead of creating
|
||||
DOM tree is often easy enough that many users process the DOM as-is instead of creating
|
||||
their own custom data structures.
|
||||
|
||||
The DOM approach was the only way to parse JSON documents up to version 0.6 of the simdjson library.
|
||||
|
||||
+3
-1
@@ -158,7 +158,9 @@ On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers
|
||||
|
||||
When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better. We do not recommend that you compile simdjson with architecture-specific flags such as `arch:AVX2`. The simdjson library automatically selects the best execution kernel at runtime.
|
||||
|
||||
Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (ClangCL). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries).
|
||||
Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (clang-cl). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries).
|
||||
|
||||
We recommend Visual Studio users prefer LLVM (clang-cl). It compiles to faster release binaries. Furthermore, it compilers faster in release mode.
|
||||
|
||||
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows is excellent (on par with Linux).
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
|
||||
// make this dynamic, so it works regardless of how it was compiled
|
||||
// or what hardware it runs on
|
||||
constexpr std::size_t Nimplementations_max=3;
|
||||
constexpr std::size_t Nimplementations_max=4;
|
||||
const std::size_t Nimplementations = supported_implementations.size();
|
||||
|
||||
if(Nimplementations>Nimplementations_max) {
|
||||
|
||||
@@ -19,7 +19,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
@@ -43,7 +43,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
@@ -96,7 +96,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
*result = value1 + value2;
|
||||
return *result < value1;
|
||||
#else
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace arm64
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace arm64 {
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
namespace {
|
||||
// Start of private section with Visual Studio workaround
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace {
|
||||
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
|
||||
// purposes (cutting it down to uint16_t costs performance in some compilers).
|
||||
simdjson_inline uint32_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
|
||||
#else
|
||||
@@ -134,12 +134,6 @@ namespace {
|
||||
tmp = vpaddq_u8(tmp, tmp);
|
||||
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
|
||||
}
|
||||
// Returns 4-bit out of each byte, alternating between the high 4 bits and low
|
||||
// bits result it is 64 bit.
|
||||
simdjson_inline uint64_t to_bitmask64() const {
|
||||
return vget_lane_u64(
|
||||
vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0);
|
||||
}
|
||||
simdjson_inline bool any() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; }
|
||||
};
|
||||
|
||||
@@ -158,7 +152,7 @@ namespace {
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
|
||||
// Member-by-member initialization
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline simd8(
|
||||
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
||||
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
|
||||
@@ -216,7 +210,7 @@ namespace {
|
||||
|
||||
// Bit-specific operations
|
||||
simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return vtstq_u8(*this, bits); }
|
||||
simdjson_inline bool any_bits_set_anywhere() const { return vmaxvq_u32(vreinterpretq_u32_u8(*this)) != 0; }
|
||||
simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; }
|
||||
simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return (*this & bits).any_bits_set_anywhere(); }
|
||||
template<int N>
|
||||
simdjson_inline simd8<uint8_t> shr() const { return vshrq_n_u8(*this, N); }
|
||||
@@ -229,12 +223,7 @@ namespace {
|
||||
return lookup_table.apply_lookup_16_to(*this);
|
||||
}
|
||||
|
||||
// Returns 4-bit out of each byte, alternating between the high 4 bits and low
|
||||
// bits result it is 64 bit.
|
||||
simdjson_inline uint64_t to_bitmask64() const {
|
||||
return vget_lane_u64(
|
||||
vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(*this), 4)), 0);
|
||||
}
|
||||
|
||||
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
|
||||
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
|
||||
// Only the first 16 - count_ones(mask) bytes of the result are significant but 16 bytes
|
||||
@@ -257,7 +246,7 @@ namespace {
|
||||
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
|
||||
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
@@ -287,7 +276,7 @@ namespace {
|
||||
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
|
||||
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
@@ -339,7 +328,7 @@ namespace {
|
||||
// Array constructor
|
||||
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
|
||||
// Member-by-member initialization
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline simd8(
|
||||
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
|
||||
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
|
||||
@@ -460,7 +449,7 @@ namespace {
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
|
||||
@@ -46,32 +46,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
};
|
||||
}
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 16;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits) / 4; }
|
||||
|
||||
uint64_t escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
simd8<bool> is_quote = (v == '"');
|
||||
simd8<bool> is_backslash = (v == '\\');
|
||||
simd8<bool> is_control = (v < 32);
|
||||
return {
|
||||
(is_backslash | is_quote | is_control).to_bitmask64()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -56,10 +56,22 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
#if defined(__apple_build_version__)
|
||||
#if __apple_build_version__ < 14000000
|
||||
#define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||
#if __cpp_concepts >= 201907L
|
||||
#include <utility>
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
||||
#else // __cpp_concepts
|
||||
#else
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif
|
||||
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||
|
||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||
|
||||
+28
-10
@@ -20,26 +20,42 @@ namespace details {
|
||||
}; \
|
||||
};
|
||||
|
||||
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back);
|
||||
SIMDJSON_IMPL_CONCEPT(emplace, emplace);
|
||||
SIMDJSON_IMPL_CONCEPT(push_back, push_back);
|
||||
SIMDJSON_IMPL_CONCEPT(add, add);
|
||||
SIMDJSON_IMPL_CONCEPT(push, push);
|
||||
SIMDJSON_IMPL_CONCEPT(append, append);
|
||||
SIMDJSON_IMPL_CONCEPT(insert, insert);
|
||||
SIMDJSON_IMPL_CONCEPT(op_append, operator+=);
|
||||
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
|
||||
SIMDJSON_IMPL_CONCEPT(emplace, emplace)
|
||||
SIMDJSON_IMPL_CONCEPT(push_back, push_back)
|
||||
SIMDJSON_IMPL_CONCEPT(add, add)
|
||||
SIMDJSON_IMPL_CONCEPT(push, push)
|
||||
SIMDJSON_IMPL_CONCEPT(append, append)
|
||||
SIMDJSON_IMPL_CONCEPT(insert, insert)
|
||||
SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
||||
|
||||
#undef SIMDJSON_IMPL_CONCEPT
|
||||
} // namespace details
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||
!std::is_convertible_v<T, const char*>;
|
||||
|
||||
template<typename T>
|
||||
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
|
||||
&& !std::is_same_v<T, std::string_view>
|
||||
&& std::is_default_constructible_v<T>;
|
||||
|
||||
template<typename M>
|
||||
concept string_view_keyed_map = string_view_like<typename M::key_type>
|
||||
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
|
||||
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
|
||||
};
|
||||
|
||||
/// Check if T is a container that we can append to, including:
|
||||
/// std::vector, std::deque, std::list, std::string, ...
|
||||
template <typename T>
|
||||
concept appendable_containers =
|
||||
details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
details::supports_push_back<T> || details::supports_push<T> ||
|
||||
details::supports_add<T> || details::supports_append<T> ||
|
||||
details::supports_insert<T>;
|
||||
details::supports_insert<T>) && !string_view_keyed_map<T>;
|
||||
|
||||
/// Insert into the container however possible
|
||||
template <appendable_containers T, typename... Args>
|
||||
@@ -107,6 +123,8 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace concepts
|
||||
} // namespace simdjson
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
* The memory allocation is strict: you
|
||||
* can you use this function to increase
|
||||
* or lower the amount of allocated memory.
|
||||
* Passsing zero clears the memory.
|
||||
* Passing zero clears the memory.
|
||||
*/
|
||||
error_code allocate(size_t len) noexcept;
|
||||
/** @private Capacity in bytes, in terms
|
||||
|
||||
@@ -372,6 +372,8 @@ public:
|
||||
* - INCORRECT_TYPE if this is not an object
|
||||
*/
|
||||
inline simdjson_result<element> operator[](const char *key) const noexcept;
|
||||
simdjson_result<element> operator[](int) const noexcept = delete;
|
||||
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
@@ -540,6 +542,7 @@ public:
|
||||
|
||||
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
|
||||
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
|
||||
simdjson_inline simdjson_result<dom::element> at_path(const std::string_view json_path) const noexcept;
|
||||
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
|
||||
|
||||
@@ -145,6 +145,7 @@ public:
|
||||
* - INCORRECT_TYPE if this is not an object
|
||||
*/
|
||||
inline simdjson_result<element> operator[](const char *key) const noexcept;
|
||||
simdjson_result<element> operator[](int) const noexcept = delete;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
@@ -258,6 +259,7 @@ public:
|
||||
|
||||
inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
|
||||
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
|
||||
simdjson_result<dom::element> operator[](int) const noexcept = delete;
|
||||
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
|
||||
inline simdjson_result<dom::element> at_path(std::string_view json_path) const noexcept;
|
||||
inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
|
||||
|
||||
@@ -202,6 +202,22 @@ public:
|
||||
* simdjson::dom::parser parser;
|
||||
* simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
|
||||
*
|
||||
* ### std::string references
|
||||
*
|
||||
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
|
||||
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
|
||||
*
|
||||
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
|
||||
* the string but before the end of the allocated memory (std::string::capacity()).
|
||||
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
|
||||
* container-overflow checks, you may encounter sanitizer warnings.
|
||||
* You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
|
||||
* string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
|
||||
* which can be be passed to the parser's parse function:
|
||||
*
|
||||
* std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
|
||||
* element doc = parser.parse(simdjson::pad(json));
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser's current capacity is less than len, it will allocate enough capacity
|
||||
@@ -324,7 +340,7 @@ public:
|
||||
* arrays or objects) MUST be separated with whitespace.
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||
* performance.
|
||||
*
|
||||
* ### Error Handling
|
||||
@@ -418,7 +434,7 @@ public:
|
||||
* arrays or objects) MUST be separated with whitespace.
|
||||
*
|
||||
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
|
||||
* Setting batch_size to excessively large or excesively small values may impact negatively the
|
||||
* Setting batch_size to excessively large or excessively small values may impact negatively the
|
||||
* performance.
|
||||
*
|
||||
* ### Error Handling
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
#include <iostream>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
inline bool is_fatal(error_code error) noexcept {
|
||||
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// We store the error code so we can validate the error message is associated with the right code
|
||||
struct error_code_info {
|
||||
|
||||
@@ -20,7 +20,7 @@ enum error_code {
|
||||
SUCCESS = 0, ///< No error
|
||||
CAPACITY, ///< This parser can't support a document that big
|
||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
|
||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||
STRING_ERROR, ///< Problem while parsing a string
|
||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||
@@ -45,14 +45,21 @@ enum error_code {
|
||||
PARSER_IN_USE, ///< parser is already in use.
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
|
||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||
OUT_OF_CAPACITY, ///< The capacity was exceeded, we cannot allocate enough memory.
|
||||
NUM_ERROR_CODES ///< Placeholder for end of error code list.
|
||||
NUM_ERROR_CODES
|
||||
};
|
||||
|
||||
/**
|
||||
* Some errors are fatal and invalidate the document. This function returns true if the
|
||||
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
|
||||
* Once a fatal error is encountered, the on-demand document is no longer valid and
|
||||
* processing should stop.
|
||||
*/
|
||||
inline bool is_fatal(error_code error) noexcept;
|
||||
|
||||
/**
|
||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||
@@ -87,7 +94,7 @@ struct simdjson_error : public std::exception {
|
||||
*/
|
||||
simdjson_error(error_code error) noexcept : _error{error} { }
|
||||
/** The error message */
|
||||
const char *what() const noexcept { return error_message(error()); }
|
||||
const char *what() const noexcept override { return error_message(error()); }
|
||||
/** The error code */
|
||||
error_code error() const noexcept { return _error; }
|
||||
private:
|
||||
|
||||
@@ -26,7 +26,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace fallback
|
||||
|
||||
@@ -29,24 +29,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
return { src[0] };
|
||||
}
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 1;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits; }
|
||||
simdjson_inline int escape_index() { return 0; }
|
||||
|
||||
bool escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
dst[0] = src[0];
|
||||
return { (src[0] == '\\') || (src[0] == '"') || (src[0] < 32) };
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -137,7 +137,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
|
||||
@@ -45,8 +45,4 @@
|
||||
#include "simdjson/generic/ondemand/token_iterator-inl.h"
|
||||
#include "simdjson/generic/ondemand/value_iterator-inl.h"
|
||||
|
||||
// JSON builder, ideally they should not be part of the ondemand directory
|
||||
// but it is convenient for now to have them here.
|
||||
#include "simdjson/generic/ondemand/json_string_builder.h"
|
||||
#include "simdjson/generic/ondemand/json_string_builder-inl.h"
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ public:
|
||||
* calling this function, if successful, the array is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
* safe to continue. Note that count_elements() does not validate the JSON values,
|
||||
* only the structure of the array.
|
||||
*
|
||||
* To check that an array is empty, it is more performant to use
|
||||
* the is_empty() method.
|
||||
|
||||
@@ -246,7 +246,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
|
||||
}
|
||||
|
||||
simdjson_inline error_code document::consume() noexcept {
|
||||
auto error = iter.skip_child(0);
|
||||
bool scalar = false;
|
||||
auto error = is_scalar().get(scalar);
|
||||
if(error) { return error; }
|
||||
if(scalar) {
|
||||
iter.return_current_and_advance();
|
||||
return SUCCESS;
|
||||
}
|
||||
error = iter.skip_child(0);
|
||||
if(error) { iter.abandon(); }
|
||||
return error;
|
||||
}
|
||||
@@ -268,6 +275,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
|
||||
// For more speed, we could do:
|
||||
// return iter.is_single_token();
|
||||
json_type this_type;
|
||||
auto error = type().get(this_type);
|
||||
if(error) { return error; }
|
||||
|
||||
@@ -239,20 +239,27 @@ public:
|
||||
if constexpr (custom_deserializable<T, document>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||
"And you do not seem to have added support for it. Indeed, we have that "
|
||||
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, or bool.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
@@ -354,7 +361,8 @@ public:
|
||||
* calling this function, if successful, the array is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
* safe to continue. Note that count_elements() does not validate the JSON values,
|
||||
* only the structure of the array.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
/**
|
||||
@@ -466,6 +474,7 @@ public:
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||
simdjson_result<value> operator[](int) & noexcept = delete;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value. It does not validate or consume the value.
|
||||
@@ -812,20 +821,27 @@ public:
|
||||
if constexpr (custom_deserializable<T, document_reference>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||
"And you do not seem to have added support for it. Indeed, we have that "
|
||||
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, or bool.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
#endif
|
||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
@@ -852,6 +868,7 @@ public:
|
||||
simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||
simdjson_result<value> operator[](int) & noexcept = delete;
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
|
||||
|
||||
@@ -930,6 +947,7 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
|
||||
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) & noexcept = delete;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||
@@ -1007,6 +1025,7 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
|
||||
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) & noexcept = delete;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
/**
|
||||
* This file is part of the builder API. It is temporarily in the ondemand directory
|
||||
* but we will move it to a builder directory later.
|
||||
*/
|
||||
#include <type_traits>
|
||||
#ifndef SIMDJSON_GENERIC_BUILDER_INL_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_BUILDER_INL_H
|
||||
#include "simdjson/generic/builder/json_string_builder.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace builder {
|
||||
|
||||
simdjson_inline string_builder::string_builder(size_t initial_capacity) :
|
||||
buffer(new (std::nothrow) char[initial_capacity]),
|
||||
position(0), capacity(buffer.get() != nullptr ? initial_capacity : 0),
|
||||
is_valid(buffer.get() != nullptr) {}
|
||||
|
||||
simdjson_inline bool string_builder::capacity_check(size_t upcoming_bytes) {
|
||||
// We use the convention that when is_valid is false, then the capacity and
|
||||
// the position are 0.
|
||||
// Most of the time, this function will return true.
|
||||
if (simdjson_likely(upcoming_bytes <= capacity - position)) { return true; }
|
||||
// check for overflow, most of the time there is no overflow
|
||||
if (simdjson_likely(position + upcoming_bytes < position)) { return false; }
|
||||
// We will rarely get here.
|
||||
grow_buffer((std::max)(capacity * 2, position + upcoming_bytes));
|
||||
// If the buffer allocation failed, we set is_valid to false.
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::grow_buffer(size_t desired_capacity) {
|
||||
if (!is_valid) { return; }
|
||||
std::unique_ptr<char[]> new_buffer(new (std::nothrow) char[desired_capacity]);
|
||||
if (new_buffer.get() == nullptr) {
|
||||
set_valid(false);
|
||||
return;
|
||||
}
|
||||
std::memcpy(new_buffer.get(), buffer.get(), position);
|
||||
buffer.swap(new_buffer);
|
||||
capacity = desired_capacity;
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::set_valid(bool valid) noexcept {
|
||||
if(!valid) {
|
||||
is_valid = false;
|
||||
capacity = 0;
|
||||
position = 0;
|
||||
buffer.reset();
|
||||
} else {
|
||||
is_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline size_t string_builder::size() const noexcept {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline void string_builder::append(char c) noexcept {
|
||||
if(capacity_check(1)) {
|
||||
buffer.get()[position++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline void string_builder::append_null() noexcept {
|
||||
constexpr char null_literal[] = "null";
|
||||
constexpr size_t null_len = sizeof(null_literal) - 1;
|
||||
if(capacity_check(null_len)) {
|
||||
std::memcpy(buffer.get() + position, null_literal, null_len);
|
||||
position += null_len;
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::clear() noexcept {
|
||||
position = 0;
|
||||
// if it was invalid, we should try to repair it
|
||||
if(!is_valid) {
|
||||
capacity = 0;
|
||||
buffer.reset();
|
||||
is_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// We could specialize further for 32-bit integers.
|
||||
int int_log2(uint32_t x) { return (63 - leading_zeroes(x | 1)); }
|
||||
|
||||
int fast_digit_count_32(uint32_t x) {
|
||||
static uint64_t table[] = {
|
||||
4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
|
||||
12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
|
||||
21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
|
||||
25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
|
||||
34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
|
||||
38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
|
||||
42949672960, 42949672960};
|
||||
return uint32_t((x + table[int_log2(x)]) >> 32);
|
||||
}
|
||||
|
||||
int int_log2(uint64_t x) { return 63 - leading_zeroes(x | 1); }
|
||||
|
||||
int digit_count_64(uint64_t x) {
|
||||
static uint64_t table[] = {9,
|
||||
99,
|
||||
999,
|
||||
9999,
|
||||
99999,
|
||||
999999,
|
||||
9999999,
|
||||
99999999,
|
||||
999999999,
|
||||
9999999999,
|
||||
99999999999,
|
||||
999999999999,
|
||||
9999999999999,
|
||||
99999999999999,
|
||||
999999999999999ULL,
|
||||
9999999999999999ULL,
|
||||
99999999999999999ULL,
|
||||
999999999999999999ULL,
|
||||
9999999999999999999ULL};
|
||||
int y = (19 * int_log2(x) >> 6);
|
||||
y += x > table[y];
|
||||
return y + 1;
|
||||
}
|
||||
|
||||
template<typename number_type,
|
||||
typename = typename std::enable_if<std::is_unsigned<number_type>::value>::type>
|
||||
simdjson_inline size_t digit_count(number_type v) noexcept {
|
||||
static_assert(sizeof(number_type) == 8
|
||||
|| sizeof(number_type) == 4
|
||||
|| sizeof(number_type) == 2
|
||||
|| sizeof(number_type) == 1, "We only support 8-bit, 16-bit, 32-bit and 64-bit numbers");
|
||||
if (sizeof(number_type) <= 4) {
|
||||
return fast_digit_count_32(v);
|
||||
} else {
|
||||
return digit_count_64(v);
|
||||
}
|
||||
}
|
||||
|
||||
} // internal
|
||||
|
||||
template<typename number_type, typename>
|
||||
simdjson_inline void string_builder::append(number_type v) noexcept {
|
||||
static_assert(std::is_same<number_type, bool>::value
|
||||
|| std::is_integral<number_type>::value || std::is_floating_point<number_type>::value, "Unsupported number type");
|
||||
// If C++17 is available, we can 'if constexpr' here.
|
||||
if constexpr (std::is_same<number_type, bool>::value) {
|
||||
if (v) {
|
||||
constexpr char true_literal[] = "true";
|
||||
constexpr size_t true_len = sizeof(true_literal) - 1;
|
||||
if(capacity_check(true_len)) {
|
||||
std::memcpy(buffer.get() + position, true_literal, true_len);
|
||||
position += true_len;
|
||||
}
|
||||
} else {
|
||||
constexpr char false_literal[] = "false";
|
||||
constexpr size_t false_len = sizeof(false_literal) - 1;
|
||||
if(capacity_check(false_len)) {
|
||||
std::memcpy(buffer.get() + position, false_literal, false_len);
|
||||
position += false_len;
|
||||
}
|
||||
}
|
||||
} else if constexpr (std::is_unsigned<number_type>::value) {
|
||||
constexpr size_t max_number_size = 20;
|
||||
if(capacity_check(max_number_size)) {
|
||||
using unsigned_type = typename std::make_unsigned<number_type>::type;
|
||||
unsigned_type pv = static_cast<unsigned_type>(v);
|
||||
size_t dc = internal::digit_count(pv);
|
||||
char *write_pointer = buffer.get() + position + dc - 1;
|
||||
// optimization opportunity: if v is large, we can do better.
|
||||
while(pv >= 10) {
|
||||
*write_pointer-- = char('0' + (pv % 10));
|
||||
pv /= 10;
|
||||
}
|
||||
*write_pointer = char('0' + pv);
|
||||
position += dc;
|
||||
}
|
||||
} else if constexpr (std::is_integral<number_type>::value) {
|
||||
constexpr size_t max_number_size = 20;
|
||||
if(capacity_check(max_number_size)) {
|
||||
using unsigned_type = typename std::make_unsigned<number_type>::type;
|
||||
bool negative = v < 0;
|
||||
unsigned_type pv = static_cast<unsigned_type>(negative ? -v : v);
|
||||
size_t dc = internal::digit_count(pv);
|
||||
if(negative) {
|
||||
buffer.get()[position++] = '-';
|
||||
}
|
||||
char *write_pointer = buffer.get() + position + dc - 1;
|
||||
// optimization opportunity: if v is large, we can do better.
|
||||
while(pv >= 10) {
|
||||
*write_pointer-- = char('0' + (pv % 10));
|
||||
pv /= 10;
|
||||
}
|
||||
*write_pointer = char('0' + pv);
|
||||
position += dc;
|
||||
}
|
||||
} else if constexpr (std::is_floating_point<number_type>::value) {
|
||||
constexpr size_t max_number_size = 24;
|
||||
if(capacity_check(max_number_size)) {
|
||||
// We could specialize for float.
|
||||
char *end = simdjson::internal::to_chars(buffer.get() + position, nullptr, double(v));
|
||||
position = end - buffer.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::escape_and_append(std::string_view input) noexcept {
|
||||
// escaping might turn a control character into \x00xx so 6 characters.
|
||||
if(capacity_check(6 * input.size())) {
|
||||
position += simdjson::write_string_escaped(input, buffer.get() + position);
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::escape_and_append_with_quotes(std::string_view input) noexcept {
|
||||
// escaping might turn a control character into \x00xx so 6 characters.
|
||||
if(capacity_check(2 + 6 * input.size())) {
|
||||
buffer.get()[position++] = '"';
|
||||
position += simdjson::write_string_escaped(input, buffer.get() + position);
|
||||
buffer.get()[position++] = '"';
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::append_raw(const char *c) noexcept {
|
||||
if(capacity_check(1)) {
|
||||
buffer.get()[position++] = *c;
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::append_raw(std::string_view input) noexcept {
|
||||
if(capacity_check(input.size())) {
|
||||
std::memcpy(buffer.get() + position, input.data(), input.size());
|
||||
position += input.size();
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline void string_builder::append_raw(const char *str, size_t len) noexcept {
|
||||
if(capacity_check(len)) {
|
||||
std::memcpy(buffer.get() + position, str, len);
|
||||
position += len;
|
||||
}
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline string_builder::operator std::string() const noexcept(false) {
|
||||
return std::string(std::string_view());
|
||||
}
|
||||
|
||||
simdjson_inline string_builder::operator std::string_view() const noexcept(false) {
|
||||
return view();
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> string_builder::view() const noexcept {
|
||||
if (!is_valid) { return simdjson::OUT_OF_CAPACITY; }
|
||||
return std::string_view(buffer.get(), position);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<const char *> string_builder::c_str() noexcept {
|
||||
if(capacity_check(1)) {
|
||||
buffer.get()[position] = '\0';
|
||||
return buffer.get();
|
||||
}
|
||||
return simdjson::OUT_OF_CAPACITY;
|
||||
}
|
||||
|
||||
simdjson_inline bool string_builder::validate_unicode() const noexcept {
|
||||
return simdjson::validate_utf8(buffer.get(), position);
|
||||
}
|
||||
|
||||
} // namespace builder
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_BUILDER_INL_H
|
||||
@@ -1,167 +0,0 @@
|
||||
/**
|
||||
* This file is part of the builder API. It is temporarily in the ondemand directory
|
||||
* but we will move it to a builder directory later.
|
||||
*/
|
||||
#ifndef SIMDJSON_GENERIC_BUILDER_H
|
||||
|
||||
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
#define SIMDJSON_GENERIC_BUILDER_H
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#endif // SIMDJSON_CONDITIONAL_INCLUDE
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace builder {
|
||||
|
||||
/**
|
||||
* A builder for JSON strings representing documents. This is a low-level
|
||||
* builder that is not meant to be used directly by end-users. Though it
|
||||
* supports atomic types (Booleans, strings), it does not support composed
|
||||
* types (arrays and objects).
|
||||
*
|
||||
* Ultimately, this class should support kernel-specific optimizations. E.g.,
|
||||
* it may make use of SIMD instructions to escape strings faster.
|
||||
*/
|
||||
class string_builder {
|
||||
public:
|
||||
simdjson_inline string_builder(size_t initial_capacity = 1024);
|
||||
|
||||
/**
|
||||
* Append number (includes Booleans). Booleans are mapped to the strings
|
||||
* false and true. Numbers are converted to strings abiding by the JSON standard.
|
||||
* Floating-point numbers are converted to the shortest string that 'correctly'
|
||||
* represents the number.
|
||||
*/
|
||||
template<typename number_type,
|
||||
typename = typename std::enable_if<std::is_arithmetic<number_type>::value>::type>
|
||||
simdjson_inline void append(number_type v) noexcept;
|
||||
|
||||
/**
|
||||
* Append character c.
|
||||
*/
|
||||
simdjson_inline void append(char c) noexcept;
|
||||
|
||||
/**
|
||||
* Append the string 'null'.
|
||||
*/
|
||||
simdjson_inline void append_null() noexcept;
|
||||
|
||||
/**
|
||||
* Clear the content.
|
||||
*/
|
||||
simdjson_inline void clear() noexcept;
|
||||
|
||||
/**
|
||||
* Append the std::string_view, after escaping it.
|
||||
* There is no UTF-8 validation.
|
||||
*/
|
||||
simdjson_inline void escape_and_append(std::string_view input) noexcept;
|
||||
|
||||
/**
|
||||
* Append the std::string_view surrounded by double quotes, after escaping it.
|
||||
* There is no UTF-8 validation.
|
||||
*/
|
||||
simdjson_inline void escape_and_append_with_quotes(std::string_view input) noexcept;
|
||||
|
||||
/**
|
||||
* Append the C string directly, without escaping.
|
||||
* There is no UTF-8 validation.
|
||||
*/
|
||||
simdjson_inline void append_raw(const char *c) noexcept;
|
||||
|
||||
/**
|
||||
* Append the std::string_view directly, without escaping.
|
||||
* There is no UTF-8 validation.
|
||||
*/
|
||||
simdjson_inline void append_raw(std::string_view input) noexcept;
|
||||
|
||||
/**
|
||||
* Append len characters from str.
|
||||
* There is no UTF-8 validation.
|
||||
*/
|
||||
simdjson_inline void append_raw(const char *str, size_t len) noexcept;
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
* Creates an std::string from the written JSON buffer.
|
||||
* Throws if memory allocation failed
|
||||
*
|
||||
* The result may not be valid UTF-8 if some of your content was not valid UTF-8.
|
||||
* Use validate_unicode() to check the content if needed.
|
||||
*/
|
||||
simdjson_inline operator std::string() const noexcept(false);
|
||||
|
||||
/**
|
||||
* Creates an std::string_view from the written JSON buffer.
|
||||
* Throws if memory allocation failed.
|
||||
*
|
||||
* The result may not be valid UTF-8 if some of your content was not valid UTF-8.
|
||||
* Use validate_unicode() to check the content if needed.
|
||||
*/
|
||||
simdjson_inline operator std::string_view() const noexcept(false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns a view on the written JSON buffer. Returns an error
|
||||
* if memory allocation failed.
|
||||
*
|
||||
* The result may not be valid UTF-8 if some of your content was not valid UTF-8.
|
||||
* Use validate_unicode() to check the content.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> view() const noexcept;
|
||||
|
||||
/**
|
||||
* Appends the null character to the buffer and returns
|
||||
* a pointer to the beginning of the written JSON buffer.
|
||||
* Returns an error if memory allocation failed.
|
||||
* The result is null-terminated.
|
||||
*
|
||||
* The result may not be valid UTF-8 if some of your content was not valid UTF-8.
|
||||
* Use validate_unicode() to check the content.
|
||||
*/
|
||||
simdjson_inline simdjson_result<const char *> c_str() noexcept;
|
||||
|
||||
/**
|
||||
* Return true if the content is valid UTF-8.
|
||||
*/
|
||||
simdjson_inline bool validate_unicode() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current size of the written JSON buffer.
|
||||
* If an error occurred, returns 0.
|
||||
*/
|
||||
simdjson_inline size_t size() const noexcept;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Returns true if we can write at least upcoming_bytes bytes.
|
||||
* The underlying buffer is reallocated if needed. It is designed
|
||||
* to be called before writing to the buffer. It should be fast.
|
||||
*/
|
||||
simdjson_inline bool capacity_check(size_t upcoming_bytes);
|
||||
|
||||
/**
|
||||
* Grow the buffer to at least desired_capacity bytes.
|
||||
* If the allocation fails, is_valid is set to false. We expect
|
||||
* that this function would not be repeatedly called.
|
||||
*/
|
||||
simdjson_inline void grow_buffer(size_t desired_capacity);
|
||||
|
||||
/**
|
||||
* We use this helper function to make sure that is_valid is kept consistent.
|
||||
*/
|
||||
simdjson_inline void set_valid(bool valid) noexcept;
|
||||
|
||||
|
||||
std::unique_ptr<char[]> buffer{};
|
||||
size_t position{0};
|
||||
size_t capacity{0};
|
||||
bool is_valid{true};
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_BUILDER_H
|
||||
@@ -84,6 +84,22 @@ public:
|
||||
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||
*
|
||||
* ### std::string references
|
||||
*
|
||||
* If you pass a mutable std::string reference (std::string&), the parser will seek to extend
|
||||
* its capacity to SIMDJSON_PADDING bytes beyond the end of the string.
|
||||
*
|
||||
* Whenever you pass an std::string reference, the parser will access the bytes beyond the end of
|
||||
* the string but before the end of the allocated memory (std::string::capacity()).
|
||||
* If you are using a sanitizer that checks for reading uninitialized bytes or std::string's
|
||||
* container-overflow checks, you may encounter sanitizer warnings.
|
||||
* You can safely ignore these warnings. Or you can call simdjson::pad(std::string&) to pad the
|
||||
* string with SIMDJSON_PADDING spaces: this function returns a simdjson::padding_string_view
|
||||
* which can be be passed to the parser's iterate function:
|
||||
*
|
||||
* std::string json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )";
|
||||
* document doc = parser.iterate(simdjson::pad(json));
|
||||
*
|
||||
* @param json The JSON to parse.
|
||||
* @param len The length of the JSON.
|
||||
* @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
|
||||
|
||||
@@ -20,36 +20,39 @@ simdjson_inline const char * raw_json_string::raw() const noexcept { return rein
|
||||
|
||||
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
|
||||
size_t pos{0};
|
||||
// if the content has no escape character, just scan through it quickly!
|
||||
for(;pos < target.size() && target[pos] != '\\';pos++) {}
|
||||
// slow path may begin.
|
||||
bool escaping{false};
|
||||
for(;pos < target.size();pos++) {
|
||||
if((target[pos] == '"') && !escaping) {
|
||||
return false;
|
||||
} else if(target[pos] == '\\') {
|
||||
escaping = !escaping;
|
||||
} else {
|
||||
escaping = false;
|
||||
while(pos < target.size()) {
|
||||
pos = target.find('"', pos);
|
||||
if(pos == std::string_view::npos) { return true; }
|
||||
if(pos != 0 && target[pos-1] != '\\') { return false; }
|
||||
if(pos > 1 && target[pos-2] == '\\') {
|
||||
size_t backslash_count{2};
|
||||
for(size_t i = 3; i <= pos; i++) {
|
||||
if(target[pos-i] == '\\') { backslash_count++; }
|
||||
else { break; }
|
||||
}
|
||||
if(backslash_count % 2 == 0) { return false; }
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
|
||||
size_t pos{0};
|
||||
// if the content has no escape character, just scan through it quickly!
|
||||
for(;target[pos] && target[pos] != '\\';pos++) {}
|
||||
// slow path may begin.
|
||||
bool escaping{false};
|
||||
for(;target[pos];pos++) {
|
||||
if((target[pos] == '"') && !escaping) {
|
||||
return false;
|
||||
} else if(target[pos] == '\\') {
|
||||
escaping = !escaping;
|
||||
} else {
|
||||
escaping = false;
|
||||
while(target[pos]) {
|
||||
const char * result = strchr(target+pos, '"');
|
||||
if(result == nullptr) { return true; }
|
||||
pos = result - target;
|
||||
if(pos != 0 && target[pos-1] != '\\') { return false; }
|
||||
if(pos > 1 && target[pos-2] == '\\') {
|
||||
size_t backslash_count{2};
|
||||
for(size_t i = 3; i <= pos; i++) {
|
||||
if(target[pos-i] == '\\') { backslash_count++; }
|
||||
else { break; }
|
||||
}
|
||||
if(backslash_count % 2 == 0) { return false; }
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -61,7 +64,7 @@ simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string
|
||||
}
|
||||
|
||||
simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
|
||||
// Assumptions: does not contain unescaped quote characters, and
|
||||
// Assumptions: does not contain unescaped quote characters("), and
|
||||
// the raw content is quote terminated within a valid JSON string.
|
||||
if(target.size() <= SIMDJSON_PADDING) {
|
||||
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
|
||||
|
||||
@@ -55,6 +55,16 @@ error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
template <concepts::constructible_from_string_view T, typename ValT>
|
||||
requires(!require_custom_serialization<T>)
|
||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v<T, std::string_view>) {
|
||||
std::string_view str;
|
||||
SIMDJSON_TRY(val.get_string().get(str));
|
||||
out = T{str};
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* STL containers have several constructors including one that takes a single
|
||||
* size argument. Thus, some compilers (Visual Studio) will not be able to
|
||||
@@ -100,6 +110,39 @@ error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We want to support std::map and std::unordered_map but only for
|
||||
* string-keyed types.
|
||||
*/
|
||||
template <concepts::string_view_keyed_map T, typename ValT>
|
||||
requires(!require_custom_serialization<T>)
|
||||
error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
|
||||
using value_type = typename std::remove_cvref_t<T>::mapped_type;
|
||||
static_assert(
|
||||
deserializable<value_type, ValT>,
|
||||
"The specified value type inside the container must itself be deserializable");
|
||||
static_assert(
|
||||
std::is_default_constructible_v<value_type>,
|
||||
"The specified value type inside the container must default constructible.");
|
||||
SIMDJSON_IMPLEMENTATION::ondemand::object obj;
|
||||
SIMDJSON_TRY(val.get_object().get(obj));
|
||||
for (auto field : obj) {
|
||||
std::string_view key;
|
||||
SIMDJSON_TRY(field.unescaped_key().get(key));
|
||||
value_type this_value;
|
||||
SIMDJSON_TRY(field.value().get<value_type>().get(this_value));
|
||||
[[maybe_unused]] std::pair<typename T::iterator, bool> result = out.emplace(key, this_value);
|
||||
// unclear what to do if the key already exists
|
||||
// if (result.second == false) {
|
||||
// // key already exists
|
||||
// }
|
||||
}
|
||||
(void)out;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This CPO (Customization Point Object) will help deserialize into
|
||||
|
||||
@@ -70,22 +70,28 @@ public:
|
||||
noexcept
|
||||
#endif
|
||||
{
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, value>) {
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
if constexpr (custom_deserializable<T, value>) {
|
||||
return deserialize(*this, out);
|
||||
} else {
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#if SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
}
|
||||
} else {
|
||||
static_assert(!sizeof(T), "The get<T> method with type T is not implemented by the simdjson library. "
|
||||
"And you do not seem to have added support for it. Indeed, we have that "
|
||||
"simdjson::custom_deserializable<T> is false and the type T is not a default type "
|
||||
"such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, or bool.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
}
|
||||
#else // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
// Unless the simdjson library or the user provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. "
|
||||
"The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, "
|
||||
"int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), "
|
||||
" get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template."
|
||||
" You may also add support for custom types, see our documentation.");
|
||||
static_cast<void>(out); // to get rid of unused errors
|
||||
return UNINITIALIZED;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -163,6 +169,17 @@ public:
|
||||
* Important: a value should be consumed once. Calling get_string() twice on the same value
|
||||
* is an error.
|
||||
*
|
||||
* In some instances, you may want to allow replacement of invalid Unicode sequences.
|
||||
* You may do so by passing the allow_replacement parameter as true. In the following
|
||||
* example, the string "431924697b\udff0L\u0001Y" is not valid Unicode. By passing true
|
||||
* to get_string, we allow the replacement of the invalid Unicode sequences with the Unicode
|
||||
* replacement character (U+FFFD).
|
||||
*
|
||||
* simdjson::ondemand::parser parser;
|
||||
* auto json = R"({"deviceId":"431924697b\udff0L\u0001Y"})"_padded;
|
||||
* simdjson::ondemand::document doc = parser.iterate(json);
|
||||
* auto view = doc["deviceId"].get_string(true);
|
||||
*
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
@@ -414,6 +431,7 @@ public:
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
|
||||
simdjson_result<value> operator[](int) noexcept = delete;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value. It does not validate or consume the value.
|
||||
@@ -781,6 +799,7 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) noexcept;
|
||||
simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](int) noexcept = delete;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value.
|
||||
|
||||
@@ -778,19 +778,23 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool(bool check_trailing) noexcept {
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("bool");
|
||||
uint8_t tmpbuf[5+1+1]; // +1 for null termination
|
||||
tmpbuf[5+1] = '\0'; // make sure that buffer is always null terminated.
|
||||
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf, 5+1)) { return incorrect_type_error("Not a boolean"); }
|
||||
auto result = parse_bool(tmpbuf);
|
||||
if(result.error() == SUCCESS) {
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
advance_root_scalar("bool");
|
||||
}
|
||||
return result;
|
||||
// We have a boolean if we have either "true" or "false" and the next character is either
|
||||
// a structural character or whitespace. We also check that the length is correct:
|
||||
// "true" and "false" are 4 and 5 characters long, respectively.
|
||||
bool value_true = (max_len >= 4 && !atomparsing::str4ncmp(json, "true") &&
|
||||
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[4])));
|
||||
bool value_false = (max_len >= 5 && !atomparsing::str4ncmp(json, "false") &&
|
||||
(max_len == 5 || jsoncharutils::is_structural_or_whitespace(json[5])));
|
||||
if(value_true == false && value_false == false) { return incorrect_type_error("Not a boolean"); }
|
||||
if (check_trailing && !_json_iter->is_single_token()) { return TRAILING_CONTENT; }
|
||||
advance_root_scalar("bool");
|
||||
return value_true;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> value_iterator::is_root_null(bool check_trailing) noexcept {
|
||||
auto max_len = peek_root_length();
|
||||
auto json = peek_root_scalar("null");
|
||||
|
||||
@@ -125,7 +125,8 @@ public:
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
|
||||
/**
|
||||
@@ -135,7 +136,8 @@ public:
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
|
||||
|
||||
@@ -257,7 +259,8 @@ public:
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
|
||||
/**
|
||||
@@ -267,7 +270,8 @@ public:
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
* array or object is incomplete). An INCOMPLETE_ARRAY_OR_OBJECT is an unrecoverable error that
|
||||
* invalidates the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace haswell
|
||||
|
||||
@@ -41,31 +41,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 32;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits); }
|
||||
|
||||
uint64_t escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
simd8<bool> is_quote = (v == '"');
|
||||
simd8<bool> is_backslash = (v == '\\');
|
||||
simd8<bool> is_control = (v < 32);
|
||||
return {
|
||||
uint64_t((is_backslash | is_quote | is_control).to_bitmask())
|
||||
};
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace haswell
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -28,7 +28,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace icelake
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace simd {
|
||||
friend simdjson_really_inline uint64_t operator==(const simd8<T> lhs, const simd8<T> rhs) {
|
||||
return _mm512_cmpeq_epi8_mask(lhs, rhs);
|
||||
}
|
||||
|
||||
static const int SIZE = sizeof(base<T>::value);
|
||||
|
||||
template<int N=1>
|
||||
@@ -147,14 +148,18 @@ namespace simd {
|
||||
|
||||
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
|
||||
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
|
||||
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
|
||||
// Only the first 64 - count_ones(mask) bytes of the result are significant but 64 bytes
|
||||
// get written.
|
||||
// Design consideration: it seems like a function with the
|
||||
// signature simd8<L> compress(uint32_t mask) would be
|
||||
// sensible, but the AVX ISA makes this kind of approach difficult.
|
||||
template<typename L>
|
||||
simdjson_inline void compress(uint64_t mask, L * output) const {
|
||||
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
// we deliberately avoid _mm512_mask_compressstoreu_epi8 for portability
|
||||
// (AMD Zen4 has terrible performance with it, it is effectively broken)
|
||||
// _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
__m512i compressed = _mm512_maskz_compress_epi8(~mask, *this);
|
||||
_mm512_storeu_si512(output, compressed); // could use a mask
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
|
||||
@@ -41,35 +41,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 64;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(uint64_t(escape_bits)); }
|
||||
|
||||
__mmask64 escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
__mmask64 is_quote = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('"'));
|
||||
__mmask64 is_backslash = _mm512_cmpeq_epi8_mask(v, _mm512_set1_epi8('\\'));
|
||||
__mmask64 is_control = _mm512_cmplt_epi8_mask(v, _mm512_set1_epi8(32));
|
||||
return {
|
||||
(is_backslash | is_quote | is_control)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace icelake
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -26,15 +26,6 @@ simdjson_inline simdjson_warn_unused bool validate_utf8(const std::string_view s
|
||||
return validate_utf8(sv.data(), sv.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the string to the output buffer while escaping double-quote, backlash and ascii control characters.
|
||||
*
|
||||
* @param input the string_view to escape
|
||||
* @param out output buffer (for escaped string): to be safe, it should have 6 * input.size() allocated bytes.
|
||||
* @return number of bytes written
|
||||
*/
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) noexcept;
|
||||
|
||||
/**
|
||||
* Validate the UTF-8 string.
|
||||
*
|
||||
@@ -136,14 +127,6 @@ public:
|
||||
*/
|
||||
simdjson_warn_unused virtual bool validate_utf8(const char *buf, size_t len) const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Write the string to the output buffer while escaping double-quote, backlash and ascii control characters.
|
||||
*
|
||||
* @param input the string_view to escape
|
||||
* @param out output buffer (for escaped string): to be safe, it should have 6 * input.size() allocated bytes.
|
||||
* @return number of bytes written
|
||||
*/
|
||||
simdjson_warn_unused virtual size_t write_string_escaped(const std::string_view input, char *out) const noexcept = 0;
|
||||
protected:
|
||||
/** @private Construct an implementation with the given name and description. For subclasses. */
|
||||
simdjson_inline implementation(
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace lasx
|
||||
|
||||
@@ -40,31 +40,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 16;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits); }
|
||||
|
||||
uint64_t escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
simd8<bool> is_quote = (v == '"');
|
||||
simd8<bool> is_backslash = (v == '\\');
|
||||
simd8<bool> is_control = (v < 32);
|
||||
return {
|
||||
(is_backslash | is_quote | is_control).to_bitmask()
|
||||
};
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace lasx
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace lsx
|
||||
|
||||
@@ -46,31 +46,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 16;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits); }
|
||||
|
||||
uint64_t escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
simd8<bool> is_quote = (v == '"');
|
||||
simd8<bool> is_backslash = (v == '\\');
|
||||
simd8<bool> is_control = (v < 32);
|
||||
return {
|
||||
(is_backslash | is_quote | is_control).to_bitmask()
|
||||
};
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace lsx
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -166,22 +166,22 @@ inline namespace literals {
|
||||
inline namespace string_view_literals {
|
||||
|
||||
|
||||
constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1)
|
||||
constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1)
|
||||
{
|
||||
return std::string_view{ str, len };
|
||||
}
|
||||
|
||||
constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2)
|
||||
constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2)
|
||||
{
|
||||
return std::u16string_view{ str, len };
|
||||
}
|
||||
|
||||
constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3)
|
||||
constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3)
|
||||
{
|
||||
return std::u32string_view{ str, len };
|
||||
}
|
||||
|
||||
constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4)
|
||||
constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4)
|
||||
{
|
||||
return std::wstring_view{ str, len };
|
||||
}
|
||||
@@ -1512,22 +1512,22 @@ nssv_inline_ns namespace string_view_literals {
|
||||
|
||||
#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
{
|
||||
return nonstd::sv_lite::string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
{
|
||||
return nonstd::sv_lite::u16string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
{
|
||||
return nonstd::sv_lite::u32string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
{
|
||||
return nonstd::sv_lite::wstring_view{ str, len };
|
||||
}
|
||||
@@ -1536,22 +1536,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str,
|
||||
|
||||
#if nssv_CONFIG_USR_SV_OPERATOR
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
{
|
||||
return nonstd::sv_lite::string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
{
|
||||
return nonstd::sv_lite::u16string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
{
|
||||
return nonstd::sv_lite::u32string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
{
|
||||
return nonstd::sv_lite::wstring_view{ str, len };
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ namespace simdjson {
|
||||
* @copydoc simdjson::builtin::ondemand
|
||||
*/
|
||||
namespace ondemand = builtin::ondemand;
|
||||
/**
|
||||
* @copydoc simdjson::builtin::builder
|
||||
*/
|
||||
namespace builder = builtin::builder;
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_ONDEMAND_H
|
||||
|
||||
@@ -187,11 +187,11 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
inline simdjson::padded_string operator "" _padded(const char *str, size_t len) {
|
||||
inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
|
||||
return simdjson::padded_string(str, len);
|
||||
}
|
||||
#ifdef __cpp_char8_t
|
||||
inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len) {
|
||||
inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len) {
|
||||
return simdjson::padded_string(reinterpret_cast<const char8_t *>(str), len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -161,9 +161,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string
|
||||
} // namespace simdjson
|
||||
|
||||
// This is deliberately outside of simdjson so that people get it without having to use the namespace
|
||||
inline simdjson::padded_string operator "" _padded(const char *str, size_t len);
|
||||
inline simdjson::padded_string operator ""_padded(const char *str, size_t len);
|
||||
#ifdef __cpp_char8_t
|
||||
inline simdjson::padded_string operator "" _padded(const char8_t *str, size_t len);
|
||||
inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len);
|
||||
#endif
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
@@ -53,6 +53,11 @@ inline bool padded_string_view::remove_utf8_bom() noexcept {
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
|
||||
#endif
|
||||
|
||||
inline padded_string_view pad(std::string& s) noexcept {
|
||||
const auto len = s.size();
|
||||
s.append(SIMDJSON_PADDING, ' ');
|
||||
return padded_string_view(s.data(), len, s.size());
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ public:
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create a padded_string_view from a string. The string will be padded with SIMDJSON_PADDING
|
||||
* space characters. The resulting padded_string_view will have a length equal to the original
|
||||
* string.
|
||||
*
|
||||
* @param s The string.
|
||||
* @return The padded string.
|
||||
*/
|
||||
inline padded_string_view pad(std::string& s) noexcept;
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_PADDED_STRING_VIEW_H
|
||||
|
||||
@@ -6,11 +6,15 @@
|
||||
#include <cstdlib>
|
||||
#include <cfloat>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#ifndef _WIN32
|
||||
// strcasecmp, strncasecmp
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
|
||||
|
||||
|
||||
// We are using size_t without namespace std:: throughout the project
|
||||
using std::size_t;
|
||||
|
||||
@@ -44,6 +48,7 @@ using std::size_t;
|
||||
#elif defined(__loongarch_lp64)
|
||||
#define SIMDJSON_IS_LOONGARCH64 1
|
||||
#elif defined(__PPC64__) || defined(_M_PPC64)
|
||||
#define SIMDJSON_IS_PPC64 1
|
||||
#if defined(__ALTIVEC__)
|
||||
#define SIMDJSON_IS_PPC64_VMX 1
|
||||
#endif // defined(__ALTIVEC__)
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf,
|
||||
size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace ppc64
|
||||
|
||||
@@ -58,31 +58,6 @@ backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 16;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits); }
|
||||
|
||||
uint64_t escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
simd8<bool> is_quote = (v == '"');
|
||||
simd8<bool> is_backslash = (v == '\\');
|
||||
simd8<bool> is_control = (v < 32);
|
||||
return {
|
||||
(is_backslash | is_quote | is_control).to_bitmask()
|
||||
};
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace ppc64
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION "3.10.1"
|
||||
#define SIMDJSON_VERSION "3.12.3"
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -15,11 +15,11 @@ enum {
|
||||
/**
|
||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MINOR = 10,
|
||||
SIMDJSON_VERSION_MINOR = 12,
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 1
|
||||
SIMDJSON_VERSION_REVISION = 3
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace westmere
|
||||
|
||||
@@ -40,31 +40,6 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
struct escaping {
|
||||
static constexpr uint32_t BYTES_PROCESSED = 16;
|
||||
simdjson_inline static escaping copy_and_find(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
simdjson_inline bool has_escape() { return escape_bits != 0; }
|
||||
simdjson_inline int escape_index() { return trailing_zeroes(escape_bits); }
|
||||
|
||||
uint64_t escape_bits;
|
||||
}; // struct escaping
|
||||
|
||||
|
||||
|
||||
simdjson_inline escaping escaping::copy_and_find(const uint8_t *src, uint8_t *dst) {
|
||||
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "escaping finder must process fewer than SIMDJSON_PADDING bytes");
|
||||
simd8<uint8_t> v(src);
|
||||
v.store(dst);
|
||||
simd8<bool> is_quote = (v == '"');
|
||||
simd8<bool> is_backslash = (v == '\\');
|
||||
simd8<bool> is_control = (v < 32);
|
||||
return {
|
||||
uint64_t((is_backslash | is_quote | is_control).to_bitmask())
|
||||
};
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
} // namespace westmere
|
||||
} // namespace simdjson
|
||||
|
||||
+34
-63
@@ -10,41 +10,12 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
import datetime
|
||||
import json
|
||||
from typing import Dict, List, Optional, Set, TextIO, Union, cast
|
||||
|
||||
# Check for Python 3, this does not actually work.
|
||||
if sys.version_info < (3, 0):
|
||||
sys.stdout.write("Sorry, requires Python 3.x or better\n")
|
||||
sys.exit(1)
|
||||
|
||||
rules = """
|
||||
|
||||
We refer your to the HACKING.md file for more information on how the project is organized.
|
||||
|
||||
To help understand the error, here are the rules for including files in simdjson:
|
||||
|
||||
All implementation-specific files, including arm64.h, arm64/implementation.h and
|
||||
arm64/ondemand.h, must be within SIMDJSON_CONDITIONAL_INCLUDE blocks.
|
||||
|
||||
Top-level headers must not be included in any SIMDJSON_CONDITIONAL_INCLUDE block.
|
||||
|
||||
Generic files must be included only in amalgamator files (arm64.h,
|
||||
arm64/implementation.h, arm64/ondemand.h, generic/amalgamated.h).
|
||||
|
||||
We fail if an implementation-specific file is included more than once in the same block.
|
||||
We fail if a generic file is included more than once per implementation in the same block.
|
||||
|
||||
|
||||
Tip: generally, "file" will search the including file's source directory first, then
|
||||
the search paths while <file> does it the other way around.
|
||||
We prefer to use <> in simdjson headers to avoid accidentally including a file from the
|
||||
wrong directory.
|
||||
|
||||
The amalgamate.py script checks that all files are included.
|
||||
|
||||
"""
|
||||
|
||||
SCRIPTPATH = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
PROJECTPATH = os.path.dirname(SCRIPTPATH)
|
||||
print(f"SCRIPTPATH={SCRIPTPATH} PROJECTPATH={PROJECTPATH}")
|
||||
@@ -91,22 +62,6 @@ class SimdjsonFile:
|
||||
def __str__(self):
|
||||
return self.include_path
|
||||
|
||||
def dump(self):
|
||||
return {
|
||||
'root': self.root,
|
||||
'include_path': self.include_path,
|
||||
'includes': [include.include_path for include in self.includes],
|
||||
'included_from': [included_from.include_path for included_from in self.included_from],
|
||||
'editor_only_includes': [editor_only_include.include_path for editor_only_include in self.editor_only_includes],
|
||||
'editor_only_included_from': [editor_only_included_from.include_path for editor_only_included_from in self.editor_only_included_from],
|
||||
'processed': self.processed,
|
||||
'dependency_file': self.dependency_file.include_path if self.dependency_file else None,
|
||||
'is_amalgamator': self.is_amalgamator,
|
||||
'implementation': self.implementation,
|
||||
}
|
||||
def json(self):
|
||||
return json.dumps(self.dump(), indent=4, sort_keys=True, ensure_ascii=False)
|
||||
|
||||
def __repr__(self):
|
||||
return self.include_path
|
||||
|
||||
@@ -207,21 +162,20 @@ class SimdjsonFile:
|
||||
|
||||
def add_include(self, include: 'SimdjsonFile'):
|
||||
if self.is_conditional_include:
|
||||
# If I have a dependency file, I can only include something that has a dependency file.
|
||||
assert include.is_conditional_include, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE. {rules}"
|
||||
assert include.is_conditional_include, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE."
|
||||
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
||||
# if include.amalgamator_file:
|
||||
# assert include.amalgamator_file == self, f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
||||
else:
|
||||
assert include.is_amalgamator or not include.is_conditional_include, f"{self} cannot include {include} because it is an amalgamated file. {rules}"
|
||||
assert include.is_amalgamator or not include.is_conditional_include, f"{self} cannot include {include} because it is an amalgamated file."
|
||||
|
||||
self.includes.append(include)
|
||||
include.included_from.add(self)
|
||||
|
||||
def add_editor_only_include(self, include: 'SimdjsonFile'):
|
||||
assert self.is_conditional_include, f"Cannot use #ifndef SIMDJSON_CONDITIONAL_INCLUDE in {self} because it is not an amalgamated file. {rules}"
|
||||
assert self.is_conditional_include, f"Cannot use #ifndef SIMDJSON_CONDITIONAL_INCLUDE in {self} because it is not an amalgamated file."
|
||||
if not include.is_conditional_include:
|
||||
assert self.dependency_file, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE. {rules}"
|
||||
assert self.dependency_file, f"{self} cannot include {include} without #ifndef SIMDJSON_CONDITIONAL_INCLUDE."
|
||||
# TODO make sure we only include amalgamated files that are guaranteed to be included with us (or before us)
|
||||
# elif include.amalgamator_file:
|
||||
# assert self.is_amalgamated_before(self.amalgamator_file), f"{self} cannot include {include}: it should be included from {include.amalgamator_file} instead."
|
||||
@@ -236,11 +190,11 @@ class SimdjsonFile:
|
||||
if file.dependency_file == self:
|
||||
for editor_only_include in file.editor_only_includes:
|
||||
if not editor_only_include.is_conditional_include:
|
||||
assert editor_only_include in self.includes, f"{file} includes {editor_only_include}, but it is not included from {self}. It must be added to {self}. {rules}"
|
||||
assert editor_only_include in self.includes, f"{file} includes {editor_only_include}, but it is not included from {self}. It must be added to {self}."
|
||||
if editor_only_include in extra_include_set:
|
||||
extra_include_set.remove(editor_only_include)
|
||||
|
||||
assert len(extra_include_set) == 0, f"{self} unnecessarily includes {extra_include_set}. They are not included in the corresponding amalgamated files. {rules}"
|
||||
assert len(extra_include_set) == 0, f"{self} unnecessarily includes {extra_include_set}. They are not included in the corresponding amalgamated files."
|
||||
|
||||
class SimdjsonRepository:
|
||||
def __init__(self, project_path: str, relative_roots: List[RelativeRoot]):
|
||||
@@ -366,7 +320,6 @@ class Amalgamator:
|
||||
|
||||
assert not self.editor_only_region
|
||||
with open(file.absolute_path, 'r') as fid2:
|
||||
print(f"including: {file}")
|
||||
for line in fid2:
|
||||
line = line.rstrip('\n')
|
||||
|
||||
@@ -376,9 +329,9 @@ class Amalgamator:
|
||||
|
||||
# Ignore lines inside #ifndef SIMDJSON_CONDITIONAL_INCLUDE
|
||||
if re.search(r'^#ifndef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
|
||||
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file! {rules}"
|
||||
assert self.in_conditional_include_block, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE without a prior #define SIMDJSON_CONDITIONAL_INCLUDE: {self.include_stack} {rules}"
|
||||
assert not self.editor_only_region, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE twice in a row {rules}"
|
||||
assert file.is_conditional_include, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE but is not an amalgamated file!"
|
||||
assert self.in_conditional_include_block, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE without a prior #define SIMDJSON_CONDITIONAL_INCLUDE: {self.include_stack}"
|
||||
assert not self.editor_only_region, f"{file} uses #ifndef SIMDJSON_CONDITIONAL_INCLUDE twice in a row"
|
||||
self.editor_only_region = True
|
||||
|
||||
# Handle ignored lines (and ending ignore blocks)
|
||||
@@ -396,7 +349,7 @@ class Amalgamator:
|
||||
self.editor_only_region = False
|
||||
continue
|
||||
|
||||
assert not end_ignore, f"{file} has #endif // SIMDJSON_CONDITIONAL_INCLUDE without #ifndef SIMDJSON_CONDITIONAL_INCLUDE {rules}"
|
||||
assert not end_ignore, f"{file} has #endif // SIMDJSON_CONDITIONAL_INCLUDE without #ifndef SIMDJSON_CONDITIONAL_INCLUDE"
|
||||
|
||||
# Handle #include lines
|
||||
included = re.search(r'^#include\s+["<]([^">]*)[">]', line)
|
||||
@@ -423,26 +376,26 @@ class Amalgamator:
|
||||
self.implementation = None
|
||||
elif re.search(r'\bSIMDJSON_IMPLEMENTATION\b', line) and file.include_path != IMPLEMENTATION_DETECTION_H:
|
||||
# copy the line, with SIMDJSON_IMPLEMENTATION replace to what it is currently defined to
|
||||
assert self.implementation, f"Use of SIMDJSON_IMPLEMENTATION while not defined in {file}: {line}\n{rules}"
|
||||
assert self.implementation, f"Use of SIMDJSON_IMPLEMENTATION while not defined in {file}: {line}"
|
||||
line = re.sub(r'\bSIMDJSON_IMPLEMENTATION\b',self.implementation,line)
|
||||
|
||||
# Handle defining and undefining SIMDJSON_CONDITIONAL_INCLUDE
|
||||
defined = re.search(r'^#define\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line)
|
||||
if defined:
|
||||
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE defined in amalgamated file {file}! Not allowed. {rules}"
|
||||
assert not self.in_conditional_include_block, f"{file} redefines SIMDJSON_CONDITIONAL_INCLUDE {rules}"
|
||||
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE defined in amalgamated file {file}! Not allowed."
|
||||
assert not self.in_conditional_include_block, f"{file} redefines SIMDJSON_CONDITIONAL_INCLUDE"
|
||||
self.in_conditional_include_block = True
|
||||
self.found_includes_per_conditional_block.clear()
|
||||
self.write(f'/* defining SIMDJSON_CONDITIONAL_INCLUDE */')
|
||||
elif re.search(r'^#undef\s+SIMDJSON_CONDITIONAL_INCLUDE\s*$', line):
|
||||
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE undefined in amalgamated file {file}! Not allowed. {rules}"
|
||||
assert self.in_conditional_include_block, f"{file} undefines SIMDJSON_CONDITIONAL_INCLUDE without defining it {rules}"
|
||||
assert not file.is_conditional_include, "SIMDJSON_CONDITIONAL_INCLUDE undefined in amalgamated file {file}! Not allowed."
|
||||
assert self.in_conditional_include_block, f"{file} undefines SIMDJSON_CONDITIONAL_INCLUDE without defining it"
|
||||
self.write(f'/* undefining SIMDJSON_CONDITIONAL_INCLUDE */')
|
||||
self.in_conditional_include_block = False
|
||||
|
||||
self.write(line)
|
||||
|
||||
assert not self.editor_only_region, f"{file} ended without #endif // SIMDJSON_CONDITIONAL_INCLUDE {rules}"
|
||||
assert not self.editor_only_region, f"{file} ended without #endif // SIMDJSON_CONDITIONAL_INCLUDE"
|
||||
|
||||
self.write(f"/* end file {self.file_to_str(file)} */")
|
||||
|
||||
@@ -488,6 +441,22 @@ if SCRIPTPATH != AMALGAMATE_OUTPUT_PATH:
|
||||
shutil.copy2(os.path.join(SCRIPTPATH,"amalgamate_demo.cpp"),AMALGAMATE_OUTPUT_PATH)
|
||||
shutil.copy2(os.path.join(SCRIPTPATH,"README.md"),AMALGAMATE_OUTPUT_PATH)
|
||||
|
||||
|
||||
|
||||
|
||||
def create_zip():
|
||||
import zipfile
|
||||
outdir = AMALGAMATE_OUTPUT_PATH
|
||||
|
||||
path = os.path.join(outdir, "singleheader.zip")
|
||||
print(f"Creating {path}")
|
||||
with zipfile.ZipFile(path, 'w') as zf:
|
||||
for name in ["simdjson.cpp", "simdjson.h"]:
|
||||
source = os.path.join(outdir, name)
|
||||
print(f"Adding {source}")
|
||||
zf.write(source, name)
|
||||
print(f"Created {path}")
|
||||
create_zip()
|
||||
print("Done with all files generation.")
|
||||
|
||||
print(f"Files have been written to directory: {AMALGAMATE_OUTPUT_PATH}/")
|
||||
@@ -496,6 +465,8 @@ print(subprocess.run(['ls', '-la', AMAL_C, AMAL_H, DEMOCPP, README],
|
||||
print("Done with all files generation.")
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Instructions to create demo
|
||||
#
|
||||
|
||||
+128
-65
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2024-10-28 20:27:26 -0400. Do not edit! */
|
||||
/* auto-generated on 2025-03-27 15:01:10 -0400. Do not edit! */
|
||||
/* including simdjson.cpp: */
|
||||
/* begin file simdjson.cpp */
|
||||
#define SIMDJSON_SRC_SIMDJSON_CPP
|
||||
@@ -83,12 +83,24 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_concepts
|
||||
#if defined(__apple_build_version__)
|
||||
#if __apple_build_version__ < 14000000
|
||||
#define SIMDJSON_CONCEPT_DISABLED 1 // apple-clang/13 doesn't support std::convertible_to
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||
#if __cpp_concepts >= 201907L
|
||||
#include <utility>
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1
|
||||
#else // __cpp_concepts
|
||||
#else
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif
|
||||
#else // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0
|
||||
#endif // defined(__cpp_concepts) && !defined(SIMDJSON_CONCEPT_DISABLED)
|
||||
|
||||
#endif // SIMDJSON_COMPILER_CHECK_H
|
||||
/* end file simdjson/compiler_check.h */
|
||||
/* including simdjson/portability.h: #include "simdjson/portability.h" */
|
||||
@@ -101,11 +113,15 @@
|
||||
#include <cstdlib>
|
||||
#include <cfloat>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#ifndef _WIN32
|
||||
// strcasecmp, strncasecmp
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
|
||||
|
||||
|
||||
// We are using size_t without namespace std:: throughout the project
|
||||
using std::size_t;
|
||||
|
||||
@@ -139,6 +155,7 @@ using std::size_t;
|
||||
#elif defined(__loongarch_lp64)
|
||||
#define SIMDJSON_IS_LOONGARCH64 1
|
||||
#elif defined(__PPC64__) || defined(_M_PPC64)
|
||||
#define SIMDJSON_IS_PPC64 1
|
||||
#if defined(__ALTIVEC__)
|
||||
#define SIMDJSON_IS_PPC64_VMX 1
|
||||
#endif // defined(__ALTIVEC__)
|
||||
@@ -759,22 +776,22 @@ inline namespace literals {
|
||||
inline namespace string_view_literals {
|
||||
|
||||
|
||||
constexpr std::string_view operator "" _sv( const char* str, size_t len ) noexcept // (1)
|
||||
constexpr std::string_view operator ""_sv( const char* str, size_t len ) noexcept // (1)
|
||||
{
|
||||
return std::string_view{ str, len };
|
||||
}
|
||||
|
||||
constexpr std::u16string_view operator "" _sv( const char16_t* str, size_t len ) noexcept // (2)
|
||||
constexpr std::u16string_view operator ""_sv( const char16_t* str, size_t len ) noexcept // (2)
|
||||
{
|
||||
return std::u16string_view{ str, len };
|
||||
}
|
||||
|
||||
constexpr std::u32string_view operator "" _sv( const char32_t* str, size_t len ) noexcept // (3)
|
||||
constexpr std::u32string_view operator ""_sv( const char32_t* str, size_t len ) noexcept // (3)
|
||||
{
|
||||
return std::u32string_view{ str, len };
|
||||
}
|
||||
|
||||
constexpr std::wstring_view operator "" _sv( const wchar_t* str, size_t len ) noexcept // (4)
|
||||
constexpr std::wstring_view operator ""_sv( const wchar_t* str, size_t len ) noexcept // (4)
|
||||
{
|
||||
return std::wstring_view{ str, len };
|
||||
}
|
||||
@@ -2105,22 +2122,22 @@ nssv_inline_ns namespace string_view_literals {
|
||||
|
||||
#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator ""sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
{
|
||||
return nonstd::sv_lite::string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator ""sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
{
|
||||
return nonstd::sv_lite::u16string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator ""sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
{
|
||||
return nonstd::sv_lite::u32string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator ""sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
{
|
||||
return nonstd::sv_lite::wstring_view{ str, len };
|
||||
}
|
||||
@@ -2129,22 +2146,22 @@ nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str,
|
||||
|
||||
#if nssv_CONFIG_USR_SV_OPERATOR
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
nssv_constexpr nonstd::sv_lite::string_view operator ""_sv( const char* str, size_t len ) nssv_noexcept // (1)
|
||||
{
|
||||
return nonstd::sv_lite::string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
nssv_constexpr nonstd::sv_lite::u16string_view operator ""_sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
|
||||
{
|
||||
return nonstd::sv_lite::u16string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
nssv_constexpr nonstd::sv_lite::u32string_view operator ""_sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
|
||||
{
|
||||
return nonstd::sv_lite::u32string_view{ str, len };
|
||||
}
|
||||
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
nssv_constexpr nonstd::sv_lite::wstring_view operator ""_sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
|
||||
{
|
||||
return nonstd::sv_lite::wstring_view{ str, len };
|
||||
}
|
||||
@@ -2414,7 +2431,7 @@ enum error_code {
|
||||
SUCCESS = 0, ///< No error
|
||||
CAPACITY, ///< This parser can't support a document that big
|
||||
MEMALLOC, ///< Error allocating memory, most likely out of memory
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error
|
||||
TAPE_ERROR, ///< Something went wrong, this is a generic error. Fatal/unrecoverable error.
|
||||
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
|
||||
STRING_ERROR, ///< Problem while parsing a string
|
||||
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
|
||||
@@ -2439,14 +2456,21 @@ enum error_code {
|
||||
PARSER_IN_USE, ///< parser is already in use.
|
||||
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order (checked when SIMDJSON_DEVELOPMENT_CHECKS=1)
|
||||
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
|
||||
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early. Fatal/unrecoverable error.
|
||||
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
|
||||
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
|
||||
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
|
||||
OUT_OF_CAPACITY, ///< The capacity was exceeded, we cannot allocate enough memory.
|
||||
NUM_ERROR_CODES ///< Placeholder for end of error code list.
|
||||
NUM_ERROR_CODES
|
||||
};
|
||||
|
||||
/**
|
||||
* Some errors are fatal and invalidate the document. This function returns true if the
|
||||
* error is fatal. It returns true for TAPE_ERROR and INCOMPLETE_ARRAY_OR_OBJECT.
|
||||
* Once a fatal error is encountered, the on-demand document is no longer valid and
|
||||
* processing should stop.
|
||||
*/
|
||||
inline bool is_fatal(error_code error) noexcept;
|
||||
|
||||
/**
|
||||
* It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whether
|
||||
* we check for OUT_OF_ORDER_ITERATION. The logic behind it is that these errors only occurs when the code
|
||||
@@ -2481,7 +2505,7 @@ struct simdjson_error : public std::exception {
|
||||
*/
|
||||
simdjson_error(error_code error) noexcept : _error{error} { }
|
||||
/** The error message */
|
||||
const char *what() const noexcept { return error_message(error()); }
|
||||
const char *what() const noexcept override { return error_message(error()); }
|
||||
/** The error code */
|
||||
error_code error() const noexcept { return _error; }
|
||||
private:
|
||||
@@ -2737,26 +2761,42 @@ namespace details {
|
||||
}; \
|
||||
};
|
||||
|
||||
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back);
|
||||
SIMDJSON_IMPL_CONCEPT(emplace, emplace);
|
||||
SIMDJSON_IMPL_CONCEPT(push_back, push_back);
|
||||
SIMDJSON_IMPL_CONCEPT(add, add);
|
||||
SIMDJSON_IMPL_CONCEPT(push, push);
|
||||
SIMDJSON_IMPL_CONCEPT(append, append);
|
||||
SIMDJSON_IMPL_CONCEPT(insert, insert);
|
||||
SIMDJSON_IMPL_CONCEPT(op_append, operator+=);
|
||||
SIMDJSON_IMPL_CONCEPT(emplace_back, emplace_back)
|
||||
SIMDJSON_IMPL_CONCEPT(emplace, emplace)
|
||||
SIMDJSON_IMPL_CONCEPT(push_back, push_back)
|
||||
SIMDJSON_IMPL_CONCEPT(add, add)
|
||||
SIMDJSON_IMPL_CONCEPT(push, push)
|
||||
SIMDJSON_IMPL_CONCEPT(append, append)
|
||||
SIMDJSON_IMPL_CONCEPT(insert, insert)
|
||||
SIMDJSON_IMPL_CONCEPT(op_append, operator+=)
|
||||
|
||||
#undef SIMDJSON_IMPL_CONCEPT
|
||||
} // namespace details
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept string_view_like = std::is_convertible_v<T, std::string_view> &&
|
||||
!std::is_convertible_v<T, const char*>;
|
||||
|
||||
template<typename T>
|
||||
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
|
||||
&& !std::is_same_v<T, std::string_view>
|
||||
&& std::is_default_constructible_v<T>;
|
||||
|
||||
template<typename M>
|
||||
concept string_view_keyed_map = string_view_like<typename M::key_type>
|
||||
&& requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
|
||||
{ m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
|
||||
};
|
||||
|
||||
/// Check if T is a container that we can append to, including:
|
||||
/// std::vector, std::deque, std::list, std::string, ...
|
||||
template <typename T>
|
||||
concept appendable_containers =
|
||||
details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
(details::supports_emplace_back<T> || details::supports_emplace<T> ||
|
||||
details::supports_push_back<T> || details::supports_push<T> ||
|
||||
details::supports_add<T> || details::supports_append<T> ||
|
||||
details::supports_insert<T>;
|
||||
details::supports_insert<T>) && !string_view_keyed_map<T>;
|
||||
|
||||
/// Insert into the container however possible
|
||||
template <appendable_containers T, typename... Args>
|
||||
@@ -2824,6 +2864,8 @@ concept optional_type = requires(std::remove_cvref_t<T> obj) {
|
||||
{ static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace concepts
|
||||
} // namespace simdjson
|
||||
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
|
||||
@@ -4495,6 +4537,11 @@ extern SIMDJSON_DLLIMPORTEXPORT const uint32_t digit_to_val32[886];
|
||||
#include <iostream>
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
inline bool is_fatal(error_code error) noexcept {
|
||||
return error == TAPE_ERROR || error == INCOMPLETE_ARRAY_OR_OBJECT;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// We store the error code so we can validate the error message is associated with the right code
|
||||
struct error_code_info {
|
||||
@@ -4680,7 +4727,7 @@ namespace internal {
|
||||
{ SUCCESS, "SUCCESS: No error" },
|
||||
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
||||
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
|
||||
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
||||
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
||||
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
||||
@@ -4705,7 +4752,7 @@ namespace internal {
|
||||
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
||||
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
||||
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
|
||||
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
||||
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
||||
@@ -6771,7 +6818,7 @@ public:
|
||||
* The memory allocation is strict: you
|
||||
* can you use this function to increase
|
||||
* or lower the amount of allocated memory.
|
||||
* Passsing zero clears the memory.
|
||||
* Passing zero clears the memory.
|
||||
*/
|
||||
error_code allocate(size_t len) noexcept;
|
||||
/** @private Capacity in bytes, in terms
|
||||
@@ -7789,7 +7836,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
@@ -7813,7 +7860,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
@@ -7866,7 +7913,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
*result = value1 + value2;
|
||||
return *result < value1;
|
||||
#else
|
||||
@@ -8009,7 +8056,7 @@ namespace arm64 {
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
namespace {
|
||||
// Start of private section with Visual Studio workaround
|
||||
|
||||
@@ -8118,7 +8165,7 @@ namespace {
|
||||
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
|
||||
// purposes (cutting it down to uint16_t costs performance in some compilers).
|
||||
simdjson_inline uint32_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
|
||||
#else
|
||||
@@ -8149,7 +8196,7 @@ namespace {
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
|
||||
// Member-by-member initialization
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline simd8(
|
||||
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
||||
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
|
||||
@@ -8243,7 +8290,7 @@ namespace {
|
||||
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
|
||||
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
@@ -8273,7 +8320,7 @@ namespace {
|
||||
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
|
||||
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
@@ -8325,7 +8372,7 @@ namespace {
|
||||
// Array constructor
|
||||
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
|
||||
// Member-by-member initialization
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline simd8(
|
||||
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
|
||||
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
|
||||
@@ -8446,7 +8493,7 @@ namespace {
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
@@ -9169,7 +9216,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -10556,7 +10603,7 @@ SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
// See issue https://github.com/simdjson/simdjson/issues/1965
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_inline int trailing_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long ret;
|
||||
// Search the mask data from least significant bit (LSB)
|
||||
// to the most significant bit (MSB) for a set bit (1).
|
||||
@@ -10580,7 +10627,7 @@ simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
|
||||
SIMDJSON_NO_SANITIZE_UNDEFINED
|
||||
/* result might be undefined when input_num is zero */
|
||||
simdjson_inline int leading_zeroes(uint64_t input_num) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
unsigned long leading_zero = 0;
|
||||
// Search the mask data from most significant bit (MSB)
|
||||
// to least significant bit (LSB) for a set bit (1).
|
||||
@@ -10633,7 +10680,7 @@ simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes)
|
||||
#endif
|
||||
|
||||
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
*result = value1 + value2;
|
||||
return *result < value1;
|
||||
#else
|
||||
@@ -10776,7 +10823,7 @@ namespace arm64 {
|
||||
namespace {
|
||||
namespace simd {
|
||||
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
namespace {
|
||||
// Start of private section with Visual Studio workaround
|
||||
|
||||
@@ -10885,7 +10932,7 @@ namespace {
|
||||
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
|
||||
// purposes (cutting it down to uint16_t costs performance in some compilers).
|
||||
simdjson_inline uint32_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
|
||||
#else
|
||||
@@ -10916,7 +10963,7 @@ namespace {
|
||||
// Splat constructor
|
||||
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
|
||||
// Member-by-member initialization
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline simd8(
|
||||
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
|
||||
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
|
||||
@@ -11010,7 +11057,7 @@ namespace {
|
||||
uint64x2_t shufmask64 = {thintable_epi8[mask1], thintable_epi8[mask2]};
|
||||
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
@@ -11040,7 +11087,7 @@ namespace {
|
||||
uint8x8_t compactmask1 = vcreate_u8(thintable_epi8[mask1]);
|
||||
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
|
||||
// we increment by 0x08 the second half of the mask
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
|
||||
#else
|
||||
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
@@ -11092,7 +11139,7 @@ namespace {
|
||||
// Array constructor
|
||||
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
|
||||
// Member-by-member initialization
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
simdjson_inline simd8(
|
||||
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
|
||||
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
|
||||
@@ -11213,7 +11260,7 @@ namespace {
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t to_bitmask() const {
|
||||
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
#if SIMDJSON_REGULAR_VISUAL_STUDIO
|
||||
const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
|
||||
@@ -14166,6 +14213,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||
return arm64::stringparsing::parse_string(src, dst, allow_replacement);
|
||||
}
|
||||
@@ -15528,7 +15576,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -20393,6 +20441,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return haswell::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -20795,14 +20844,18 @@ namespace simd {
|
||||
|
||||
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
|
||||
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
|
||||
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
|
||||
// Only the first 64 - count_ones(mask) bytes of the result are significant but 64 bytes
|
||||
// get written.
|
||||
// Design consideration: it seems like a function with the
|
||||
// signature simd8<L> compress(uint32_t mask) would be
|
||||
// sensible, but the AVX ISA makes this kind of approach difficult.
|
||||
template<typename L>
|
||||
simdjson_inline void compress(uint64_t mask, L * output) const {
|
||||
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
// we deliberately avoid _mm512_mask_compressstoreu_epi8 for portability
|
||||
// (AMD Zen4 has terrible performance with it, it is effectively broken)
|
||||
// _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
__m512i compressed = _mm512_maskz_compress_epi8(~mask, *this);
|
||||
_mm512_storeu_si512(output, compressed); // could use a mask
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
@@ -21747,7 +21800,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -23425,14 +23478,18 @@ namespace simd {
|
||||
|
||||
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset).
|
||||
// Passing a 0 value for mask would be equivalent to writing out every byte to output.
|
||||
// Only the first 32 - count_ones(mask) bytes of the result are significant but 32 bytes
|
||||
// Only the first 64 - count_ones(mask) bytes of the result are significant but 64 bytes
|
||||
// get written.
|
||||
// Design consideration: it seems like a function with the
|
||||
// signature simd8<L> compress(uint32_t mask) would be
|
||||
// sensible, but the AVX ISA makes this kind of approach difficult.
|
||||
template<typename L>
|
||||
simdjson_inline void compress(uint64_t mask, L * output) const {
|
||||
_mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
// we deliberately avoid _mm512_mask_compressstoreu_epi8 for portability
|
||||
// (AMD Zen4 has terrible performance with it, it is effectively broken)
|
||||
// _mm512_mask_compressstoreu_epi8 (output,~mask,*this);
|
||||
__m512i compressed = _mm512_maskz_compress_epi8(~mask, *this);
|
||||
_mm512_storeu_si512(output, compressed); // could use a mask
|
||||
}
|
||||
|
||||
template<typename L>
|
||||
@@ -26647,6 +26704,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return icelake::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -28122,7 +28180,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -33071,6 +33129,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return ppc64::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -34863,7 +34922,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -40159,6 +40218,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return westmere::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -41428,7 +41488,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -46156,6 +46216,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||
return lsx::stringparsing::parse_string(src, dst, allow_replacement);
|
||||
}
|
||||
@@ -47438,7 +47499,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -52178,6 +52239,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||
return lasx::stringparsing::parse_string(src, dst, allow_replacement);
|
||||
}
|
||||
@@ -53047,7 +53109,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
|
||||
// floor(log(5**power)/log(2))
|
||||
//
|
||||
// Note that this is not magic: 152170/(1<<16) is
|
||||
// approximatively equal to log(5)/log(2).
|
||||
// approximately equal to log(5)/log(2).
|
||||
// The 1<<16 value is a power of two; we could use a
|
||||
// larger power of 2 if we wanted to.
|
||||
//
|
||||
@@ -56151,6 +56213,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return fallback::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
|
||||
+1697
-2326
File diff suppressed because it is too large
Load Diff
+1
-4
@@ -150,6 +150,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||
return arm64::stringparsing::parse_string(src, dst, allow_replacement);
|
||||
}
|
||||
@@ -164,10 +165,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return arm64::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+1
-4
@@ -388,6 +388,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return fallback::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -402,10 +403,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return fallback::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -236,101 +236,6 @@ simdjson_warn_unused simdjson_inline uint8_t *parse_wobbly_string(const uint8_t
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) noexcept {
|
||||
// We are making the following assumption: most strings will either be very short or they will not
|
||||
// need escaping.
|
||||
size_t i = 0;
|
||||
size_t pos = 0;
|
||||
if(input.size() >= escaping::BYTES_PROCESSED) {
|
||||
auto vec_processing = [input,out]() -> size_t {
|
||||
size_t i = 0;
|
||||
size_t pos = 0;
|
||||
for(;input.size() - i >= escaping::BYTES_PROCESSED; i += escaping::BYTES_PROCESSED) {
|
||||
escaping vinput = escaping::copy_and_find(reinterpret_cast<const uint8_t *>(input.data()) + i, reinterpret_cast<uint8_t *>(out) + pos);
|
||||
if(vinput.has_escape()) {
|
||||
return i + vinput.escape_index(); // We have a character that needs escaping
|
||||
}
|
||||
pos += escaping::BYTES_PROCESSED;
|
||||
}
|
||||
if(i == input.size()) { return input.size(); }
|
||||
// We virtually backtrack so we can load a full vector register
|
||||
i = input.size() - escaping::BYTES_PROCESSED;
|
||||
pos = i;
|
||||
escaping vinput = escaping::copy_and_find(reinterpret_cast<const uint8_t *>(input.data()) + i, reinterpret_cast<uint8_t *>(out) + pos);
|
||||
if(vinput.has_escape()) {
|
||||
return i + vinput.escape_index(); // We have a character that needs escaping
|
||||
}
|
||||
return input.size();
|
||||
};
|
||||
i = vec_processing();
|
||||
pos = i;
|
||||
if(i == input.size()) { return pos; }
|
||||
// Here we only continue if there was a character that needed escaping.
|
||||
}
|
||||
static std::string_view control_chars[] = {
|
||||
"\\x0000", "\\x0001", "\\x0002", "\\x0003", "\\x0004", "\\x0005", "\\x0006",
|
||||
"\\x0007", "\\x0008", "\\t", "\\n", "\\x000b", "\\f", "\\r",
|
||||
"\\x000e", "\\x000f", "\\x0010", "\\x0011", "\\x0012", "\\x0013", "\\x0014",
|
||||
"\\x0015", "\\x0016", "\\x0017", "\\x0018", "\\x0019", "\\x001a", "\\x001b",
|
||||
"\\x001c", "\\x001d", "\\x001e", "\\x001f"};
|
||||
static std::array<uint8_t, 256> json_quotable_character =
|
||||
[]() constexpr {
|
||||
std::array<uint8_t, 256> result{};
|
||||
for (int i = 0; i < 32; i++) {
|
||||
result[i] = 1;
|
||||
}
|
||||
for (int i : {'"', '\\'}) {
|
||||
result[i] = 1;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
// The rest could possibly be vectorized, but consider that we expect most strings
|
||||
// to be short or not to require escaping.
|
||||
for (; i < input.size(); i++) {
|
||||
uint8_t c = static_cast<uint8_t>(input[i]);
|
||||
if(json_quotable_character[c]) {
|
||||
switch (c) {
|
||||
case '"':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = '"';
|
||||
break;
|
||||
case '\\':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = '\\';
|
||||
break;
|
||||
case '\b':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = 'b';
|
||||
break;
|
||||
case '\f':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
out[pos++] = '\\';
|
||||
out[pos++] = 't';
|
||||
break;
|
||||
default:
|
||||
control_chars[c].copy(out + pos, 6);
|
||||
pos += 6;
|
||||
}
|
||||
} else {
|
||||
out[pos++] = c;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
||||
+1
-4
@@ -147,6 +147,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return haswell::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -161,10 +162,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return haswell::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+1
-4
@@ -193,6 +193,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return icelake::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -207,10 +208,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return icelake::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace icelake
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -186,9 +186,6 @@ public:
|
||||
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override {
|
||||
return set_best()->validate_utf8(buf, len);
|
||||
}
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final {
|
||||
return set_best()->write_string_escaped(input, out);
|
||||
}
|
||||
simdjson_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {}
|
||||
private:
|
||||
const implementation *set_best() const noexcept;
|
||||
@@ -239,9 +236,6 @@ public:
|
||||
simdjson_warn_unused error_code minify(const uint8_t *, size_t, uint8_t *, size_t &) const noexcept final override {
|
||||
return UNSUPPORTED_ARCHITECTURE;
|
||||
}
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) const noexcept final {
|
||||
return 0;
|
||||
}
|
||||
simdjson_warn_unused bool validate_utf8(const char *, size_t) const noexcept final override {
|
||||
return false; // Just refuse to validate. Given that we have a fallback implementation
|
||||
// it seems unlikely that unsupported_implementation will ever be used. If it is used,
|
||||
@@ -325,9 +319,6 @@ simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, s
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
|
||||
return get_active_implementation()->validate_utf8(buf, len);
|
||||
}
|
||||
simdjson_warn_unused size_t write_string_escaped(const std::string_view input, char *out) noexcept {
|
||||
return get_active_implementation()->write_string_escaped(input, out);
|
||||
}
|
||||
const implementation * builtin_implementation() {
|
||||
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
|
||||
assert(builtin_impl);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace internal {
|
||||
{ SUCCESS, "SUCCESS: No error" },
|
||||
{ CAPACITY, "CAPACITY: This parser can't support a document that big" },
|
||||
{ MEMALLOC, "MEMALLOC: Error allocating memory, we're most likely out of memory" },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc." },
|
||||
{ TAPE_ERROR, "TAPE_ERROR: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc. This is a fatal and unrecoverable error." },
|
||||
{ DEPTH_ERROR, "DEPTH_ERROR: The JSON document was too deep (too many nested objects and arrays)" },
|
||||
{ STRING_ERROR, "STRING_ERROR: Problem while parsing a string" },
|
||||
{ T_ATOM_ERROR, "T_ATOM_ERROR: Problem while parsing an atom starting with the letter 't'" },
|
||||
@@ -36,7 +36,7 @@ namespace internal {
|
||||
{ PARSER_IN_USE, "PARSER_IN_USE: Cannot parse a new document while a document is still in use." },
|
||||
{ OUT_OF_ORDER_ITERATION, "OUT_OF_ORDER_ITERATION: Objects and arrays can only be iterated when they are first encountered." },
|
||||
{ INSUFFICIENT_PADDING, "INSUFFICIENT_PADDING: simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array." },
|
||||
{ INCOMPLETE_ARRAY_OR_OBJECT, "INCOMPLETE_ARRAY_OR_OBJECT: JSON document ended early in the middle of an object or array. This is a fatal and unrecoverable error." },
|
||||
{ SCALAR_DOCUMENT_AS_VALUE, "SCALAR_DOCUMENT_AS_VALUE: A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
|
||||
{ OUT_OF_BOUNDS, "OUT_OF_BOUNDS: Attempt to access location outside of document."},
|
||||
{ TRAILING_CONTENT, "TRAILING_CONTENT: Unexpected trailing content in the JSON input."}
|
||||
|
||||
+1
-4
@@ -110,6 +110,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||
return lasx::stringparsing::parse_string(src, dst, allow_replacement);
|
||||
}
|
||||
@@ -124,10 +125,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return lasx::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace lasx
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+1
-4
@@ -114,6 +114,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool allow_replacement) const noexcept {
|
||||
return lsx::stringparsing::parse_string(src, dst, allow_replacement);
|
||||
}
|
||||
@@ -128,10 +129,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return lsx::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace lsx
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+1
-4
@@ -120,6 +120,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return ppc64::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -134,10 +135,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return ppc64::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace ppc64
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
+1
-4
@@ -152,6 +152,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
SIMDJSON_NO_SANITIZE_MEMORY
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst, bool replacement_char) const noexcept {
|
||||
return westmere::stringparsing::parse_string(src, dst, replacement_char);
|
||||
}
|
||||
@@ -166,10 +167,6 @@ simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *
|
||||
return stage2(_doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused size_t implementation::write_string_escaped(const std::string_view input, char *out) const noexcept {
|
||||
return westmere::stringparsing::write_string_escaped(input, out);
|
||||
}
|
||||
|
||||
} // namespace westmere
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -26,4 +26,3 @@ endif()
|
||||
add_cpp_test(checkimplementation LABELS other per_implementation)
|
||||
|
||||
add_subdirectory(compilation_failure_tests)
|
||||
add_subdirectory(builder)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# All remaining tests link with simdjson proper
|
||||
link_libraries(simdjson)
|
||||
include_directories(..)
|
||||
add_cpp_test(builder_string_builder_tests LABELS ondemand acceptance per_implementation)
|
||||
|
||||
# Copy the simdjson dll into the tests directory
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
add_custom_command(TARGET builder_string_builder_tests POST_BUILD # Adds a post-build event
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
||||
"$<TARGET_FILE:simdjson>" # <--this is in-file
|
||||
"$<TARGET_FILE_DIR:builder_string_builder_tests>") # <--this is out-file path
|
||||
endif(MSVC AND BUILD_SHARED_LIBS)
|
||||
@@ -1,178 +0,0 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_builder.h"
|
||||
#include <string_view>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace builder_tests {
|
||||
using namespace std;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool string_convertion_except() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser p;
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append('a');
|
||||
std::string r(sb);
|
||||
ASSERT_EQUAL(r, "a");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool append_char() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append('a');
|
||||
ASSERT_EQUAL(sb.size(), 1);
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "a");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool append_integer() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append(42);
|
||||
ASSERT_EQUAL(sb.size(), 2);
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "42");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool append_float() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append(1.1);
|
||||
ASSERT_EQUAL(sb.size(), 3);
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "1.1");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool append_null() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append_null();
|
||||
ASSERT_EQUAL(sb.size(), 4);
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "null");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool clear() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append('a');
|
||||
sb.clear();
|
||||
ASSERT_EQUAL(sb.size(), 0);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool escape_and_append() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.escape_and_append("Hello, \"world\"!");
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "Hello, \"world\"!");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool escape_and_append_with_quotes() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.escape_and_append_with_quotes("Hello, \"world\"!");
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "\"Hello, \\\"world\\\"!\"");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool append_raw() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append_raw("Test");
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "Test");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool raw_with_length() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append_raw("Test String", 4);
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "Test");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool string_convertion() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append('a');
|
||||
std::string_view p;
|
||||
auto result = sb.view().get(p);
|
||||
ASSERT_EQUAL(result, SUCCESS);
|
||||
ASSERT_EQUAL(p, "a");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool unicode_validation() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
sb.append('a');
|
||||
ASSERT_TRUE(sb.validate_unicode());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool buffer_growth() {
|
||||
TEST_START();
|
||||
simdjson::builder::string_builder sb;
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
sb.append('a');
|
||||
}
|
||||
ASSERT_EQUAL(sb.size(), 3);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
string_convertion_except() &&
|
||||
#endif
|
||||
append_char() &&
|
||||
append_integer() &&
|
||||
append_float() &&
|
||||
append_null() &&
|
||||
clear() &&
|
||||
escape_and_append() &&
|
||||
escape_and_append_with_quotes() &&
|
||||
append_raw() &&
|
||||
raw_with_length() &&
|
||||
string_convertion() &&
|
||||
buffer_growth() &&
|
||||
unicode_validation() &&
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace twitter_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, builder_tests::run);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#ifndef ONDEMAND_TEST_BUILDER_H
|
||||
#define ONDEMAND_TEST_BUILDER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include "simdjson.h"
|
||||
#include "cast_tester.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template<typename F>
|
||||
int test_main(int argc, char *argv[], const F& test_function) {
|
||||
std::cout << std::unitbuf;
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "a:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a': {
|
||||
const simdjson::implementation *impl = simdjson::get_available_implementations()[optarg];
|
||||
if (!impl) {
|
||||
std::fprintf(stderr, "Unsupported architecture value -a %s\n", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
simdjson::get_active_implementation() = impl;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::fprintf(stderr, "Unexpected argument %c\n", c);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// this is put here deliberately to check that the documentation is correct (README),
|
||||
// should this fail to compile, you should update the documentation:
|
||||
if (simdjson::get_active_implementation()->name() == "unsupported") {
|
||||
std::printf("unsupported CPU\n");
|
||||
std::abort();
|
||||
}
|
||||
// We want to know what we are testing.
|
||||
std::cout << "builtin_implementation -- " << simdjson::builtin_implementation()->name() << std::endl;
|
||||
std::cout << "------------------------------------------------------------" << std::endl;
|
||||
|
||||
std::cout << "Running tests." << std::endl;
|
||||
if (test_function()) {
|
||||
std::cout << "Success!" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
std::cerr << "FAILED." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ONDEMAND_TEST_BUILDER_H
|
||||
@@ -461,6 +461,13 @@ void parse_documentation_lowlevel() {
|
||||
(void)element;
|
||||
}
|
||||
|
||||
void simplepad() {
|
||||
std::string json = "[1]";
|
||||
dom::parser parser;
|
||||
dom::element doc;
|
||||
auto error = parser.parse(simdjson::pad(json)).get(doc);
|
||||
if(error) { exit(-1); }
|
||||
}
|
||||
|
||||
void jsondollar() {
|
||||
dom::parser parser;
|
||||
@@ -497,6 +504,7 @@ void jsonpath() {
|
||||
}
|
||||
|
||||
int main() {
|
||||
simplepad();
|
||||
jsonpath();
|
||||
jsondollar();
|
||||
basics_dom_1();
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
@@ -238,6 +240,40 @@ bool optional_car_deserialize() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool car_deserialize_to_map() {
|
||||
TEST_START();
|
||||
std::map<std::string,std::string> expected = { {"make", "Toyota"}, {"model", "Camry"}};
|
||||
padded_string json =
|
||||
R"( { "make": "Toyota", "model": "Camry" })"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
|
||||
static_assert(simdjson::concepts::string_view_keyed_map<std::map<std::string, std::string>>, "should be custom deserializable");
|
||||
using map_type = typename std::map<std::string,std::string>;
|
||||
static_assert(simdjson::custom_deserializable<map_type,simdjson::ondemand::value>, "should be custom deserializable");
|
||||
map_type brands;
|
||||
error = doc.get<map_type>().get(brands);
|
||||
ASSERT_TRUE(brands == expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool car_deserialize_with_map() {
|
||||
TEST_START();
|
||||
padded_string json =
|
||||
R"( { "car1": { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
"tire_pressure": [ 40.1, 39.9 ] }
|
||||
})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
[[maybe_unused]] auto error = parser.iterate(json).get(doc);
|
||||
std::map<std::string,Car> car;
|
||||
error = doc.get<std::map<std::string,Car>>().get(car);
|
||||
std::optional<Car> expected = Car{"Toyota", "Camry", 2018, {40.1f, 39.9f}};
|
||||
ASSERT_TRUE(car["car1"] == expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool car_doc_deserialize() {
|
||||
TEST_START();
|
||||
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
|
||||
@@ -320,7 +356,9 @@ bool car_unique_ptr_deserialize() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() { return list_car_deserialize()
|
||||
bool run() { return car_deserialize_with_map()
|
||||
&& car_deserialize_to_map()
|
||||
&& list_car_deserialize()
|
||||
&& optional_car_deserialize()
|
||||
&& car_unique_ptr_deserialize()
|
||||
&& vector_car_deserialize()
|
||||
|
||||
@@ -5,6 +5,51 @@ using namespace simdjson;
|
||||
|
||||
namespace misc_tests {
|
||||
using namespace std;
|
||||
bool issue2354() {
|
||||
TEST_START();
|
||||
auto json = "true "_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
bool b;
|
||||
ASSERT_SUCCESS(doc.get_bool().get(b));
|
||||
ASSERT_TRUE(b);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue2355() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
auto json = "[\"extra close\"]]"_padded;
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
simdjson::ondemand::array test;
|
||||
ASSERT_SUCCESS(doc.get_array().get(test));
|
||||
for(auto vale : test) {
|
||||
std::string_view str;
|
||||
ASSERT_SUCCESS(vale.get_string().get(str));
|
||||
ASSERT_EQUAL(str, "extra close");
|
||||
}
|
||||
ASSERT_FALSE(doc.at_end());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue2322() {
|
||||
TEST_START();
|
||||
std::vector<std::pair<std::string, bool>> examples = {{R"("hello")", false},
|
||||
{R"(\"hello)", true},
|
||||
{R"("hello\")", true},
|
||||
{R"("hel\"lo")", false},
|
||||
{R"("hel\\lo")", false},
|
||||
{R"(\"hel\\\"lo\")", true},
|
||||
{R"(\\"hel\\\"lo\")", false}};
|
||||
for (std::pair<std::string, bool> v : examples) {
|
||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first),
|
||||
v.second);
|
||||
ASSERT_EQUAL(ondemand::raw_json_string::is_free_from_unescaped_quote(v.first.c_str()),
|
||||
v.second);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
// user reported an asan error:
|
||||
bool issue2199() {
|
||||
@@ -537,6 +582,24 @@ namespace misc_tests {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
simdjson_warn_unused bool issue2312() {
|
||||
TEST_START();
|
||||
std::string init_string = R"("abc":)";
|
||||
init_string.resize(init_string.size() + simdjson::SIMDJSON_PADDING);
|
||||
simdjson::padded_string_view padded_view{init_string.data(), 5, init_string.size()};
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(padded_view).get(doc));
|
||||
std::string_view abc;
|
||||
ASSERT_SUCCESS(doc.get_string().get(abc));
|
||||
ASSERT_EQUAL(abc, "abc");
|
||||
ASSERT_SUCCESS(parser.iterate(padded_view).get(doc));
|
||||
std::string_view raw;
|
||||
ASSERT_SUCCESS(doc.raw_json().get(raw));
|
||||
ASSERT_EQUAL(raw, "\"abc\"");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
simdjson_warn_unused bool big_integer() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
@@ -620,6 +683,10 @@ namespace misc_tests {
|
||||
|
||||
bool run() {
|
||||
return
|
||||
issue2355() &&
|
||||
issue2354() &&
|
||||
issue2322() &&
|
||||
issue2312() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
issue2199() &&
|
||||
#endif
|
||||
|
||||
@@ -8,20 +8,42 @@
|
||||
#endif
|
||||
using namespace std;
|
||||
using namespace simdjson;
|
||||
using error_code=simdjson::error_code;
|
||||
using error_code = simdjson::error_code;
|
||||
|
||||
bool fatal_error() {
|
||||
TEST_START();
|
||||
padded_string badjson = R"( { "make": "Toyota", "model": "Camry", "year"})"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
auto errordoc = parser.iterate(badjson).get(doc);
|
||||
if(errordoc != simdjson::SUCCESS) { return false; }
|
||||
simdjson::ondemand::value v;
|
||||
auto error = doc.get_object()["year"].get(v);
|
||||
ASSERT_TRUE(simdjson::is_fatal(error));
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simplepad() {
|
||||
std::string json = "[1]";
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
auto error = parser.iterate(simdjson::pad(json)).get(doc);
|
||||
return error == SUCCESS;
|
||||
}
|
||||
|
||||
bool string1() {
|
||||
const char * data = "my data"; // 7 bytes
|
||||
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
|
||||
std::cout << my_padded_data << std::endl;
|
||||
return true;
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool string2() {
|
||||
std::string data = "my data";
|
||||
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
|
||||
std::cout << my_padded_data << std::endl;
|
||||
return true;
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool to_string_example_no_except() {
|
||||
@@ -264,6 +286,22 @@ bool at_end() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool at_end_array() {
|
||||
TEST_START();
|
||||
auto json = R"(["extra close"]])"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
ondemand::array array = doc.get_array();
|
||||
for (std::string_view values : array) {
|
||||
std::cout << values << std::endl;
|
||||
}
|
||||
if(!doc.at_end()) {
|
||||
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool examplecrt() {
|
||||
TEST_START();
|
||||
padded_string padded_input_json = R"([
|
||||
@@ -1885,6 +1923,7 @@ bool value_raw_json_object() {
|
||||
#endif
|
||||
bool run() {
|
||||
return true
|
||||
&& fatal_error()
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
#if SIMDJSON_CPLUSPLUS17
|
||||
&& big_int_array()
|
||||
@@ -1918,6 +1957,7 @@ bool run() {
|
||||
&& using_the_parsed_json_4()
|
||||
&& using_the_parsed_json_5()
|
||||
#endif
|
||||
&& simplepad()
|
||||
&& using_the_parsed_json_6()
|
||||
&& json_pointer_simple()
|
||||
&& json_pointer_unicode()
|
||||
@@ -1947,8 +1987,9 @@ bool run() {
|
||||
&& current_location_tape_error_with_except()
|
||||
&& examplecrt()
|
||||
&& examplecrt_realloc()
|
||||
&& at_end_array()
|
||||
#endif
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -184,8 +184,6 @@ else:
|
||||
if(detectedreadme != toversionstring(*newversion)):
|
||||
print(colored(255, 0, 0, "Consider updating the readme link to "+toversionstring(*newversion)))
|
||||
|
||||
|
||||
|
||||
print("Please run the tests before issuing a release. \n")
|
||||
print("to issue release, enter \n git commit -a && git push && git tag -a v"+toversionstring(*newversion)+" -m \"version "+toversionstring(*newversion)+"\" && git push --tags \n")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user