mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d2455029d | |||
| e94f027310 | |||
| 2b766e4c09 | |||
| a5db75e1a6 | |||
| 4bd66cb891 | |||
| 960a7ebba1 | |||
| d520062f8e | |||
| db08d78ed0 | |||
| 46292b8d4b | |||
| 46241287c6 | |||
| 137cb14bcc | |||
| 5e6be3ed7a | |||
| c6ab52eebb | |||
| a1aab1fafe | |||
| b92cbbe280 | |||
| 6d2a09f8e5 | |||
| 00564bf7d5 | |||
| 5809e51ae4 | |||
| d27e7cce71 | |||
| f7dc03f93d | |||
| d4ac1b51d0 | |||
| 6a4222da71 | |||
| bba88eb5e5 | |||
| 16b3816455 | |||
| e5a408386b | |||
| e65f28e61a | |||
| fbb46b99e2 | |||
| 933c2ebeac | |||
| db3e813aa6 | |||
| 9c95a48fe6 | |||
| cb20f7e7df | |||
| 18b9168eec |
@@ -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
|
||||
@@ -78,6 +78,7 @@
|
||||
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.editorconfig export-ignore
|
||||
|
||||
# Sources
|
||||
*.c text eol=lf diff=c
|
||||
|
||||
@@ -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)
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Macos (Xcode 11)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
macos-build:
|
||||
if: >-
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
|
||||
! contains(toJSON(github.event.commits.*.message), '[skip github]')
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: dependencies/.cache
|
||||
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
|
||||
- name: Use cmake
|
||||
run: |
|
||||
xcversion select 11.7
|
||||
mkdir builddebug &&
|
||||
cd builddebug &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
cd .. &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||
cmake --build . &&
|
||||
ctest -j --output-on-failure -LE explicitonly &&
|
||||
cmake --install . &&
|
||||
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
|
||||
cd ../tests/installation_tests/find &&
|
||||
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
|
||||
+21
-3
@@ -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 3.0.1
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,8 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "13.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "13" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "14.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "14" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 = "3.0.1"
|
||||
|
||||
# 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
@@ -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.**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[/badge.svg)](https://simdjson.org/plots.html)
|
||||

|
||||

|
||||
[![][license img]][license] [](https://simdjson.org/api/2.0.0/index.html)
|
||||
[![][license img]][license] [](https://simdjson.org/api/3.0.0/index.html)
|
||||
|
||||
simdjson : Parsing gigabytes of JSON per second
|
||||
===============================================
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,7 @@ private:
|
||||
simdjson_inline void
|
||||
write_raw_string(simdjson::ondemand::raw_json_string rjs);
|
||||
inline void recursive_processor(simdjson::ondemand::value element);
|
||||
inline void recursive_processor_ref(simdjson::ondemand::value& element);
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
uint8_t *buff{};
|
||||
@@ -74,17 +75,34 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
write_byte(0xc2 + doc.get_bool());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::null:
|
||||
write_byte(0xc0);
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(doc.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
case simdjson::ondemand::json_type::array:
|
||||
case simdjson::ondemand::json_type::object:
|
||||
default:
|
||||
// impossible
|
||||
break;
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
simdjson::ondemand::value val = doc;
|
||||
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
|
||||
#if SIMDJSON_GCC_COMPILER
|
||||
// the GCC compiler does well with by-value passing.
|
||||
// GCC has superior recursive inlining:
|
||||
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
|
||||
// https://godbolt.org/z/TeK4doE51
|
||||
recursive_processor(val);
|
||||
#else
|
||||
recursive_processor_ref(val);
|
||||
#endif
|
||||
}
|
||||
if (doc.current_location().error() == simdjson::SUCCESS) {
|
||||
// Example of error detection - this won't be reached on twitter.json in the benchmark.
|
||||
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
|
||||
}
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
@@ -156,7 +174,58 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::null:
|
||||
write_byte(0xc0);
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdd);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto child : element.get_array()) {
|
||||
counter++;
|
||||
simdjson::ondemand::value v = child.value();
|
||||
recursive_processor_ref(v);
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::ondemand::json_type::object: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdf);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto field : element.get_object()) {
|
||||
counter++;
|
||||
write_raw_string(field.key());
|
||||
simdjson::ondemand::value v = field.value();
|
||||
recursive_processor_ref(v);
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::ondemand::json_type::number:
|
||||
write_double(element.get_double());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::string:
|
||||
write_raw_string(element.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::boolean:
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 Python’s 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()
|
||||
Vendored
+2
-2
@@ -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)
|
||||
|
||||
+47
-13
@@ -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;
|
||||
@@ -480,8 +482,20 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2"
|
||||
```
|
||||
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
|
||||
with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the `type()` method. You can also represent arbitrary JSON values with
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You may also access [raw strings](#raw-strings).
|
||||
with a known type, and are trying to generically inspect or walk over JSON elements.
|
||||
You can also represent arbitrary JSON values with
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
|
||||
You can query the type of a document or a value with the `type()` method.
|
||||
The `type()` method does not consume or validate documents and values, but it tells you whether they are
|
||||
- arrays (`json_type::array`),
|
||||
- objects (`json_type::object`)
|
||||
- numbers (`json_type::number`),
|
||||
- strings (`json_type::string`),
|
||||
- Booleans (`json_type::boolean`),
|
||||
- null (`json_type::null`).
|
||||
|
||||
You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`.
|
||||
You may also access [raw strings](#raw-strings).
|
||||
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
|
||||
```c++
|
||||
void recursive_print_json(ondemand::value element) {
|
||||
@@ -530,7 +544,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
cout << element.get_bool();
|
||||
break;
|
||||
case ondemand::json_type::null:
|
||||
cout << "null";
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
cout << "null";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -929,11 +947,11 @@ bool parse() {
|
||||
// Iterating through an array of objects
|
||||
auto error = parser.iterate(cars_json).get(doc);
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
ondemand::array cars;
|
||||
ondemand::array cars; // invalid until the get() succeeds
|
||||
error = doc.get_array().get(cars);
|
||||
|
||||
for (auto car_value : cars) {
|
||||
ondemand::object car;
|
||||
ondemand::object car; // invalid until the get() succeeds
|
||||
error = car_value.get_object().get(car);
|
||||
if(error) { std::cerr << error << std::endl; return false; }
|
||||
|
||||
@@ -970,6 +988,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; // invalid until the get() succeeds
|
||||
// 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.
|
||||
@@ -979,7 +1010,7 @@ having to handle exceptions.
|
||||
ondemand::document doc;
|
||||
auto error = parser.iterate(json).get(doc);
|
||||
if(error) { return false; }
|
||||
ondemand::object object;
|
||||
ondemand::object object; // invalid until the get() succeeds
|
||||
error = doc.get_object().get(object);
|
||||
if(error) { return false; }
|
||||
for(auto field : object) {
|
||||
@@ -1008,7 +1039,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
|
||||
@@ -1095,6 +1126,9 @@ for (auto val : doc) {
|
||||
std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS
|
||||
```
|
||||
|
||||
Conversely, if `doc.current_location().error() == simdjson::SUCCESS`,
|
||||
then the document has more content.
|
||||
|
||||
Finally, the `current_location()` method may also be used even when no exceptions/errors
|
||||
are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example:
|
||||
|
||||
@@ -1103,7 +1137,7 @@ auto json = R"( [[1,2,3], -23.4, {"key": "value"}, true] )"_padded;
|
||||
ondemand::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto val : doc) {
|
||||
ondemand::object obj;
|
||||
ondemand::object obj; // invalid until the get() succeeds
|
||||
auto error = val.get_object().get(obj); // Only get objects
|
||||
if (!error) {
|
||||
std::cout << doc.current_location() << std::endl; // Prints ""key": "value"}, true] "
|
||||
@@ -1516,7 +1550,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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
|
||||
|
||||
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
|
||||
* parse_many: https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
|
||||
* iterate_many: https://github.com/simdjson/simdjson/blob/master/doc/iterate_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
|
||||
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
|
||||
|
||||
+9
-9
@@ -47,7 +47,7 @@ dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padde
|
||||
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
|
||||
You cannot copy a `parser` instance, you may only move it.
|
||||
|
||||
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
|
||||
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. The `element`, `object` or `array` instances are mere thin wrappers akin to an `std::vector<int>::iterator`: they are invalid when default constructed, they must be tied to a valid document instance. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
|
||||
|
||||
During the`load` or `parse` calls, neither the input file nor the input string are ever modified. After calling `load` or `parse`, the source (either a file or a string) can be safely discarded. All of the JSON data is stored in the `parser` instance. The parsed document is also immutable in simdjson: you do not modify it by accessing it.
|
||||
|
||||
@@ -167,7 +167,7 @@ While the simdjson library can be used in any project using C++ 11 and above, fi
|
||||
```c++
|
||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||
dom::parser parser;
|
||||
dom::object object;
|
||||
dom::object object; // invalid until the get() succeeds
|
||||
auto error = parser.parse(json).get(object);
|
||||
if (error) { cerr << error << endl; return; }
|
||||
for (auto [key, value] : object) {
|
||||
@@ -181,7 +181,7 @@ For comparison, here is the C++ 11 version of the same code:
|
||||
// C++ 11 version for comparison
|
||||
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
|
||||
dom::parser parser;
|
||||
dom::object object;
|
||||
dom::object object; // invalid until the get() succeeds
|
||||
auto error = parser.parse(json).get(object);
|
||||
if (error) { cerr << error << endl; return; }
|
||||
for (dom::key_value_pair field : object) {
|
||||
@@ -227,7 +227,7 @@ dom::parser parser;
|
||||
dom::element cars = parser.parse(cars_json);
|
||||
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
|
||||
for (dom::element car_element : cars) {
|
||||
dom::object car;
|
||||
dom::object car; // invalid until the get() succeeds
|
||||
simdjson::error_code error;
|
||||
if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
|
||||
double x = car.at_pointer("/tire_pressure/1");
|
||||
@@ -283,11 +283,11 @@ it selects the key "count" within that object.
|
||||
|
||||
int main(void) {
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element tweets;
|
||||
simdjson::dom::element tweets; // invalid until the get() succeeds
|
||||
auto error = parser.load("twitter.json").get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
simdjson::dom::element res;
|
||||
simdjson::dom::element res; // invalid until the get() succeeds
|
||||
if ((error = tweets["search_metadata"]["count"].get(res))) {
|
||||
std::cerr << "could not access keys" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
@@ -311,7 +311,7 @@ Observe how we use the `at` method when querying an index into an array, and not
|
||||
|
||||
int main(void) {
|
||||
simdjson::dom::parser parser;
|
||||
simdjson::dom::element tweets;
|
||||
simdjson::dom::element tweets; // invalid until the get() succeeds
|
||||
auto error = parser.load("twitter.json").get(tweets);
|
||||
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
uint64_t identifier;
|
||||
@@ -336,7 +336,7 @@ auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::array cars;
|
||||
dom::array cars; // invalid until the get() succeeds
|
||||
auto error = parser.parse(cars_json).get(cars);
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
|
||||
@@ -382,7 +382,7 @@ auto abstract_json = R"( [
|
||||
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
|
||||
] )"_padded;
|
||||
dom::parser parser;
|
||||
dom::array array;
|
||||
dom::array array; // invalid until after the next line
|
||||
auto error = parser.parse(abstract_json).get(array);
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
// Iterate through an array of objects
|
||||
|
||||
@@ -322,4 +322,11 @@ namespace std {
|
||||
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
||||
#endif // simdjson_fallthrough
|
||||
|
||||
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
|
||||
#else
|
||||
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif // SIMDJSON_COMMON_DEFS_H
|
||||
|
||||
@@ -53,18 +53,23 @@ namespace dom {
|
||||
simdjson_inline array::array() noexcept : tape{} {}
|
||||
simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
|
||||
inline array::iterator array::begin() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return internal::tape_ref(tape.doc, tape.json_index + 1);
|
||||
}
|
||||
inline array::iterator array::end() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return internal::tape_ref(tape.doc, tape.after_element() - 1);
|
||||
}
|
||||
inline size_t array::size() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return tape.scope_count();
|
||||
}
|
||||
inline size_t array::number_of_slots() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return tape.matching_brace_index() - tape.json_index;
|
||||
}
|
||||
inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
if(json_pointer.empty()) { // an empty string means that we return the current node
|
||||
return element(this->tape); // copy the current node
|
||||
} else if(json_pointer[0] != '/') { // otherwise there is an error
|
||||
@@ -105,6 +110,7 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
|
||||
}
|
||||
|
||||
inline simdjson_result<element> array::at(size_t index) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
size_t i=0;
|
||||
for (auto element : *this) {
|
||||
if (i == index) { return element; }
|
||||
|
||||
@@ -186,11 +186,13 @@ simdjson_inline element::element() noexcept : tape{} {}
|
||||
simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
|
||||
|
||||
inline element_type element::type() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
auto tape_type = tape.tape_ref_type();
|
||||
return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> element::get_bool() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
if(tape.is_true()) {
|
||||
return true;
|
||||
} else if(tape.is_false()) {
|
||||
@@ -199,6 +201,7 @@ inline simdjson_result<bool> element::get_bool() const noexcept {
|
||||
return INCORRECT_TYPE;
|
||||
}
|
||||
inline simdjson_result<const char *> element::get_c_str() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::STRING: {
|
||||
return tape.get_c_str();
|
||||
@@ -208,6 +211,7 @@ inline simdjson_result<const char *> element::get_c_str() const noexcept {
|
||||
}
|
||||
}
|
||||
inline simdjson_result<size_t> element::get_string_length() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::STRING: {
|
||||
return tape.get_string_length();
|
||||
@@ -217,6 +221,7 @@ inline simdjson_result<size_t> element::get_string_length() const noexcept {
|
||||
}
|
||||
}
|
||||
inline simdjson_result<std::string_view> element::get_string() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::STRING:
|
||||
return tape.get_string_view();
|
||||
@@ -225,6 +230,7 @@ inline simdjson_result<std::string_view> element::get_string() const noexcept {
|
||||
}
|
||||
}
|
||||
inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
|
||||
if(tape.is_int64()) {
|
||||
int64_t result = tape.next_tape_value<int64_t>();
|
||||
@@ -238,6 +244,7 @@ inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
|
||||
return tape.next_tape_value<int64_t>();
|
||||
}
|
||||
inline simdjson_result<int64_t> element::get_int64() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
|
||||
if(tape.is_uint64()) {
|
||||
uint64_t result = tape.next_tape_value<uint64_t>();
|
||||
@@ -252,6 +259,7 @@ inline simdjson_result<int64_t> element::get_int64() const noexcept {
|
||||
return tape.next_tape_value<int64_t>();
|
||||
}
|
||||
inline simdjson_result<double> element::get_double() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
// Performance considerations:
|
||||
// 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
|
||||
// comparison.
|
||||
@@ -273,6 +281,7 @@ inline simdjson_result<double> element::get_double() const noexcept {
|
||||
return tape.next_tape_value<double>();
|
||||
}
|
||||
inline simdjson_result<array> element::get_array() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::START_ARRAY:
|
||||
return array(tape);
|
||||
@@ -281,6 +290,7 @@ inline simdjson_result<array> element::get_array() const noexcept {
|
||||
}
|
||||
}
|
||||
inline simdjson_result<object> element::get_object() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::START_OBJECT:
|
||||
return object(tape);
|
||||
@@ -360,6 +370,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
|
||||
}
|
||||
|
||||
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
switch (tape.tape_ref_type()) {
|
||||
case internal::tape_type::START_OBJECT:
|
||||
return object(tape).at_pointer(json_pointer);
|
||||
@@ -395,6 +406,7 @@ inline simdjson_result<element> element::at_key_case_insensitive(std::string_vie
|
||||
}
|
||||
|
||||
inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return tape.doc->dump_raw_tape(out);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,12 +65,15 @@ namespace dom {
|
||||
simdjson_inline object::object() noexcept : tape{} {}
|
||||
simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
|
||||
inline object::iterator object::begin() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return internal::tape_ref(tape.doc, tape.json_index + 1);
|
||||
}
|
||||
inline object::iterator object::end() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return internal::tape_ref(tape.doc, tape.after_element() - 1);
|
||||
}
|
||||
inline size_t object::size() const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
return tape.scope_count();
|
||||
}
|
||||
|
||||
@@ -81,6 +84,7 @@ inline simdjson_result<element> object::operator[](const char *key) const noexce
|
||||
return at_key(key);
|
||||
}
|
||||
inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
|
||||
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
|
||||
if(json_pointer.empty()) { // an empty string means that we return the current node
|
||||
return element(this->tape); // copy the current node
|
||||
} else if(json_pointer[0] != '/') { // otherwise there is an error
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -142,6 +148,9 @@ simdjson_inline simdjson_result<element> parser::parse(const std::string &s) & n
|
||||
simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
|
||||
return parse(s.data(), s.length(), false);
|
||||
}
|
||||
simdjson_inline simdjson_result<element> parser::parse(const padded_string_view &v) & noexcept {
|
||||
return parse(v.data(), v.length(), false);
|
||||
}
|
||||
|
||||
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
|
||||
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
|
||||
|
||||
@@ -199,6 +199,9 @@ public:
|
||||
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||
simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
|
||||
simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete;
|
||||
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
|
||||
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) & noexcept;
|
||||
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) && =delete;
|
||||
|
||||
/** @private We do not want to allow implicit conversion from C string to std::string. */
|
||||
simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -94,7 +94,7 @@ simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string()
|
||||
simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
|
||||
return get_root_value_iterator().get_root_bool();
|
||||
}
|
||||
simdjson_inline bool document::is_null() noexcept {
|
||||
simdjson_inline simdjson_result<bool> document::is_null() noexcept {
|
||||
return get_root_value_iterator().is_root_null();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -360,7 +354,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
||||
if (error()) { return error(); }
|
||||
return first.get_value();
|
||||
}
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
@@ -510,7 +504,7 @@ simdjson_inline simdjson_result<std::string_view> document_reference::get_string
|
||||
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_raw_json_string(); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_bool(); }
|
||||
simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
|
||||
simdjson_inline bool document_reference::is_null() noexcept { return doc->is_null(); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->is_null(); }
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
|
||||
@@ -642,7 +636,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
|
||||
if (error()) { return error(); }
|
||||
return first.get_value();
|
||||
}
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
@@ -654,7 +648,7 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
|
||||
@@ -126,11 +126,14 @@ public:
|
||||
simdjson_inline simdjson_result<value> get_value() noexcept;
|
||||
|
||||
/**
|
||||
* Checks if this JSON value is null.
|
||||
* Checks if this JSON value is null. If and only if the value is
|
||||
* null, then it is consumed (we advance). If we find a token that
|
||||
* begins with 'n' but is not 'null', then an error is returned.
|
||||
*
|
||||
* @returns Whether the value is null.
|
||||
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
|
||||
*/
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
@@ -363,7 +366,9 @@ public:
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value.
|
||||
* Get the type of this JSON value. It does not validate or consume the value.
|
||||
* E.g., you must still call "is_null()" to check that a value is null even if
|
||||
* "type()" returns json_type::null.
|
||||
*
|
||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||
@@ -595,7 +600,7 @@ public:
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<value> get_value() noexcept;
|
||||
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
simdjson_inline operator document&() const noexcept;
|
||||
|
||||
@@ -660,7 +665,7 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
|
||||
@@ -727,7 +732,7 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() noexcept;
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
|
||||
@@ -754,8 +759,8 @@ public:
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_inline int32_t current_depth() const noexcept;
|
||||
simdjson_inline bool is_negative() noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_negative() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> get_number() 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;
|
||||
}
|
||||
@@ -321,6 +325,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
|
||||
SIMDJSON_ASSUME(_depth == child_depth - 1);
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||
SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
|
||||
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
|
||||
#endif
|
||||
#endif
|
||||
@@ -331,11 +336,13 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
|
||||
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
|
||||
return parser->start_positions[depth];
|
||||
SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
|
||||
return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
|
||||
parser->start_positions[depth] = position;
|
||||
SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
|
||||
if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
/**
|
||||
|
||||
@@ -109,11 +109,10 @@ simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -230,13 +230,22 @@ 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). */
|
||||
/**
|
||||
* The maximum depth of this parser (the most deeply nested objects and arrays it can process).
|
||||
* This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
|
||||
* The document's instance current_depth() method should be used to monitor the parsing
|
||||
* depth and limit it if desired.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
|
||||
* The document's instance current_depth() method should be used to monitor the parsing
|
||||
* depth and limit it if desired.
|
||||
*
|
||||
* @param capacity The new capacity.
|
||||
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
|
||||
* @return The error, if there is one.
|
||||
|
||||
@@ -4,23 +4,27 @@
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Create a string-view instance out of a document instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again.
|
||||
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept;
|
||||
/**
|
||||
* Create a string-view instance out of a value instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again. The value must
|
||||
* not have been accessed previously.
|
||||
* not have been accessed previously. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept;
|
||||
/**
|
||||
* Create a string-view instance out of an object instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again.
|
||||
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::object& x) noexcept;
|
||||
/**
|
||||
* Create a string-view instance out of an array instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again.
|
||||
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept;
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x);
|
||||
@@ -39,7 +43,8 @@ inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON
|
||||
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand {
|
||||
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The element.
|
||||
@@ -50,7 +55,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value> x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The array.
|
||||
@@ -61,7 +67,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::array> x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The array.
|
||||
@@ -76,7 +83,8 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTA
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream.
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The object.
|
||||
|
||||
@@ -54,10 +54,9 @@ simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
|
||||
simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||
return iter.get_bool();
|
||||
}
|
||||
simdjson_inline bool value::is_null() noexcept {
|
||||
simdjson_inline simdjson_result<bool> value::is_null() noexcept {
|
||||
return iter.is_null();
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
|
||||
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
||||
@@ -311,8 +310,8 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
|
||||
if (error()) { return false; }
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
|
||||
@@ -404,7 +403,7 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
|
||||
simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_depth();
|
||||
}
|
||||
|
||||
@@ -150,11 +150,14 @@ public:
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
|
||||
/**
|
||||
* Checks if this JSON value is null.
|
||||
* Checks if this JSON value is null. If and only if the value is
|
||||
* null, then it is consumed (we advance). If we find a token that
|
||||
* begins with 'n' but is not 'null', then an error is returned.
|
||||
*
|
||||
* @returns Whether the value is null.
|
||||
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
|
||||
*/
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
@@ -246,6 +249,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 +267,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;
|
||||
/**
|
||||
@@ -328,7 +337,9 @@ public:
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value.
|
||||
* Get the type of this JSON value. It does not validate or consume the value.
|
||||
* E.g., you must still call "is_null()" to check that a value is null even if
|
||||
* "type()" returns json_type::null.
|
||||
*
|
||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||
@@ -577,7 +588,7 @@ public:
|
||||
simdjson_inline simdjson_result<std::string_view> get_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
|
||||
|
||||
@@ -670,7 +681,7 @@ public:
|
||||
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
/** @copydoc simdjson_inline int32_t current_depth() const noexcept */
|
||||
simdjson_inline int32_t current_depth() const noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -468,8 +468,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
|
||||
if (error) { return incorrect_type_error("Not a boolean"); }
|
||||
return simdjson_result<bool>(!not_true);
|
||||
}
|
||||
simdjson_inline bool value_iterator::parse_null(const uint8_t *json) const noexcept {
|
||||
return !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
|
||||
bool is_null_string = !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]);
|
||||
// if we start with 'n', we must be a null
|
||||
if(!is_null_string && json[0]=='n') { return incorrect_type_error("Not a null but starts with n"); }
|
||||
return is_null_string;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept {
|
||||
@@ -516,10 +519,11 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_b
|
||||
if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
|
||||
return result;
|
||||
}
|
||||
simdjson_inline bool value_iterator::is_null() noexcept {
|
||||
auto result = parse_null(peek_non_root_scalar("null"));
|
||||
if(result) { advance_non_root_scalar("null"); }
|
||||
return result;
|
||||
simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
|
||||
bool is_null_value;
|
||||
SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
|
||||
if(is_null_value) { advance_non_root_scalar("null"); }
|
||||
return is_null_value;
|
||||
}
|
||||
simdjson_inline bool value_iterator::is_negative() noexcept {
|
||||
return numberparsing::is_negative(peek_non_root_scalar("numbersign"));
|
||||
@@ -547,10 +551,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 +571,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 +592,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 +612,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 +627,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 +643,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 +659,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 +677,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 +696,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 +708,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") &&
|
||||
|
||||
@@ -289,7 +289,7 @@ public:
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline bool is_null() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
@@ -350,7 +350,7 @@ protected:
|
||||
inline std::string to_string() const noexcept;
|
||||
simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
|
||||
|
||||
simdjson_inline bool parse_null(const uint8_t *json) const noexcept;
|
||||
simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
|
||||
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
|
||||
simdjson_inline const uint8_t *peek_start() const noexcept;
|
||||
simdjson_inline uint32_t peek_start_length() const noexcept;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,9 @@ simdjson_inline tape_ref::tape_ref(const dom::document *_doc, size_t _json_index
|
||||
simdjson_inline bool tape_ref::is_document_root() const noexcept {
|
||||
return json_index == 1; // should we ever change the structure of the tape, this should get updated.
|
||||
}
|
||||
|
||||
simdjson_inline bool tape_ref::usable() const noexcept {
|
||||
return doc != nullptr; // when the document pointer is null, this tape_ref is uninitialized (should not be accessed).
|
||||
}
|
||||
// Some value types have a specific on-tape word value. It can be faster
|
||||
// to check the type by doing a word-to-word comparison instead of extracting the
|
||||
// most significant 8 bits.
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
simdjson_inline const char * get_c_str() const noexcept;
|
||||
inline std::string_view get_string_view() const noexcept;
|
||||
simdjson_inline bool is_document_root() const noexcept;
|
||||
simdjson_inline bool usable() const noexcept;
|
||||
|
||||
/** The document this element references. */
|
||||
const dom::document *doc;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION 2.2.1
|
||||
#define SIMDJSON_VERSION 3.0.1
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
/**
|
||||
* The major version (MAJOR.minor.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MAJOR = 2,
|
||||
SIMDJSON_VERSION_MAJOR = 3,
|
||||
/**
|
||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MINOR = 2,
|
||||
SIMDJSON_VERSION_MINOR = 0,
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
|
||||
@@ -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@
|
||||
+140
-95
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2022-07-19 16:40:02 -0400. Do not edit! */
|
||||
/* auto-generated on 2022-11-23 10:31:42 -0500. Do not edit! */
|
||||
/* begin file src/simdjson.cpp */
|
||||
#include "simdjson.h"
|
||||
|
||||
@@ -868,9 +868,9 @@ inline char *format_buffer(char *buf, int len, int decimal_exponent,
|
||||
|
||||
std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
|
||||
// Make it look like a floating-point number (#362, #378)
|
||||
// buf[n + 0] = '.';
|
||||
// buf[n + 1] = '0';
|
||||
return buf + (static_cast<size_t>(n));
|
||||
buf[n + 0] = '.';
|
||||
buf[n + 1] = '0';
|
||||
return buf + (static_cast<size_t>(n)) + 2;
|
||||
}
|
||||
|
||||
if (0 < n && n <= max_exp) {
|
||||
@@ -933,10 +933,8 @@ char *to_chars(char *first, const char *last, double value) {
|
||||
{
|
||||
*first++ = '0';
|
||||
// Make it look like a floating-point number (#362, #378)
|
||||
if(negative) {
|
||||
*first++ = '.';
|
||||
*first++ = '0';
|
||||
}
|
||||
*first++ = '.';
|
||||
*first++ = '0';
|
||||
return first;
|
||||
}
|
||||
// Compute v = buffer * 10^decimal_exponent.
|
||||
@@ -1589,7 +1587,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 +3104,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 +3121,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 +3504,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 +4190,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 +5667,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 +6896,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 +6913,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 +7298,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 +8030,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 +9290,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 +9307,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 +9690,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 +10375,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 +11598,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 +11615,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 +11998,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 +12683,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 +13941,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 +13958,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 +14341,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 +15026,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)
|
||||
|
||||
+344
-206
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+5
-7
@@ -860,9 +860,9 @@ inline char *format_buffer(char *buf, int len, int decimal_exponent,
|
||||
|
||||
std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
|
||||
// Make it look like a floating-point number (#362, #378)
|
||||
// buf[n + 0] = '.';
|
||||
// buf[n + 1] = '0';
|
||||
return buf + (static_cast<size_t>(n));
|
||||
buf[n + 0] = '.';
|
||||
buf[n + 1] = '0';
|
||||
return buf + (static_cast<size_t>(n)) + 2;
|
||||
}
|
||||
|
||||
if (0 < n && n <= max_exp) {
|
||||
@@ -925,10 +925,8 @@ char *to_chars(char *first, const char *last, double value) {
|
||||
{
|
||||
*first++ = '0';
|
||||
// Make it look like a floating-point number (#362, #378)
|
||||
if(negative) {
|
||||
*first++ = '.';
|
||||
*first++ = '0';
|
||||
}
|
||||
*first++ = '.';
|
||||
*first++ = '0';
|
||||
return first;
|
||||
}
|
||||
// Compute v = buffer * 10^decimal_exponent.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,6 +732,10 @@ namespace document_stream_tests {
|
||||
}
|
||||
count++;
|
||||
}
|
||||
if(count != 1) {
|
||||
std::cerr << "bad count" << std::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,11 @@ namespace ondemand_treewalk {
|
||||
cout << element.get_bool();
|
||||
break;
|
||||
case ondemand::json_type::null:
|
||||
cout << "null";
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
cout << "null";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -119,7 +119,9 @@ namespace error_tests {
|
||||
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
|
||||
simdjson_result<ondemand::value> val = doc["val"];
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -131,15 +133,18 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
ASSERT_SUCCESS( val.get_bool() );
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
|
||||
ondemand::value val;
|
||||
ASSERT_SUCCESS( doc["val"].get(val) );
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -151,14 +156,17 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
ASSERT_SUCCESS( val.get_bool() );
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
json = R"(true)"_padded;
|
||||
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> val) {
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -170,14 +178,17 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
ASSERT_SUCCESS( val.get_bool());
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
|
||||
ondemand::document val;
|
||||
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
@@ -189,8 +200,9 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), false );
|
||||
ASSERT_SUCCESS( val.get_bool() );
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
|
||||
@@ -216,13 +228,16 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
|
||||
ondemand::value val;
|
||||
ASSERT_SUCCESS( doc["val"].get(val) );
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
@@ -236,7 +251,9 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
json = R"(null)"_padded;
|
||||
@@ -255,7 +272,9 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
|
||||
@@ -274,7 +293,9 @@ namespace error_tests {
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_EQUAL( val.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace json_pointer_tests {
|
||||
ASSERT_SUCCESS(val.get_bool().error());
|
||||
break;
|
||||
case ondemand::json_type::null:
|
||||
ASSERT_TRUE(val.is_null());
|
||||
ASSERT_SUCCESS(val.is_null().error());
|
||||
break;
|
||||
default:
|
||||
TEST_FAIL("unexpected type");
|
||||
|
||||
@@ -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;
|
||||
@@ -235,7 +271,9 @@ namespace misc_tests {
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
ondemand::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_TRUE(!shadowable.is_null());
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS(shadowable.is_null().get(is_null_value));
|
||||
ASSERT_TRUE(!is_null_value);
|
||||
ondemand::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
@@ -459,6 +497,9 @@ namespace misc_tests {
|
||||
bool run() {
|
||||
return
|
||||
issue1870() &&
|
||||
issue1894() &&
|
||||
issue1894toolarge() &&
|
||||
issue1894success() &&
|
||||
is_alive_root_array() &&
|
||||
is_alive_root_object() &&
|
||||
is_alive_array() &&
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -87,7 +87,11 @@ void recursive_print_json(ondemand::value element) {
|
||||
cout << element.get_bool();
|
||||
break;
|
||||
case ondemand::json_type::null:
|
||||
cout << "null";
|
||||
// we check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
cout << "null";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -166,7 +170,11 @@ void recursive_print_json_breakline(ondemand::value element) {
|
||||
cout << element.get_bool();
|
||||
break;
|
||||
case ondemand::json_type::null:
|
||||
cout << "null";
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
cout << "null";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,11 +206,15 @@ namespace scalar_tests {
|
||||
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
|
||||
ondemand::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_EQUAL( doc.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( doc.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
|
||||
ASSERT_EQUAL( doc_result.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( doc_result.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
return true;
|
||||
}));
|
||||
json = "[null]"_padded;
|
||||
@@ -219,7 +223,9 @@ namespace scalar_tests {
|
||||
for (auto value_result : doc_result) {
|
||||
ondemand::value value;
|
||||
ASSERT_SUCCESS( value_result.get(value) );
|
||||
ASSERT_EQUAL( value.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( value.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL( count, 1 );
|
||||
@@ -228,7 +234,9 @@ namespace scalar_tests {
|
||||
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (auto value_result : doc_result) {
|
||||
ASSERT_EQUAL( value_result.is_null(), true );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( value_result.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL( count, 1 );
|
||||
|
||||
@@ -63,7 +63,19 @@ int main(int argc, const char *argv[]) {
|
||||
simdjson::ondemand::document doc;
|
||||
error = parser.iterate(docdata).get(doc);
|
||||
if(error != simdjson::SUCCESS) { std::cout << error << std::endl; return EXIT_FAILURE; }
|
||||
// This locates the document and captures a string_view instance, it does
|
||||
// not validate the document:
|
||||
std::cout << doc;
|
||||
// check if there is more content
|
||||
const char * endofstream;
|
||||
if(doc.current_location().get(endofstream) == simdjson::SUCCESS) {
|
||||
// there is more content !
|
||||
// let us find what it is:
|
||||
size_t len = docdata.data() + docdata.size() - endofstream;
|
||||
std::string_view content{endofstream, len};
|
||||
std::cerr << "\nThere is leftover content: '" << content << "'" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
simdjson::dom::parser parser;
|
||||
|
||||
Reference in New Issue
Block a user