Compare commits

...

23 Commits

Author SHA1 Message Date
Daniel Lemire 797e61742c release bump 2025-02-14 16:12:28 -05:00
Daniel Lemire f289412e0a fixing performance issue under Zen 4 processors (#2335)
* fixing performance issue under Zen 4 processors

* trying something else

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2025-02-14 16:11:36 -05:00
Daniel Lemire 7bd79b4445 Update README.md 2025-02-14 16:03:01 -05:00
Daniel Lemire 078e2c9073 patch release 3.12.1 2025-02-11 13:46:03 -05:00
Daniel Lemire d7b6b20511 creating zip files. 2025-02-11 13:43:34 -05:00
Daniel Lemire dbea3bbd62 Update README.md 2025-01-29 11:48:36 -05:00
Daniel Lemire e422933414 release 3.12.0 2025-01-27 20:35:57 -05:00
Daniel Lemire de4d69b367 Introducing dual licensing (#2328)
* Introducing dual licensing

* adding missing file
2025-01-27 20:34:35 -05:00
Paul Dreik b8675a7f7b fix fuzzing when running on icelake (#2327) 2025-01-26 05:36:33 +01:00
Paul Dreik 5642bb93a4 fix fuzzer CI job (#2324) 2025-01-16 13:33:53 -05:00
Daniel Lemire 1b23a77e03 3.11.6 2025-01-14 21:33:29 -05:00
Daniel Lemire 57699bfed8 release candidate (#2323) 2025-01-09 11:01:48 -05:00
Daniel Lemire 648303b26a typo 2025-01-08 21:29:11 -05:00
Daniel Lemire 9008960e36 fixed comment 2025-01-08 20:35:30 -05:00
Daniel Lemire 8a9e8a1792 fixing issue 2322 2025-01-08 20:28:25 -05:00
Daniel Lemire ba33e9e78f release 2025-01-06 19:33:53 -05:00
Daniel Lemire d98b351eef let us be more careful with concepts, we require __cpp_concepts >= 201907L and check for old versions of Apple clang (#2321)
* let us be more careful with concepts, we require __cpp_concepts >= 202002L

* checking Apple version

* let us be more specific

* removing extra endif
2025-01-06 19:23:09 -05:00
Daniel Lemire 5488dca126 Accidentally, it appears that PPC64 was always disabled by default. (#2320) 2025-01-03 11:01:04 -05:00
Daniel Lemire 7712ecf164 adding char bit check (pedantic) (#2316) 2024-12-31 14:34:13 -05:00
Paul Dreik 2803ca3093 use clang 19 in fuzzer job (#2315)
* use clang 19 in fuzzer job

* fix syntax error in msys2-clang.yml
2024-12-22 15:00:58 -05:00
Daniel Lemire e7f2463920 some tweaks 2024-12-17 16:27:31 -05:00
Daniel Lemire 5bfa0b098c patch release 3.11.3 (#2313)
* preparing patch release 3.11.3
2024-12-12 13:38:22 -05:00
Daniel Lemire f7ba9cb11b Update basics.md 2024-12-10 11:47:21 -05:00
22 changed files with 526 additions and 262 deletions
+4 -4
View File
@@ -24,7 +24,7 @@ jobs:
implementations: haswell westmere fallback implementations: haswell westmere fallback
UBSAN_OPTIONS: halt_on_error=1 UBSAN_OPTIONS: halt_on_error=1
MAXLEN: -max_len=4000 MAXLEN: -max_len=4000
CLANGVERSION: 15 CLANGVERSION: 19
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh) # which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
OPTLEVEL: -O3 OPTLEVEL: -O3
@@ -125,7 +125,7 @@ jobs:
done done
- name: Save the corpus as a github artifact - name: Save the corpus as a github artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: corpus name: corpus
path: corpus.tar path: corpus.tar
@@ -148,7 +148,7 @@ jobs:
run: tar cf valgrind.tar valgrind-*.txt run: tar cf valgrind.tar valgrind-*.txt
- name: Save valgrind output as a github artifact - name: Save valgrind output as a github artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: always() if: always()
with: with:
name: valgrindresults name: valgrindresults
@@ -156,7 +156,7 @@ jobs:
if-no-files-found: ignore if-no-files-found: ignore
- name: Archive any crashes as an artifact - name: Archive any crashes as an artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: always() if: always()
with: with:
name: crashes name: crashes
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- 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 install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Debug 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 install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: RelWithDebInfo type: RelWithDebInfo
env: env:
+3 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project( project(
simdjson simdjson
# The version number is modified by tools/release.py # The version number is modified by tools/release.py
VERSION 3.11.2 VERSION 3.12.2
DESCRIPTION "Parsing gigabytes of JSON per second" DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/" HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ---- # ---- Options, variables ----
# These version numbers are modified by tools/release.py # These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "24.0.0" CACHE STRING "simdjson library version") set(SIMDJSON_LIB_VERSION "25.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "24" CACHE STRING "simdjson library soversion") 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) 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) if(SIMDJSON_BUILD_STATIC_LIB AND NOT BUILD_SHARED_LIBS)
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = "3.11.2" PROJECT_NUMBER = "3.12.2"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # 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 # for a project that appears at the top of each page and should give viewer a
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
+18
View File
@@ -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.
+10 -3
View File
@@ -1,7 +1,7 @@
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](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]
[![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/) [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/)
@@ -62,6 +62,8 @@ Real-world usage
- [ada-url](https://github.com/ada-url/ada) - [ada-url](https://github.com/ada-url/ada)
- [fastgron](https://github.com/adamritter/fastgron) - [fastgron](https://github.com/adamritter/fastgron)
- [WasmEdge](https://wasmedge.org) - [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. If you are planning to use simdjson in a product, please work from one of our releases.
@@ -211,6 +213,11 @@ RGPIN-2017-03910 and RGPIN-2024-03787.
[license]: LICENSE [license]: LICENSE
[license img]: https://img.shields.io/badge/License-Apache%202-blue.svg [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 Contributing to simdjson
------------------------ ------------------------
@@ -220,7 +227,7 @@ Head over to [CONTRIBUTING.md](CONTRIBUTING.md) for information on contributing
License 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. 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.
+11 -6
View File
@@ -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. - 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. 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.
@@ -422,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 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 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. 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, * **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 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 * **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 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 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
@@ -557,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 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 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 whole array. You should only call `count_elements` as a last resort as it may
require scanning the document twice or more. In the spirit of On-Demand, the `count_elements` function does not validate the values in the array. You may use it as follows if your document is itself an array: 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++ ```C++
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded; auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
@@ -1625,7 +1629,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: 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 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. - 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. Observe how we use the `at` method when querying an index into an array, and not the bracket operator.
@@ -1650,8 +1654,8 @@ int main(void) {
} }
``` ```
The `at` method can only be called once on an array. It cannot be used *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. 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 ### Error handling examples without exceptions
@@ -1970,6 +1974,7 @@ to the document `rewind()` method, except that it does not rewind the
internal string buffer. Thus you should consume values only once internal string buffer. Thus you should consume values only once
even if you can iterate through the array or object more than 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. 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 Newline-Delimited JSON (ndjson) and JSON lines
+1 -1
View File
@@ -102,7 +102,7 @@ or indexing (`object["key"]`). In some cases, the values are even deserialized d
maps. maps.
The DOM approach is conceptually simple and "programmer friendly". Using the 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. 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. The DOM approach was the only way to parse JSON documents up to version 0.6 of the simdjson library.
+3 -1
View File
@@ -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. 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). 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).
+1 -1
View File
@@ -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 // make this dynamic, so it works regardless of how it was compiled
// or what hardware it runs on // 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(); const std::size_t Nimplementations = supported_implementations.size();
if(Nimplementations>Nimplementations_max) { if(Nimplementations>Nimplementations_max) {
+14 -2
View File
@@ -56,10 +56,22 @@
#endif #endif
#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> #include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else // __cpp_concepts #else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif #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 #endif // SIMDJSON_COMPILER_CHECK_H
@@ -246,7 +246,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -268,6 +275,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; 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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+6 -2
View File
@@ -148,14 +148,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
+5
View File
@@ -6,11 +6,15 @@
#include <cstdlib> #include <cstdlib>
#include <cfloat> #include <cfloat>
#include <cassert> #include <cassert>
#include <climits>
#ifndef _WIN32 #ifndef _WIN32
// strcasecmp, strncasecmp // strcasecmp, strncasecmp
#include <strings.h> #include <strings.h>
#endif #endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project // We are using size_t without namespace std:: throughout the project
using std::size_t; using std::size_t;
@@ -44,6 +48,7 @@ using std::size_t;
#elif defined(__loongarch_lp64) #elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1 #define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64) #elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__) #if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1 #define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__) #endif // defined(__ALTIVEC__)
+2 -2
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H #define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */ /** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.11.2" #define SIMDJSON_VERSION "3.12.2"
namespace simdjson { namespace simdjson {
enum { enum {
@@ -15,7 +15,7 @@ enum {
/** /**
* The minor version (major.MINOR.revision) of simdjson being used. * The minor version (major.MINOR.revision) of simdjson being used.
*/ */
SIMDJSON_VERSION_MINOR = 11, SIMDJSON_VERSION_MINOR = 12,
/** /**
* The revision (major.minor.REVISION) of simdjson being used. * The revision (major.minor.REVISION) of simdjson being used.
*/ */
+18
View File
@@ -441,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,"amalgamate_demo.cpp"),AMALGAMATE_OUTPUT_PATH)
shutil.copy2(os.path.join(SCRIPTPATH,"README.md"),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("Done with all files generation.")
print(f"Files have been written to directory: {AMALGAMATE_OUTPUT_PATH}/") print(f"Files have been written to directory: {AMALGAMATE_OUTPUT_PATH}/")
@@ -449,6 +465,8 @@ print(subprocess.run(['ls', '-la', AMAL_C, AMAL_H, DEMOCPP, README],
print("Done with all files generation.") print("Done with all files generation.")
# #
# Instructions to create demo # Instructions to create demo
# #
+32 -7
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-12-09 21:36:12 -0500. Do not edit! */ /* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
/* including simdjson.cpp: */ /* including simdjson.cpp: */
/* begin file simdjson.cpp */ /* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP #define SIMDJSON_SRC_SIMDJSON_CPP
@@ -83,12 +83,24 @@
#endif #endif
#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> #include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else // __cpp_concepts #else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif #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 #endif // SIMDJSON_COMPILER_CHECK_H
/* end file simdjson/compiler_check.h */ /* end file simdjson/compiler_check.h */
/* including simdjson/portability.h: #include "simdjson/portability.h" */ /* including simdjson/portability.h: #include "simdjson/portability.h" */
@@ -101,11 +113,15 @@
#include <cstdlib> #include <cstdlib>
#include <cfloat> #include <cfloat>
#include <cassert> #include <cassert>
#include <climits>
#ifndef _WIN32 #ifndef _WIN32
// strcasecmp, strncasecmp // strcasecmp, strncasecmp
#include <strings.h> #include <strings.h>
#endif #endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project // We are using size_t without namespace std:: throughout the project
using std::size_t; using std::size_t;
@@ -139,6 +155,7 @@ using std::size_t;
#elif defined(__loongarch_lp64) #elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1 #define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64) #elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__) #if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1 #define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__) #endif // defined(__ALTIVEC__)
@@ -20796,14 +20813,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
@@ -23426,14 +23447,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
+322 -201
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2024-12-09 21:36:12 -0500. Do not edit! */ /* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
/* including simdjson.h: */ /* including simdjson.h: */
/* begin file simdjson.h */ /* begin file simdjson.h */
#ifndef SIMDJSON_H #ifndef SIMDJSON_H
@@ -103,12 +103,24 @@
#endif #endif
#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> #include <utility>
#define SIMDJSON_SUPPORTS_DESERIALIZATION 1 #define SIMDJSON_SUPPORTS_DESERIALIZATION 1
#else // __cpp_concepts #else
#define SIMDJSON_SUPPORTS_DESERIALIZATION 0 #define SIMDJSON_SUPPORTS_DESERIALIZATION 0
#endif #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 #endif // SIMDJSON_COMPILER_CHECK_H
/* end file simdjson/compiler_check.h */ /* end file simdjson/compiler_check.h */
/* including simdjson/portability.h: #include "simdjson/portability.h" */ /* including simdjson/portability.h: #include "simdjson/portability.h" */
@@ -121,11 +133,15 @@
#include <cstdlib> #include <cstdlib>
#include <cfloat> #include <cfloat>
#include <cassert> #include <cassert>
#include <climits>
#ifndef _WIN32 #ifndef _WIN32
// strcasecmp, strncasecmp // strcasecmp, strncasecmp
#include <strings.h> #include <strings.h>
#endif #endif
static_assert(CHAR_BIT == 8, "simdjson requires 8-bit bytes");
// We are using size_t without namespace std:: throughout the project // We are using size_t without namespace std:: throughout the project
using std::size_t; using std::size_t;
@@ -159,6 +175,7 @@ using std::size_t;
#elif defined(__loongarch_lp64) #elif defined(__loongarch_lp64)
#define SIMDJSON_IS_LOONGARCH64 1 #define SIMDJSON_IS_LOONGARCH64 1
#elif defined(__PPC64__) || defined(_M_PPC64) #elif defined(__PPC64__) || defined(_M_PPC64)
#define SIMDJSON_IS_PPC64 1
#if defined(__ALTIVEC__) #if defined(__ALTIVEC__)
#define SIMDJSON_IS_PPC64_VMX 1 #define SIMDJSON_IS_PPC64_VMX 1
#endif // defined(__ALTIVEC__) #endif // defined(__ALTIVEC__)
@@ -2420,7 +2437,7 @@ namespace std {
#define SIMDJSON_SIMDJSON_VERSION_H #define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */ /** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.11.2" #define SIMDJSON_VERSION "3.12.2"
namespace simdjson { namespace simdjson {
enum { enum {
@@ -2431,7 +2448,7 @@ enum {
/** /**
* The minor version (major.MINOR.revision) of simdjson being used. * The minor version (major.MINOR.revision) of simdjson being used.
*/ */
SIMDJSON_VERSION_MINOR = 11, SIMDJSON_VERSION_MINOR = 12,
/** /**
* The revision (major.minor.REVISION) of simdjson being used. * The revision (major.minor.REVISION) of simdjson being used.
*/ */
@@ -17931,14 +17948,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
@@ -38216,7 +38237,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -38238,6 +38266,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -40939,36 +40969,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -40980,7 +41013,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -49180,7 +49213,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -49202,6 +49242,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -51903,36 +51945,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -51944,7 +51989,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -60636,7 +60681,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -60658,6 +60710,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -63359,36 +63413,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -63400,7 +63457,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -65348,14 +65405,18 @@ namespace simd {
// Copies to 'output" all bytes corresponding to a 0 in the mask (interpreted as a bitset). // 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. // 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. // get written.
// Design consideration: it seems like a function with the // Design consideration: it seems like a function with the
// signature simd8<L> compress(uint32_t mask) would be // signature simd8<L> compress(uint32_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult. // sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L> template<typename L>
simdjson_inline void compress(uint64_t mask, L * output) const { 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> template<typename L>
@@ -72085,7 +72146,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -72107,6 +72175,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -74808,36 +74878,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -74849,7 +74922,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -83655,7 +83728,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -83677,6 +83757,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -86378,36 +86460,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -86419,7 +86504,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -95542,7 +95627,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -95564,6 +95656,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -98265,36 +98359,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -98306,7 +98403,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -106906,7 +107003,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -106928,6 +107032,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -109629,36 +109735,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -109670,7 +109779,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
@@ -118283,7 +118392,14 @@ simdjson_inline simdjson_result<value> document::operator[](const char *key) & n
} }
simdjson_inline error_code document::consume() noexcept { 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(); } if(error) { iter.abandon(); }
return error; return error;
} }
@@ -118305,6 +118421,8 @@ simdjson_inline simdjson_result<json_type> document::type() noexcept {
} }
simdjson_inline simdjson_result<bool> document::is_scalar() 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; json_type this_type;
auto error = type().get(this_type); auto error = type().get(this_type);
if(error) { return error; } if(error) { return error; }
@@ -121006,36 +121124,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 { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(pos < target.size()) {
for(;pos < target.size() && target[pos] != '\\';pos++) {} pos = target.find('"', pos);
// slow path may begin. if(pos == std::string_view::npos) { return true; }
bool escaping{false}; if(pos != 0 && target[pos-1] != '\\') { return false; }
for(;pos < target.size();pos++) { if(pos > 1 && target[pos-2] == '\\') {
if((target[pos] == '"') && !escaping) { size_t backslash_count{2};
return false; for(size_t i = 3; i <= pos; i++) {
} else if(target[pos] == '\\') { if(target[pos-i] == '\\') { backslash_count++; }
escaping = !escaping; else { break; }
} else { }
escaping = false; if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
size_t pos{0}; size_t pos{0};
// if the content has no escape character, just scan through it quickly! while(target[pos]) {
for(;target[pos] && target[pos] != '\\';pos++) {} const char * result = strchr(target+pos, '"');
// slow path may begin. if(result == nullptr) { return true; }
bool escaping{false}; pos = result - target;
for(;target[pos];pos++) { if(pos != 0 && target[pos-1] != '\\') { return false; }
if((target[pos] == '"') && !escaping) { if(pos > 1 && target[pos-2] == '\\') {
return false; size_t backslash_count{2};
} else if(target[pos] == '\\') { for(size_t i = 3; i <= pos; i++) {
escaping = !escaping; if(target[pos-i] == '\\') { backslash_count++; }
} else { else { break; }
escaping = false; }
if(backslash_count % 2 == 0) { return false; }
} }
pos++;
} }
return true; return true;
} }
@@ -121047,7 +121168,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 { 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. // the raw content is quote terminated within a valid JSON string.
if(target.size() <= SIMDJSON_PADDING) { if(target.size() <= SIMDJSON_PADDING) {
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
+37
View File
@@ -5,6 +5,23 @@ using namespace simdjson;
namespace misc_tests { namespace misc_tests {
using namespace std; using namespace std;
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 #if SIMDJSON_EXCEPTIONS
// user reported an asan error: // user reported an asan error:
bool issue2199() { bool issue2199() {
@@ -537,6 +554,24 @@ namespace misc_tests {
TEST_SUCCEED(); 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() { simdjson_warn_unused bool big_integer() {
TEST_START(); TEST_START();
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
@@ -620,6 +655,8 @@ namespace misc_tests {
bool run() { bool run() {
return return
issue2322() &&
issue2312() &&
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
issue2199() && issue2199() &&
#endif #endif
-2
View File
@@ -184,8 +184,6 @@ else:
if(detectedreadme != toversionstring(*newversion)): if(detectedreadme != toversionstring(*newversion)):
print(colored(255, 0, 0, "Consider updating the readme link to "+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("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") 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")