Compare commits

..

15 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
15 changed files with 345 additions and 239 deletions
+3 -3
View File
@@ -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
+3 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 3.11.4
VERSION 3.12.2
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 "24.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "24" 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
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "3.11.4"
PROJECT_NUMBER = "3.12.2"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+1 -1
View File
@@ -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
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)
[![][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/)
@@ -62,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.
@@ -211,6 +213,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
------------------------
@@ -220,7 +227,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.
+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
// 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) {
@@ -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());
+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).
// 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>
+3 -3
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.11.4"
#define SIMDJSON_VERSION "3.12.2"
namespace simdjson {
enum {
@@ -15,11 +15,11 @@ enum {
/**
* 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.
*/
SIMDJSON_VERSION_REVISION = 4
SIMDJSON_VERSION_REVISION = 2
};
} // namespace simdjson
+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,"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}/")
@@ -449,6 +465,8 @@ print(subprocess.run(['ls', '-la', AMAL_C, AMAL_H, DEMOCPP, README],
print("Done with all files generation.")
#
# Instructions to create demo
#
+13 -5
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2025-01-06 19:23:09 -0500. Do not edit! */
/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
/* including simdjson.cpp: */
/* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP
@@ -20813,14 +20813,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>
@@ -23443,14 +23447,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>
+224 -192
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2025-01-06 19:23:09 -0500. Do not edit! */
/* auto-generated on 2025-02-14 16:11:36 -0500. Do not edit! */
/* including simdjson.h: */
/* begin file simdjson.h */
#ifndef SIMDJSON_H
@@ -2437,7 +2437,7 @@ namespace std {
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.11.4"
#define SIMDJSON_VERSION "3.12.2"
namespace simdjson {
enum {
@@ -2448,11 +2448,11 @@ enum {
/**
* 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.
*/
SIMDJSON_VERSION_REVISION = 4
SIMDJSON_VERSION_REVISION = 2
};
} // namespace simdjson
@@ -17948,14 +17948,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>
@@ -40965,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 {
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;
}
@@ -41006,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 {
// 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());
@@ -51938,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 {
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;
}
@@ -51979,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 {
// 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());
@@ -63403,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 {
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;
}
@@ -63444,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 {
// 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());
@@ -65392,14 +65405,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>
@@ -74861,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 {
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;
}
@@ -74902,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 {
// 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());
@@ -86440,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 {
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;
}
@@ -86481,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 {
// 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());
@@ -98336,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 {
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;
}
@@ -98377,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 {
// 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());
@@ -109709,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 {
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;
}
@@ -109750,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 {
// 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());
@@ -121095,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 {
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;
}
@@ -121136,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 {
// 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());
+18
View File
@@ -5,6 +5,23 @@ using namespace simdjson;
namespace misc_tests {
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
// user reported an asan error:
bool issue2199() {
@@ -638,6 +655,7 @@ namespace misc_tests {
bool run() {
return
issue2322() &&
issue2312() &&
#if SIMDJSON_EXCEPTIONS
issue2199() &&
-2
View File
@@ -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")