Compare commits

...

24 Commits

Author SHA1 Message Date
Daniel Lemire 6d909a5d12 Deprecated method. 2022-10-04 10:07:18 -04:00
Daniel Lemire b4c0cad4fe Documentation tweak. 2022-10-04 10:02:34 -04:00
Daniel Lemire 0c284d07b1 Removing max_depth from ondemand::parser 2022-10-04 09:58:37 -04:00
Daniel Lemire 7d30aecf0c Removing start_positions. 2022-10-04 09:52:40 -04:00
Tyson Andre c6ab52eebb [skip ci] Add an .editorconfig for .cpp/.h/.md for whitespace settings (#1901)
Make it less likely to accidentally introduce tabs, trailing whitespace,
carriage returns, non-utf8 in files, or files without trailing newlines.

https://editorconfig.org/ has plugins for various editors/IDEs and is
enabled by default in some IDEs.
2022-10-03 11:14:00 -04:00
Daniel Lemire a1aab1fafe Preparing release 2.2.3 2022-10-02 16:32:37 -04:00
Daniel Lemire b92cbbe280 Fixing issue 1898 (#1899)
* Fixing issue 1898 Preserve sign for number with underflowing exponent (#1900)


Before this commit, simdjson parsed "-1e-999" and "-0e-999" and "-1e-342"
as 0.0.
After this commit, those JSON strings get parsed as -0.0.
(https://en.wikipedia.org/wiki/Signed_zero)

The old behavior was inconsistent with the way simdjson parsed "-0.0" as -0.0.

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

Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>
2022-10-02 16:25:39 -04:00
Tyson Andre 6d2a09f8e5 [skip ci] Fix typo, formatting nit in HACKING.md (#1902)
vim syntax highlighting doesn't work properly without space between a
bulleted list and the start of a code snippet.
2022-10-02 16:19:34 -04:00
Tyson Andre 00564bf7d5 Micro-optimization for parsing surrogate pairs (#1897)
Load 2 bytes and compare the 2 bytes against `"\u"`
Compilers with optimizations turned on will turn this into a 16-bit load
then 16-bit compare on supported platforms
(with smaller compiled code size).

Make it obvious to the compiler that it's reading two
consecutive bytes of the same pointer

Add parse_surrogate_pairs to show the difference exists.
See discussion in #1896
2022-10-02 12:10:53 -04:00
Tyson Andre 5809e51ae4 fix: Reject surrogate pairs with invalid low surrogate (#1896)
Closes #1894

Reject low surrogates outside of the range U+DC00—U+DFFF

Related to https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs

A surrogate pair should consist of a high surrogate and low surrogate.
They're used to represent 0x010000-0x10FFFF in the JSON spec because
the JavaScript specification originally only supported `\uXXXX`.

Previously, simdjson would accept some combinations of valid high
surrogates and invalid low surrogates due to a bug in the check.
(e.g. `\uD888\u1234` was accepted)

U+D800—U+DBFF (1,024 code points): high surrogates
U+DC00—U+DFFF (1,024 code points): low surrogates
2022-09-30 12:13:16 -04:00
Tyson Andre d27e7cce71 Fix typos in doc/basics.md (#1893) 2022-09-30 08:34:37 -04:00
David Korenchuk f7dc03f93d Fix documentation of description() method in implementation (#1895) 2022-09-30 08:34:06 -04:00
sean d4ac1b51d0 Fix various warnings & if constexpr (#1888) 2022-09-27 23:22:47 -04:00
Daniel Lemire 6a4222da71 Adding a remark to the documentation. 2022-09-19 15:28:33 -04:00
Daniel Lemire bba88eb5e5 Fixing typo in the documentation. 2022-09-19 10:21:11 -04:00
Daniel Lemire 16b3816455 This fixes an error caused by overeager gcc static analyser (#1891) 2022-09-19 10:20:48 -04:00
Andrea Pappacoda e5a408386b build: add pkg-config support (#1767)
* build: add pkg-config support

The CMake build script now generates a simple pkg-config files that can
be easily used by non-CMake users.

The file is generated from a template file that gets filled in at
configure time.

As CMake doesn't have anything similar to Meson's pkg-config generator
the file is quite static, i.e. new simdjson public defines/dependencies
won't be picked up automatically.

This approach also suffers from one minor issue, mentioned in
[jtojnar/cmake-snips][]; in short, it doesn't work well when users
specify CMAKE_INSTALL_INCLUDEDIR and similar as absolute paths. It's not
a big deal, and it will easily fixable once you'll require CMake >=3.20.

Fixes #1763

[jtojnar/cmake-snips]: https://github.com/jtojnar/cmake-snips#concatenating-paths-when-building-pkg-config-files

* build: handle absolute paths in .pc generation

As mentioned in the previous commit message, correct concatenation of
paths is only available in CMake >=3.20, so handling absolute paths in
pkg-config file generation requires using jtojnar's JoinPaths module.

* ci: add debian job

This new jobs compiles simdjson on Debian Testing, a semi-rolling
release, so that new compilers are always tested.

This job also tests the pkg-config file introduced in commit
1096c3b299
2022-08-26 16:20:51 -04:00
Herman Semenov e65f28e61a Fixed if condition, Win64 _fseeki64, trivial constructors C++11 (#1883) 2022-08-18 14:16:46 -04:00
Daniel Lemire fbb46b99e2 Fixes and verifies issue 1878. (#1880)
* Fixes and verifies issue 1878.

* Changing how NULL is handled.

* Different design.
2022-08-08 22:00:38 -04:00
Daniel Lemire 933c2ebeac Preparing release 2022-07-28 21:46:45 -04:00
Daniel Lemire db3e813aa6 Verifying and fixing issue 1876 (#1877)
* Verifying and fixing issue 1876

* Typo
2022-07-28 21:45:54 -04:00
Daniel Lemire 9c95a48fe6 cleaning on-demand benchmarks (#1875)
* Setting RapidJSON and yyjson to their latest version.

* Let us stop dumping all of the benchmarks (it is confusing) on screen.
2022-07-28 20:28:29 -04:00
Daniel Lemire cb20f7e7df Update CONTRIBUTING.md 2022-07-20 09:46:52 -04:00
Dirk Stolle 18b9168eec remove empty if block (#1873)
I guess it will be thrown away by the compiler's optimizer
anyway, but there is no need to keep this in the code.
2022-07-19 20:36:51 -04:00
55 changed files with 1065 additions and 451 deletions
+12
View File
@@ -0,0 +1,12 @@
# https://editorconfig.org/
root = true
# Conservatively avoid changing defaults for other file types, e.g. raw json files for test cases,
# Makefiles, etc.
[*.{cpp,h,md}]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
tab_width = 2
trim_trailing_whitespace = true
+1
View File
@@ -78,6 +78,7 @@
.gitattributes export-ignore
.gitignore export-ignore
.editorconfig export-ignore
# Sources
*.c text eol=lf diff=c
+33
View File
@@ -0,0 +1,33 @@
name: Debian
on: [push, pull_request]
defaults:
run:
shell: sh
permissions:
contents: read
jobs:
pkg-config:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
apt -y update
apt -y --no-install-recommends install g++ cmake make pkg-config
- name: Build and install
run: |
cmake -B build
cmake --build build
cmake --install build
- name: Test pkg-config
run: g++ examples/quickstart/quickstart.cpp $(pkg-config --cflags --libs simdjson)
+19 -1
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 2.2.1
VERSION 2.2.3
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -152,6 +152,24 @@ install(
COMPONENT example_Development
)
# pkg-config
include(cmake/JoinPaths.cmake)
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
if(SIMDJSON_ENABLE_THREADS)
set(PKGCONFIG_CFLAGS "-DSIMDJSON_THREADS_ENABLED=1")
if(CMAKE_THREAD_LIBS_INIT)
set(PKGCONFIG_LIBS_PRIVATE "Libs.private: ${CMAKE_THREAD_LIBS_INIT}")
endif()
endif()
configure_file("simdjson.pc.in" "simdjson.pc" @ONLY)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/simdjson.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
)
#
# CPack
#
+1 -1
View File
@@ -54,7 +54,7 @@ Contributors are encouraged to :
- Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code.
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency.
- Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on.
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer if we do not understand.
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer.
- Provide tests for any new feature. We will not merge a new feature without tests.
Pull Requests
+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 = "2.2.1"
PROJECT_NUMBER = "2.2.3"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+2 -2
View File
@@ -82,7 +82,7 @@ Other important files and directories:
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script).
* **benchmark:** This is where we do benchmarking. Benchmarking is core to every change we make; the
cardinal rule is don't regress performance without knowing exactly why, and what you're trading
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnnecessary system calls. We recommend checking the performance as follows:
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnecessary system calls. We recommend checking the performance as follows:
```bash
mkdir build
cd build
@@ -114,7 +114,7 @@ Other important files and directories:
* `json2json mydoc.json` parses the document, constructs a model and then dumps back the result to standard output.
* `json2json -d mydoc.json` parses the document, constructs a model and then dumps model (as a tape) to standard output. The tape format is described in the accompanying file `tape.md`.
* `minify mydoc.json` minifies the JSON document, outputting the result to standard output. Minifying means to remove the unneeded white space characters.
*`jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
* `jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
> **Don't modify the files in singleheader/ directly; these are automatically generated.**
+25
View File
@@ -656,6 +656,31 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
}
BENCHMARK(error_code_twitter_image_sizes);
static void parse_surrogate_pairs(State& state) {
// NOTE: This mostly exists to show there's a tiny benefit to
// loading and comparing both bytes of "\\u" simultaneously.
// (which should also reduce the compiled code size).
// The repeated surrogate pairs make this easier to measure.
dom::parser parser;
const std::string_view data = "\"\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\"";
padded_string docdata{data};
// we do not want mem. alloc. in the loop.
auto error = parser.allocate(docdata.size());
if (error) {
cout << error << endl;
return;
}
for (simdjson_unused auto _ : state) {
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse string" << error << endl;
return;
}
}
}
BENCHMARK(parse_surrogate_pairs);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
+101 -59
View File
@@ -25,74 +25,116 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
#include <benchmark/benchmark.h>
SIMDJSON_POP_DISABLE_WARNINGS
#include "json2msgpack/simdjson_dom.h"
#include "json2msgpack/simdjson_ondemand.h"
#include "json2msgpack/rapidjson.h"
#include "json2msgpack/simdjson_dom.h"
#include "json2msgpack/yyjson.h"
#include "json2msgpack/rapidjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "json2msgpack/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "json2msgpack/nlohmann_json.h"
#include "partial_tweets/simdjson_ondemand.h"
#include "partial_tweets/simdjson_dom.h"
#include "partial_tweets/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "partial_tweets/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "partial_tweets/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "partial_tweets/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "partial_tweets/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "partial_tweets/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/simdjson_ondemand.h"
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
#include "distinct_user_id/simdjson_dom.h"
#include "distinct_user_id/simdjson_dom_json_pointer.h"
#include "distinct_user_id/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "distinct_user_id/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "distinct_user_id/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "find_tweet/simdjson_ondemand.h"
#include "find_tweet/simdjson_dom.h"
#include "find_tweet/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "find_tweet/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "find_tweet/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "find_tweet/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "find_tweet/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "find_tweet/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "top_tweet/simdjson_ondemand.h"
#include "top_tweet/simdjson_dom.h"
#include "top_tweet/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "top_tweet/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "top_tweet/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "top_tweet/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "top_tweet/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "top_tweet/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "kostya/simdjson_ondemand.h"
#include "kostya/simdjson_dom.h"
#include "kostya/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "kostya/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "kostya/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "kostya/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "kostya/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "kostya/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "large_random/simdjson_ondemand.h"
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
#include "large_random/simdjson_ondemand_unordered.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
#include "large_random/simdjson_dom.h"
#include "large_random/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "large_random/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "large_random/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "large_random/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "large_random/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "large_random/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "amazon_cellphones/simdjson_dom.h"
#include "amazon_cellphones/simdjson_ondemand.h"
#include "large_amazon_cellphones/simdjson_dom.h"
#include "large_amazon_cellphones/simdjson_ondemand.h"
#include "partial_tweets/simdjson_dom.h"
#include "partial_tweets/simdjson_ondemand.h"
#include "partial_tweets/yyjson.h"
#include "partial_tweets/sajson.h"
#include "partial_tweets/rapidjson.h"
#include "partial_tweets/rapidjson_sax.h"
#include "partial_tweets/nlohmann_json.h"
#include "partial_tweets/nlohmann_json_sax.h"
#include "large_random/simdjson_dom.h"
#include "large_random/simdjson_ondemand.h"
#include "large_random/simdjson_ondemand_unordered.h"
#include "large_random/yyjson.h"
#include "large_random/sajson.h"
#include "large_random/rapidjson.h"
#include "large_random/rapidjson_sax.h"
#include "large_random/nlohmann_json.h"
#include "large_random/nlohmann_json_sax.h"
#include "kostya/simdjson_dom.h"
#include "kostya/simdjson_ondemand.h"
#include "kostya/yyjson.h"
#include "kostya/sajson.h"
#include "kostya/rapidjson.h"
#include "kostya/rapidjson_sax.h"
#include "kostya/nlohmann_json.h"
#include "kostya/nlohmann_json_sax.h"
#include "distinct_user_id/simdjson_dom.h"
#include "distinct_user_id/simdjson_dom_json_pointer.h"
#include "distinct_user_id/simdjson_ondemand.h"
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
#include "distinct_user_id/yyjson.h"
#include "distinct_user_id/sajson.h"
#include "distinct_user_id/rapidjson.h"
#include "distinct_user_id/rapidjson_sax.h"
#include "distinct_user_id/nlohmann_json.h"
#include "distinct_user_id/nlohmann_json_sax.h"
#include "find_tweet/simdjson_dom.h"
#include "find_tweet/simdjson_ondemand.h"
#include "find_tweet/yyjson.h"
#include "find_tweet/sajson.h"
#include "find_tweet/rapidjson.h"
#include "find_tweet/rapidjson_sax.h"
#include "find_tweet/nlohmann_json.h"
#include "find_tweet/nlohmann_json_sax.h"
#include "top_tweet/simdjson_dom.h"
#include "top_tweet/simdjson_ondemand.h"
#include "top_tweet/yyjson.h"
#include "top_tweet/sajson.h"
#include "top_tweet/rapidjson.h"
#include "top_tweet/rapidjson_sax.h"
#include "top_tweet/nlohmann_json.h"
#include "top_tweet/nlohmann_json_sax.h"
BENCHMARK_MAIN();
+2 -1
View File
@@ -46,13 +46,14 @@ struct rapidjson : rapidjson_base {
};
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -1
View File
@@ -49,13 +49,14 @@ struct yyjson : yyjson_base {
};
BENCHMARK_TEMPLATE(distinct_user_id, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_YYJSON
+2 -1
View File
@@ -40,13 +40,14 @@ struct rapidjson : rapidjson_base {
};
BENCHMARK_TEMPLATE(find_tweet, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -2
View File
@@ -40,14 +40,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(find_tweet, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_YYJSON
+9 -7
View File
@@ -122,19 +122,21 @@ struct rapidjson_base {
};
using rapidjson_lossless = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_lossless)->UseManualTime();
using rapidjson = rapidjson_base<kParseValidateEncodingFlag>;
using rapidjson = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
using rapidjson_approx = rapidjson_base<kParseValidateEncodingFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_approx)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
using rapidjson_insitu = rapidjson_base<kParseValidateEncodingFlag|kParseInsituFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -1
View File
@@ -106,6 +106,7 @@ struct yyjson : yyjson2msgpack {
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson2msgpack {
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
@@ -116,7 +117,7 @@ struct yyjson_insitu : yyjson2msgpack {
}
};
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_YYJSON
+8 -7
View File
@@ -34,28 +34,29 @@ struct rapidjson_base {
return true;
}
};
struct rapidjson : rapidjson_base {
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_approx : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
BENCHMARK_TEMPLATE(kostya, rapidjson_approx)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_lossless : rapidjson_base {
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson_lossless)->UseManualTime();
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace kostya
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -2
View File
@@ -53,14 +53,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(kostya, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(kostya, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace kostya
#endif // SIMDJSON_COMPETITION_YYJSON
+8 -6
View File
@@ -31,28 +31,30 @@ struct rapidjson_base {
return true;
}
};
struct rapidjson : rapidjson_base {
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_approx : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson)->UseManualTime();
BENCHMARK_TEMPLATE(large_random, rapidjson_approx)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_lossless : rapidjson_base {
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson_lossless)->UseManualTime();
BENCHMARK_TEMPLATE(large_random, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace large_random
+2 -2
View File
@@ -51,14 +51,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(large_random, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(large_random, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace large_random
#endif // SIMDJSON_COMPETITION_YYJSON
+2 -2
View File
@@ -67,14 +67,14 @@ struct rapidjson : rapidjson_base {
}
};
BENCHMARK_TEMPLATE(partial_tweets, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -2
View File
@@ -66,14 +66,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(partial_tweets, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(partial_tweets, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_YYJSON
+2 -2
View File
@@ -56,14 +56,14 @@ struct rapidjson : rapidjson_base {
}
};
BENCHMARK_TEMPLATE(top_tweet, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), max_retweet_count, result);
}
};
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace top_tweet
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -2
View File
@@ -55,14 +55,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(top_tweet, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), max_retweet_count, result);
}
};
BENCHMARK_TEMPLATE(top_tweet, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace top_tweet
#endif // SIMDJSON_COMPETITION_YYJSON
+23
View File
@@ -0,0 +1,23 @@
# This module provides function for joining paths
# known from most languages
#
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()
+2 -2
View File
@@ -91,7 +91,7 @@ int main() {}
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
import_dependency(rapidjson Tencent/rapidjson b32cd94)
import_dependency(rapidjson Tencent/rapidjson f54b0e4)
add_library(rapidjson INTERFACE)
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
target_include_directories(rapidjson SYSTEM INTERFACE
@@ -114,7 +114,7 @@ int main() {}
"${ujson4c_SOURCE_DIR}/3rdparty")
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
import_dependency(yyjson ibireme/yyjson aa33ec5)
import_dependency(yyjson ibireme/yyjson c385651)
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
+21 -6
View File
@@ -99,7 +99,7 @@ We recommend CMake version 3.15 or better.
See [our CMake demonstration](https://github.com/simdjson/cmake_demo_single_file). It works under Linux, FreeBSD, macOS and Windows (including Visual Studio).
The CMake build in simdjson can be taylored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
The CMake build in simdjson can be tailored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
Versions
@@ -433,7 +433,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
* **Counting elements in arrays:** Sometimes it is useful to scan an array to determine its length prior to parsing it.
For this purpose, `array` instances have a `count_elements` method. Users should be
aware that the `count_elements` method can be costly since it requires scanning the
whole array. You may use it as follows if your document is itself an array:
whole array. You should only call `count_elements` as a last resort as it may
require scanning the document twice or more. You may use it as follows if your document is itself an array:
```C++
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
@@ -453,14 +454,15 @@ support for users who avoid exceptions. See [the simdjson error handling documen
size_t count = test_array.count_elements(); // requires simdjson 1.0 or better
std::cout << "Number of elements: " << count << std::endl;
for(ondemand::object elem: test_array) {
std::cout << simdjson::to_string(elem);
std::cout << simdjson::to_json_string(elem);
}
```
* **Counting fields in objects:** Other times, it is useful to scan an object to determine the number of fields prior to
parsing it.
For this purpose, `object` instances have a `count_fields` method. Again, users should be
aware that the `count_fields` method can be costly since it requires scanning the
whole objects. You may use it as follows if your document is itself an object:
whole objects. You should only call `count_fields` as a last resort as it may
require scanning the document twice or more. You may use it as follows if your document is itself an object:
```C++
ondemand::parser parser;
@@ -970,6 +972,19 @@ bool parse() {
}
```
For safety, you should only use our ondemand instances (e.g., `ondemand::object`)
after you have initialized them and checked that there is no error:
```c++
ondemand::object car;
// the `car` instance should not use used before it is initialized
error = car_value.get_object().get(car);
if(error) {
// the `car` instance should not use used
} else {
// the `car` instance can be safely used
}
```
The following examples illustrates how to iterate through the content of an object without
having to handle exceptions.
@@ -1008,7 +1023,7 @@ target_compile_definitions(simdjson PUBLIC SIMDJSON_EXCEPTIONS=OFF)
Users more comfortable with an exception flow may choose to directly cast the `simdjson_result<T>` to the desired type:
```c++
simdjson::ondemande::document doc = parser.iterate(json); // Throws an exception if there was an error!
simdjson::ondemand::document doc = parser.iterate(json); // Throws an exception if there was an error!
```
When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
@@ -1516,7 +1531,7 @@ Standard Compliance
The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification.
- The only insignificant whitespace characters allowed are the space, the horizontal tab, the line feed and the carriage return. In particular, a JSON document may not contain an unespaced null character.
- The only insignificant whitespace characters allowed are the space, the horizontal tab, the line feed and the carriage return. In particular, a JSON document may not contain an unescaped null character.
- A single string or a single number is considered to be a valid JSON document.
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
+7 -1
View File
@@ -42,7 +42,13 @@ inline simdjson_result<size_t> parser::read_file(const std::string &path) noexce
}
// Get the file size
if(std::fseek(fp, 0, SEEK_END) < 0) {
int ret;
#if defined(SIMDJSON_VISUAL_STUDIO) && !SIMDJSON_IS_32BITS
ret = _fseeki64(fp, 0, SEEK_END);
#else
ret = std::fseek(fp, 0, SEEK_END);
#endif // _WIN64
if(ret < 0) {
std::fclose(fp);
return IO_ERROR;
}
+2 -1
View File
@@ -18,7 +18,7 @@ enum error_code {
SUCCESS = 0, ///< No error
CAPACITY, ///< This parser can't support a document that big
MEMALLOC, ///< Error allocating memory, most likely out of memory
TAPE_ERROR, ///< Something went wrong while writing to the tape (stage 2), this is a generic error
TAPE_ERROR, ///< Something went wrong, this is a generic error
DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
STRING_ERROR, ///< Problem while parsing a string
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't'
@@ -45,6 +45,7 @@ enum error_code {
INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
OUT_OF_BOUNDS, ///< Attempted to access location outside of document.
TRAILING_CONTENT, ///< Unexpected trailing content in the JSON input
NUM_ERROR_CODES
};
+22 -21
View File
@@ -112,7 +112,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// In the slow path, we need to adjust i so that it is > 1<<63 which is always
// possible, except if i == 0, so we handle i == 0 separately.
if(i == 0) {
d = 0.0;
d = negative ? -0.0 : 0.0;
return true;
}
@@ -227,7 +227,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
if (simdjson_unlikely(real_exponent <= 0)) { // we have a subnormal?
// Here have that real_exponent <= 0 so -real_exponent >= 0
if(-real_exponent + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
d = 0.0;
d = negative ? -0.0 : 0.0;
return true;
}
// next line is safe because -real_exponent + 1 < 0
@@ -497,7 +497,8 @@ simdjson_inline error_code write_float(const uint8_t *const src, bool negative,
static_assert(simdjson::internal::smallest_power <= -342, "smallest_power is not small enough");
//
if((exponent < simdjson::internal::smallest_power) || (i == 0)) {
WRITE_DOUBLE(0, src, writer);
// E.g. Parse "-0.0e-999" into the same value as "-0.0". See https://en.wikipedia.org/wiki/Signed_zero
WRITE_DOUBLE(negative ? -0.0 : 0.0, src, writer);
return SUCCESS;
} else { // (exponent > largest_power) and (i != 0)
// We have, for sure, an infinite value and simdjson refuses to parse infinite values.
@@ -549,7 +550,7 @@ simdjson_inline error_code parse_number(const uint8_t *const src, W &writer) {
// Check for minus sign
//
bool negative = (*src == '-');
const uint8_t *p = src + negative;
const uint8_t *p = src + uint8_t(negative);
//
// Parse the integer part.
@@ -846,7 +847,7 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer(const uin
// Check for minus sign
//
bool negative = (*src == '-');
const uint8_t *p = src + negative;
const uint8_t *p = src + uint8_t(negative);
//
// Parse the integer part.
@@ -890,7 +891,7 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer(const uin
//
if(src == src_end) { return NUMBER_ERROR; }
bool negative = (*src == '-');
const uint8_t *p = src + negative;
const uint8_t *p = src + uint8_t(negative);
//
// Parse the integer part.
@@ -932,19 +933,19 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer_in_string
// Check for minus sign
//
bool negative = (*(src + 1) == '-');
const uint8_t *p = src + negative + 1;
src += uint8_t(negative) + 1;
//
// Parse the integer part.
//
// PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare
const uint8_t *const start_digits = p;
const uint8_t *const start_digits = src;
uint64_t i = 0;
while (parse_digit(*p, i)) { p++; }
while (parse_digit(*src, i)) { src++; }
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
// Optimization note: size_t is expected to be unsigned.
size_t digit_count = size_t(p - start_digits);
size_t digit_count = size_t(src - start_digits);
// We go from
// -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
// so we can never represent numbers that have more than 19 digits.
@@ -956,11 +957,11 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer_in_string
// Here digit_count > 0.
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
// We can do the following...
// if (!jsoncharutils::is_structural_or_whitespace(*p)) {
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
// if (!jsoncharutils::is_structural_or_whitespace(*src)) {
// return (*src == '.' || *src == 'e' || *src == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
// }
// as a single table lookup:
if(*p != '"') { return NUMBER_ERROR; }
if(*src != '"') { return NUMBER_ERROR; }
// Negative numbers have can go down to - INT64_MAX - 1 whereas positive numbers are limited to INT64_MAX.
// Performance note: This check is only needed when digit_count == longest_digit_count but it is
// so cheap that we might as well always make it.
@@ -973,7 +974,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
// Check for minus sign
//
bool negative = (*src == '-');
src += negative;
src += uint8_t(negative);
//
// Parse the integer part.
@@ -1040,7 +1041,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
if (simdjson_likely(!overflow)) {
if (compute_float_64(exponent, i, negative, d)) { return d; }
}
if (!parse_float_fallback(src-negative, &d)) {
if (!parse_float_fallback(src - uint8_t(negative), &d)) {
return NUMBER_ERROR;
}
return d;
@@ -1052,7 +1053,7 @@ simdjson_unused simdjson_inline bool is_negative(const uint8_t * src) noexcept {
simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept {
bool negative = (*src == '-');
src += negative;
src += uint8_t(negative);
const uint8_t *p = src;
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
if ( p == src ) { return NUMBER_ERROR; }
@@ -1062,7 +1063,7 @@ simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t *
simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept {
bool negative = (*src == '-');
src += negative;
src += uint8_t(negative);
const uint8_t *p = src;
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
if ( p == src ) { return NUMBER_ERROR; }
@@ -1092,7 +1093,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
// Check for minus sign
//
bool negative = (*src == '-');
src += negative;
src += uint8_t(negative);
//
// Parse the integer part.
@@ -1161,7 +1162,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
if (simdjson_likely(!overflow)) {
if (compute_float_64(exponent, i, negative, d)) { return d; }
}
if (!parse_float_fallback(src-negative, src_end, &d)) {
if (!parse_float_fallback(src - uint8_t(negative), src_end, &d)) {
return NUMBER_ERROR;
}
return d;
@@ -1172,7 +1173,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
// Check for minus sign
//
bool negative = (*(src + 1) == '-');
src += negative + 1;
src += uint8_t(negative) + 1;
//
// Parse the integer part.
@@ -1239,7 +1240,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
if (simdjson_likely(!overflow)) {
if (compute_float_64(exponent, i, negative, d)) { return d; }
}
if (!parse_float_fallback(src-negative, &d)) {
if (!parse_float_fallback(src - uint8_t(negative), &d)) {
return NUMBER_ERROR;
}
return d;
@@ -139,20 +139,14 @@ simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
auto a = get_array();
simdjson_result<size_t> answer = a.count_elements();
/* If there was an array, we are now left pointing at its first element. */
if(answer.error() == SUCCESS) {
iter._depth = 1 ; /* undoing the increment so we go back at the doc depth.*/
iter.assert_at_document_depth();
}
if(answer.error() == SUCCESS) { rewind(); }
return answer;
}
simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
auto a = get_object();
simdjson_result<size_t> answer = a.count_fields();
/* If there was an array, we are now left pointing at its first element. */
if(answer.error() == SUCCESS) {
iter._depth = 1 ; /* undoing the increment so we go back at the doc depth.*/
iter.assert_at_document_depth();
}
/* If there was an object, we are now left pointing at its first element. */
if(answer.error() == SUCCESS) { rewind(); }
return answer;
}
simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
@@ -154,6 +154,10 @@ simdjson_inline bool json_iterator::at_root() const noexcept {
return position() == root_position();
}
simdjson_inline bool json_iterator::is_single_token() const noexcept {
return parser->implementation->n_structural_indexes == 1;
}
simdjson_inline bool json_iterator::streaming() const noexcept {
return _streaming;
}
@@ -117,6 +117,14 @@ public:
*/
simdjson_inline const uint8_t *return_current_and_advance() noexcept;
/**
* Returns true if there is a single token in the index (i.e., it is
* a JSON with a scalar value such as a single number).
*
* @return whether there is a single token
*/
simdjson_inline bool is_single_token() const noexcept;
/**
* Assert that there are at least the given number of tokens left.
*
@@ -152,7 +152,7 @@ inline void log_line(const json_iterator &iter, token_position index, depth_t de
printf(" ");
}
// printf("| %5u ", *(index+1));
printf("| %5u ", depth);
printf("| %5i ", depth);
printf("| %.*s ", int(detail.size()), detail.data());
printf("|\n");
fflush(stdout);
@@ -166,6 +166,9 @@ public:
*
* To check that an object is empty, it is more performant to use
* the is_empty() method.
*
* Performance hint: You should only call count_fields() as a last
* resort as it may require scanning the document twice or more.
*/
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
/**
+7 -12
View File
@@ -8,15 +8,12 @@ simdjson_inline parser::parser(size_t max_capacity) noexcept
simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
if (new_capacity > max_capacity()) { return CAPACITY; }
if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
if (string_buf && new_capacity == capacity()) { return SUCCESS; }
// string_capacity copied from document::allocate
_capacity = 0;
size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
#if SIMDJSON_DEVELOPMENT_CHECKS
start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
#endif
if (implementation) {
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
@@ -24,7 +21,6 @@ simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capa
SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
}
_capacity = new_capacity;
_max_depth = new_max_depth;
return SUCCESS;
}
@@ -33,7 +29,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(p
// Allocate if needed
if (capacity() < json.length() || !string_buf) {
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
SIMDJSON_TRY( allocate(json.length()) );
}
// Run stage 1.
@@ -76,7 +72,7 @@ simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iter
// Allocate if needed
if (capacity() < json.length()) {
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
SIMDJSON_TRY( allocate(json.length()) );
}
// Run stage 1.
@@ -104,16 +100,15 @@ simdjson_inline size_t parser::capacity() const noexcept {
simdjson_inline size_t parser::max_capacity() const noexcept {
return _max_capacity;
}
// deprecated method
simdjson_inline size_t parser::max_depth() const noexcept {
return _max_depth;
return DEFAULT_MAX_DEPTH;
}
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
size_t MINIMAL_DOCUMENT_CAPACITY = 32;
if(max_capacity < MINIMAL_DOCUMENT_CAPACITY) {
if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
_max_capacity = max_capacity;
} else {
_max_capacity = MINIMAL_DOCUMENT_CAPACITY;
_max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
}
}
+2 -7
View File
@@ -230,15 +230,14 @@ public:
/** The maximum capacity of this parser (the largest document it is allowed to process). */
simdjson_inline size_t max_capacity() const noexcept;
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
/** The maximum depth of this parser (the most deeply nested objects and arrays it can process). */
/** Deprecated method. */
simdjson_inline size_t max_depth() const noexcept;
/**
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
* and `max_depth` depth.
*
* @param capacity The new capacity.
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH. (This parameter has no effect.)
* @return The error, if there is one.
*/
simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
@@ -278,11 +277,7 @@ private:
std::unique_ptr<internal::dom_parser_implementation> implementation{};
size_t _capacity{0};
size_t _max_capacity;
size_t _max_depth{DEFAULT_MAX_DEPTH};
std::unique_ptr<uint8_t[]> string_buf{};
#if SIMDJSON_DEVELOPMENT_CHECKS
std::unique_ptr<token_position[]> start_positions{};
#endif
friend class json_iterator;
friend class document_stream;
@@ -246,6 +246,9 @@ public:
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
* there is a missing comma), then an error is returned and it is no longer
* safe to continue.
*
* Performance hint: You should only call count_elements() as a last
* resort as it may require scanning the document twice or more.
*/
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
/**
@@ -261,6 +264,9 @@ public:
*
* To check that an object is empty, it is more performant to use
* the is_empty() method on the object instance.
*
* Performance hint: You should only call count_fields() as a last
* resort as it may require scanning the document twice or more.
*/
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
/**
@@ -547,10 +547,16 @@ simdjson_inline simdjson_result<bool> value_iterator::is_root_integer() noexcept
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) {
return false; // if there are more than 20 characters, it cannot be represented as an integer.
}
return numberparsing::is_integer(tmpbuf);
auto answer = numberparsing::is_integer(tmpbuf);
// If the parsing was a success, we must still check that it is
// a single scalar. Note that we parse first because of cases like '[]' where
// getting TRAILING_CONTENT is wrong.
if((answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
return answer;
}
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> value_iterator::get_root_number_type() noexcept {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
auto max_len = peek_start_length();
auto json = peek_root_scalar("number");
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/,
@@ -561,7 +567,12 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type>
logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
return NUMBER_ERROR;
}
return numberparsing::get_number_type(tmpbuf);
// If the parsing was a success, we must still check that it is
// a single scalar. Note that we parse first because of cases like '[]' where
// getting TRAILING_CONTENT is wrong.
auto answer = numberparsing::get_number_type(tmpbuf);
if((answer.error() == SUCCESS) && (!_json_iter->is_single_token())) { return TRAILING_CONTENT; }
return answer;
}
simdjson_inline simdjson_result<number> value_iterator::get_root_number() noexcept {
auto max_len = peek_start_length();
@@ -577,6 +588,7 @@ simdjson_inline simdjson_result<number> value_iterator::get_root_number() noexce
number num;
error_code error = numberparsing::parse_number(tmpbuf, num);
if(error) { return error; }
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("number");
return num;
}
@@ -596,7 +608,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::g
return NUMBER_ERROR;
}
auto result = numberparsing::parse_unsigned(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("uint64"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("uint64");
}
return result;
}
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string() noexcept {
@@ -608,7 +623,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::g
return NUMBER_ERROR;
}
auto result = numberparsing::parse_unsigned_in_string(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("uint64"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("uint64");
}
return result;
}
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64() noexcept {
@@ -621,7 +639,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::ge
}
auto result = numberparsing::parse_integer(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("int64"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("int64");
}
return result;
}
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string() noexcept {
@@ -634,7 +655,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::ge
}
auto result = numberparsing::parse_integer_in_string(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("int64"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("int64");
}
return result;
}
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double() noexcept {
@@ -649,7 +673,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
return NUMBER_ERROR;
}
auto result = numberparsing::parse_double(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("double"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("double");
}
return result;
}
@@ -665,7 +692,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
return NUMBER_ERROR;
}
auto result = numberparsing::parse_double_in_string(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("double"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("double");
}
return result;
}
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool() noexcept {
@@ -674,10 +704,15 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_r
uint8_t tmpbuf[5+1];
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); }
auto result = parse_bool(tmpbuf);
if(result.error() == SUCCESS) { advance_root_scalar("bool"); }
if(result.error() == SUCCESS) {
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("bool");
}
return result;
}
simdjson_inline bool value_iterator::is_root_null() noexcept {
// If there is trailing content, then the document is not null.
if (!_json_iter->is_single_token()) { return false; }
auto max_len = peek_start_length();
auto json = peek_root_scalar("null");
bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
+5 -6
View File
@@ -57,7 +57,7 @@ public:
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64".
*/
virtual const std::string &name() const { return _name; }
@@ -67,7 +67,7 @@ public:
* const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl;
*
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
* @return the description of the implementation, e.g. "Intel/AMD AVX2", "Intel/AMD SSE4.2", "ARM NEON".
*/
virtual const std::string &description() const { return _description; }
@@ -76,8 +76,7 @@ public:
* and the current CPU match. This function may poll the current CPU/system
* and should therefore not be called too often if performance is a concern.
*
*
* @return true if the implementation can be safely used on the current system (determined at runtime)
* @return true if the implementation can be safely used on the current system (determined at runtime).
*/
bool supported_by_runtime_system() const;
@@ -86,7 +85,7 @@ public:
*
* The instruction sets this implementation is compiled against.
*
* @return a mask of all required `internal::instruction_set::` values
* @return a mask of all required `internal::instruction_set::` values.
*/
virtual uint32_t required_instruction_sets() const { return _required_instruction_sets; };
@@ -99,7 +98,7 @@ public:
* @param capacity The largest document that will be passed to the parser.
* @param max_depth The maximum JSON object/array nesting this parser is expected to handle.
* @param dst The place to put the resulting parser implementation.
* @return the name of the implementation, e.g. "haswell", "westmere", "arm64"
* @return the error code, or SUCCESS if there was no error.
*/
virtual error_code create_dom_parser_implementation(
size_t capacity,
+1 -1
View File
@@ -115,7 +115,7 @@ constexpr uint32_t cpuid_avx512pf_bit = 1 << 26; ///< @private bit 26 of EBX
constexpr uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512cd_bit = 1 << 28; ///< @private bit 28 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512bw_bit = 1 << 30; ///< @private bit 30 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512vl_bit = 1 << 31; ///< @private bit 31 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512vl_bit = 1U << 31; ///< @private bit 31 of EBX for EAX=0x7
constexpr uint32_t cpuid_avx512vbmi2_bit = 1 << 6; ///< @private bit 6 of ECX for EAX=0x7
constexpr uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1
constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
+8 -2
View File
@@ -45,7 +45,7 @@ inline char *allocate_padded_buffer(size_t length) noexcept {
} // namespace internal
inline padded_string::padded_string() noexcept {}
inline padded_string::padded_string() noexcept = default;
inline padded_string::padded_string(size_t length) noexcept
: viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) {
}
@@ -127,7 +127,13 @@ inline simdjson_result<padded_string> padded_string::load(std::string_view filen
}
// Get the file size
if(std::fseek(fp, 0, SEEK_END) < 0) {
int ret;
#if defined(SIMDJSON_VISUAL_STUDIO) && !SIMDJSON_IS_32BITS
ret = _fseeki64(fp, 0, SEEK_END);
#else
ret = std::fseek(fp, 0, SEEK_END);
#endif // _WIN64
if(ret < 0) {
std::fclose(fp);
return IO_ERROR;
}
+2 -2
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 2.2.1
#define SIMDJSON_VERSION 2.2.3
namespace simdjson {
enum {
@@ -19,7 +19,7 @@ enum {
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 1
SIMDJSON_VERSION_REVISION = 3
};
} // namespace simdjson
+11
View File
@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=@PKGCONFIG_INCLUDEDIR@
libdir=@PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Cflags: -I${includedir} @PKGCONFIG_CFLAGS@
Libs: -L${libdir} -l@PROJECT_NAME@
@PKGCONFIG_LIBS_PRIVATE@
+135 -88
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2022-07-19 16:40:02 -0400. Do not edit! */
/* auto-generated on 2022-10-02 16:25:39 -0400. Do not edit! */
/* begin file src/simdjson.cpp */
#include "simdjson.h"
@@ -1589,7 +1589,8 @@ namespace internal {
{ INSUFFICIENT_PADDING, "simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
{ INCOMPLETE_ARRAY_OR_OBJECT, "JSON document ended early in the middle of an object or array." },
{ SCALAR_DOCUMENT_AS_VALUE, "A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
{ OUT_OF_BOUNDS, "Attempted to access location outside of document."}
{ OUT_OF_BOUNDS, "Attempted to access location outside of document."},
{ TRAILING_CONTENT, "Unexpected trailing content in the JSON input."}
}; // error_messages[]
} // namespace internal
@@ -3105,6 +3106,14 @@ using namespace simd;
this->error |= this->prev_incomplete;
}
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete;
@@ -3114,12 +3123,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -3497,7 +3506,7 @@ private:
*/
class json_scanner {
public:
json_scanner() {}
json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish();
@@ -4183,30 +4192,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
@@ -5659,30 +5669,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
@@ -6887,6 +6898,14 @@ using namespace simd;
this->error |= this->prev_incomplete;
}
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete;
@@ -6896,12 +6915,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -7281,7 +7300,7 @@ private:
*/
class json_scanner {
public:
json_scanner() {}
json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish();
@@ -8013,30 +8032,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
@@ -9272,6 +9292,14 @@ using namespace simd;
this->error |= this->prev_incomplete;
}
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete;
@@ -9281,12 +9309,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -9664,7 +9692,7 @@ private:
*/
class json_scanner {
public:
json_scanner() {}
json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish();
@@ -10349,30 +10377,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
@@ -11571,6 +11600,14 @@ using namespace simd;
this->error |= this->prev_incomplete;
}
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete;
@@ -11580,12 +11617,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -11963,7 +12000,7 @@ private:
*/
class json_scanner {
public:
json_scanner() {}
json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish();
@@ -12648,30 +12685,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
@@ -13905,6 +13943,14 @@ using namespace simd;
this->error |= this->prev_incomplete;
}
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete;
@@ -13914,12 +13960,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -14297,7 +14343,7 @@ private:
*/
class json_scanner {
public:
json_scanner() {}
json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish();
@@ -14982,30 +15028,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
+229 -162
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -96,7 +96,7 @@ private:
*/
class json_scanner {
public:
json_scanner() {}
json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish();
+11 -3
View File
@@ -162,6 +162,14 @@ using namespace simd;
this->error |= this->prev_incomplete;
}
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete;
@@ -171,12 +179,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block.");
if(simd8x64<uint8_t>::NUM_CHUNKS == 1) {
SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 1) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
} if(simd8x64<uint8_t>::NUM_CHUNKS == 2) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 2) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
} else if(simd8x64<uint8_t>::NUM_CHUNKS == 4) {
} else SIMDJSON_IF_CONSTEXPR (simd8x64<uint8_t>::NUM_CHUNKS == 4) {
this->check_utf8_bytes(input.chunks[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
+12 -11
View File
@@ -47,30 +47,31 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// multilingual plane check
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
*src_ptr += 6;
if (code_point >= 0xd800 && code_point < 0xdc00) {
}
// If we found a high surrogate, we must
// check for low surrogate for characters
// outside the Basic
// Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) {
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
const uint8_t *src_data = *src_ptr;
/* Compiler optimizations convert this to a single 16-bit load and compare on most platforms */
if (((src_data[0] << 8) | src_data[1]) != ((static_cast<uint8_t> ('\\') << 8) | static_cast<uint8_t> ('u'))) {
return false;
}
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(src_data + 2);
// if the first code point is invalid we will get here, as we will go past
// the check for being outside the Basic Multilingual plane. If we don't
// find a \u immediately afterwards we fail out anyhow, but if we do,
// this check catches both the case of the first code point being invalid
// or the second code point being invalid.
if ((code_point | code_point_2) >> 16) {
// We have already checked that the high surrogate is valid and
// (code_point - 0xd800) < 1024.
//
// Check that code_point_2 is in the range 0xdc00..0xdfff
// and that code_point_2 was parsed from valid hex.
uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false;
}
code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
(((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate)
+2 -1
View File
@@ -33,7 +33,8 @@ namespace internal {
{ INSUFFICIENT_PADDING, "simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." },
{ INCOMPLETE_ARRAY_OR_OBJECT, "JSON document ended early in the middle of an object or array." },
{ SCALAR_DOCUMENT_AS_VALUE, "A JSON document made of a scalar (number, Boolean, null or string) is treated as a value. Use get_bool(), get_double(), etc. on the document instead. "},
{ OUT_OF_BOUNDS, "Attempted to access location outside of document."}
{ OUT_OF_BOUNDS, "Attempted to access location outside of document."},
{ TRAILING_CONTENT, "Unexpected trailing content in the JSON input."}
}; // error_messages[]
} // namespace internal
+70 -2
View File
@@ -221,6 +221,64 @@ namespace number_tests {
std::vector<char> buf(1024);
simdjson::dom::parser parser;
bool is_pow_correct{1e-308 == std::pow(10,-308)};
int start_point = is_pow_correct ? -1000 : -307;
if(!is_pow_correct) {
std::cout << "On your system, the pow function is busted. Sorry about that. " << std::endl;
}
for (int i = start_point; i <= 308; ++i) {// large negative values should be zero.
size_t n = snprintf(buf.data(), buf.size(), "1e%d", i);
if (n >= buf.size()) { abort(); }
double actual;
auto error = parser.parse(buf.data(), n).get(actual);
if (error) { std::cerr << error << std::endl; return false; }
double expected = ((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i));
// In floating-point arithmetic, -0.0 == 0.0, so compare signs by checking the inverse of the numbers as well
if(actual!=expected || (actual == 0.0 && 1.0/actual!=1.0/expected)) {
std::cerr << "JSON '" << buf.data() << " parsed to ";
fprintf( stderr," %18.18g instead of %18.18g\n", actual, expected); // formatting numbers is easier with printf
SIMDJSON_SHOW_DEFINE(FLT_EVAL_METHOD);
return false;
}
}
printf("Powers of 10 can be parsed.\n");
return true;
}
bool negative_powers_of_ten() {
std::cout << __func__ << std::endl;
std::vector<char> buf(1024);
simdjson::dom::parser parser;
bool is_pow_correct{-1e-308 == -std::pow(10,-308)};
int start_point = is_pow_correct ? -1000 : -307;
if(!is_pow_correct) {
std::cout << "On your system, the pow function is busted. Sorry about that. " << std::endl;
}
for (int i = start_point; i <= 308; ++i) {// large negative values should be zero.
size_t n = snprintf(buf.data(), buf.size(), "-1e%d", i);
if (n >= buf.size()) { abort(); }
double actual;
auto error = parser.parse(buf.data(), n).get(actual);
if (error) { std::cerr << error << std::endl; return false; }
double expected = -(((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i)));
// In floating-point arithmetic, -0.0 == 0.0, so compare signs by checking the inverse of the numbers as well
if(actual!=expected || (actual == 0.0 && 1.0/actual!=1.0/expected)) {
std::cerr << "JSON '" << buf.data() << " parsed to ";
fprintf( stderr," %18.18g instead of %18.18g\n", actual, expected); // formatting numbers is easier with printf
SIMDJSON_SHOW_DEFINE(FLT_EVAL_METHOD);
return false;
}
}
printf("Negative values of powers of 10 can be parsed.\n");
return true;
}
bool signed_zero_underflow_exponent() {
std::cout << __func__ << std::endl;
std::vector<char> buf(1024);
simdjson::dom::parser parser;
bool is_pow_correct{1e-308 == std::pow(10,-308)};
int start_point = is_pow_correct ? -1000 : -307;
if(!is_pow_correct) {
@@ -269,6 +327,13 @@ namespace number_tests {
std::cerr << error << std::endl;
return false;
}
if(std::signbit(actual) != std::signbit(val)) {
std::cerr << std::hexfloat << actual << " but I was expecting " << val
<< std::endl;
std::cerr << "string: " << vals << std::endl;
std::cout << std::dec;
return false;
}
if (actual != val) {
std::cerr << std::hexfloat << actual << " but I was expecting " << val
<< std::endl;
@@ -284,16 +349,18 @@ namespace number_tests {
std::cout << std::dec;
return true;
}
bool truncated_borderline() {
std::cout << __func__ << std::endl;
std::string round_to_even = "9007199254740993.0";
for(size_t i = 0; i < 1000; i++) { round_to_even += "0"; }
return basic_test_64bit(round_to_even,9007199254740992);
return basic_test_64bit(round_to_even, 9007199254740992);
}
bool specific_tests() {
std::cout << __func__ << std::endl;
return basic_test_64bit("-2402844368454405395.2",-2402844368454405395.2) &&
return basic_test_64bit("-1e-999", -0.0) &&
basic_test_64bit("-2402844368454405395.2",-2402844368454405395.2) &&
basic_test_64bit("4503599627370496.5", 4503599627370496.5) &&
basic_test_64bit("4503599627475352.5", 4503599627475352.5) &&
basic_test_64bit("4503599627475353.5", 4503599627475353.5) &&
@@ -315,6 +382,7 @@ namespace number_tests {
small_integers() &&
powers_of_two() &&
powers_of_ten() &&
negative_powers_of_ten() &&
nines();
}
}
+4
View File
@@ -732,6 +732,10 @@ namespace document_stream_tests {
}
count++;
}
if(count != 1) {
std::cerr << "bad count" << std::endl;
return false;
}
#endif
return true;
}
+21
View File
@@ -128,6 +128,26 @@ namespace array_tests {
TEST_SUCCEED();
}
bool issue1876() {
TEST_START();
auto json = R"( [] )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
size_t count;
ASSERT_SUCCESS(doc.count_elements().get(count));
ondemand::array arr;
ASSERT_SUCCESS(doc.get_array().get(arr));
ASSERT_EQUAL(count, 0);
for (auto element : arr) {
double value;
ASSERT_SUCCESS(element.get_double().get(value));
std::cout << value << std::endl;
}
TEST_SUCCEED();
}
bool iterate_complex_array_count() {
TEST_START();
ondemand::parser parser;
@@ -810,6 +830,7 @@ namespace array_tests {
bool run() {
return
issue1876() &&
issue1742() &&
empty_rewind_convoluted() &&
empty_rewind() &&
+39
View File
@@ -63,6 +63,42 @@ namespace misc_tests {
TEST_SUCCEED();
}
// Test a surrogate pair with the low surrogate out of range
bool issue1894() {
TEST_START();
ondemand::parser parser;
auto json = R"("\uD888\u1234")"_padded;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
std::string_view view;
ASSERT_ERROR(doc.get_string().get(view), STRING_ERROR);
TEST_SUCCEED();
}
bool issue1894toolarge() {
TEST_START();
ondemand::parser parser;
auto json = R"("\uD888\uE000")"_padded;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
std::string_view view;
ASSERT_ERROR(doc.get_string().get(view), STRING_ERROR);
TEST_SUCCEED();
}
// Test the smallest surrogate pair, largest surrogate pair, and a surrogate pair in range.
bool issue1894success() {
TEST_START();
ondemand::parser parser;
auto json = R"("\uD888\uDC00\uD800\uDC00\uDBFF\uDFFF")"_padded;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
std::string_view view;
ASSERT_SUCCESS(doc.get_string().get(view));
ASSERT_EQUAL(view, "\xf0\xb2\x80\x80\xf0\x90\x80\x80\xf4\x8f\xbf\xbf");
TEST_SUCCEED();
}
bool issue1660() {
TEST_START();
ondemand::parser parser;
@@ -459,6 +495,9 @@ namespace misc_tests {
bool run() {
return
issue1870() &&
issue1894() &&
issue1894toolarge() &&
issue1894success() &&
is_alive_root_array() &&
is_alive_root_object() &&
is_alive_array() &&
+72 -1
View File
@@ -170,6 +170,20 @@ namespace number_tests {
simdjson_unused auto blah2=blah.get(x);
}
bool issue_1898() {
TEST_START();
padded_string negative_zero_string(std::string_view("-1e-999"));
simdjson::ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(negative_zero_string).get(doc));
double x;
ASSERT_SUCCESS(doc.get(x));
// should be minus 0
ASSERT_TRUE(std::signbit(x));
ASSERT_TRUE(x == -0);
TEST_SUCCEED();
}
bool old_crashes() {
TEST_START();
github_issue_1273();
@@ -264,6 +278,61 @@ namespace number_tests {
TEST_SUCCEED();
}
bool issue1878() {
TEST_START();
ondemand::parser parser;
auto json = R"(123_abc)"_padded;
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_int64().error(), NUMBER_ERROR);
}
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_int64().error(), TRAILING_CONTENT);
}
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_uint64().error(), NUMBER_ERROR);
}
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_uint64().error(), TRAILING_CONTENT);
}
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_double().error(), NUMBER_ERROR);
}
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_double().error(), TRAILING_CONTENT);
}
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_number().error(), NUMBER_ERROR);
}
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
json.data()[3] = ch;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ASSERT_ERROR(doc.get_number().error(), TRAILING_CONTENT);
}
TEST_SUCCEED();
}
bool get_root_number_tests() {
TEST_START();
ondemand::parser parser;
@@ -321,7 +390,9 @@ namespace number_tests {
TEST_SUCCEED();
}
bool run() {
return get_root_number_tests() &&
return issue_1898() &&
issue1878() &&
get_root_number_tests() &&
get_number_tests()&&
small_integers() &&
powers_of_two() &&
+45
View File
@@ -896,6 +896,49 @@ namespace object_tests {
TEST_SUCCEED();
}
bool issue1876a() {
TEST_START();
auto json = R"( {} )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
ondemand::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
size_t count;
ASSERT_SUCCESS(obj.count_fields().get(count));
ASSERT_EQUAL(count, 0);
for (auto field : obj) {
std::string_view key;
ASSERT_SUCCESS(field.unescaped_key().get(key));
double value;
ASSERT_SUCCESS(field.value().get_double().get(value));
std::cout << key << " " << value << std::endl;
}
TEST_SUCCEED();
}
bool issue1876() {
TEST_START();
auto json = R"( {} )"_padded;
ondemand::parser parser;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(json).get(doc));
size_t count;
ASSERT_SUCCESS(doc.count_fields().get(count));
ondemand::object obj;
ASSERT_SUCCESS(doc.get_object().get(obj));
ASSERT_EQUAL(count, 0);
for (auto field : obj) {
std::string_view key;
ASSERT_SUCCESS(field.unescaped_key().get(key));
double value;
ASSERT_SUCCESS(field.value().get_double().get(value));
std::cout << key << " " << value << std::endl;
}
TEST_SUCCEED();
}
bool issue1742() {
TEST_START();
auto json = R"( {
@@ -1178,6 +1221,8 @@ namespace object_tests {
bool run() {
return
issue1876a() &&
issue1876() &&
test_strager() &&
issue1745() &&
issue1742() &&