Compare commits

..

21 Commits

Author SHA1 Message Date
Daniel Lemire d520062f8e Bumping API 2022-10-06 11:50:33 -04:00
Daniel Lemire db08d78ed0 Documents better the type method and makes is_null return an error condition in some instances (#1909) 2022-10-06 11:47:40 -04:00
Daniel Lemire 46292b8d4b Update basics.md 2022-10-05 08:50:52 -04:00
Tyson Andre 46241287c6 Check for trailing tokens in json2msgpack ondemand benchmark (#1908)
Related to #1904

Users of the simdjson library will see json2msgpack as an available
example of how to recursively process json with the ondemand parser,
and checking for trailing tokens in a document is one part of json validation.

These checks shouldn't affect benchmark results performance.
The benchmark is run on the 631KB twitter.json file.
2022-10-05 08:49:09 -04:00
Daniel Lemire 137cb14bcc Documenting how one can check for the end of the document. (#1907) 2022-10-04 20:23:52 -04:00
Daniel Lemire 5e6be3ed7a Minor fix (documentation and safety) regarding max. depth in ondemand. (#1906) 2022-10-04 12:24:20 -04:00
Tyson Andre c6ab52eebb [skip ci] Add an .editorconfig for .cpp/.h/.md for whitespace settings (#1901)
Make it less likely to accidentally introduce tabs, trailing whitespace,
carriage returns, non-utf8 in files, or files without trailing newlines.

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes #1763

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

* build: handle absolute paths in .pc generation

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

* ci: add debian job

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

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

* Changing how NULL is handled.

* Different design.
2022-08-08 22:00:38 -04:00
48 changed files with 1083 additions and 453 deletions
+12
View File
@@ -0,0 +1,12 @@
# https://editorconfig.org/
root = true
# Conservatively avoid changing defaults for other file types, e.g. raw json files for test cases,
# Makefiles, etc.
[*.{cpp,h,md}]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
tab_width = 2
trim_trailing_whitespace = true
+1
View File
@@ -78,6 +78,7 @@
.gitattributes export-ignore .gitattributes export-ignore
.gitignore export-ignore .gitignore export-ignore
.editorconfig export-ignore
# Sources # Sources
*.c text eol=lf diff=c *.c text eol=lf diff=c
+33
View File
@@ -0,0 +1,33 @@
name: Debian
on: [push, pull_request]
defaults:
run:
shell: sh
permissions:
contents: read
jobs:
pkg-config:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
apt -y update
apt -y --no-install-recommends install g++ cmake make pkg-config
- name: Build and install
run: |
cmake -B build
cmake --build build
cmake --install build
- name: Test pkg-config
run: g++ examples/quickstart/quickstart.cpp $(pkg-config --cflags --libs simdjson)
-34
View File
@@ -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
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project( project(
simdjson simdjson
# The version number is modified by tools/release.py # The version number is modified by tools/release.py
VERSION 2.2.2 VERSION 3.0.0
DESCRIPTION "Parsing gigabytes of JSON per second" DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/" HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ---- # ---- Options, variables ----
# These version numbers are modified by tools/release.py # These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "13.0.0" CACHE STRING "simdjson library version") set(SIMDJSON_LIB_VERSION "14.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "13" CACHE STRING "simdjson library soversion") set(SIMDJSON_LIB_SOVERSION "14" CACHE STRING "simdjson library soversion")
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON) option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
@@ -152,6 +152,24 @@ install(
COMPONENT example_Development 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 # CPack
# #
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = "2.2.2" PROJECT_NUMBER = "3.0.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
+2 -2
View File
@@ -82,7 +82,7 @@ Other important files and directories:
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script). * **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 * **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 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 ```bash
mkdir build mkdir build
cd 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 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`. * `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. * `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.** > **Don't modify the files in singleheader/ directly; these are automatically generated.**
+1 -1
View File
@@ -3,7 +3,7 @@
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html) [![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg) ![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg)
![MinGW64-CI](https://github.com/simdjson/simdjson/workflows/MinGW64-CI/badge.svg) ![MinGW64-CI](https://github.com/simdjson/simdjson/workflows/MinGW64-CI/badge.svg)
[![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/2.0.0/index.html) [![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/3.0.0/index.html)
simdjson : Parsing gigabytes of JSON per second simdjson : Parsing gigabytes of JSON per second
=============================================== ===============================================
+25
View File
@@ -656,6 +656,31 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
} }
BENCHMARK(error_code_twitter_image_sizes); 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 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS
+15 -3
View File
@@ -74,18 +74,26 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
write_byte(0xc2 + doc.get_bool()); write_byte(0xc2 + doc.get_bool());
break; break;
case simdjson::ondemand::json_type::null: 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; break;
case simdjson::ondemand::json_type::array: case simdjson::ondemand::json_type::array:
case simdjson::ondemand::json_type::object: case simdjson::ondemand::json_type::object:
default: default:
// impossible // impossible
break; SIMDJSON_UNREACHABLE();
} }
} else { } else {
simdjson::ondemand::value val = doc; simdjson::ondemand::value val = doc;
recursive_processor(val); recursive_processor(val);
} }
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)); return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
} }
@@ -156,7 +164,11 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
write_byte(0xc2 + element.get_bool()); write_byte(0xc2 + element.get_bool());
break; break;
case simdjson::ondemand::json_type::null: 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; break;
default: default:
SIMDJSON_UNREACHABLE(); SIMDJSON_UNREACHABLE();
+23
View File
@@ -0,0 +1,23 @@
# This module provides function for joining paths
# known from most languages
#
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()
+39 -7
View File
@@ -99,7 +99,7 @@ We recommend CMake version 3.15 or better.
See [our CMake demonstration](https://github.com/simdjson/cmake_demo_single_file). It works under Linux, FreeBSD, macOS and Windows (including Visual Studio). 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 Versions
@@ -454,7 +454,7 @@ 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 size_t count = test_array.count_elements(); // requires simdjson 1.0 or better
std::cout << "Number of elements: " << count << std::endl; std::cout << "Number of elements: " << count << std::endl;
for(ondemand::object elem: test_array) { 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 * **Counting fields in objects:** Other times, it is useful to scan an object to determine the number of fields prior to
@@ -482,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" 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 * **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 with a known type, and are trying to generically inspect or walk over JSON elements.
`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). 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`. 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++ ```c++
void recursive_print_json(ondemand::value element) { void recursive_print_json(ondemand::value element) {
@@ -532,7 +544,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: 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; break;
} }
} }
@@ -972,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;
// 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 The following examples illustrates how to iterate through the content of an object without
having to handle exceptions. having to handle exceptions.
@@ -1010,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: Users more comfortable with an exception flow may choose to directly cast the `simdjson_result<T>` to the desired type:
```c++ ```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 When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
@@ -1097,6 +1126,9 @@ for (auto val : doc) {
std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS 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 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: are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example:
@@ -1518,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 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. - 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*. - 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. - The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
+7 -1
View File
@@ -42,7 +42,13 @@ inline simdjson_result<size_t> parser::read_file(const std::string &path) noexce
} }
// Get the file size // 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); std::fclose(fp);
return IO_ERROR; return IO_ERROR;
} }
+2 -1
View File
@@ -18,7 +18,7 @@ enum error_code {
SUCCESS = 0, ///< No error SUCCESS = 0, ///< No error
CAPACITY, ///< This parser can't support a document that big CAPACITY, ///< This parser can't support a document that big
MEMALLOC, ///< Error allocating memory, most likely out of memory 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 DEPTH_ERROR, ///< Your document exceeds the user-specified depth limitation
STRING_ERROR, ///< Problem while parsing a string STRING_ERROR, ///< Problem while parsing a string
T_ATOM_ERROR, ///< Problem while parsing an atom starting with the letter 't' 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. INCOMPLETE_ARRAY_OR_OBJECT, ///< The document ends early.
SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value. SCALAR_DOCUMENT_AS_VALUE, ///< A scalar document is treated as a value.
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
NUM_ERROR_CODES NUM_ERROR_CODES
}; };
+22 -21
View File
@@ -112,7 +112,7 @@ simdjson_inline bool compute_float_64(int64_t power, uint64_t i, bool negative,
// In the slow path, we need to adjust i so that it is > 1<<63 which is always // 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. // possible, except if i == 0, so we handle i == 0 separately.
if(i == 0) { if(i == 0) {
d = 0.0; d = negative ? -0.0 : 0.0;
return true; 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? if (simdjson_unlikely(real_exponent <= 0)) { // we have a subnormal?
// Here have that real_exponent <= 0 so -real_exponent >= 0 // 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. 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; return true;
} }
// next line is safe because -real_exponent + 1 < 0 // 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"); static_assert(simdjson::internal::smallest_power <= -342, "smallest_power is not small enough");
// //
if((exponent < simdjson::internal::smallest_power) || (i == 0)) { 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; return SUCCESS;
} else { // (exponent > largest_power) and (i != 0) } else { // (exponent > largest_power) and (i != 0)
// We have, for sure, an infinite value and simdjson refuses to parse infinite values. // 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 // Check for minus sign
// //
bool negative = (*src == '-'); bool negative = (*src == '-');
const uint8_t *p = src + negative; const uint8_t *p = src + uint8_t(negative);
// //
// Parse the integer part. // Parse the integer part.
@@ -846,7 +847,7 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer(const uin
// Check for minus sign // Check for minus sign
// //
bool negative = (*src == '-'); bool negative = (*src == '-');
const uint8_t *p = src + negative; const uint8_t *p = src + uint8_t(negative);
// //
// Parse the integer part. // 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; } if(src == src_end) { return NUMBER_ERROR; }
bool negative = (*src == '-'); bool negative = (*src == '-');
const uint8_t *p = src + negative; const uint8_t *p = src + uint8_t(negative);
// //
// Parse the integer part. // Parse the integer part.
@@ -932,19 +933,19 @@ simdjson_unused simdjson_inline simdjson_result<int64_t> parse_integer_in_string
// Check for minus sign // Check for minus sign
// //
bool negative = (*(src + 1) == '-'); bool negative = (*(src + 1) == '-');
const uint8_t *p = src + negative + 1; src += uint8_t(negative) + 1;
// //
// Parse the integer part. // Parse the integer part.
// //
// PERF NOTE: we don't use is_made_of_eight_digits_fast because large integers like 123456789 are rare // 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; 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. // 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. // 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 // We go from
// -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 // -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. // 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. // Here digit_count > 0.
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; } if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
// We can do the following... // We can do the following...
// if (!jsoncharutils::is_structural_or_whitespace(*p)) { // if (!jsoncharutils::is_structural_or_whitespace(*src)) {
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR; // return (*src == '.' || *src == 'e' || *src == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
// } // }
// as a single table lookup: // 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. // 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 // 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. // 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 // Check for minus sign
// //
bool negative = (*src == '-'); bool negative = (*src == '-');
src += negative; src += uint8_t(negative);
// //
// Parse the integer part. // Parse the integer part.
@@ -1040,7 +1041,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
if (simdjson_likely(!overflow)) { if (simdjson_likely(!overflow)) {
if (compute_float_64(exponent, i, negative, d)) { return d; } 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 NUMBER_ERROR;
} }
return d; 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 { simdjson_unused simdjson_inline simdjson_result<bool> is_integer(const uint8_t * src) noexcept {
bool negative = (*src == '-'); bool negative = (*src == '-');
src += negative; src += uint8_t(negative);
const uint8_t *p = src; const uint8_t *p = src;
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; } while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
if ( p == src ) { return NUMBER_ERROR; } 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 { simdjson_unused simdjson_inline simdjson_result<ondemand::number_type> get_number_type(const uint8_t * src) noexcept {
bool negative = (*src == '-'); bool negative = (*src == '-');
src += negative; src += uint8_t(negative);
const uint8_t *p = src; const uint8_t *p = src;
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; } while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
if ( p == src ) { return NUMBER_ERROR; } 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 // Check for minus sign
// //
bool negative = (*src == '-'); bool negative = (*src == '-');
src += negative; src += uint8_t(negative);
// //
// Parse the integer part. // Parse the integer part.
@@ -1161,7 +1162,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double(const uint8
if (simdjson_likely(!overflow)) { if (simdjson_likely(!overflow)) {
if (compute_float_64(exponent, i, negative, d)) { return d; } 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 NUMBER_ERROR;
} }
return d; return d;
@@ -1172,7 +1173,7 @@ simdjson_unused simdjson_inline simdjson_result<double> parse_double_in_string(c
// Check for minus sign // Check for minus sign
// //
bool negative = (*(src + 1) == '-'); bool negative = (*(src + 1) == '-');
src += negative + 1; src += uint8_t(negative) + 1;
// //
// Parse the integer part. // 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 (simdjson_likely(!overflow)) {
if (compute_float_64(exponent, i, negative, d)) { return d; } 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 NUMBER_ERROR;
} }
return d; 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 { simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
return get_root_value_iterator().get_root_bool(); 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(); return get_root_value_iterator().is_root_null();
} }
@@ -354,7 +354,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
if (error()) { return error(); } if (error()) { return error(); }
return first.get_value(); 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(); } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -504,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<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<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 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 #if SIMDJSON_EXCEPTIONS
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); } simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
@@ -636,7 +636,7 @@ simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjs
if (error()) { return error(); } if (error()) { return error(); }
return first.get_value(); 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(); } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -648,7 +648,7 @@ simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::o
if (error()) { return error(); } if (error()) { return error(); }
return first.is_scalar(); 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(); } if (error()) { return error(); }
return first.is_negative(); return first.is_negative();
} }
+13 -8
View File
@@ -126,11 +126,14 @@ public:
simdjson_inline simdjson_result<value> get_value() noexcept; 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 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. * Get this value as the given type.
@@ -363,7 +366,9 @@ public:
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept; 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 * 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 * 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<bool> get_bool() noexcept;
simdjson_inline simdjson_result<value> get_value() 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 simdjson_result<std::string_view> raw_json() noexcept;
simdjson_inline operator document&() const 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<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() 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;
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<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept; simdjson_inline simdjson_result<bool> get_bool() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> get_value() 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 #if SIMDJSON_EXCEPTIONS
simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false); 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<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_inline simdjson_result<bool> is_scalar() noexcept; simdjson_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_inline simdjson_result<const char *> current_location() noexcept; simdjson_inline simdjson_result<const char *> current_location() noexcept;
simdjson_inline int32_t current_depth() const noexcept; simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
simdjson_inline bool is_negative() noexcept; simdjson_inline simdjson_result<bool> is_negative() noexcept;
simdjson_inline simdjson_result<bool> is_integer() 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_type> get_number_type() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number> get_number() 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(); 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 { simdjson_inline bool json_iterator::streaming() const noexcept {
return _streaming; return _streaming;
} }
@@ -321,6 +325,7 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
SIMDJSON_ASSUME(_depth == child_depth - 1); SIMDJSON_ASSUME(_depth == child_depth - 1);
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO #ifndef SIMDJSON_CLANG_VISUAL_STUDIO
SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]); SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
#endif #endif
#endif #endif
@@ -331,11 +336,13 @@ simdjson_inline void json_iterator::reenter_child(token_position position, depth
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept { 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 { 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 #endif
@@ -117,6 +117,14 @@ public:
*/ */
simdjson_inline const uint8_t *return_current_and_advance() noexcept; 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. * 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(" ");
} }
// printf("| %5u ", *(index+1)); // printf("| %5u ", *(index+1));
printf("| %5u ", depth); printf("| %5i ", depth);
printf("| %.*s ", int(detail.size()), detail.data()); printf("| %.*s ", int(detail.size()), detail.data());
printf("|\n"); printf("|\n");
fflush(stdout); fflush(stdout);
@@ -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 { simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
size_t MINIMAL_DOCUMENT_CAPACITY = 32; if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
if(max_capacity < MINIMAL_DOCUMENT_CAPACITY) {
_max_capacity = max_capacity; _max_capacity = max_capacity;
} else { } else {
_max_capacity = MINIMAL_DOCUMENT_CAPACITY; _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
} }
} }
+10 -1
View File
@@ -230,13 +230,22 @@ public:
/** The maximum capacity of this parser (the largest document it is allowed to process). */ /** The maximum capacity of this parser (the largest document it is allowed to process). */
simdjson_inline size_t max_capacity() const noexcept; simdjson_inline size_t max_capacity() const noexcept;
simdjson_inline void set_max_capacity(size_t max_capacity) 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; simdjson_inline size_t max_depth() const noexcept;
/** /**
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length * Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
* and `max_depth` depth. * 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 capacity The new capacity.
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH. * @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
* @return The error, if there is one. * @return The error, if there is one.
@@ -4,23 +4,27 @@
namespace simdjson { namespace simdjson {
/** /**
* Create a string-view instance out of a document instance. The string-view instance * 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; 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 * 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 * 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; 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 * 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; 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 * 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_IMPLEMENTATION::ondemand::array& x) noexcept;
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x); 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 { 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 out The output stream.
* @param value The element. * @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); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::value> x);
#endif #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 out The output stream.
* @param value The array. * @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); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::array> x);
#endif #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 out The output stream.
* @param value The array. * @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); inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::ondemand::document_reference>&& x);
#endif #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 out The output stream.
* @param value The object. * @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 { simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
return iter.get_bool(); return iter.get_bool();
} }
simdjson_inline bool value::is_null() noexcept { simdjson_inline simdjson_result<bool> value::is_null() noexcept {
return iter.is_null(); return iter.is_null();
} }
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); } 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<object> value::get() noexcept { return get_object(); }
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); } 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(); } if (error()) { return error(); }
return first.get_bool(); return first.get_bool();
} }
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept { simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::is_null() noexcept {
if (error()) { return false; } if (error()) { return error(); }
return first.is_null(); return first.is_null();
} }
@@ -404,7 +403,7 @@ simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENT
return first.current_location(); 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(); } if (error()) { return error(); }
return first.current_depth(); return first.current_depth();
} }
+10 -5
View File
@@ -150,11 +150,14 @@ public:
simdjson_inline simdjson_result<bool> get_bool() noexcept; 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 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 #if SIMDJSON_EXCEPTIONS
/** /**
@@ -334,7 +337,9 @@ public:
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept; 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 * 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 * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
@@ -583,7 +588,7 @@ public:
simdjson_inline simdjson_result<std::string_view> get_string() noexcept; 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<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() 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; template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
@@ -676,7 +681,7 @@ public:
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */ /** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
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 */ /** @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; 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"); } if (error) { return incorrect_type_error("Not a boolean"); }
return simdjson_result<bool>(!not_true); return simdjson_result<bool>(!not_true);
} }
simdjson_inline bool value_iterator::parse_null(const uint8_t *json) const noexcept { simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse_null(const uint8_t *json) const noexcept {
return !atomparsing::str4ncmp(json, "null") && jsoncharutils::is_structural_or_whitespace(json[4]); 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 { 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"); } if(result.error() == SUCCESS) { advance_non_root_scalar("bool"); }
return result; return result;
} }
simdjson_inline bool value_iterator::is_null() noexcept { simdjson_inline simdjson_result<bool> value_iterator::is_null() noexcept {
auto result = parse_null(peek_non_root_scalar("null")); bool is_null_value;
if(result) { advance_non_root_scalar("null"); } SIMDJSON_TRY(parse_null(peek_non_root_scalar("null")).get(is_null_value));
return result; if(is_null_value) { advance_non_root_scalar("null"); }
return is_null_value;
} }
simdjson_inline bool value_iterator::is_negative() noexcept { simdjson_inline bool value_iterator::is_negative() noexcept {
return numberparsing::is_negative(peek_non_root_scalar("numbersign")); 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)) { 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 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 { 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 max_len = peek_start_length();
auto json = peek_root_scalar("number"); auto json = peek_root_scalar("number");
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, // 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"); logger::log_error(*_json_iter, start_position(), depth(), "Root number more than 1082 characters");
return NUMBER_ERROR; 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 { simdjson_inline simdjson_result<number> value_iterator::get_root_number() noexcept {
auto max_len = peek_start_length(); auto max_len = peek_start_length();
@@ -577,6 +592,7 @@ simdjson_inline simdjson_result<number> value_iterator::get_root_number() noexce
number num; number num;
error_code error = numberparsing::parse_number(tmpbuf, num); error_code error = numberparsing::parse_number(tmpbuf, num);
if(error) { return error; } if(error) { return error; }
if (!_json_iter->is_single_token()) { return TRAILING_CONTENT; }
advance_root_scalar("number"); advance_root_scalar("number");
return num; return num;
} }
@@ -596,7 +612,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::g
return NUMBER_ERROR; return NUMBER_ERROR;
} }
auto result = numberparsing::parse_unsigned(tmpbuf); 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; return result;
} }
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> value_iterator::get_root_uint64_in_string() noexcept { 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; return NUMBER_ERROR;
} }
auto result = numberparsing::parse_unsigned_in_string(tmpbuf); 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; return result;
} }
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64() noexcept { 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); 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; return result;
} }
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> value_iterator::get_root_int64_in_string() noexcept { 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); 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; return result;
} }
simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get_root_double() noexcept { 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; return NUMBER_ERROR;
} }
auto result = numberparsing::parse_double(tmpbuf); 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; return result;
} }
@@ -665,7 +696,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<double> value_iterator::get
return NUMBER_ERROR; return NUMBER_ERROR;
} }
auto result = numberparsing::parse_double_in_string(tmpbuf); 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; return result;
} }
simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::get_root_bool() noexcept { 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]; uint8_t tmpbuf[5+1];
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); } if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); }
auto result = parse_bool(tmpbuf); 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; return result;
} }
simdjson_inline bool value_iterator::is_root_null() noexcept { 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 max_len = peek_start_length();
auto json = peek_root_scalar("null"); auto json = peek_root_scalar("null");
bool result = (max_len >= 4 && !atomparsing::str4ncmp(json, "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() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() 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_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 bool is_negative() noexcept;
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() 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; 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; 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 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 simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
simdjson_inline const uint8_t *peek_start() const noexcept; simdjson_inline const uint8_t *peek_start() const noexcept;
simdjson_inline uint32_t peek_start_length() const noexcept; simdjson_inline uint32_t peek_start_length() const noexcept;
+5 -6
View File
@@ -57,7 +57,7 @@ public:
* const implementation *impl = simdjson::get_active_implementation(); * const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl; * 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; } virtual const std::string &name() const { return _name; }
@@ -67,7 +67,7 @@ public:
* const implementation *impl = simdjson::get_active_implementation(); * const implementation *impl = simdjson::get_active_implementation();
* cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl; * 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; } 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 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. * 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; bool supported_by_runtime_system() const;
@@ -86,7 +85,7 @@ public:
* *
* The instruction sets this implementation is compiled against. * 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; }; 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 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 max_depth The maximum JSON object/array nesting this parser is expected to handle.
* @param dst The place to put the resulting parser implementation. * @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( virtual error_code create_dom_parser_implementation(
size_t capacity, size_t capacity,
+1 -1
View File
@@ -115,7 +115,7 @@ constexpr uint32_t cpuid_avx512pf_bit = 1 << 26; ///< @private bit 26 of EBX
constexpr uint32_t cpuid_avx512er_bit = 1 << 27; ///< @private bit 27 of EBX for EAX=0x7 constexpr uint32_t cpuid_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_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_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_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_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 constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1
+8 -2
View File
@@ -45,7 +45,7 @@ inline char *allocate_padded_buffer(size_t length) noexcept {
} // namespace internal } // namespace internal
inline padded_string::padded_string() noexcept {} inline padded_string::padded_string() noexcept = default;
inline padded_string::padded_string(size_t length) noexcept inline padded_string::padded_string(size_t length) noexcept
: viable_size(length), data_ptr(internal::allocate_padded_buffer(length)) { : 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 // 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); std::fclose(fp);
return IO_ERROR; return IO_ERROR;
} }
+4 -4
View File
@@ -4,22 +4,22 @@
#define SIMDJSON_SIMDJSON_VERSION_H #define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */ /** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 2.2.2 #define SIMDJSON_VERSION 3.0.0
namespace simdjson { namespace simdjson {
enum { enum {
/** /**
* The major version (MAJOR.minor.revision) of simdjson being used. * 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. * 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. * The revision (major.minor.REVISION) of simdjson being used.
*/ */
SIMDJSON_VERSION_REVISION = 2 SIMDJSON_VERSION_REVISION = 0
}; };
} // namespace simdjson } // namespace simdjson
+11
View File
@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=@PKGCONFIG_INCLUDEDIR@
libdir=@PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@
URL: @PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
Cflags: -I${includedir} @PKGCONFIG_CFLAGS@
Libs: -L${libdir} -l@PROJECT_NAME@
@PKGCONFIG_LIBS_PRIVATE@
+135 -76
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2022-07-28 21:45:54 -0400. Do not edit! */ /* auto-generated on 2022-10-06 11:47:40 -0400. Do not edit! */
/* begin file src/simdjson.cpp */ /* begin file src/simdjson.cpp */
#include "simdjson.h" #include "simdjson.h"
@@ -1589,7 +1589,8 @@ namespace internal {
{ INSUFFICIENT_PADDING, "simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." }, { 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." }, { 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. "}, { 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[] }; // error_messages[]
} // namespace internal } // namespace internal
@@ -3105,6 +3106,14 @@ using namespace simd;
this->error |= this->prev_incomplete; 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) { simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) { if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete; this->error |= this->prev_incomplete;
@@ -3114,12 +3123,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) ||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4), || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block."); "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); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]); this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -3497,7 +3506,7 @@ private:
*/ */
class json_scanner { class json_scanner {
public: public:
json_scanner() {} json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in); simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS // Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish(); simdjson_inline error_code finish();
@@ -4189,22 +4198,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
@@ -5663,22 +5675,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
@@ -6883,6 +6898,14 @@ using namespace simd;
this->error |= this->prev_incomplete; 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) { simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) { if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete; this->error |= this->prev_incomplete;
@@ -6892,12 +6915,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) ||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4), || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block."); "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); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]); this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -7277,7 +7300,7 @@ private:
*/ */
class json_scanner { class json_scanner {
public: public:
json_scanner() {} json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in); simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS // Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish(); simdjson_inline error_code finish();
@@ -8015,22 +8038,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
@@ -9266,6 +9292,14 @@ using namespace simd;
this->error |= this->prev_incomplete; 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) { simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) { if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete; this->error |= this->prev_incomplete;
@@ -9275,12 +9309,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) ||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4), || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block."); "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); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]); this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -9658,7 +9692,7 @@ private:
*/ */
class json_scanner { class json_scanner {
public: public:
json_scanner() {} json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in); simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS // Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish(); simdjson_inline error_code finish();
@@ -10349,22 +10383,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
@@ -11563,6 +11600,14 @@ using namespace simd;
this->error |= this->prev_incomplete; 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) { simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) { if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete; this->error |= this->prev_incomplete;
@@ -11572,12 +11617,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) ||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4), || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block."); "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); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]); this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -11955,7 +12000,7 @@ private:
*/ */
class json_scanner { class json_scanner {
public: public:
json_scanner() {} json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in); simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS // Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish(); simdjson_inline error_code finish();
@@ -12646,22 +12691,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
@@ -13895,6 +13943,14 @@ using namespace simd;
this->error |= this->prev_incomplete; 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) { simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) { if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete; this->error |= this->prev_incomplete;
@@ -13904,12 +13960,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) ||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4), || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block."); "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); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]); this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
@@ -14287,7 +14343,7 @@ private:
*/ */
class json_scanner { class json_scanner {
public: public:
json_scanner() {} json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in); simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS // Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish(); simdjson_inline error_code finish();
@@ -14978,22 +15034,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
+294 -197
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -96,7 +96,7 @@ private:
*/ */
class json_scanner { class json_scanner {
public: public:
json_scanner() {} json_scanner() = default;
simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in); simdjson_inline json_block next(const simd::simd8x64<uint8_t>& in);
// Returns either UNCLOSED_STRING or SUCCESS // Returns either UNCLOSED_STRING or SUCCESS
simdjson_inline error_code finish(); simdjson_inline error_code finish();
+11 -3
View File
@@ -162,6 +162,14 @@ using namespace simd;
this->error |= this->prev_incomplete; 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) { simdjson_inline void check_next_input(const simd8x64<uint8_t>& input) {
if(simdjson_likely(is_ascii(input))) { if(simdjson_likely(is_ascii(input))) {
this->error |= this->prev_incomplete; this->error |= this->prev_incomplete;
@@ -171,12 +179,12 @@ using namespace simd;
||(simd8x64<uint8_t>::NUM_CHUNKS == 2) ||(simd8x64<uint8_t>::NUM_CHUNKS == 2)
|| (simd8x64<uint8_t>::NUM_CHUNKS == 4), || (simd8x64<uint8_t>::NUM_CHUNKS == 4),
"We support one, two or four chunks per 64-byte block."); "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); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); 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[0], this->prev_input_block);
this->check_utf8_bytes(input.chunks[1], input.chunks[0]); this->check_utf8_bytes(input.chunks[1], input.chunks[0]);
this->check_utf8_bytes(input.chunks[2], input.chunks[1]); this->check_utf8_bytes(input.chunks[2], input.chunks[1]);
+12 -9
View File
@@ -53,22 +53,25 @@ simdjson_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
// outside the Basic // outside the Basic
// Multilingual Plane. // Multilingual Plane.
if (code_point >= 0xd800 && code_point < 0xdc00) { 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; 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 // We have already checked that the high surrogate is valid and
// the check for being outside the Basic Multilingual plane. If we don't // (code_point - 0xd800) < 1024.
// 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 // Check that code_point_2 is in the range 0xdc00..0xdfff
// or the second code point being invalid. // and that code_point_2 was parsed from valid hex.
if ((code_point | code_point_2) >> 16) { uint32_t low_bit = code_point_2 - 0xdc00;
if (low_bit >> 10) {
return false; return false;
} }
code_point = code_point =
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000; (((code_point - 0xd800) << 10) | low_bit) + 0x10000;
*src_ptr += 6; *src_ptr += 6;
} else if (code_point >= 0xdc00 && code_point <= 0xdfff) { } else if (code_point >= 0xdc00 && code_point <= 0xdfff) {
// If we encounter a low surrogate (not preceded by a high surrogate) // If we encounter a low surrogate (not preceded by a high surrogate)
+2 -1
View File
@@ -33,7 +33,8 @@ namespace internal {
{ INSUFFICIENT_PADDING, "simdjson requires the input JSON string to have at least SIMDJSON_PADDING extra bytes allocated, beyond the string's length. Consider using the simdjson::padded_string class if needed." }, { 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." }, { 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. "}, { 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[] }; // error_messages[]
} // namespace internal } // namespace internal
+70 -2
View File
@@ -221,6 +221,64 @@ namespace number_tests {
std::vector<char> buf(1024); std::vector<char> buf(1024);
simdjson::dom::parser parser; 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)}; bool is_pow_correct{1e-308 == std::pow(10,-308)};
int start_point = is_pow_correct ? -1000 : -307; int start_point = is_pow_correct ? -1000 : -307;
if(!is_pow_correct) { if(!is_pow_correct) {
@@ -269,6 +327,13 @@ namespace number_tests {
std::cerr << error << std::endl; std::cerr << error << std::endl;
return false; 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) { if (actual != val) {
std::cerr << std::hexfloat << actual << " but I was expecting " << val std::cerr << std::hexfloat << actual << " but I was expecting " << val
<< std::endl; << std::endl;
@@ -284,16 +349,18 @@ namespace number_tests {
std::cout << std::dec; std::cout << std::dec;
return true; return true;
} }
bool truncated_borderline() { bool truncated_borderline() {
std::cout << __func__ << std::endl; std::cout << __func__ << std::endl;
std::string round_to_even = "9007199254740993.0"; std::string round_to_even = "9007199254740993.0";
for(size_t i = 0; i < 1000; i++) { round_to_even += "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() { bool specific_tests() {
std::cout << __func__ << std::endl; 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("4503599627370496.5", 4503599627370496.5) &&
basic_test_64bit("4503599627475352.5", 4503599627475352.5) && basic_test_64bit("4503599627475352.5", 4503599627475352.5) &&
basic_test_64bit("4503599627475353.5", 4503599627475353.5) && basic_test_64bit("4503599627475353.5", 4503599627475353.5) &&
@@ -315,6 +382,7 @@ namespace number_tests {
small_integers() && small_integers() &&
powers_of_two() && powers_of_two() &&
powers_of_ten() && powers_of_ten() &&
negative_powers_of_ten() &&
nines(); nines();
} }
} }
+4
View File
@@ -732,6 +732,10 @@ namespace document_stream_tests {
} }
count++; count++;
} }
if(count != 1) {
std::cerr << "bad count" << std::endl;
return false;
}
#endif #endif
return true; return true;
} }
+5 -1
View File
@@ -160,7 +160,11 @@ namespace ondemand_treewalk {
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: 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; break;
} }
} }
+33 -12
View File
@@ -119,7 +119,9 @@ namespace error_tests {
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) { SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
simdjson_result<ondemand::value> val = doc["val"]; simdjson_result<ondemand::value> val = doc["val"];
// Get everything that can fail in both forward and backwards order // 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_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), 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_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.get_bool() );
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
ondemand::value val; ondemand::value val;
ASSERT_SUCCESS( doc["val"].get(val) ); ASSERT_SUCCESS( doc["val"].get(val) );
// Get everything that can fail in both forward and backwards order // 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_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), 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_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.get_bool() );
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
json = R"(true)"_padded; json = R"(true)"_padded;
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> val) { 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 // 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_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), 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_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool()); ASSERT_SUCCESS( val.get_bool());
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
ondemand::document val; ondemand::document val;
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order 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_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), 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_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() ); ASSERT_SUCCESS( val.get_bool() );
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
ASSERT_EQUAL( is_null_value, false );
TEST_SUCCEED(); TEST_SUCCEED();
})); }));
@@ -216,13 +228,16 @@ namespace error_tests {
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), 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();
})); }));
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) { SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
ondemand::value val; ondemand::value val;
ASSERT_SUCCESS( doc["val"].get(val) ); ASSERT_SUCCESS( doc["val"].get(val) );
// Get everything that can fail in both forward and backwards order // Get everything that can fail in both forward and backwards order
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), 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_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), 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();
})); }));
json = R"(null)"_padded; json = R"(null)"_padded;
@@ -255,7 +272,9 @@ namespace error_tests {
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), 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();
})); }));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) { 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_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE ); ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), 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();
})); }));
TEST_SUCCEED(); TEST_SUCCEED();
@@ -71,7 +71,7 @@ namespace json_pointer_tests {
ASSERT_SUCCESS(val.get_bool().error()); ASSERT_SUCCESS(val.get_bool().error());
break; break;
case ondemand::json_type::null: case ondemand::json_type::null:
ASSERT_TRUE(val.is_null()); ASSERT_SUCCESS(val.is_null().error());
break; break;
default: default:
TEST_FAIL("unexpected type"); TEST_FAIL("unexpected type");
+42 -1
View File
@@ -63,6 +63,42 @@ namespace misc_tests {
TEST_SUCCEED(); 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() { bool issue1660() {
TEST_START(); TEST_START();
ondemand::parser parser; ondemand::parser parser;
@@ -235,7 +271,9 @@ namespace misc_tests {
ASSERT_SUCCESS(global.get(global_object)); ASSERT_SUCCESS(global.get(global_object));
ondemand::value shadowable; ondemand::value shadowable;
ASSERT_SUCCESS(global_object["shadowable"].get(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; ondemand::value badvalue;
auto error = global_object["writable"].get(badvalue); auto error = global_object["writable"].get(badvalue);
if(error == SUCCESS) { if(error == SUCCESS) {
@@ -459,6 +497,9 @@ namespace misc_tests {
bool run() { bool run() {
return return
issue1870() && issue1870() &&
issue1894() &&
issue1894toolarge() &&
issue1894success() &&
is_alive_root_array() && is_alive_root_array() &&
is_alive_root_object() && is_alive_root_object() &&
is_alive_array() && is_alive_array() &&
+72 -1
View File
@@ -170,6 +170,20 @@ namespace number_tests {
simdjson_unused auto blah2=blah.get(x); 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() { bool old_crashes() {
TEST_START(); TEST_START();
github_issue_1273(); github_issue_1273();
@@ -264,6 +278,61 @@ namespace number_tests {
TEST_SUCCEED(); 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() { bool get_root_number_tests() {
TEST_START(); TEST_START();
ondemand::parser parser; ondemand::parser parser;
@@ -321,7 +390,9 @@ namespace number_tests {
TEST_SUCCEED(); TEST_SUCCEED();
} }
bool run() { bool run() {
return get_root_number_tests() && return issue_1898() &&
issue1878() &&
get_root_number_tests() &&
get_number_tests()&& get_number_tests()&&
small_integers() && small_integers() &&
powers_of_two() && powers_of_two() &&
+10 -2
View File
@@ -87,7 +87,11 @@ void recursive_print_json(ondemand::value element) {
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: 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; break;
} }
} }
@@ -166,7 +170,11 @@ void recursive_print_json_breakline(ondemand::value element) {
cout << element.get_bool(); cout << element.get_bool();
break; break;
case ondemand::json_type::null: 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; break;
} }
} }
+12 -4
View File
@@ -206,11 +206,15 @@ namespace scalar_tests {
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc; ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(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; return true;
})); }));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) { 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; return true;
})); }));
json = "[null]"_padded; json = "[null]"_padded;
@@ -219,7 +223,9 @@ namespace scalar_tests {
for (auto value_result : doc_result) { for (auto value_result : doc_result) {
ondemand::value value; ondemand::value value;
ASSERT_SUCCESS( value_result.get(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++; count++;
} }
ASSERT_EQUAL( count, 1 ); ASSERT_EQUAL( count, 1 );
@@ -228,7 +234,9 @@ namespace scalar_tests {
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) { SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) {
int count = 0; int count = 0;
for (auto value_result : doc_result) { 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++; count++;
} }
ASSERT_EQUAL( count, 1 ); ASSERT_EQUAL( count, 1 );
+12
View File
@@ -63,7 +63,19 @@ int main(int argc, const char *argv[]) {
simdjson::ondemand::document doc; simdjson::ondemand::document doc;
error = parser.iterate(docdata).get(doc); error = parser.iterate(docdata).get(doc);
if(error != simdjson::SUCCESS) { std::cout << error << std::endl; return EXIT_FAILURE; } 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; 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; return EXIT_SUCCESS;
} }
simdjson::dom::parser parser; simdjson::dom::parser parser;