From bbb3cb80a6d618ff36716ff0123790ccaa85a2ef Mon Sep 17 00:00:00 2001 From: "M. Bahoosh" <12122474+the-moisrex@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:27:38 -1000 Subject: [PATCH] Minimal tag_invokes for STL types --- .../simdjson/generic/ondemand/amalgamated.h | 5 +- .../simdjson/generic/ondemand/deserialize.h | 46 ++++++--- include/simdjson/generic/ondemand/document.h | 8 +- .../simdjson/generic/ondemand/tag_invoke.h | 96 ------------------- include/simdjson/generic/ondemand/value.h | 6 +- include/simdjson/std/list.h | 45 +++++++++ include/simdjson/std/memory.h | 55 +++++++++++ include/simdjson/std/std.h | 52 ++++++++++ include/simdjson/std/string.h | 37 +++++++ include/simdjson/std/vector.h | 52 ++++++++++ tests/ondemand/CMakeLists.txt | 1 + .../ondemand_custom_types_document_tests.cpp | 9 +- .../ondemand/ondemand_custom_types_tests.cpp | 13 +-- tests/ondemand/ondemand_stl_types_tests.cpp | 50 ++++++++++ 14 files changed, 347 insertions(+), 128 deletions(-) delete mode 100644 include/simdjson/generic/ondemand/tag_invoke.h create mode 100644 include/simdjson/std/list.h create mode 100644 include/simdjson/std/memory.h create mode 100644 include/simdjson/std/std.h create mode 100644 include/simdjson/std/string.h create mode 100644 include/simdjson/std/vector.h create mode 100644 tests/ondemand/ondemand_stl_types_tests.cpp diff --git a/include/simdjson/generic/ondemand/amalgamated.h b/include/simdjson/generic/ondemand/amalgamated.h index 06186c1e8..f7af38a80 100644 --- a/include/simdjson/generic/ondemand/amalgamated.h +++ b/include/simdjson/generic/ondemand/amalgamated.h @@ -3,8 +3,8 @@ #endif // Stuff other things depend on -#include "simdjson/generic/ondemand/deserialize.h" #include "simdjson/generic/ondemand/base.h" +#include "simdjson/generic/ondemand/deserialize.h" #include "simdjson/generic/ondemand/value_iterator.h" #include "simdjson/generic/ondemand/value.h" #include "simdjson/generic/ondemand/logger.h" @@ -42,4 +42,5 @@ #include "simdjson/generic/ondemand/token_iterator-inl.h" #include "simdjson/generic/ondemand/value_iterator-inl.h" -#include "simdjson/generic/ondemand/tag_invoke.h" +// Conversions +#include "simdjson/std/std.h" diff --git a/include/simdjson/generic/ondemand/deserialize.h b/include/simdjson/generic/ondemand/deserialize.h index ca00bbad8..b64d0d2c3 100644 --- a/include/simdjson/generic/ondemand/deserialize.h +++ b/include/simdjson/generic/ondemand/deserialize.h @@ -1,6 +1,7 @@ #ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H #ifndef SIMDJSON_CONDITIONAL_INCLUDE #define SIMDJSON_ONDEMAND_DESERIALIZE_H +#include "simdjson/generic/ondemand/base.h" #endif // SIMDJSON_CONDITIONAL_INCLUDE #ifdef __has_include #if __has_include() @@ -15,6 +16,9 @@ namespace simdjson { #ifdef __cpp_concepts +#define SIMDJSON_SUPPORTS_DESERIALIZATION 1 + + namespace tag_invoke_fn_ns { void tag_invoke(); @@ -60,20 +64,36 @@ using tag_invoke_result_t = template using tag_t = std::decay_t; -namespace SIMDJSON_IMPLEMENTATION { -namespace ondemand { -class value; -class document; -} -} // namespace SIMDJSON_IMPLEMENTATION struct deserialize_tag; -template -concept deserializable = tag_invocable; +/// These types are deserializable in a built-in way +template struct is_builtin_deserializable : std::false_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; +template <> struct is_builtin_deserializable : std::true_type {}; + +template +concept is_builtin_deserializable_v = is_builtin_deserializable::value; template -concept nothrow_deserializable = nothrow_tag_invocable; +concept custom_deserializable = tag_invocable; + +template +concept deserializable = custom_deserializable || is_builtin_deserializable_v; + +template +concept nothrow_custom_deserializable = nothrow_tag_invocable; + +// built-in types are noexcept and if an error happens, the value simply gets ignored and the error is returned. +template +concept nothrow_deserializable = nothrow_custom_deserializable || is_builtin_deserializable_v; /// Deserialize Tag inline constexpr struct deserialize_tag { @@ -82,15 +102,15 @@ inline constexpr struct deserialize_tag { // Customization Point for value template - requires deserializable - [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_deserializable) { + requires custom_deserializable + [[nodiscard]] constexpr /* error_code */ auto operator()(value_type &object, T& output) const noexcept(nothrow_custom_deserializable) { return tag_invoke(*this, object, output); } // Customization Point for document template - requires deserializable - [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_deserializable) { + requires custom_deserializable + [[nodiscard]] constexpr /* error_code */ auto operator()(document_type &object, T& output) const noexcept(nothrow_custom_deserializable) { return tag_invoke(*this, object, output); } diff --git a/include/simdjson/generic/ondemand/document.h b/include/simdjson/generic/ondemand/document.h index 70b4c36dc..489035ba9 100644 --- a/include/simdjson/generic/ondemand/document.h +++ b/include/simdjson/generic/ondemand/document.h @@ -184,7 +184,7 @@ public: template simdjson_inline simdjson_result get() & #ifdef __cpp_concepts - noexcept(deserializable ? nothrow_deserializable : true) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif @@ -207,7 +207,7 @@ public: template simdjson_inline simdjson_result get() && #ifdef __cpp_concepts - noexcept(deserializable ? nothrow_deserializable : true) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif @@ -230,13 +230,13 @@ public: template simdjson_inline error_code get(T &out) & #ifdef __cpp_concepts - noexcept(deserializable ? nothrow_deserializable : true) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { #ifdef __cpp_concepts - if constexpr (deserializable) { + if constexpr (custom_deserializable) { return deserialize(*this, out); } else { #endif // __cpp_concepts diff --git a/include/simdjson/generic/ondemand/tag_invoke.h b/include/simdjson/generic/ondemand/tag_invoke.h deleted file mode 100644 index 3b140a6bc..000000000 --- a/include/simdjson/generic/ondemand/tag_invoke.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef SIMDJSON_TAG_INVOKE_H - -#ifndef SIMDJSON_CONDITIONAL_INCLUDE -#define SIMDJSON_TAG_INVOKE_H -#include "simdjson/generic/ondemand/base.h" -#include "simdjson/generic/ondemand/deserialize.h" -#endif // SIMDJSON_CONDITIONAL_INCLUDE -#ifdef __has_include -#if __has_include() -#include -#endif -#endif - -#ifdef __cpp_concepts -#include -#include -#include - -/** - * Provides convenience functions for deserialization of common types. - */ -namespace simdjson { -namespace SIMDJSON_IMPLEMENTATION { -namespace ondemand { - -template -error_code tag_invoke(deserialize_tag, auto &val, T& out) noexcept { - uint64_t x; - SIMDJSON_TRY(val.get_uint64().get(x)); - if(x > (std::numeric_limits::max)() || x < (std::numeric_limits::min)()) { - return NUMBER_OUT_OF_RANGE; - } - out = static_cast(x); - return SUCCESS; -} - -template -error_code tag_invoke(deserialize_tag, auto &val, T& out) noexcept { - double x; - SIMDJSON_TRY(val.get_double().get(x)); - out = static_cast(x); - return SUCCESS; -} - -template -error_code tag_invoke(deserialize_tag, auto &val, T& out) noexcept { - int64_t x; - SIMDJSON_TRY(val.get_int64().get(x)); - if(x > (std::numeric_limits::max)() || x < (std::numeric_limits::min)()) { - return NUMBER_OUT_OF_RANGE; - } - out = static_cast(x); - return SUCCESS; -} - -error_code tag_invoke(deserialize_tag, auto &val, std::string& out) noexcept { - SIMDJSON_TRY(val.get_string(out)); - return SUCCESS; -} - -/** - * STL containers have several constructors including one that takes a single - * size argument. Thus some compilers (Visual Studio) will not be able to - * disambiguate between the size and container constructor. Users should - * explicitly specify the type of the container as needed: e.g., - * doc.get>(). - */ - -template > -error_code tag_invoke(deserialize_tag, auto &val, std::vector& out) noexcept { - array array; - SIMDJSON_TRY(val.get_array().get(array)); - for (auto v : array) { - T value; - SIMDJSON_TRY(v.get().get(value)); - out.push_back(value); - } - return SUCCESS; -} - -template > -error_code tag_invoke(deserialize_tag, auto &val, std::list& out) noexcept { - array array; - SIMDJSON_TRY(val.get_array().get(array)); - for (auto v : array) { - T value; - SIMDJSON_TRY(v.get().get(value)); - out.push_back(value); - } - return SUCCESS; -} -} -} -} -#endif // __cpp_concepts -#endif // SIMDJSON_TAG_INVOKE_H diff --git a/include/simdjson/generic/ondemand/value.h b/include/simdjson/generic/ondemand/value.h index 6e95aa8c0..fb308554e 100644 --- a/include/simdjson/generic/ondemand/value.h +++ b/include/simdjson/generic/ondemand/value.h @@ -41,7 +41,7 @@ public: template simdjson_inline simdjson_result get() #ifdef __cpp_concepts - noexcept(deserializable ? nothrow_deserializable : true) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif @@ -65,13 +65,13 @@ public: template simdjson_inline error_code get(T &out) #ifdef __cpp_concepts - noexcept(deserializable ? nothrow_deserializable : true) + noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { #ifdef __cpp_concepts - if constexpr (deserializable) { + if constexpr (custom_deserializable) { return deserialize(*this, out); } else { #endif // __cpp_concepts diff --git a/include/simdjson/std/list.h b/include/simdjson/std/list.h new file mode 100644 index 000000000..3b30dd3ee --- /dev/null +++ b/include/simdjson/std/list.h @@ -0,0 +1,45 @@ +#ifndef SIMDJSON_STD_LIST_H +#define SIMDJSON_STD_LIST_H + +#ifndef SIMDJSON_SUPPORTS_DESERIALIZATION +#include "simdjson/generic/ondemand/deserialize.h" +#endif + +#ifdef SIMDJSON_SUPPORTS_DESERIALIZATION +#include + +namespace simdjson { + +template +error_code tag_invoke(deserialize_tag, ValT &val, + std::list &out) noexcept(false) { + + // For better error messages, don't use these as constraints on + // the tag_invoke CPO. + static_assert( + deserializable, + "The specified type inside the list must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified type inside the list must default constructible."); + + ondemand::array arr; + SIMDJSON_TRY(val.get_array().get(arr)); + for (auto v : arr) { + if (auto const err = v.get().get(out.emplace_back()); err) { + // If an error occurs, the empty element that we just inserted gets + // removed. We're not using a temp variable because if T is a heavy type, + // we want the valid path to be the fast path and the slow path be the + // path that has errors in it. + static_cast(out.pop_back()); + return err; + } + } + return SUCCESS; +} + +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION + +#endif // SIMDJSON_STD_LIST_H diff --git a/include/simdjson/std/memory.h b/include/simdjson/std/memory.h new file mode 100644 index 000000000..525dbd638 --- /dev/null +++ b/include/simdjson/std/memory.h @@ -0,0 +1,55 @@ +#ifndef SIMDJSON_STD_MEMORY_H +#define SIMDJSON_STD_MEMORY_H + +#ifndef SIMDJSON_SUPPORTS_DESERIALIZATION +#include "simdjson/generic/ondemand/deserialize.h" +#endif + +#ifdef SIMDJSON_SUPPORTS_DESERIALIZATION +#include + +namespace simdjson { + +/** + * This CPO (Customization Point Object) will help deserialize into + * `unique_ptr`s. + * + * If constructing T is nothrow, this conversion should be nothrow as well since + * we return MEMALLOC if we're not able to allocate memory instead of throwing + * the the error message. + * + * @tparam T The type inside the unique_ptr + * @tparam Deleter The Deleter of the unique_ptr + * @tparam ValT document/value type + * @param val document/value + * @param out output unique_ptr + * @return status of the conversion + */ +template +error_code tag_invoke(deserialize_tag, ValT &val, + std::unique_ptr + &out) noexcept(nothrow_deserializable) { + + // For better error messages, don't use these as constraints on + // the tag_invoke CPO. + static_assert( + deserializable, + "The specified type inside the unique_ptr must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified type inside the unique_ptr must default constructible."); + + auto ptr = new (std::nothrow) T(); + if (ptr == nullptr) { + return MEMALLOC; + } + SIMDJSON_TRY(val.template get(*ptr)); + out.reset(ptr); + return SUCCESS; +} + +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION + +#endif // SIMDJSON_STD_MEMORY_H diff --git a/include/simdjson/std/std.h b/include/simdjson/std/std.h new file mode 100644 index 000000000..ca7e22fe6 --- /dev/null +++ b/include/simdjson/std/std.h @@ -0,0 +1,52 @@ +#ifndef SIMDJSON_STD_STD_H +#define SIMDJSON_STD_STD_H + +#ifndef SIMDJSON_SUPPORTS_DESERIALIZATION +#include "simdjson/generic/ondemand/deserialize.h" +#endif + +#ifdef SIMDJSON_SUPPORTS_DESERIALIZATION +#include +#include + +namespace simdjson { + +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { + using limits = std::numeric_limits; + + uint64_t x; + SIMDJSON_TRY(val.get_uint64().get(x)); + if (x > limits::max()) { + return NUMBER_OUT_OF_RANGE; + } + out = static_cast(x); + return SUCCESS; +} + +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { + double x; + SIMDJSON_TRY(val.get_double().get(x)); + out = static_cast(x); + return SUCCESS; +} + +template +error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept { + using limits = std::numeric_limits; + + int64_t x; + SIMDJSON_TRY(val.get_int64().get(x)); + if (x > limits::max() || x < limits::min()) { + return NUMBER_OUT_OF_RANGE; + } + out = static_cast(x); + return SUCCESS; +} + +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION + +#endif // SIMDJSON_STD_STD_H diff --git a/include/simdjson/std/string.h b/include/simdjson/std/string.h new file mode 100644 index 000000000..c457e99e6 --- /dev/null +++ b/include/simdjson/std/string.h @@ -0,0 +1,37 @@ +#ifndef SIMDJSON_STD_LIST_H +#define SIMDJSON_STD_LIST_H + +#ifndef SIMDJSON_SUPPORTS_DESERIALIZATION +#include "simdjson/generic/ondemand/deserialize.h" +#endif + +#ifdef SIMDJSON_SUPPORTS_DESERIALIZATION +#include + +namespace simdjson { + +template +error_code tag_invoke(deserialize_tag, ValT &val, std::basic_string &out) noexcept(false) { + using string_type = std::basic_string; + + if constexpr (std::same_as) { + SIMDJSON_TRY(val.get_string(out)); + } else { + // todo: optimize performance + std::string tmp; + SIMDJSON_TRY(val.get_string(tmp)); + for (auto const ch : tmp) { + out.push_back(ch); + } + } + return SUCCESS; +} + +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION + +#endif // SIMDJSON_STD_LIST_H diff --git a/include/simdjson/std/vector.h b/include/simdjson/std/vector.h new file mode 100644 index 000000000..f191f30f2 --- /dev/null +++ b/include/simdjson/std/vector.h @@ -0,0 +1,52 @@ +#ifndef SIMDJSON_STD_VECTOR_H +#define SIMDJSON_STD_VECTOR_H + +#ifndef SIMDJSON_SUPPORTS_DESERIALIZATION +#include "simdjson/generic/ondemand/deserialize.h" +#endif + +#ifdef SIMDJSON_SUPPORTS_DESERIALIZATION +#include + +namespace simdjson { + +/** + * STL containers have several constructors including one that takes a single + * size argument. Thus, some compilers (Visual Studio) will not be able to + * disambiguate between the size and container constructor. Users should + * explicitly specify the type of the container as needed: e.g., + * doc.get>(). + */ +template +error_code tag_invoke(deserialize_tag, ValT &val, + std::vector &out) noexcept(false) { + + // For better error messages, don't use these as constraints on + // the tag_invoke CPO. + static_assert( + deserializable, + "The specified type inside the vector must itself be deserializable"); + static_assert( + std::is_default_constructible_v, + "The specified type inside the vector must default constructible."); + + ondemand::array arr; + SIMDJSON_TRY(val.get_array().get(arr)); + for (auto v : arr) { + if (auto const err = v.get().get(out.emplace_back()); err) { + // If an error occurs, the empty element that we just inserted gets + // removed. We're not using a temp variable because if T is a heavy type, + // we want the valid path to be the fast path and the slow path be the + // path that has errors in it. + static_cast(out.pop_back()); + return err; + } + } + return SUCCESS; +} + +} // namespace simdjson + +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION + +#endif // SIMDJSON_STD_VECTOR_H diff --git a/tests/ondemand/CMakeLists.txt b/tests/ondemand/CMakeLists.txt index 78eb1d1ea..0ec597d51 100644 --- a/tests/ondemand/CMakeLists.txt +++ b/tests/ondemand/CMakeLists.txt @@ -30,6 +30,7 @@ add_cpp_test(ondemand_wrong_type_error_tests LABELS ondemand acceptance add_cpp_test(ondemand_iterate_many_csv LABELS ondemand acceptance per_implementation) add_cpp_test(ondemand_custom_types_tests LABELS ondemand acceptance per_implementation) add_cpp_test(ondemand_custom_types_document_tests LABELS ondemand acceptance per_implementation) +add_cpp_test(ondemand_stl_types_tests LABELS ondemand acceptance per_implementation) if(NOT SIMDJSON_SANITIZE) add_cpp_test(ondemand_cacheline LABELS ondemand acceptance per_implementation) endif() diff --git a/tests/ondemand/ondemand_custom_types_document_tests.cpp b/tests/ondemand/ondemand_custom_types_document_tests.cpp index 23561d30b..dcf201cd0 100644 --- a/tests/ondemand/ondemand_custom_types_document_tests.cpp +++ b/tests/ondemand/ondemand_custom_types_document_tests.cpp @@ -1,5 +1,6 @@ #include "simdjson.h" #include "test_ondemand.h" +#include "simdjson/std/vector.h" #include #include @@ -63,10 +64,10 @@ struct Car { } }; -static_assert(simdjson::deserializable, simdjson::ondemand::value>, "It should be invocable"); -static_assert(simdjson::deserializable, simdjson::ondemand::document>, "Tag_invoke should work with document as well."); -static_assert(simdjson::deserializable, simdjson::ondemand::value>, "It should be invocable"); -static_assert(simdjson::deserializable, simdjson::ondemand::document>, "Tag_invoke should work with document as well."); +static_assert(simdjson::custom_deserializable, simdjson::ondemand::value>, "It should be invocable"); +static_assert(simdjson::custom_deserializable, simdjson::ondemand::document>, "Tag_invoke should work with document as well."); +static_assert(simdjson::custom_deserializable, simdjson::ondemand::value>, "It should be invocable"); +static_assert(simdjson::custom_deserializable, simdjson::ondemand::document>, "Tag_invoke should work with document as well."); bool custom_test() { TEST_START(); diff --git a/tests/ondemand/ondemand_custom_types_tests.cpp b/tests/ondemand/ondemand_custom_types_tests.cpp index d95f3f627..13ad004f6 100644 --- a/tests/ondemand/ondemand_custom_types_tests.cpp +++ b/tests/ondemand/ondemand_custom_types_tests.cpp @@ -1,10 +1,11 @@ #include "simdjson.h" +#include "simdjson/std/vector.h" #include "test_ondemand.h" #include #include -#ifdef __cpp_concepts +#ifdef SIMDJSON_SUPPORTS_DESERIALIZATION template struct is_unique_ptr : std::false_type { @@ -27,7 +28,7 @@ namespace simdjson { // This tag_invoke MUST be inside simdjson namespace template requires is_unique_ptr_v -auto tag_invoke(deserialize_tag, ondemand::value &val, T& out) { +auto tag_invoke(deserialize_tag, auto &val, T& out) { using type = typename T::element_type; out = std::make_unique(val.template get()); return SUCCESS; @@ -36,11 +37,11 @@ auto tag_invoke(deserialize_tag, ondemand::value &val, T& out) { } // namespace simdjson -#endif // __cpp_concepts +#endif // SIMDJSON_SUPPORTS_DESERIALIZATION namespace custom_types_tests { -#if SIMDJSON_EXCEPTIONS && defined(__cpp_concepts) +#if SIMDJSON_EXCEPTIONS && defined(SIMDJSON_SUPPORTS_DESERIALIZATION) struct Car { std::string make{}; std::string model{}; @@ -87,7 +88,7 @@ struct Car { } }; -static_assert(simdjson::deserializable>, "It should be deserializable"); +static_assert(simdjson::custom_deserializable>, "It should be deserializable"); bool custom_uniqueptr_test() { TEST_START(); @@ -214,7 +215,7 @@ bool custom_no_except() { #endif // SIMDJSON_EXCEPTIONS bool run() { return -#if SIMDJSON_EXCEPTIONS && defined(__cpp_concepts) +#if SIMDJSON_EXCEPTIONS && defined(SIMDJSON_SUPPORTS_DESERIALIZATION) custom_test() && custom_uniqueptr_test() && custom_no_except() && diff --git a/tests/ondemand/ondemand_stl_types_tests.cpp b/tests/ondemand/ondemand_stl_types_tests.cpp new file mode 100644 index 000000000..8f728749b --- /dev/null +++ b/tests/ondemand/ondemand_stl_types_tests.cpp @@ -0,0 +1,50 @@ +#include "simdjson.h" +#include "simdjson/std/memory.h" +#include "simdjson/std/vector.h" +#include "test_ondemand.h" + +#include +#include + +namespace stl_types { +#if SIMDJSON_EXCEPTIONS && defined(SIMDJSON_SUPPORTS_DESERIALIZATION) + +bool basic_general_madness() { + TEST_START(); + simdjson::padded_string json = + R"( [ { "codes": [1.2, 3.4, 5.6, 7.8, 9.0] }, + { "codes": [2.2, 4.4, 6.6, 8.8, 10.0] } ])"_padded; + + simdjson::ondemand::parser parser; + simdjson::ondemand::document doc = parser.iterate(json); + std::vector> codes; + for (auto val : doc) { + simdjson::ondemand::object obj; + SIMDJSON_TRY(val.get_object().get(obj)); + obj["codes"].get(codes); // append to it + } + + if (codes.size() != 10) { + return false; + } + if (*codes[5] != 2.2f || *codes[7] != 6.6f || *codes[9] != 10.0f) { + return false; + } + + TEST_SUCCEED(); +} + +#endif // SIMDJSON_EXCEPTIONS +bool run() { + return +#if SIMDJSON_EXCEPTIONS && defined(SIMDJSON_SUPPORTS_DESERIALIZATION) + basic_general_madness() && +#endif // SIMDJSON_EXCEPTIONS + true; +} + +} // namespace stl_types + +int main(int argc, char *argv[]) { + return test_main(argc, argv, stl_types::run); +}