Compare commits

...

8 Commits

Author SHA1 Message Date
Daniel Lemire 3cb79e6977 Trying again. (#671) 2020-04-02 19:24:43 -04:00
John Keiser c5e21a2469 Merge pull request #669 from simdjson/jkeiser/type-switch
Add element.type() for type switching
2020-04-02 15:01:51 -07:00
John Keiser 13aee51011 Add element.type() for type switching 2020-04-02 14:07:19 -07:00
Daniel Lemire 53fca1b5e6 This is a first attempt at fixing issue 660. (#668)
* This is a first attempt at fixing issue 660. The hard part is not the fix by itself, the hard part is to make sure we never get caught with our pants down like that again.

I expect the CI tests will fail. Further commits will solve the issues.

* Setting the rpath properly.

* For the sanitize tests, we want verify the installation.
2020-04-02 15:18:58 -04:00
Daniel Lemire 7dad9fca0f In the future, we will bump the so version with even minor releases. (#664) 2020-04-01 16:08:28 -04:00
John Keiser b249d7c76c Merge pull request #666 from Mengesh/patch-1
Update basics.md
2020-04-01 10:54:01 -07:00
Marko Radišić 4060f64232 Update basics.md
Fix links to singleheader .h and .cpp
2020-04-01 17:13:53 +02:00
M. Zhou 5b2f7d3374 CMake: Bump SOVERSION to "1" due to the breaking changes in API/ABI. (fixes #661) (#662) 2020-04-01 09:53:45 -04:00
12 changed files with 921 additions and 137 deletions
+17 -7
View File
@@ -41,7 +41,7 @@ commands:
- run: ARCHFLAGS=-march=haswell make test # this breaks runtime dispatch, but see https://github.com/lemire/simdjson/issues/444... this is a code robustness test
- run: make clean
- run: EXTRAFLAGS=-DSIMDJSON_NO_COMPUTED_GOTO=true make test # this should run tests with computed gotos disabled
make_test_strict:
make_test_strict: # this version fails when a warning is detected.
steps:
- checkout
- run: EXTRAFLAGS=-Werror make
@@ -50,15 +50,25 @@ commands:
- run: EXTRAFLAGS=-Werror make quicktests
- run: make clean
cmake_test:
cmake_simple_test: # this version just builds and test
steps:
- run: apt-get update -qq
- run: apt-get install -y cmake
- checkout
- run: cmake $CMAKE_TEST_FLAGS
- run: make
- run: make all
- run: make test
cmake_test: # this version builds, install, test and then verifyi from the installation
steps:
- run: apt-get update -qq
- run: apt-get install -y cmake
- checkout
- run: cmake $CMAKE_TEST_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination
- run: make all install
- run: make test
- run: 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 # we not only want cmake to build and run tests, but we want also a succesful installation from which we can build, link and run programs
jobs:
gcc-avx-unthreaded:
@@ -114,7 +124,7 @@ jobs:
description: Build, run tests and check performance on GCC 7 and AVX 2 with a cmake sanitize build
executor: gcc7
environment: { CMAKE_TEST_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON }
steps: [ cmake_test ]
steps: [ cmake_simple_test ]
gcc-sse:
description: Build, run tests and check performance on GCC 7 and SSE 4.2
@@ -135,7 +145,7 @@ jobs:
description: Build, run tests and check performance on GCC 7 and SSE 4.2 with a cmake sanitize build
executor: gcc7
environment: { CMAKE_TEST_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON }
steps: [ cmake_test ]
steps: [ cmake_simple_test ]
clang-avx:
description: Build, run tests and check performance on clang 6 and AVX 2
@@ -160,7 +170,7 @@ jobs:
description: Build, run tests and check performance on clang 6 and AVX 2 with a cmake sanitize build
executor: clang6
environment: { CMAKE_TEST_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON }
steps: [ init_clang6, cmake_test ]
steps: [ init_clang6, cmake_simple_test ]
clang-sse:
description: Build, run tests and check performance on Clang 6 and SSE 4.2
@@ -181,7 +191,7 @@ jobs:
description: Build, run tests and check performance on Clang 6 and SSE 4.2 with a cmake sanitize build
executor: clang6
environment: { CMAKE_TEST_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON }
steps: [ init_clang6, cmake_test ]
steps: [ init_clang6, cmake_simple_test ]
workflows:
version: 2.1
+7 -3
View File
@@ -27,9 +27,9 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
set(SIMDJSON_LIB_NAME simdjson)
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 3)
set(PROJECT_VERSION_PATCH 0)
set(SIMDJSON_LIB_VERSION "0.3.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "0" CACHE STRING "simdjson library soversion")
set(PROJECT_VERSION_PATCH 1)
set(SIMDJSON_LIB_VERSION "0.3.1" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "1" CACHE STRING "simdjson library soversion")
option(SIMDJSON_IMPLEMENTATION_HASWELL "Include the haswell implementation" ON)
option(SIMDJSON_IMPLEMENTATION_WESTMERE "Include the westmere implementation" ON)
@@ -50,7 +50,11 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake")
find_package(CTargets)
find_package(Options)
# We used to have install(DIRECTORY include/${SIMDJSON_LIB_NAME} DESTINATION include)
# alone.
# However, this fails because we also need the root level simdjson.h file.
install(DIRECTORY include/${SIMDJSON_LIB_NAME} DESTINATION include)
install(FILES include/${SIMDJSON_LIB_NAME}.h DESTINATION include)
set (TEST_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/jsonchecker/")
set (BENCHMARK_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/jsonexamples/")
add_definitions(-DSIMDJSON_TEST_DATA_DIR="${TEST_DATA_DIR}")
+63 -6
View File
@@ -8,15 +8,16 @@ An overview of what you need to know to use simdjson, with examples.
* [Using the Parsed JSON](#using-the-parsed-json)
* [JSON Pointer](#json-pointer)
* [Error Handling](#error-handling)
* [Error Handling Example](#error-handling-example)
* [Exceptions](#exceptions)
* [Error Handling Example](#error-handling-example)
* [Exceptions](#exceptions)
* [Tree Walking and JSON Element Types](#tree-walking-and-json-element-types)
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
* [Thread Safety](#thread-safety)
Including simdjson
------------------
To include simdjson, copy [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp)
To include simdjson, copy [simdjson.h](/singleheader/simdjson.h) and [simdjson.cpp](/singleheader/simdjson.cpp)
into your project. Then include it in your project with:
```c++
@@ -67,6 +68,8 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
first element.
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
> O(1) operation, which it is not presently in simdjson.
* **Checking an Element Type:** You can check an element's type with `element.type()`. It
returns an `element_type`.
Here are some examples of all of the above:
@@ -152,9 +155,9 @@ This is how the example in "Using the Parsed JSON" could be written using only e
```c++
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
auto [cars, error] = parser.parse(cars_json).get<dom::array>();
@@ -210,6 +213,60 @@ dom::element doc = parser.parse(json); // Throws an exception if there was an er
When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
program from continuing if there was an error.
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. For
example, here's a quick and dirty recursive function that verbosely prints the JSON document as JSON
(* ignoring nuances like trailing commas and escaping strings, for brevity's sake):
```c++
void print_json(dom::element element) {
switch (element.type()) {
case dom::element_type::ARRAY:
cout << "[";
for (dom::element child : dom::array(element)) {
print_json(child);
cout << ",";
}
cout << "]";
break;
case dom::element_type::OBJECT:
cout << "{";
for (dom::key_value_pair field : dom::object(element)) {
cout << "\"" << field.key << "\": ";
print_json(field.value);
}
cout << "}";
break;
case dom::element_type::INT64:
cout << int64_t(element) << endl;
break;
case dom::element_type::UINT64:
cout << uint64_t(element) << endl;
break;
case dom::element_type::DOUBLE:
cout << double(element) << endl;
break;
case dom::element_type::STRING:
cout << std::string_view(element) << endl;
break;
case dom::element_type::BOOL:
cout << bool(element) << endl;
break;
case dom::element_type::NULL_VALUE:
cout << "null" << endl;
break;
}
}
void basics_treewalk_1() {
dom::parser parser;
print_json(parser.load("twitter.json"));
}
```
Newline-Delimited JSON (ndjson) and JSON lines
----------------------------------------------
+86 -37
View File
@@ -41,50 +41,65 @@ namespace simdjson::internal {
using namespace simdjson::dom;
constexpr const uint64_t JSON_VALUE_MASK = 0x00FFFFFFFFFFFFFF;
enum class tape_type;
class tape_ref;
/**
* The possible types in the tape. Internal only.
*/
enum class tape_type {
ROOT = 'r',
START_ARRAY = '[',
START_OBJECT = '{',
END_ARRAY = ']',
END_OBJECT = '}',
STRING = '"',
INT64 = 'l',
UINT64 = 'u',
DOUBLE = 'd',
TRUE_VALUE = 't',
FALSE_VALUE = 'f',
NULL_VALUE = 'n'
};
/**
* A reference to an element on the tape. Internal only.
*/
class tape_ref {
public:
really_inline tape_ref() noexcept;
really_inline tape_ref(const document *doc, size_t json_index) noexcept;
inline size_t after_element() const noexcept;
really_inline tape_type type() const noexcept;
really_inline uint64_t tape_value() const noexcept;
template<typename T>
really_inline T next_tape_value() const noexcept;
inline std::string_view get_string_view() const noexcept;
/**
* The possible types in the tape. Internal only.
*/
enum class tape_type {
ROOT = 'r',
START_ARRAY = '[',
START_OBJECT = '{',
END_ARRAY = ']',
END_OBJECT = '}',
STRING = '"',
INT64 = 'l',
UINT64 = 'u',
DOUBLE = 'd',
TRUE_VALUE = 't',
FALSE_VALUE = 'f',
NULL_VALUE = 'n'
};
/** The document this element references. */
const document *doc;
/**
* A reference to an element on the tape. Internal only.
*/
class tape_ref {
public:
really_inline tape_ref() noexcept;
really_inline tape_ref(const document *doc, size_t json_index) noexcept;
inline size_t after_element() const noexcept;
really_inline tape_type tape_ref_type() const noexcept;
really_inline uint64_t tape_value() const noexcept;
template<typename T>
really_inline T next_tape_value() const noexcept;
inline std::string_view get_string_view() const noexcept;
/** The document this element references. */
const document *doc;
/** The index of this element on `doc.tape[]` */
size_t json_index;
};
/** The index of this element on `doc.tape[]` */
size_t json_index;
};
} // namespace simdjson::internal
namespace simdjson::dom {
/**
* The actual concrete type of a JSON element
* This is the type it is most easily cast to with get<>.
*/
enum class element_type {
ARRAY, ///< dom::array
OBJECT, ///< dom::object
INT64, ///< int64_t
UINT64, ///< uint64_t: any integer that fits in uint64_t but *not* int64_t
DOUBLE, ///< double: Any number with a "." or "e" that fits in double.
STRING, ///< std::string_view
BOOL, ///< bool
NULL_VALUE ///< null
};
/**
* JSON array.
*/
@@ -367,6 +382,9 @@ public:
/** Create a new, invalid element. */
really_inline element() noexcept;
/** The type of this element. */
really_inline element_type type() const noexcept;
/** Whether this element is a json `null`. */
really_inline bool is_null() const noexcept;
@@ -1121,6 +1139,36 @@ inline std::ostream& operator<<(std::ostream& out, const object &value) { return
*/
inline std::ostream& operator<<(std::ostream& out, const key_value_pair &value) { return out << minify(value); }
/**
* Print element type to an output stream.
*
* @param out The output stream.
* @param value The value to print.
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
*/
inline std::ostream& operator<<(std::ostream& out, element_type type) {
switch (type) {
case element_type::ARRAY:
return out << "array";
case element_type::OBJECT:
return out << "object";
case element_type::INT64:
return out << "int64_t";
case element_type::UINT64:
return out << "uint64_t";
case element_type::DOUBLE:
return out << "double";
case element_type::STRING:
return out << "string";
case element_type::BOOL:
return out << "bool";
case element_type::NULL_VALUE:
return out << "null";
default:
abort();
}
}
} // namespace dom
#if SIMDJSON_EXCEPTIONS
@@ -1172,6 +1220,7 @@ public:
really_inline simdjson_result(dom::element &&value) noexcept; ///< @private
really_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element_type> type() const noexcept;
inline simdjson_result<bool> is_null() const noexcept;
template<typename T>
inline simdjson_result<bool> is() const noexcept;
+50 -20
View File
@@ -23,6 +23,10 @@ really_inline simdjson_result<dom::element>::simdjson_result(dom::element &&valu
: internal::simdjson_result_base<dom::element>(std::forward<dom::element>(value)) {}
really_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<dom::element>(error) {}
inline simdjson_result<dom::element_type> simdjson_result<dom::element>::type() const noexcept {
if (error()) { return error(); }
return first.type();
}
inline simdjson_result<bool> simdjson_result<dom::element>::is_null() const noexcept {
if (error()) { return error(); }
return first.is_null();
@@ -715,13 +719,39 @@ inline key_value_pair::key_value_pair(const std::string_view &_key, element _val
really_inline element::element() noexcept : internal::tape_ref() {}
really_inline element::element(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) { }
inline element_type element::type() const noexcept {
switch (tape_ref_type()) {
case internal::tape_type::START_ARRAY:
return element_type::ARRAY;
case internal::tape_type::START_OBJECT:
return element_type::OBJECT;
case internal::tape_type::INT64:
return element_type::INT64;
case internal::tape_type::UINT64:
return element_type::UINT64;
case internal::tape_type::DOUBLE:
return element_type::DOUBLE;
case internal::tape_type::STRING:
return element_type::STRING;
case internal::tape_type::TRUE_VALUE:
case internal::tape_type::FALSE_VALUE:
return element_type::BOOL;
case internal::tape_type::NULL_VALUE:
return element_type::NULL_VALUE;
case internal::tape_type::ROOT:
case internal::tape_type::END_ARRAY:
case internal::tape_type::END_OBJECT:
default:
abort();
}
}
really_inline bool element::is_null() const noexcept {
return type() == internal::tape_type::NULL_VALUE;
return tape_ref_type() == internal::tape_type::NULL_VALUE;
}
template<>
inline simdjson_result<bool> element::get<bool>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::TRUE_VALUE:
return true;
case internal::tape_type::FALSE_VALUE:
@@ -732,7 +762,7 @@ inline simdjson_result<bool> element::get<bool>() const noexcept {
}
template<>
inline simdjson_result<const char *> element::get<const char *>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::STRING: {
size_t string_buf_index = tape_value();
return reinterpret_cast<const char *>(&doc->string_buf[string_buf_index + sizeof(uint32_t)]);
@@ -743,7 +773,7 @@ inline simdjson_result<const char *> element::get<const char *>() const noexcept
}
template<>
inline simdjson_result<std::string_view> element::get<std::string_view>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::STRING:
return get_string_view();
default:
@@ -752,7 +782,7 @@ inline simdjson_result<std::string_view> element::get<std::string_view>() const
}
template<>
inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::UINT64:
return next_tape_value<uint64_t>();
case internal::tape_type::INT64: {
@@ -768,11 +798,11 @@ inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
}
template<>
inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::UINT64: {
uint64_t result = next_tape_value<uint64_t>();
// Wrapping max in parens to handle Windows issue: https://stackoverflow.com/questions/11544073/how-do-i-deal-with-the-max-macro-in-windows-h-colliding-with-max-in-std
if (result > (std::numeric_limits<uint64_t>::max)()) {
if (result > (std::numeric_limits<int64_t>::max)()) {
return NUMBER_OUT_OF_RANGE;
}
return static_cast<int64_t>(result);
@@ -785,7 +815,7 @@ inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
}
template<>
inline simdjson_result<double> element::get<double>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::UINT64:
return next_tape_value<uint64_t>();
case internal::tape_type::INT64: {
@@ -804,7 +834,7 @@ inline simdjson_result<double> element::get<double>() const noexcept {
}
template<>
inline simdjson_result<array> element::get<array>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::START_ARRAY:
return array(doc, json_index);
default:
@@ -813,7 +843,7 @@ inline simdjson_result<array> element::get<array>() const noexcept {
}
template<>
inline simdjson_result<object> element::get<object>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(doc, json_index);
default:
@@ -838,10 +868,10 @@ inline element::operator double() const noexcept(false) { return get<double>();
inline element::operator array() const noexcept(false) { return get<array>(); }
inline element::operator object() const noexcept(false) { return get<object>(); }
inline dom::array::iterator dom::element::begin() const noexcept(false) {
inline array::iterator element::begin() const noexcept(false) {
return get<array>().begin();
}
inline dom::array::iterator dom::element::end() const noexcept(false) {
inline array::iterator element::end() const noexcept(false) {
return get<array>().end();
}
@@ -854,7 +884,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
return at_key(key);
}
inline simdjson_result<element> element::at(const std::string_view &json_pointer) const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(doc, json_index).at(json_pointer);
case internal::tape_type::START_ARRAY:
@@ -905,7 +935,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
out << '"' << internal::escape_json_string(iter.get_string_view()) << "\":";
iter.json_index++;
}
switch (iter.type()) {
switch (iter.tape_ref_type()) {
// Arrays
case tape_type::START_ARRAY: {
@@ -923,7 +953,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
iter.json_index++;
// Handle empty [] (we don't want to come back around and print commas)
if (iter.type() == tape_type::END_ARRAY) {
if (iter.tape_ref_type() == tape_type::END_ARRAY) {
out << ']';
depth--;
break;
@@ -950,7 +980,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
iter.json_index++;
// Handle empty {} (we don't want to come back around and print commas)
if (iter.type() == tape_type::END_OBJECT) {
if (iter.tape_ref_type() == tape_type::END_OBJECT) {
out << '}';
depth--;
break;
@@ -997,8 +1027,8 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
after_value = true;
// Handle multiple ends in a row
while (depth != 0 && (iter.type() == tape_type::END_ARRAY || iter.type() == tape_type::END_OBJECT)) {
out << char(iter.type());
while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY || iter.tape_ref_type() == tape_type::END_OBJECT)) {
out << char(iter.tape_ref_type());
depth--;
iter.json_index++;
}
@@ -1070,7 +1100,7 @@ really_inline tape_ref::tape_ref() noexcept : doc{nullptr}, json_index{0} {}
really_inline tape_ref::tape_ref(const document *_doc, size_t _json_index) noexcept : doc{_doc}, json_index{_json_index} {}
inline size_t tape_ref::after_element() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case tape_type::START_ARRAY:
case tape_type::START_OBJECT:
return tape_value();
@@ -1082,7 +1112,7 @@ inline size_t tape_ref::after_element() const noexcept {
return json_index + 1;
}
}
really_inline tape_type tape_ref::type() const noexcept {
really_inline tape_type tape_ref::tape_ref_type() const noexcept {
return static_cast<tape_type>(doc->tape[json_index] >> 56);
}
really_inline uint64_t internal::tape_ref::tape_value() const noexcept {
+2 -2
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 0.3.0
#define SIMDJSON_VERSION 0.3.1
namespace simdjson {
enum {
@@ -19,7 +19,7 @@ enum {
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 0
SIMDJSON_VERSION_REVISION = 1
};
} // namespace simdjson
+1 -1
View File
@@ -1,4 +1,4 @@
/* auto-generated on Tue 31 Mar 2020 17:00:28 EDT. Do not edit! */
/* auto-generated on Thu 2 Apr 2020 18:58:25 EDT. Do not edit! */
#include <iostream>
#include "simdjson.h"
+1 -1
View File
@@ -1,4 +1,4 @@
/* auto-generated on Tue 31 Mar 2020 17:00:28 EDT. Do not edit! */
/* auto-generated on Thu 2 Apr 2020 18:58:25 EDT. Do not edit! */
#include "simdjson.h"
/* used for http://dmalloc.com/ Dmalloc - Debug Malloc Library */
+139 -60
View File
@@ -1,4 +1,4 @@
/* auto-generated on Tue 31 Mar 2020 17:00:28 EDT. Do not edit! */
/* auto-generated on Thu 2 Apr 2020 18:58:25 EDT. Do not edit! */
/* begin file include/simdjson.h */
#ifndef SIMDJSON_H
#define SIMDJSON_H
@@ -40,7 +40,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION 0.3.0
#define SIMDJSON_VERSION 0.3.1
namespace simdjson {
enum {
@@ -55,7 +55,7 @@ enum {
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
SIMDJSON_VERSION_REVISION = 0
SIMDJSON_VERSION_REVISION = 1
};
} // namespace simdjson
@@ -744,50 +744,65 @@ namespace simdjson::internal {
using namespace simdjson::dom;
constexpr const uint64_t JSON_VALUE_MASK = 0x00FFFFFFFFFFFFFF;
enum class tape_type;
class tape_ref;
/**
* The possible types in the tape. Internal only.
*/
enum class tape_type {
ROOT = 'r',
START_ARRAY = '[',
START_OBJECT = '{',
END_ARRAY = ']',
END_OBJECT = '}',
STRING = '"',
INT64 = 'l',
UINT64 = 'u',
DOUBLE = 'd',
TRUE_VALUE = 't',
FALSE_VALUE = 'f',
NULL_VALUE = 'n'
};
/**
* A reference to an element on the tape. Internal only.
*/
class tape_ref {
public:
really_inline tape_ref() noexcept;
really_inline tape_ref(const document *doc, size_t json_index) noexcept;
inline size_t after_element() const noexcept;
really_inline tape_type type() const noexcept;
really_inline uint64_t tape_value() const noexcept;
template<typename T>
really_inline T next_tape_value() const noexcept;
inline std::string_view get_string_view() const noexcept;
/**
* The possible types in the tape. Internal only.
*/
enum class tape_type {
ROOT = 'r',
START_ARRAY = '[',
START_OBJECT = '{',
END_ARRAY = ']',
END_OBJECT = '}',
STRING = '"',
INT64 = 'l',
UINT64 = 'u',
DOUBLE = 'd',
TRUE_VALUE = 't',
FALSE_VALUE = 'f',
NULL_VALUE = 'n'
};
/** The document this element references. */
const document *doc;
/**
* A reference to an element on the tape. Internal only.
*/
class tape_ref {
public:
really_inline tape_ref() noexcept;
really_inline tape_ref(const document *doc, size_t json_index) noexcept;
inline size_t after_element() const noexcept;
really_inline tape_type tape_ref_type() const noexcept;
really_inline uint64_t tape_value() const noexcept;
template<typename T>
really_inline T next_tape_value() const noexcept;
inline std::string_view get_string_view() const noexcept;
/** The document this element references. */
const document *doc;
/** The index of this element on `doc.tape[]` */
size_t json_index;
};
/** The index of this element on `doc.tape[]` */
size_t json_index;
};
} // namespace simdjson::internal
namespace simdjson::dom {
/**
* The actual concrete type of a JSON element
* This is the type it is most easily cast to with get<>.
*/
enum class element_type {
ARRAY, ///< dom::array
OBJECT, ///< dom::object
INT64, ///< int64_t
UINT64, ///< uint64_t: any integer that fits in uint64_t but *not* int64_t
DOUBLE, ///< double: Any number with a "." or "e" that fits in double.
STRING, ///< std::string_view
BOOL, ///< bool
NULL_VALUE ///< null
};
/**
* JSON array.
*/
@@ -1070,6 +1085,9 @@ public:
/** Create a new, invalid element. */
really_inline element() noexcept;
/** The type of this element. */
really_inline element_type type() const noexcept;
/** Whether this element is a json `null`. */
really_inline bool is_null() const noexcept;
@@ -1824,6 +1842,36 @@ inline std::ostream& operator<<(std::ostream& out, const object &value) { return
*/
inline std::ostream& operator<<(std::ostream& out, const key_value_pair &value) { return out << minify(value); }
/**
* Print element type to an output stream.
*
* @param out The output stream.
* @param value The value to print.
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
*/
inline std::ostream& operator<<(std::ostream& out, element_type type) {
switch (type) {
case element_type::ARRAY:
return out << "array";
case element_type::OBJECT:
return out << "object";
case element_type::INT64:
return out << "int64_t";
case element_type::UINT64:
return out << "uint64_t";
case element_type::DOUBLE:
return out << "double";
case element_type::STRING:
return out << "string";
case element_type::BOOL:
return out << "bool";
case element_type::NULL_VALUE:
return out << "null";
default:
abort();
}
}
} // namespace dom
#if SIMDJSON_EXCEPTIONS
@@ -1875,6 +1923,7 @@ public:
really_inline simdjson_result(dom::element &&value) noexcept; ///< @private
really_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element_type> type() const noexcept;
inline simdjson_result<bool> is_null() const noexcept;
template<typename T>
inline simdjson_result<bool> is() const noexcept;
@@ -2867,6 +2916,10 @@ really_inline simdjson_result<dom::element>::simdjson_result(dom::element &&valu
: internal::simdjson_result_base<dom::element>(std::forward<dom::element>(value)) {}
really_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<dom::element>(error) {}
inline simdjson_result<dom::element_type> simdjson_result<dom::element>::type() const noexcept {
if (error()) { return error(); }
return first.type();
}
inline simdjson_result<bool> simdjson_result<dom::element>::is_null() const noexcept {
if (error()) { return error(); }
return first.is_null();
@@ -3559,13 +3612,39 @@ inline key_value_pair::key_value_pair(const std::string_view &_key, element _val
really_inline element::element() noexcept : internal::tape_ref() {}
really_inline element::element(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) { }
inline element_type element::type() const noexcept {
switch (tape_ref_type()) {
case internal::tape_type::START_ARRAY:
return element_type::ARRAY;
case internal::tape_type::START_OBJECT:
return element_type::OBJECT;
case internal::tape_type::INT64:
return element_type::INT64;
case internal::tape_type::UINT64:
return element_type::UINT64;
case internal::tape_type::DOUBLE:
return element_type::DOUBLE;
case internal::tape_type::STRING:
return element_type::STRING;
case internal::tape_type::TRUE_VALUE:
case internal::tape_type::FALSE_VALUE:
return element_type::BOOL;
case internal::tape_type::NULL_VALUE:
return element_type::NULL_VALUE;
case internal::tape_type::ROOT:
case internal::tape_type::END_ARRAY:
case internal::tape_type::END_OBJECT:
default:
abort();
}
}
really_inline bool element::is_null() const noexcept {
return type() == internal::tape_type::NULL_VALUE;
return tape_ref_type() == internal::tape_type::NULL_VALUE;
}
template<>
inline simdjson_result<bool> element::get<bool>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::TRUE_VALUE:
return true;
case internal::tape_type::FALSE_VALUE:
@@ -3576,7 +3655,7 @@ inline simdjson_result<bool> element::get<bool>() const noexcept {
}
template<>
inline simdjson_result<const char *> element::get<const char *>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::STRING: {
size_t string_buf_index = tape_value();
return reinterpret_cast<const char *>(&doc->string_buf[string_buf_index + sizeof(uint32_t)]);
@@ -3587,7 +3666,7 @@ inline simdjson_result<const char *> element::get<const char *>() const noexcept
}
template<>
inline simdjson_result<std::string_view> element::get<std::string_view>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::STRING:
return get_string_view();
default:
@@ -3596,7 +3675,7 @@ inline simdjson_result<std::string_view> element::get<std::string_view>() const
}
template<>
inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::UINT64:
return next_tape_value<uint64_t>();
case internal::tape_type::INT64: {
@@ -3612,11 +3691,11 @@ inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
}
template<>
inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::UINT64: {
uint64_t result = next_tape_value<uint64_t>();
// Wrapping max in parens to handle Windows issue: https://stackoverflow.com/questions/11544073/how-do-i-deal-with-the-max-macro-in-windows-h-colliding-with-max-in-std
if (result > (std::numeric_limits<uint64_t>::max)()) {
if (result > (std::numeric_limits<int64_t>::max)()) {
return NUMBER_OUT_OF_RANGE;
}
return static_cast<int64_t>(result);
@@ -3629,7 +3708,7 @@ inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
}
template<>
inline simdjson_result<double> element::get<double>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::UINT64:
return next_tape_value<uint64_t>();
case internal::tape_type::INT64: {
@@ -3648,7 +3727,7 @@ inline simdjson_result<double> element::get<double>() const noexcept {
}
template<>
inline simdjson_result<array> element::get<array>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::START_ARRAY:
return array(doc, json_index);
default:
@@ -3657,7 +3736,7 @@ inline simdjson_result<array> element::get<array>() const noexcept {
}
template<>
inline simdjson_result<object> element::get<object>() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(doc, json_index);
default:
@@ -3682,10 +3761,10 @@ inline element::operator double() const noexcept(false) { return get<double>();
inline element::operator array() const noexcept(false) { return get<array>(); }
inline element::operator object() const noexcept(false) { return get<object>(); }
inline dom::array::iterator dom::element::begin() const noexcept(false) {
inline array::iterator element::begin() const noexcept(false) {
return get<array>().begin();
}
inline dom::array::iterator dom::element::end() const noexcept(false) {
inline array::iterator element::end() const noexcept(false) {
return get<array>().end();
}
@@ -3698,7 +3777,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
return at_key(key);
}
inline simdjson_result<element> element::at(const std::string_view &json_pointer) const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(doc, json_index).at(json_pointer);
case internal::tape_type::START_ARRAY:
@@ -3749,7 +3828,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
out << '"' << internal::escape_json_string(iter.get_string_view()) << "\":";
iter.json_index++;
}
switch (iter.type()) {
switch (iter.tape_ref_type()) {
// Arrays
case tape_type::START_ARRAY: {
@@ -3767,7 +3846,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
iter.json_index++;
// Handle empty [] (we don't want to come back around and print commas)
if (iter.type() == tape_type::END_ARRAY) {
if (iter.tape_ref_type() == tape_type::END_ARRAY) {
out << ']';
depth--;
break;
@@ -3794,7 +3873,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
iter.json_index++;
// Handle empty {} (we don't want to come back around and print commas)
if (iter.type() == tape_type::END_OBJECT) {
if (iter.tape_ref_type() == tape_type::END_OBJECT) {
out << '}';
depth--;
break;
@@ -3841,8 +3920,8 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
after_value = true;
// Handle multiple ends in a row
while (depth != 0 && (iter.type() == tape_type::END_ARRAY || iter.type() == tape_type::END_OBJECT)) {
out << char(iter.type());
while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY || iter.tape_ref_type() == tape_type::END_OBJECT)) {
out << char(iter.tape_ref_type());
depth--;
iter.json_index++;
}
@@ -3914,7 +3993,7 @@ really_inline tape_ref::tape_ref() noexcept : doc{nullptr}, json_index{0} {}
really_inline tape_ref::tape_ref(const document *_doc, size_t _json_index) noexcept : doc{_doc}, json_index{_json_index} {}
inline size_t tape_ref::after_element() const noexcept {
switch (type()) {
switch (tape_ref_type()) {
case tape_type::START_ARRAY:
case tape_type::START_OBJECT:
return tape_value();
@@ -3926,7 +4005,7 @@ inline size_t tape_ref::after_element() const noexcept {
return json_index + 1;
}
}
really_inline tape_type tape_ref::type() const noexcept {
really_inline tape_type tape_ref::tape_ref_type() const noexcept {
return static_cast<tape_type>(doc->tape[json_index] >> 56);
}
really_inline uint64_t internal::tape_ref::tape_value() const noexcept {
+488
View File
@@ -23,6 +23,11 @@
#define NDJSON_TEST_PATH "jsonexamples/amazon_cellphones.ndjson"
#endif
#define ASSERT_EQUAL(ACTUAL, EXPECTED) if ((ACTUAL) != (EXPECTED)) { std::cerr << "Expected " << #ACTUAL << " to be " << (EXPECTED) << ", got " << (ACTUAL) << " instead!" << std::endl; return false; }
#define ASSERT_TRUE(ACTUAL) ASSERT_EQUAL(ACTUAL, true)
#define ASSERT_FALSE(ACTUAL) ASSERT_EQUAL(ACTUAL, false)
#define ASSERT_SUCCESS(ERROR) if (ERROR) { std::cerr << (ERROR) << std::endl; return false; }
namespace number_tests {
// ulp distance
@@ -1104,6 +1109,488 @@ namespace dom_api_tests {
}
}
namespace type_tests {
using namespace simdjson;
using namespace std;
const padded_string ALL_TYPES_JSON = R"(
{
"array": [],
"object": {},
"string": "foo",
"0": 0,
"1": 1,
"-1": -1,
"9223372036854775807": 9223372036854775807,
"-9223372036854775808": -9223372036854775808,
"9223372036854775808": 9223372036854775808,
"18446744073709551615": 18446744073709551615,
"0.0": 0.0,
"0.1": 0.1,
"1e0": 1e0,
"1e100": 1e100,
"true": true,
"false": false,
"null": null
}
)"_padded;
bool test_array() {
std::cout << "Running " << __func__ << std::endl;
const auto key = "array";
const auto expected_type = dom::element_type::ARRAY;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_TRUE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_FALSE(result.is<uint64_t>());
ASSERT_FALSE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_TRUE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_FALSE(element.is<uint64_t>());
ASSERT_FALSE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
dom::array value;
result.get<dom::array>().tie(value, error);
ASSERT_SUCCESS(error);
return true;
}
bool test_object() {
std::cout << "Running " << __func__ << std::endl;
const auto key = "object";
const auto expected_type = dom::element_type::OBJECT;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_TRUE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_FALSE(result.is<uint64_t>());
ASSERT_FALSE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_TRUE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_FALSE(element.is<uint64_t>());
ASSERT_FALSE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
dom::object value;
result.get<dom::object>().tie(value, error);
ASSERT_SUCCESS(error);
return true;
}
bool test_string() {
std::cout << "Running " << __func__ << std::endl;
const auto key = "string";
const auto expected_type = dom::element_type::STRING;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_TRUE(result.is<std::string_view>());
ASSERT_TRUE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_FALSE(result.is<uint64_t>());
ASSERT_FALSE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_TRUE(element.is<std::string_view>());
ASSERT_TRUE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_FALSE(element.is<uint64_t>());
ASSERT_FALSE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
std::string_view value;
result.get<std::string_view>().tie(value, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(value, string_view("foo"));
const char *value2;
result.get<const char *>().tie(value2, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(string_view(value2), string_view("foo"));
return true;
}
bool test_int64(const char *key, int64_t expected_value) {
std::cout << "Running " << __func__ << "(" << key << ")" << std::endl;
const auto expected_type = dom::element_type::INT64;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_TRUE(result.is<int64_t>());
if (expected_value < 0) {
ASSERT_FALSE(result.is<uint64_t>());
} else {
ASSERT_TRUE(result.is<uint64_t>());
}
ASSERT_TRUE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_TRUE(element.is<int64_t>());
if (expected_value < 0) {
ASSERT_FALSE(element.is<uint64_t>());
} else {
ASSERT_TRUE(element.is<uint64_t>());
}
ASSERT_TRUE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
int64_t value;
result.get<int64_t>().tie(value, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(value, expected_value);
return true;
}
bool test_uint64(const char *key, uint64_t expected_value) {
std::cout << "Running " << __func__ << "(" << key << ")" << std::endl;
const auto expected_type = dom::element_type::UINT64;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_TRUE(result.is<uint64_t>());
ASSERT_TRUE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_TRUE(element.is<uint64_t>());
ASSERT_TRUE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
uint64_t value;
result.get<uint64_t>().tie(value, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(value, expected_value);
return true;
}
bool test_double(const char *key, double expected_value) {
std::cout << "Running " << __func__ << "(" << key << ")" << std::endl;
const auto expected_type = dom::element_type::DOUBLE;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_FALSE(result.is<uint64_t>());
ASSERT_TRUE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_FALSE(element.is<uint64_t>());
ASSERT_TRUE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
double value;
result.get<double>().tie(value, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(value, expected_value);
return true;
}
bool test_bool(const char *key, bool expected_value) {
std::cout << "Running " << __func__ << "(" << key << ")" << std::endl;
const auto expected_type = dom::element_type::BOOL;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)[key];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_FALSE(result.is<uint64_t>());
ASSERT_FALSE(result.is<double>());
ASSERT_TRUE(result.is<bool>());
ASSERT_FALSE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_FALSE(element.is<uint64_t>());
ASSERT_FALSE(element.is<double>());
ASSERT_TRUE(element.is<bool>());
ASSERT_FALSE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
bool value;
result.get<bool>().tie(value, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(value, expected_value);
return true;
}
bool test_null() {
std::cout << "Running " << __func__ << std::endl;
const auto expected_type = dom::element_type::NULL_VALUE;
dom::parser parser;
simdjson_result<dom::element> result = parser.parse(ALL_TYPES_JSON)["null"];
ASSERT_SUCCESS(result.error());
// Test simdjson_result<element>.is<T>() (error chain)
ASSERT_FALSE(result.is<dom::array>());
ASSERT_FALSE(result.is<dom::object>());
ASSERT_FALSE(result.is<std::string_view>());
ASSERT_FALSE(result.is<const char *>());
ASSERT_FALSE(result.is<int64_t>());
ASSERT_FALSE(result.is<uint64_t>());
ASSERT_FALSE(result.is<double>());
ASSERT_FALSE(result.is<bool>());
ASSERT_TRUE(result.is_null());
// Test simdjson_result<element>.type() (error chain)
simdjson::error_code error;
dom::element_type type;
result.type().tie(type, error);
ASSERT_SUCCESS(error);
ASSERT_EQUAL(type, expected_type);
// Test element.is<T>()
dom::element element = result.first;
ASSERT_FALSE(element.is<dom::array>());
ASSERT_FALSE(element.is<dom::object>());
ASSERT_FALSE(element.is<std::string_view>());
ASSERT_FALSE(element.is<const char *>());
ASSERT_FALSE(element.is<int64_t>());
ASSERT_FALSE(element.is<uint64_t>());
ASSERT_FALSE(element.is<double>());
ASSERT_FALSE(element.is<bool>());
ASSERT_TRUE(element.is_null());
// Test element.type()
ASSERT_EQUAL(element.type(), expected_type);
// Test element.get<T>()
return true;
}
bool run() {
return test_array() &&
test_object() &&
test_string() &&
test_int64("0", 0) &&
test_int64("1", 1) &&
test_int64("-1", -1) &&
test_int64("9223372036854775807", 9223372036854775807LL) &&
test_int64("-9223372036854775808", -1 - 9223372036854775807LL) &&
test_uint64("9223372036854775808", 9223372036854775808ULL) &&
test_uint64("18446744073709551615", 18446744073709551615ULL) &&
test_double("0.0", 0.0) &&
test_double("0.1", 0.1) &&
test_double("1e0", 1e0) &&
test_double("1e100", 1e100) &&
test_bool("true", true) &&
test_bool("false", false) &&
test_null() &&
true;
}
}
namespace format_tests {
using namespace simdjson;
using namespace simdjson::dom;
@@ -1378,6 +1865,7 @@ int main(int argc, char *argv[]) {
std::cout << "Running basic tests." << std::endl;
if (parse_api_tests::run() &&
dom_api_tests::run() &&
type_tests::run() &&
format_tests::run() &&
document_tests::run() &&
number_tests::run() &&
+46
View File
@@ -64,6 +64,52 @@ void basics_dom_2() {
cout << cars.at("0/tire_pressure/1") << endl; // Prints 39.9}
}
namespace treewalk_1 {
void print_json(dom::element element) {
switch (element.type()) {
case dom::element_type::ARRAY:
cout << "[";
for (dom::element child : dom::array(element)) {
print_json(child);
cout << ",";
}
cout << "]";
break;
case dom::element_type::OBJECT:
cout << "{";
for (dom::key_value_pair field : dom::object(element)) {
cout << "\"" << field.key << "\": ";
print_json(field.value);
}
cout << "}";
break;
case dom::element_type::INT64:
cout << int64_t(element) << endl;
break;
case dom::element_type::UINT64:
cout << uint64_t(element) << endl;
break;
case dom::element_type::DOUBLE:
cout << double(element) << endl;
break;
case dom::element_type::STRING:
cout << std::string_view(element) << endl;
break;
case dom::element_type::BOOL:
cout << bool(element) << endl;
break;
case dom::element_type::NULL_VALUE:
cout << "null" << endl;
break;
}
}
void basics_treewalk_1() {
dom::parser parser;
print_json(parser.load("twitter.json"));
}
}
void basics_ndjson() {
dom::parser parser;
for (dom::element doc : parser.load_many("x.txt")) {
+21
View File
@@ -76,7 +76,10 @@ elif (newversion[1] != currentv[1]):
else :
assert newversion[2] == currentv[2] + 1
atleastminor= (currentv[0] != newversion[0]) or (currentv[1] != newversion[1])
if(atleastminor):
print("This is more than a revision.")
versionfilerel = os.sep + "include" + os.sep + "simdjson" + os.sep + "simdjson_version.h"
versionfile = maindir + versionfilerel
@@ -114,17 +117,35 @@ print(versionfile + " modified")
import fileinput
import re
newmajorversionstring = str(newversion[0])
mewminorversionstring = str(newversion[1])
newrevversionstring = str(newversion[2])
newversionstring = str(newversion[0]) + "." + str(newversion[1]) + "." + str(newversion[2])
cmakefile = maindir + os.sep + "CMakeLists.txt"
sonumber = None
pattern = re.compile("set\(SIMDJSON_LIB_SOVERSION \"(\d+)\" CACHE STRING \"simdjson library soversion\"\)")
with open (cmakefile, 'rt') as myfile:
for line in myfile:
m = pattern.search(line)
if m != None:
sonumber = int(m.group(1))
break
print("so library number "+str(sonumber))
if(atleastminor):
print("Given that we have a minor revision, it seems necessary to bump the so library number")
print("See https://github.com/simdjson/simdjson/issues/661")
sonumber += 1
for line in fileinput.input(cmakefile, inplace=1, backup='.bak'):
line = re.sub('SIMDJSON_LIB_VERSION "\d+\.\d+\.\d+','SIMDJSON_LIB_VERSION "'+newversionstring, line.rstrip())
line = re.sub('SIMDJSON_LIB_SOVERSION "\d+','SIMDJSON_LIB_SOVERSION "'+newmajorversionstring, line)
line = re.sub('set\(PROJECT_VERSION_MAJOR \d+','set(PROJECT_VERSION_MAJOR '+newmajorversionstring, line)
line = re.sub('set\(PROJECT_VERSION_MINOR \d+','set(PROJECT_VERSION_MINOR '+mewminorversionstring, line)
line = re.sub('set\(PROJECT_VERSION_PATCH \d+','set(PROJECT_VERSION_PATCH '+newrevversionstring, line)
line = re.sub('set\(SIMDJSON_LIB_SOVERSION \"\d+\"','set(SIMDJSON_LIB_SOVERSION \"'+str(sonumber)+'\"', line)
print(line)