diff --git a/include/simdjson/dom/array.h b/include/simdjson/dom/array.h index 62a48c9e6..55d3ec8a8 100644 --- a/include/simdjson/dom/array.h +++ b/include/simdjson/dom/array.h @@ -16,12 +16,12 @@ class element; /** * JSON array. */ -class array : protected internal::tape_ref { +class array { public: /** Create a new, invalid array */ really_inline array() noexcept; - class iterator : protected internal::tape_ref { + class iterator { public: /** * Get the actual value @@ -41,7 +41,8 @@ public: */ inline bool operator!=(const iterator& other) const noexcept; private: - really_inline iterator(const document *doc, size_t json_index) noexcept; + really_inline iterator(const internal::tape_ref &tape) noexcept; + internal::tape_ref tape; friend class array; }; @@ -98,7 +99,8 @@ public: inline simdjson_result at(size_t index) const noexcept; private: - really_inline array(const document *doc, size_t json_index) noexcept; + really_inline array(const internal::tape_ref &tape) noexcept; + internal::tape_ref tape; friend class element; friend struct simdjson_result; template diff --git a/include/simdjson/dom/element.h b/include/simdjson/dom/element.h index 80b6a3958..cee2920eb 100644 --- a/include/simdjson/dom/element.h +++ b/include/simdjson/dom/element.h @@ -35,7 +35,7 @@ enum class element_type { * References an element in a JSON document, representing a JSON null, boolean, string, number, * array or object. */ -class element : protected internal::tape_ref { +class element { public: /** Create a new, invalid element. */ really_inline element() noexcept; @@ -43,8 +43,135 @@ public: /** 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; + /** + * Cast this element to an array. + * + * Equivalent to get(). + * + * @returns An object that can be used to iterate the array, or: + * INCORRECT_TYPE if the JSON element is not an array. + */ + inline simdjson_result get_array() const noexcept; + /** + * Cast this element to an object. + * + * Equivalent to get(). + * + * @returns An object that can be used to look up or iterate the object's fields, or: + * INCORRECT_TYPE if the JSON element is not an object. + */ + inline simdjson_result get_object() const noexcept; + /** + * Cast this element to a string. + * + * Equivalent to get(). + * + * @returns An pointer to a null-terminated string. This string is stored in the parser and will + * be invalidated the next time it parses a document or when it is destroyed. + * Returns INCORRECT_TYPE if the JSON element is not a string. + */ + inline simdjson_result get_c_str() const noexcept; + /** + * Cast this element to a string. + * + * Equivalent to get(). + * + * @returns A string. The string is stored in the parser and will be invalidated the next time it + * parses a document or when it is destroyed. + * Returns INCORRECT_TYPE if the JSON element is not a string. + */ + inline simdjson_result get_string() const noexcept; + /** + * Cast this element to a signed integer. + * + * Equivalent to get(). + * + * @returns A signed 64-bit integer. + * Returns INCORRECT_TYPE if the JSON element is not an integer, or NUMBER_OUT_OF_RANGE + * if it is negative. + */ + inline simdjson_result get_int64_t() const noexcept; + /** + * Cast this element to an unsigned integer. + * + * Equivalent to get(). + * + * @returns An unsigned 64-bit integer. + * Returns INCORRECT_TYPE if the JSON element is not an integer, or NUMBER_OUT_OF_RANGE + * if it is too large. + */ + inline simdjson_result get_uint64_t() const noexcept; + /** + * Cast this element to an double floating-point. + * + * Equivalent to get(). + * + * @returns A double value. + * Returns INCORRECT_TYPE if the JSON element is not a number. + */ + inline simdjson_result get_double() const noexcept; + /** + * Cast this element to a bool. + * + * Equivalent to get(). + * + * @returns A bool value. + * Returns INCORRECT_TYPE if the JSON element is not a boolean. + */ + inline simdjson_result get_bool() const noexcept; + + /** + * Whether this element is a json array. + * + * Equivalent to is(). + */ + inline bool is_array() const noexcept; + /** + * Whether this element is a json object. + * + * Equivalent to is(). + */ + inline bool is_object() const noexcept; + /** + * Whether this element is a json string. + * + * Equivalent to is() or is(). + */ + inline bool is_string() const noexcept; + /** + * Whether this element is a json number that fits in a signed 64-bit integer. + * + * Equivalent to is(). + */ + inline bool is_int64_t() const noexcept; + /** + * Whether this element is a json number that fits in an unsigned 64-bit integer. + * + * Equivalent to is(). + */ + inline bool is_uint64_t() const noexcept; + /** + * Whether this element is a json number that fits in a double. + * + * Equivalent to is(). + */ + inline bool is_double() const noexcept; + /** + * Whether this element is a json number. + * + * Both integers and floating points will return true. + */ + inline bool is_number() const noexcept; + /** + * Whether this element is a json `true` or `false`. + * + * Equivalent to is(). + */ + inline bool is_bool() const noexcept; + /** + * Whether this element is a json `null`. + */ + inline bool is_null() const noexcept; /** * Tell whether the value can be cast to provided type (T). @@ -249,7 +376,8 @@ public: inline bool dump_raw_tape(std::ostream &out) const noexcept; private: - really_inline element(const document *doc, size_t json_index) noexcept; + really_inline element(const internal::tape_ref &tape) noexcept; + internal::tape_ref tape; friend class document; friend class object; friend class array; @@ -289,12 +417,29 @@ public: really_inline simdjson_result(error_code error) noexcept; ///< @private inline simdjson_result type() const noexcept; - inline simdjson_result is_null() const noexcept; template inline simdjson_result is() const noexcept; template inline simdjson_result get() const noexcept; + inline simdjson_result get_array() const noexcept; + inline simdjson_result get_object() const noexcept; + inline simdjson_result get_c_str() const noexcept; + inline simdjson_result get_string() const noexcept; + inline simdjson_result get_int64_t() const noexcept; + inline simdjson_result get_uint64_t() const noexcept; + inline simdjson_result get_double() const noexcept; + inline simdjson_result get_bool() const noexcept; + + inline simdjson_result is_array() const noexcept; + inline simdjson_result is_object() const noexcept; + inline simdjson_result is_string() const noexcept; + inline simdjson_result is_int64_t() const noexcept; + inline simdjson_result is_uint64_t() const noexcept; + inline simdjson_result is_double() const noexcept; + inline simdjson_result is_bool() const noexcept; + inline simdjson_result is_null() const noexcept; + inline simdjson_result operator[](const std::string_view &key) const noexcept; inline simdjson_result operator[](const char *key) const noexcept; inline simdjson_result at(const std::string_view &json_pointer) const noexcept; diff --git a/include/simdjson/dom/object.h b/include/simdjson/dom/object.h index 03f3aaa9b..9316914d9 100644 --- a/include/simdjson/dom/object.h +++ b/include/simdjson/dom/object.h @@ -17,12 +17,12 @@ class key_value_pair; /** * JSON object. */ -class object : protected internal::tape_ref { +class object { public: /** Create a new, invalid object */ really_inline object() noexcept; - class iterator : protected internal::tape_ref { + class iterator { public: /** * Get the actual key/value pair @@ -70,7 +70,10 @@ public: */ inline element value() const noexcept; private: - really_inline iterator(const document *doc, size_t json_index) noexcept; + really_inline iterator(const internal::tape_ref &tape) noexcept; + + internal::tape_ref tape; + friend class object; }; @@ -172,7 +175,10 @@ public: inline simdjson_result at_key_case_insensitive(const std::string_view &key) const noexcept; private: - really_inline object(const document *doc, size_t json_index) noexcept; + really_inline object(const internal::tape_ref &tape) noexcept; + + internal::tape_ref tape; + friend class element; friend struct simdjson_result; template diff --git a/include/simdjson/inline/array.h b/include/simdjson/inline/array.h index da5081425..790977dde 100644 --- a/include/simdjson/inline/array.h +++ b/include/simdjson/inline/array.h @@ -50,16 +50,16 @@ namespace dom { // // array inline implementation // -really_inline array::array() noexcept : internal::tape_ref() {} -really_inline array::array(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) {} +really_inline array::array() noexcept : tape{} {} +really_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {} inline array::iterator array::begin() const noexcept { - return iterator(doc, json_index + 1); + return internal::tape_ref(tape.doc, tape.json_index + 1); } inline array::iterator array::end() const noexcept { - return iterator(doc, after_element() - 1); + return internal::tape_ref(tape.doc, tape.after_element() - 1); } inline size_t array::size() const noexcept { - return scope_count(); + return tape.scope_count(); } inline simdjson_result array::at(const std::string_view &json_pointer) const noexcept { // - means "the append position" or "the element after the end of the array" @@ -83,7 +83,7 @@ inline simdjson_result array::at(const std::string_view &json_pointer) if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index" // Get the child - auto child = array(doc, json_index).at(array_index); + auto child = array(tape).at(array_index); // If there is a /, we're not done yet, call recursively. if (i < json_pointer.length()) { child = child.at(json_pointer.substr(i+1)); @@ -102,15 +102,15 @@ inline simdjson_result array::at(size_t index) const noexcept { // // array::iterator inline implementation // -really_inline array::iterator::iterator(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) { } +really_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { } inline element array::iterator::operator*() const noexcept { - return element(doc, json_index); + return element(tape); } inline bool array::iterator::operator!=(const array::iterator& other) const noexcept { - return json_index != other.json_index; + return tape.json_index != other.tape.json_index; } inline array::iterator& array::iterator::operator++() noexcept { - json_index = after_element(); + tape.json_index = tape.after_element(); return *this; } diff --git a/include/simdjson/inline/document.h b/include/simdjson/inline/document.h index 028aac776..f78eba022 100644 --- a/include/simdjson/inline/document.h +++ b/include/simdjson/inline/document.h @@ -17,7 +17,7 @@ namespace dom { // document inline implementation // inline element document::root() const noexcept { - return element(this, 1); + return element(internal::tape_ref(this, 1)); } WARN_UNUSED diff --git a/include/simdjson/inline/element.h b/include/simdjson/inline/element.h index c77be566b..f2cc95882 100644 --- a/include/simdjson/inline/element.h +++ b/include/simdjson/inline/element.h @@ -22,10 +22,7 @@ inline simdjson_result simdjson_result::type() if (error()) { return error(); } return first.type(); } -inline simdjson_result simdjson_result::is_null() const noexcept { - if (error()) { return error(); } - return first.is_null(); -} + template inline simdjson_result simdjson_result::is() const noexcept { if (error()) { return error(); } @@ -37,6 +34,73 @@ inline simdjson_result simdjson_result::get() const noexcept { return first.get(); } +inline simdjson_result simdjson_result::get_array() const noexcept { + if (error()) { return error(); } + return first.get_array(); +} +inline simdjson_result simdjson_result::get_object() const noexcept { + if (error()) { return error(); } + return first.get_object(); +} +inline simdjson_result simdjson_result::get_c_str() const noexcept { + if (error()) { return error(); } + return first.get_c_str(); +} +inline simdjson_result simdjson_result::get_string() const noexcept { + if (error()) { return error(); } + return first.get_string(); +} +inline simdjson_result simdjson_result::get_int64_t() const noexcept { + if (error()) { return error(); } + return first.get_int64_t(); +} +inline simdjson_result simdjson_result::get_uint64_t() const noexcept { + if (error()) { return error(); } + return first.get_uint64_t(); +} +inline simdjson_result simdjson_result::get_double() const noexcept { + if (error()) { return error(); } + return first.get_double(); +} +inline simdjson_result simdjson_result::get_bool() const noexcept { + if (error()) { return error(); } + return first.get_bool(); +} + +inline simdjson_result simdjson_result::is_array() const noexcept { + if (error()) { return error(); } + return first.is_array(); +} +inline simdjson_result simdjson_result::is_object() const noexcept { + if (error()) { return error(); } + return first.is_object(); +} +inline simdjson_result simdjson_result::is_string() const noexcept { + if (error()) { return error(); } + return first.is_string(); +} +inline simdjson_result simdjson_result::is_int64_t() const noexcept { + if (error()) { return error(); } + return first.is_int64_t(); +} +inline simdjson_result simdjson_result::is_uint64_t() const noexcept { + if (error()) { return error(); } + return first.is_uint64_t(); +} +inline simdjson_result simdjson_result::is_double() const noexcept { + if (error()) { return error(); } + return first.is_double(); +} +inline simdjson_result simdjson_result::is_bool() const noexcept { + if (error()) { return error(); } + return first.is_bool(); +} + +inline simdjson_result simdjson_result::is_null() const noexcept { + if (error()) { return error(); } + return first.is_null(); +} + inline simdjson_result simdjson_result::operator[](const std::string_view &key) const noexcept { if (error()) { return error(); } return first[key]; @@ -105,50 +169,43 @@ namespace dom { // // element inline implementation // -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() noexcept : tape{} {} +really_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { } inline element_type element::type() const noexcept { - auto tape_type = tape_ref_type(); + auto tape_type = tape.tape_ref_type(); return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast(tape_type); } -really_inline bool element::is_null() const noexcept { - return is_null_on_tape(); -} -template<> -inline simdjson_result element::get() const noexcept { - if(is_true()) { +inline simdjson_result element::get_bool() const noexcept { + if(tape.is_true()) { return true; - } else if(is_false()) { + } else if(tape.is_false()) { return false; } return INCORRECT_TYPE; } -template<> -inline simdjson_result element::get() const noexcept { - switch (tape_ref_type()) { +inline simdjson_result element::get_c_str() const noexcept { + switch (tape.tape_ref_type()) { case internal::tape_type::STRING: { - return get_c_str(); + return tape.get_c_str(); } default: return INCORRECT_TYPE; } } -template<> -inline simdjson_result element::get() const noexcept { - switch (tape_ref_type()) { +inline simdjson_result element::get_string() const noexcept { + switch (tape.tape_ref_type()) { case internal::tape_type::STRING: - return get_string_view(); + return tape.get_string_view(); default: return INCORRECT_TYPE; } } -template<> -inline simdjson_result element::get() const noexcept { - if(unlikely(!is_uint64())) { // branch rarely taken - if(is_int64()) { - int64_t result = next_tape_value(); +inline simdjson_result element::get_uint64_t() const noexcept { + if(unlikely(!tape.is_uint64())) { // branch rarely taken + if(tape.is_int64()) { + int64_t result = tape.next_tape_value(); if (result < 0) { return NUMBER_OUT_OF_RANGE; } @@ -156,13 +213,12 @@ inline simdjson_result element::get() const noexcept { } return INCORRECT_TYPE; } - return next_tape_value(); + return tape.next_tape_value(); } -template<> -inline simdjson_result element::get() const noexcept { - if(unlikely(!is_int64())) { // branch rarely taken - if(is_uint64()) { - uint64_t result = next_tape_value(); +inline simdjson_result element::get_int64_t() const noexcept { + if(unlikely(!tape.is_int64())) { // branch rarely taken + if(tape.is_uint64()) { + uint64_t result = tape.next_tape_value(); // 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 > uint64_t((std::numeric_limits::max)())) { return NUMBER_OUT_OF_RANGE; @@ -171,10 +227,9 @@ inline simdjson_result element::get() const noexcept { } return INCORRECT_TYPE; } - return next_tape_value(); + return tape.next_tape_value(); } -template<> -inline simdjson_result element::get() const noexcept { +inline simdjson_result element::get_double() const noexcept { // Performance considerations: // 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight // comparison. @@ -184,42 +239,61 @@ inline simdjson_result element::get() const noexcept { // We can expect get to refer to a double type almost all the time. // It is important to craft the code accordingly so that the compiler can use this // information. (This could also be solved with profile-guided optimization.) - if(unlikely(!is_double())) { // branch rarely taken - if(is_uint64()) { - return double(next_tape_value()); - } else if(is_int64()) { - return double(next_tape_value()); + if(unlikely(!tape.is_double())) { // branch rarely taken + if(tape.is_uint64()) { + return double(tape.next_tape_value()); + } else if(tape.is_int64()) { + return double(tape.next_tape_value()); } return INCORRECT_TYPE; } // this is common: - return next_tape_value(); + return tape.next_tape_value(); } -template<> -inline simdjson_result element::get() const noexcept { - switch (tape_ref_type()) { +inline simdjson_result element::get_array() const noexcept { + switch (tape.tape_ref_type()) { case internal::tape_type::START_ARRAY: - return array(doc, json_index); + return array(tape); default: return INCORRECT_TYPE; } } -template<> -inline simdjson_result element::get() const noexcept { - switch (tape_ref_type()) { +inline simdjson_result element::get_object() const noexcept { + switch (tape.tape_ref_type()) { case internal::tape_type::START_OBJECT: - return object(doc, json_index); + return object(tape); default: return INCORRECT_TYPE; } } template -really_inline bool element::is() const noexcept { +inline bool element::is() const noexcept { auto result = get(); return !result.error(); } +template<> inline simdjson_result element::get() const noexcept { return get_array(); } +template<> inline simdjson_result element::get() const noexcept { return get_object(); } +template<> inline simdjson_result element::get() const noexcept { return get_c_str(); } +template<> inline simdjson_result element::get() const noexcept { return get_string(); } +template<> inline simdjson_result element::get() const noexcept { return get_int64_t(); } +template<> inline simdjson_result element::get() const noexcept { return get_uint64_t(); } +template<> inline simdjson_result element::get() const noexcept { return get_double(); } +template<> inline simdjson_result element::get() const noexcept { return get_bool(); } + +inline bool element::is_array() const noexcept { return is(); } +inline bool element::is_object() const noexcept { return is(); } +inline bool element::is_string() const noexcept { return is(); } +inline bool element::is_int64_t() const noexcept { return is(); } +inline bool element::is_uint64_t() const noexcept { return is(); } +inline bool element::is_double() const noexcept { return is(); } +inline bool element::is_bool() const noexcept { return is(); } + +inline bool element::is_null() const noexcept { + return tape.is_null_on_tape(); +} + #if SIMDJSON_EXCEPTIONS inline element::operator bool() const noexcept(false) { return get(); } @@ -247,11 +321,11 @@ inline simdjson_result element::operator[](const char *key) const noexc return at_key(key); } inline simdjson_result element::at(const std::string_view &json_pointer) const noexcept { - switch (tape_ref_type()) { + switch (tape.tape_ref_type()) { case internal::tape_type::START_OBJECT: - return object(doc, json_index).at(json_pointer); + return object(tape).at(json_pointer); case internal::tape_type::START_ARRAY: - return array(doc, json_index).at(json_pointer); + return array(tape).at(json_pointer); default: return INCORRECT_TYPE; } @@ -267,7 +341,7 @@ inline simdjson_result element::at_key_case_insensitive(const std::stri } inline bool element::dump_raw_tape(std::ostream &out) const noexcept { - return doc->dump_raw_tape(out); + return tape.doc->dump_raw_tape(out); } inline std::ostream& operator<<(std::ostream& out, const element &value) { @@ -308,7 +382,7 @@ inline std::ostream& minifier::print(std::ostream& out) { is_object[0] = false; bool after_value = false; - internal::tape_ref iter(value); + internal::tape_ref iter(value.tape); do { // print commas after each value if (after_value) { @@ -326,7 +400,7 @@ inline std::ostream& minifier::print(std::ostream& out) { // If we're too deep, we need to recurse to go deeper. depth++; if (unlikely(depth >= MAX_DEPTH)) { - out << minify(dom::array(iter.doc, iter.json_index)); + out << minify(dom::array(iter)); iter.json_index = iter.matching_brace_index() - 1; // Jump to the ] depth--; break; @@ -353,7 +427,7 @@ inline std::ostream& minifier::print(std::ostream& out) { // If we're too deep, we need to recurse to go deeper. depth++; if (unlikely(depth >= MAX_DEPTH)) { - out << minify(dom::object(iter.doc, iter.json_index)); + out << minify(dom::object(iter)); iter.json_index = iter.matching_brace_index() - 1; // Jump to the } depth--; break; diff --git a/include/simdjson/inline/object.h b/include/simdjson/inline/object.h index bbd69818c..f12a5252b 100644 --- a/include/simdjson/inline/object.h +++ b/include/simdjson/inline/object.h @@ -62,16 +62,16 @@ namespace dom { // // object inline implementation // -really_inline object::object() noexcept : internal::tape_ref() {} -really_inline object::object(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) { } +really_inline object::object() noexcept : tape{} {} +really_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { } inline object::iterator object::begin() const noexcept { - return iterator(doc, json_index + 1); + return internal::tape_ref(tape.doc, tape.json_index + 1); } inline object::iterator object::end() const noexcept { - return iterator(doc, after_element() - 1); + return internal::tape_ref(tape.doc, tape.after_element() - 1); } inline size_t object::size() const noexcept { - return scope_count(); + return tape.scope_count(); } inline simdjson_result object::operator[](const std::string_view &key) const noexcept { @@ -142,29 +142,29 @@ inline simdjson_result object::at_key_case_insensitive(const std::strin // // object::iterator inline implementation // -really_inline object::iterator::iterator(const document *_doc, size_t _json_index) noexcept : internal::tape_ref(_doc, _json_index) { } +really_inline object::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { } inline const key_value_pair object::iterator::operator*() const noexcept { return key_value_pair(key(), value()); } inline bool object::iterator::operator!=(const object::iterator& other) const noexcept { - return json_index != other.json_index; + return tape.json_index != other.tape.json_index; } inline object::iterator& object::iterator::operator++() noexcept { - json_index++; - json_index = after_element(); + tape.json_index++; + tape.json_index = tape.after_element(); return *this; } inline std::string_view object::iterator::key() const noexcept { - return get_string_view(); + return tape.get_string_view(); } inline uint32_t object::iterator::key_length() const noexcept { - return get_string_length(); + return tape.get_string_length(); } inline const char* object::iterator::key_c_str() const noexcept { - return reinterpret_cast(&doc->string_buf[size_t(tape_value()) + sizeof(uint32_t)]); + return reinterpret_cast(&tape.doc->string_buf[size_t(tape.tape_value()) + sizeof(uint32_t)]); } inline element object::iterator::value() const noexcept { - return element(doc, json_index + 1); + return element(internal::tape_ref(tape.doc, tape.json_index + 1)); } /** diff --git a/tests/basictests.cpp b/tests/basictests.cpp index 697e4261a..b464ee966 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -14,37 +14,8 @@ #include #include "simdjson.h" - -#ifndef SIMDJSON_BENCHMARK_DATA_DIR -#define SIMDJSON_BENCHMARK_DATA_DIR "jsonexamples/" -#endif -const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json"; -const char *TWITTER_TIMELINE_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter_timeline.json"; -const char *REPEAT_JSON = SIMDJSON_BENCHMARK_DATA_DIR "repeat.json"; -const char *AMAZON_CELLPHONES_NDJSON = SIMDJSON_BENCHMARK_DATA_DIR "amazon_cellphones.ndjson"; - -#define SIMDJSON_BENCHMARK_SMALLDATA_DIR SIMDJSON_BENCHMARK_DATA_DIR "small/" - -const char *ADVERSARIAL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "adversarial.json"; -const char *FLATADVERSARIAL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "flatadversarial.json"; -const char *DEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "demo.json"; -const char *SMALLDEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "smalldemo.json"; -const char *TRUENULL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "truenull.json"; - - - -template -bool equals_expected(T actual, T expected) { - return actual == expected; -} -template<> -bool equals_expected(const char *actual, const char *expected) { - return !strcmp(actual, expected); -} - -#define ASSERT_EQUAL(ACTUAL, EXPECTED) if (!equals_expected(ACTUAL, EXPECTED)) { std::cerr << "Expected " << #ACTUAL << " to be " << (EXPECTED) << ", got " << (ACTUAL) << " instead!" << std::endl; return false; } -#define ASSERT(RESULT, MESSAGE) if (!(RESULT)) { std::cerr << MESSAGE << std::endl; return false; } -#define ASSERT_SUCCESS(ERROR) if (ERROR) { std::cerr << (ERROR) << std::endl; return false; } +#include "cast_tester.h" +#include "test_macros.h" namespace number_tests { @@ -1367,222 +1338,73 @@ namespace type_tests { } )"_padded; - // test_implicit_cast::with(value, [](T value) { return true; }) - // Makes it so we test implicit casts for anything that supports them, but *don't* test them - // for const char * - template - class test_implicit_cast { - public: - template - static bool with(A input, F const & test); - template - static bool error_with(A input, simdjson::error_code expected_error); - }; - - template - template - bool test_implicit_cast::with(A input, F const & test) { - T actual; - actual = input; - return test(actual); - } - - template<> - template - bool test_implicit_cast::with(A, F const &) { - return true; - } - - template - template - bool test_implicit_cast::error_with(A input, simdjson::error_code expected_error) { - try { - UNUSED T actual; - actual = input; - return false; - } catch(simdjson_error &e) { - ASSERT_EQUAL(e.error(), expected_error); - return true; - } - } - - template<> - template - bool test_implicit_cast::error_with(A, simdjson::error_code) { - return true; - } - template bool test_cast(simdjson_result result, T expected) { + cast_tester tester; std::cout << " test_cast<" << typeid(T).name() << "> expecting " << expected << std::endl; // Grab the element out and check success dom::element element = result.first; - // get() == expected - T actual; - simdjson::error_code error; - result.get().tie(actual, error); - ASSERT_SUCCESS(error); - ASSERT_EQUAL(actual, expected); - - element.get().tie(actual, error); - ASSERT_SUCCESS(error); - ASSERT_EQUAL(actual, expected); - - // is() - bool actual_is; - result.is().tie(actual_is, error); - ASSERT_SUCCESS(error); - ASSERT_EQUAL(actual_is, true); - - actual_is = element.is(); - ASSERT_EQUAL(actual_is, true); - + RUN_TEST( tester.test_get(element, expected ) ); + RUN_TEST( tester.test_get(result, expected) ); + // RUN_TEST( tester.test_named_get(element, expected) ); + // RUN_TEST( tester.test_named_get(result, expected) ); + RUN_TEST( tester.test_is(element, true) ); + RUN_TEST( tester.test_is(result, true) ); + // RUN_TEST( tester.test_named_is(element, true) ); + // RUN_TEST( tester.test_named_is(result, true) ); #if SIMDJSON_EXCEPTIONS - try { - - // T() == expected - actual = T(result); - ASSERT_EQUAL(actual, expected); - actual = T(element); - ASSERT_EQUAL(actual, expected); - - test_implicit_cast::with(result, [&](T a) { ASSERT_EQUAL(a, expected); return false; }); - - test_implicit_cast::with(element, [&](T a) { ASSERT_EQUAL(a, expected); return false; }); - - // get() == expected - actual = result.get(); - ASSERT_EQUAL(actual, expected); - - actual = element.get(); - ASSERT_EQUAL(actual, expected); - - // is() - actual_is = result.is(); - ASSERT_EQUAL(actual_is, true); - - } catch(simdjson_error &e) { - std::cerr << e.error() << std::endl; - return false; - } - + RUN_TEST( tester.test_implicit_cast(element, expected) ); + RUN_TEST( tester.test_implicit_cast(result, expected) ); #endif return true; } - template bool test_cast(simdjson_result result) { - std::cout << " test_cast<" << typeid(T).name() << "> expecting success" << std::endl; + cast_tester tester; + std::cout << " test_cast<" << typeid(T).name() << ">" << std::endl; // Grab the element out and check success dom::element element = result.first; - // get() == expected - T actual; - simdjson::error_code error; - result.get().tie(actual, error); - ASSERT_SUCCESS(error); - - element.get().tie(actual, error); - ASSERT_SUCCESS(error); - - // is() - bool actual_is; - result.is().tie(actual_is, error); - ASSERT_SUCCESS(error); - ASSERT_EQUAL(actual_is, true); - - actual_is = element.is(); - ASSERT_EQUAL(actual_is, true); - + RUN_TEST( tester.test_get(element) ); + RUN_TEST( tester.test_get(result) ); + RUN_TEST( tester.test_named_get(element) ); + RUN_TEST( tester.test_named_get(result) ); + RUN_TEST( tester.test_is(element, true) ); + RUN_TEST( tester.test_is(result, true) ); + RUN_TEST( tester.test_named_is(element, true) ); + RUN_TEST( tester.test_named_is(result, true) ); #if SIMDJSON_EXCEPTIONS - - try { - - // T() - actual = T(result); - - actual = T(element); - - test_implicit_cast::with(result, [&](T) { return true; }); - - test_implicit_cast::with(element, [&](T) { return true; }); - - // get() == expected - actual = result.get(); - - actual = element.get(); - - // is() - actual_is = result.is(); - ASSERT_EQUAL(actual_is, true); - - } catch(simdjson_error &e) { - std::cerr << e.error() << std::endl; - return false; - } - + RUN_TEST( tester.test_implicit_cast(element) ); + RUN_TEST( tester.test_implicit_cast(result) ); #endif return true; } + // + // Test that we get errors when we cast to the wrong type + // template - bool test_cast(simdjson_result result, simdjson::error_code expected_error) { - std::cout << " test_cast<" << typeid(T).name() << "> expecting error '" << expected_error << "'" << std::endl; + bool test_cast_error(simdjson_result result, simdjson::error_code expected_error) { + std::cout << " test_cast_error<" << typeid(T).name() << "> expecting error '" << expected_error << "'" << std::endl; dom::element element = result.first; - // get() == expected - T actual; - simdjson::error_code error; - result.get().tie(actual, error); - ASSERT_EQUAL(error, expected_error); - element.get().tie(actual, error); - ASSERT_EQUAL(error, expected_error); - - // is() - bool actual_is; - result.is().tie(actual_is, error); - ASSERT_SUCCESS(error); - ASSERT_EQUAL(actual_is, false); - - actual_is = element.is(); - ASSERT_EQUAL(actual_is, false); + cast_tester tester; + RUN_TEST( tester.test_get_error(element, expected_error) ); + RUN_TEST( tester.test_get_error(result, expected_error) ); + RUN_TEST( tester.test_named_get_error(element, expected_error) ); + RUN_TEST( tester.test_named_get_error(result, expected_error) ); + RUN_TEST( tester.test_is(element, false) ); + RUN_TEST( tester.test_is(result, false) ); + RUN_TEST( tester.test_named_is(element, false) ); + RUN_TEST( tester.test_named_is(result, false) ); #if SIMDJSON_EXCEPTIONS - - // T() - try { - actual = T(result); - return false; - } catch(simdjson_error &e) { - ASSERT_EQUAL(e.error(), expected_error); - } - - try { - actual = T(element); - return false; - } catch(simdjson_error &e) { - ASSERT_EQUAL(e.error(), expected_error); - } - - if (!test_implicit_cast::error_with(result, expected_error)) { return false; } - - if (!test_implicit_cast::error_with(result, expected_error)) { return true; } - - try { - - // is() - actual_is = result.is(); - ASSERT_EQUAL(actual_is, false); - - } catch(simdjson_error &e) { - std::cerr << e.error() << std::endl; - return false; - } - + RUN_TEST( tester.test_implicit_cast_error(element, expected_error) ); + RUN_TEST( tester.test_implicit_cast_error(result, expected_error) ); #endif return true; @@ -1657,13 +1479,13 @@ namespace type_tests { return true && test_type(result, dom::element_type::ARRAY) && test_cast(result) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, false); } @@ -1675,14 +1497,14 @@ namespace type_tests { return true && test_type(result, dom::element_type::OBJECT) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_cast(result) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, false); } @@ -1694,14 +1516,14 @@ namespace type_tests { return true && test_type(result, dom::element_type::STRING) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_cast(result, "foo") && test_cast(result, "foo") - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, false); } @@ -1712,16 +1534,16 @@ namespace type_tests { simdjson_result result = parser.parse(ALL_TYPES_JSON)[key]; return true && test_type(result, dom::element_type::INT64) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_cast(result, expected_value) && (expected_value >= 0 ? test_cast(result, expected_value) : - test_cast(result, NUMBER_OUT_OF_RANGE)) + test_cast_error(result, NUMBER_OUT_OF_RANGE)) && test_cast(result, static_cast(expected_value)) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, false); } @@ -1733,14 +1555,14 @@ namespace type_tests { return true && test_type(result, dom::element_type::UINT64) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, NUMBER_OUT_OF_RANGE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, NUMBER_OUT_OF_RANGE) && test_cast(result, expected_value) && test_cast(result, static_cast(expected_value)) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, false); } @@ -1751,14 +1573,14 @@ namespace type_tests { simdjson_result result = parser.parse(ALL_TYPES_JSON)[key]; return true && test_type(result, dom::element_type::DOUBLE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_cast(result, expected_value) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, false); } @@ -1770,13 +1592,13 @@ namespace type_tests { return true && test_type(result, dom::element_type::BOOL) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_cast(result, expected_value) && test_is_null(result, false); } @@ -1788,14 +1610,14 @@ namespace type_tests { simdjson_result result = parser.parse(ALL_TYPES_JSON)["null"]; return true && test_type(result, dom::element_type::NULL_VALUE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) - && test_cast(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) + && test_cast_error(result, INCORRECT_TYPE) && test_is_null(result, true); } diff --git a/tests/cast_tester.h b/tests/cast_tester.h new file mode 100644 index 000000000..37d443b34 --- /dev/null +++ b/tests/cast_tester.h @@ -0,0 +1,284 @@ +#ifndef CAST_TESTER_H +#define CAST_TESTER_H + +#include "simdjson.h" +#include "test_macros.h" + +namespace { + using simdjson::error_code; + using simdjson::simdjson_error; + using simdjson::simdjson_result; + using simdjson::dom::array; + using simdjson::dom::element; + using simdjson::dom::object; +} + +// cast_tester tester; +// tester.test_implicit(value, [](T value) { return true; }) +// tester.test_implicit_error(value, error) +// Used to test casts to a type. In the case of const char * in particular, we don't test +// implicit casts at all, so that method always returns true. +template +class cast_tester { +public: + bool test_get(element element, T expected = {}); + bool test_get(simdjson_result element, T expected = {}); + bool test_get_error(element element, error_code expected_error); + bool test_get_error(simdjson_result element, error_code expected_error); + +#if SIMDJSON_EXCEPTIONS + bool test_implicit_cast(element element, T expected = {}); + bool test_implicit_cast(simdjson_result element, T expected = {}); + bool test_implicit_cast_error(element element, error_code expected_error); + bool test_implicit_cast_error(simdjson_result element, error_code expected_error); +#endif // SIMDJSON_EXCEPTIONS + + bool test_is(element element, bool expected); + bool test_is(simdjson_result element, bool expected); + bool test_is_error(simdjson_result element, error_code expected_error); + + bool test_named_get(element element, T expected = {}); + bool test_named_get(simdjson_result element, T expected = {}); + bool test_named_get_error(element element, error_code expected_error); + bool test_named_get_error(simdjson_result element, error_code expected_error); + + bool test_named_is(element element, bool expected); + bool test_named_is(simdjson_result element, bool expected); + bool test_named_is_error(simdjson_result element, error_code expected_error); + +private: + simdjson_result named_get(element element); + simdjson_result named_get(simdjson_result element); + bool named_is(element element); + simdjson_result named_is(simdjson_result element); + bool assert_equal(const T& expected, const T& actual); +}; + +template +bool cast_tester::test_get(element element, T expected) { + T actual; + error_code error; + element.get().tie(actual, error); + ASSERT_SUCCESS(error); + return assert_equal(actual, expected); +} + +template +bool cast_tester::test_get(simdjson_result element, T expected) { + T actual; + error_code error; + element.get().tie(actual, error); + ASSERT_SUCCESS(error); + return assert_equal(actual, expected); +} + +template +bool cast_tester::test_get_error(element element, error_code expected_error) { + T actual; + error_code error; + element.get().tie(actual, error); + ASSERT_EQUAL(error, expected_error); + return true; +} + +template +bool cast_tester::test_get_error(simdjson_result element, error_code expected_error) { + T actual; + error_code error; + element.get().tie(actual, error); + ASSERT_EQUAL(error, expected_error); + return true; +} + +template +bool cast_tester::test_named_get(element element, T expected) { + T actual; + error_code error; + named_get(element).tie(actual, error); + ASSERT_SUCCESS(error); + return assert_equal(actual, expected); +} + +template +bool cast_tester::test_named_get(simdjson_result element, T expected) { + T actual; + error_code error; + named_get(element).tie(actual, error); + ASSERT_SUCCESS(error); + return assert_equal(actual, expected); +} + +template +bool cast_tester::test_named_get_error(element element, error_code expected_error) { + T actual; + error_code error; + named_get(element).tie(actual, error); + ASSERT_EQUAL(error, expected_error); + return true; +} + +template +bool cast_tester::test_named_get_error(simdjson_result element, error_code expected_error) { + T actual; + error_code error; + named_get(element).tie(actual, error); + ASSERT_EQUAL(error, expected_error); + return true; +} + +#if SIMDJSON_EXCEPTIONS + +template +bool cast_tester::test_implicit_cast(element element, T expected) { + T actual; + try { + actual = element; + } catch(simdjson_error &e) { + std::cerr << e.error() << std::endl; + return false; + } + return assert_equal(actual, expected); +} + +template +bool cast_tester::test_implicit_cast(simdjson_result element, T expected) { + T actual; + try { + actual = element; + } catch(simdjson_error &e) { + std::cerr << e.error() << std::endl; + return false; + } + return assert_equal(actual, expected); +} + +template +bool cast_tester::test_implicit_cast_error(element element, error_code expected_error) { + try { + UNUSED T actual; + actual = element; + return false; + } catch(simdjson_error &e) { + ASSERT_EQUAL(e.error(), expected_error); + return true; + } +} + +template +bool cast_tester::test_implicit_cast_error(simdjson_result element, error_code expected_error) { + try { + UNUSED T actual; + actual = element; + return false; + } catch(simdjson_error &e) { + ASSERT_EQUAL(e.error(), expected_error); + return true; + } +} + +template<> bool cast_tester::test_implicit_cast(element, const char *) { return true; } +template<> bool cast_tester::test_implicit_cast(simdjson_result, const char *) { return true; } +template<> bool cast_tester::test_implicit_cast_error(element, error_code) { return true; } +template<> bool cast_tester::test_implicit_cast_error(simdjson_result, error_code) { return true; } + +#endif // SIMDJSON_EXCEPTIONS + +template +bool cast_tester::test_is(element element, bool expected) { + ASSERT_EQUAL(element.is(), expected); + return true; +} + +template +bool cast_tester::test_is(simdjson_result element, bool expected) { + bool actual; + error_code error; + element.is().tie(actual, error); + ASSERT_SUCCESS(error); + ASSERT_EQUAL(actual, expected); + return true; +} + +template +bool cast_tester::test_is_error(simdjson_result element, error_code expected_error) { + UNUSED bool actual; + error_code error; + element.is().tie(actual, error); + ASSERT_EQUAL(error, expected_error); + return true; +} + +template +bool cast_tester::test_named_is(element element, bool expected) { + ASSERT_EQUAL(named_is(element), expected); + return true; +} + +template +bool cast_tester::test_named_is(simdjson_result element, bool expected) { + bool actual; + error_code error; + named_is(element).tie(actual, error); + ASSERT_SUCCESS(error); + ASSERT_EQUAL(actual, expected); + return true; +} + +template +bool cast_tester::test_named_is_error(simdjson_result element, error_code expected_error) { + bool actual; + error_code error; + named_is(element, error).tie(actual, error); + ASSERT_EQUAL(error, expected_error); + return true; +} + +template<> simdjson_result cast_tester::named_get(element element) { return element.get_array(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_object(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_c_str(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_string(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_uint64_t(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_int64_t(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_double(); } +template<> simdjson_result cast_tester::named_get(element element) { return element.get_bool(); } + +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_array(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_object(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_c_str(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_string(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_uint64_t(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_int64_t(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_double(); } +template<> simdjson_result cast_tester::named_get(simdjson_result element) { return element.get_bool(); } + +template<> bool cast_tester::named_is(element element) { return element.is_array(); } +template<> bool cast_tester::named_is(element element) { return element.is_object(); } +template<> bool cast_tester::named_is(element element) { return element.is_string(); } +template<> bool cast_tester::named_is(element element) { return element.is_string(); } +template<> bool cast_tester::named_is(element element) { return element.is_uint64_t(); } +template<> bool cast_tester::named_is(element element) { return element.is_int64_t(); } +template<> bool cast_tester::named_is(element element) { return element.is_double(); } +template<> bool cast_tester::named_is(element element) { return element.is_bool(); } + +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_array(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_object(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_string(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_string(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_uint64_t(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_int64_t(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_double(); } +template<> simdjson_result cast_tester::named_is(simdjson_result element) { return element.is_bool(); } + +template bool cast_tester::assert_equal(const T& expected, const T& actual) { + ASSERT_EQUAL(expected, actual); + return true; +} +// We don't actually check equality for objects and arrays, just check that they actually cast +template<> bool cast_tester::assert_equal(const array&, const array&) { + return true; +} +template<> bool cast_tester::assert_equal(const object&, const object&) { + return true; +} + +#endif \ No newline at end of file diff --git a/tests/test_macros.h b/tests/test_macros.h new file mode 100644 index 000000000..909deb10e --- /dev/null +++ b/tests/test_macros.h @@ -0,0 +1,34 @@ +#ifndef TEST_MACROS_H +#define TEST_MACROS_H + +#ifndef SIMDJSON_BENCHMARK_DATA_DIR +#define SIMDJSON_BENCHMARK_DATA_DIR "jsonexamples/" +#endif +const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json"; +const char *TWITTER_TIMELINE_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter_timeline.json"; +const char *REPEAT_JSON = SIMDJSON_BENCHMARK_DATA_DIR "repeat.json"; +const char *AMAZON_CELLPHONES_NDJSON = SIMDJSON_BENCHMARK_DATA_DIR "amazon_cellphones.ndjson"; + +#define SIMDJSON_BENCHMARK_SMALLDATA_DIR SIMDJSON_BENCHMARK_DATA_DIR "small/" + +const char *ADVERSARIAL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "adversarial.json"; +const char *FLATADVERSARIAL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "flatadversarial.json"; +const char *DEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "demo.json"; +const char *SMALLDEMO_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "smalldemo.json"; +const char *TRUENULL_JSON = SIMDJSON_BENCHMARK_SMALLDATA_DIR "truenull.json"; + +// For the ASSERT_EQUAL macro +template +bool equals_expected(T actual, T expected) { + return actual == expected; +} +template<> +bool equals_expected(const char *actual, const char *expected) { + return !strcmp(actual, expected); +} +#define ASSERT_EQUAL(ACTUAL, EXPECTED) if (!equals_expected(ACTUAL, EXPECTED)) { std::cerr << "Expected " << #ACTUAL << " to be " << (EXPECTED) << ", got " << (ACTUAL) << " instead!" << std::endl; return false; } +#define ASSERT(RESULT, MESSAGE) if (!(RESULT)) { std::cerr << MESSAGE << std::endl; return false; } +#define RUN_TEST(RESULT) if (!RESULT) { return false; } +#define ASSERT_SUCCESS(ERROR) if (ERROR) { std::cerr << (ERROR) << std::endl; return false; } + +#endif // TEST_MACROS_H \ No newline at end of file