Add element.type() for type switching
This commit is contained in:
parent
7dad9fca0f
commit
13aee51011
|
@ -10,6 +10,7 @@ An overview of what you need to know to use simdjson, with examples.
|
||||||
* [Error Handling](#error-handling)
|
* [Error Handling](#error-handling)
|
||||||
* [Error Handling Example](#error-handling-example)
|
* [Error Handling Example](#error-handling-example)
|
||||||
* [Exceptions](#exceptions)
|
* [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)
|
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||||
* [Thread Safety](#thread-safety)
|
* [Thread Safety](#thread-safety)
|
||||||
|
|
||||||
|
@ -67,6 +68,8 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
|
||||||
first element.
|
first element.
|
||||||
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
|
> 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.
|
> 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:
|
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++
|
```c++
|
||||||
auto cars_json = R"( [
|
auto cars_json = R"( [
|
||||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
{ "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": "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": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||||
] )"_padded;
|
] )"_padded;
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
auto [cars, error] = parser.parse(cars_json).get<dom::array>();
|
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
|
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.
|
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
|
Newline-Delimited JSON (ndjson) and JSON lines
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,11 @@ namespace simdjson::internal {
|
||||||
using namespace simdjson::dom;
|
using namespace simdjson::dom;
|
||||||
|
|
||||||
constexpr const uint64_t JSON_VALUE_MASK = 0x00FFFFFFFFFFFFFF;
|
constexpr const uint64_t JSON_VALUE_MASK = 0x00FFFFFFFFFFFFFF;
|
||||||
enum class tape_type;
|
|
||||||
class tape_ref;
|
/**
|
||||||
/**
|
|
||||||
* The possible types in the tape. Internal only.
|
* The possible types in the tape. Internal only.
|
||||||
*/
|
*/
|
||||||
enum class tape_type {
|
enum class tape_type {
|
||||||
ROOT = 'r',
|
ROOT = 'r',
|
||||||
START_ARRAY = '[',
|
START_ARRAY = '[',
|
||||||
START_OBJECT = '{',
|
START_OBJECT = '{',
|
||||||
|
@ -59,17 +58,17 @@ class tape_ref;
|
||||||
TRUE_VALUE = 't',
|
TRUE_VALUE = 't',
|
||||||
FALSE_VALUE = 'f',
|
FALSE_VALUE = 'f',
|
||||||
NULL_VALUE = 'n'
|
NULL_VALUE = 'n'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference to an element on the tape. Internal only.
|
* A reference to an element on the tape. Internal only.
|
||||||
*/
|
*/
|
||||||
class tape_ref {
|
class tape_ref {
|
||||||
public:
|
public:
|
||||||
really_inline tape_ref() noexcept;
|
really_inline tape_ref() noexcept;
|
||||||
really_inline tape_ref(const document *doc, size_t json_index) noexcept;
|
really_inline tape_ref(const document *doc, size_t json_index) noexcept;
|
||||||
inline size_t after_element() const noexcept;
|
inline size_t after_element() const noexcept;
|
||||||
really_inline tape_type type() const noexcept;
|
really_inline tape_type tape_ref_type() const noexcept;
|
||||||
really_inline uint64_t tape_value() const noexcept;
|
really_inline uint64_t tape_value() const noexcept;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
really_inline T next_tape_value() const noexcept;
|
really_inline T next_tape_value() const noexcept;
|
||||||
|
@ -80,11 +79,27 @@ class tape_ref;
|
||||||
|
|
||||||
/** The index of this element on `doc.tape[]` */
|
/** The index of this element on `doc.tape[]` */
|
||||||
size_t json_index;
|
size_t json_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace simdjson::internal
|
} // namespace simdjson::internal
|
||||||
|
|
||||||
namespace simdjson::dom {
|
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.
|
* JSON array.
|
||||||
*/
|
*/
|
||||||
|
@ -367,6 +382,9 @@ public:
|
||||||
/** Create a new, invalid element. */
|
/** Create a new, invalid element. */
|
||||||
really_inline element() noexcept;
|
really_inline element() noexcept;
|
||||||
|
|
||||||
|
/** The type of this element. */
|
||||||
|
really_inline element_type type() const noexcept;
|
||||||
|
|
||||||
/** Whether this element is a json `null`. */
|
/** Whether this element is a json `null`. */
|
||||||
really_inline bool is_null() const noexcept;
|
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); }
|
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
|
} // namespace dom
|
||||||
|
|
||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
@ -1172,6 +1220,7 @@ public:
|
||||||
really_inline simdjson_result(dom::element &&value) noexcept; ///< @private
|
really_inline simdjson_result(dom::element &&value) noexcept; ///< @private
|
||||||
really_inline simdjson_result(error_code error) 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;
|
inline simdjson_result<bool> is_null() const noexcept;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline simdjson_result<bool> is() const noexcept;
|
inline simdjson_result<bool> is() const noexcept;
|
||||||
|
|
|
@ -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)) {}
|
: internal::simdjson_result_base<dom::element>(std::forward<dom::element>(value)) {}
|
||||||
really_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
|
really_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
|
||||||
: internal::simdjson_result_base<dom::element>(error) {}
|
: 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 {
|
inline simdjson_result<bool> simdjson_result<dom::element>::is_null() const noexcept {
|
||||||
if (error()) { return error(); }
|
if (error()) { return error(); }
|
||||||
return first.is_null();
|
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() noexcept : internal::tape_ref() {}
|
||||||
really_inline element::element(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) { }
|
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 {
|
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<>
|
template<>
|
||||||
inline simdjson_result<bool> element::get<bool>() const noexcept {
|
inline simdjson_result<bool> element::get<bool>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::TRUE_VALUE:
|
case internal::tape_type::TRUE_VALUE:
|
||||||
return true;
|
return true;
|
||||||
case internal::tape_type::FALSE_VALUE:
|
case internal::tape_type::FALSE_VALUE:
|
||||||
|
@ -732,7 +762,7 @@ inline simdjson_result<bool> element::get<bool>() const noexcept {
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline simdjson_result<const char *> element::get<const char *>() const noexcept {
|
inline simdjson_result<const char *> element::get<const char *>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::STRING: {
|
case internal::tape_type::STRING: {
|
||||||
size_t string_buf_index = tape_value();
|
size_t string_buf_index = tape_value();
|
||||||
return reinterpret_cast<const char *>(&doc->string_buf[string_buf_index + sizeof(uint32_t)]);
|
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<>
|
template<>
|
||||||
inline simdjson_result<std::string_view> element::get<std::string_view>() const noexcept {
|
inline simdjson_result<std::string_view> element::get<std::string_view>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::STRING:
|
case internal::tape_type::STRING:
|
||||||
return get_string_view();
|
return get_string_view();
|
||||||
default:
|
default:
|
||||||
|
@ -752,7 +782,7 @@ inline simdjson_result<std::string_view> element::get<std::string_view>() const
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
|
inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::UINT64:
|
case internal::tape_type::UINT64:
|
||||||
return next_tape_value<uint64_t>();
|
return next_tape_value<uint64_t>();
|
||||||
case internal::tape_type::INT64: {
|
case internal::tape_type::INT64: {
|
||||||
|
@ -768,11 +798,11 @@ inline simdjson_result<uint64_t> element::get<uint64_t>() const noexcept {
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
|
inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::UINT64: {
|
case internal::tape_type::UINT64: {
|
||||||
uint64_t result = next_tape_value<uint64_t>();
|
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
|
// 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 NUMBER_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
return static_cast<int64_t>(result);
|
return static_cast<int64_t>(result);
|
||||||
|
@ -785,7 +815,7 @@ inline simdjson_result<int64_t> element::get<int64_t>() const noexcept {
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline simdjson_result<double> element::get<double>() const noexcept {
|
inline simdjson_result<double> element::get<double>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::UINT64:
|
case internal::tape_type::UINT64:
|
||||||
return next_tape_value<uint64_t>();
|
return next_tape_value<uint64_t>();
|
||||||
case internal::tape_type::INT64: {
|
case internal::tape_type::INT64: {
|
||||||
|
@ -804,7 +834,7 @@ inline simdjson_result<double> element::get<double>() const noexcept {
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline simdjson_result<array> element::get<array>() const noexcept {
|
inline simdjson_result<array> element::get<array>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::START_ARRAY:
|
case internal::tape_type::START_ARRAY:
|
||||||
return array(doc, json_index);
|
return array(doc, json_index);
|
||||||
default:
|
default:
|
||||||
|
@ -813,7 +843,7 @@ inline simdjson_result<array> element::get<array>() const noexcept {
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline simdjson_result<object> element::get<object>() const noexcept {
|
inline simdjson_result<object> element::get<object>() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case internal::tape_type::START_OBJECT:
|
case internal::tape_type::START_OBJECT:
|
||||||
return object(doc, json_index);
|
return object(doc, json_index);
|
||||||
default:
|
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 array() const noexcept(false) { return get<array>(); }
|
||||||
inline element::operator object() const noexcept(false) { return get<object>(); }
|
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();
|
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();
|
return get<array>().end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,7 +884,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
|
||||||
return at_key(key);
|
return at_key(key);
|
||||||
}
|
}
|
||||||
inline simdjson_result<element> element::at(const std::string_view &json_pointer) const noexcept {
|
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:
|
case internal::tape_type::START_OBJECT:
|
||||||
return object(doc, json_index).at(json_pointer);
|
return object(doc, json_index).at(json_pointer);
|
||||||
case internal::tape_type::START_ARRAY:
|
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()) << "\":";
|
out << '"' << internal::escape_json_string(iter.get_string_view()) << "\":";
|
||||||
iter.json_index++;
|
iter.json_index++;
|
||||||
}
|
}
|
||||||
switch (iter.type()) {
|
switch (iter.tape_ref_type()) {
|
||||||
|
|
||||||
// Arrays
|
// Arrays
|
||||||
case tape_type::START_ARRAY: {
|
case tape_type::START_ARRAY: {
|
||||||
|
@ -923,7 +953,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
|
||||||
iter.json_index++;
|
iter.json_index++;
|
||||||
|
|
||||||
// Handle empty [] (we don't want to come back around and print commas)
|
// 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 << ']';
|
out << ']';
|
||||||
depth--;
|
depth--;
|
||||||
break;
|
break;
|
||||||
|
@ -950,7 +980,7 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
|
||||||
iter.json_index++;
|
iter.json_index++;
|
||||||
|
|
||||||
// Handle empty {} (we don't want to come back around and print commas)
|
// 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 << '}';
|
out << '}';
|
||||||
depth--;
|
depth--;
|
||||||
break;
|
break;
|
||||||
|
@ -997,8 +1027,8 @@ inline std::ostream& minify<dom::element>::print(std::ostream& out) {
|
||||||
after_value = true;
|
after_value = true;
|
||||||
|
|
||||||
// Handle multiple ends in a row
|
// Handle multiple ends in a row
|
||||||
while (depth != 0 && (iter.type() == tape_type::END_ARRAY || iter.type() == tape_type::END_OBJECT)) {
|
while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY || iter.tape_ref_type() == tape_type::END_OBJECT)) {
|
||||||
out << char(iter.type());
|
out << char(iter.tape_ref_type());
|
||||||
depth--;
|
depth--;
|
||||||
iter.json_index++;
|
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} {}
|
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 {
|
inline size_t tape_ref::after_element() const noexcept {
|
||||||
switch (type()) {
|
switch (tape_ref_type()) {
|
||||||
case tape_type::START_ARRAY:
|
case tape_type::START_ARRAY:
|
||||||
case tape_type::START_OBJECT:
|
case tape_type::START_OBJECT:
|
||||||
return tape_value();
|
return tape_value();
|
||||||
|
@ -1082,7 +1112,7 @@ inline size_t tape_ref::after_element() const noexcept {
|
||||||
return json_index + 1;
|
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);
|
return static_cast<tape_type>(doc->tape[json_index] >> 56);
|
||||||
}
|
}
|
||||||
really_inline uint64_t internal::tape_ref::tape_value() const noexcept {
|
really_inline uint64_t internal::tape_ref::tape_value() const noexcept {
|
||||||
|
|
|
@ -23,6 +23,11 @@
|
||||||
#define NDJSON_TEST_PATH "jsonexamples/amazon_cellphones.ndjson"
|
#define NDJSON_TEST_PATH "jsonexamples/amazon_cellphones.ndjson"
|
||||||
#endif
|
#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 {
|
namespace number_tests {
|
||||||
|
|
||||||
// ulp distance
|
// 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 {
|
namespace format_tests {
|
||||||
using namespace simdjson;
|
using namespace simdjson;
|
||||||
using namespace simdjson::dom;
|
using namespace simdjson::dom;
|
||||||
|
@ -1378,6 +1865,7 @@ int main(int argc, char *argv[]) {
|
||||||
std::cout << "Running basic tests." << std::endl;
|
std::cout << "Running basic tests." << std::endl;
|
||||||
if (parse_api_tests::run() &&
|
if (parse_api_tests::run() &&
|
||||||
dom_api_tests::run() &&
|
dom_api_tests::run() &&
|
||||||
|
type_tests::run() &&
|
||||||
format_tests::run() &&
|
format_tests::run() &&
|
||||||
document_tests::run() &&
|
document_tests::run() &&
|
||||||
number_tests::run() &&
|
number_tests::run() &&
|
||||||
|
|
|
@ -64,6 +64,52 @@ void basics_dom_2() {
|
||||||
cout << cars.at("0/tire_pressure/1") << endl; // Prints 39.9}
|
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() {
|
void basics_ndjson() {
|
||||||
dom::parser parser;
|
dom::parser parser;
|
||||||
for (dom::element doc : parser.load_many("x.txt")) {
|
for (dom::element doc : parser.load_many("x.txt")) {
|
||||||
|
|
Loading…
Reference in New Issue