diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 6b8ed31..ed40887 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2536,7 +2537,10 @@ namespace meta_hpp [[nodiscard]] const void* get_cdata() const noexcept; [[nodiscard]] uvalue operator*() const; + [[nodiscard]] bool has_deref_op() const noexcept; + [[nodiscard]] uvalue operator[](std::size_t index) const; + [[nodiscard]] bool has_index_op() const noexcept; template < typename T > [[nodiscard]] T get_as() &&; @@ -8134,7 +8138,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits { uvalue operator()(T* v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; @@ -8142,7 +8146,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits { uvalue operator()(const T* v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; @@ -8150,7 +8154,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits> { uvalue operator()(const std::shared_ptr& v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; @@ -8158,7 +8162,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits> { uvalue operator()(const std::unique_ptr& v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; } @@ -8181,7 +8185,7 @@ namespace meta_hpp::detail struct index_traits { uvalue operator()(T* v, std::size_t i) const { // NOLINTNEXTLINE(*-pointer-arithmetic) - return uvalue{v[i]}; + return v != nullptr ? uvalue{v[i]} : uvalue{}; } }; @@ -8190,7 +8194,7 @@ namespace meta_hpp::detail struct index_traits { uvalue operator()(const T* v, std::size_t i) const { // NOLINTNEXTLINE(*-pointer-arithmetic) - return uvalue{v[i]}; + return v != nullptr ? uvalue{v[i]} : uvalue{}; } }; @@ -8198,7 +8202,15 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::array& v, std::size_t i) const { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; + } + }; + + template < typename T, typename Allocator > + requires std::is_copy_constructible_v + struct index_traits> { + uvalue operator()(const std::deque& v, std::size_t i) { + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; @@ -8206,7 +8218,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::span& v, std::size_t i) const { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; @@ -8214,7 +8226,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::basic_string& v, std::size_t i) const { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; @@ -8222,7 +8234,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::vector& v, std::size_t i) { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; } @@ -8392,21 +8404,26 @@ namespace meta_hpp self.vtable_ = nullptr; }, - .deref = +[]([[maybe_unused]] const storage_u& from) -> uvalue { - if constexpr ( detail::has_deref_traits ) { - return detail::deref_traits{}(*storage_cast(from)); - } else { - META_HPP_THROW_AS(exception, "value type doesn't have value deref traits"); - } - }, - .index = +[]([[maybe_unused]] const storage_u& from, [[maybe_unused]] std::size_t i) -> uvalue { - if constexpr ( detail::has_index_traits ) { - return detail::index_traits{}(*storage_cast(from), i); + .deref = [](){ + if constexpr ( detail::has_deref_traits ) { + return +[](const storage_u& from) -> uvalue { + return detail::deref_traits{}(*storage_cast(from)); + }; } else { - META_HPP_THROW_AS(exception, "value type doesn't have value index traits"); + return nullptr; } - }, + }(), + + .index = [](){ + if constexpr ( detail::has_index_traits ) { + return +[](const storage_u& from, std::size_t i) -> uvalue { + return detail::index_traits{}(*storage_cast(from), i); + }; + } else { + return nullptr; + } + }(), }; return &table; @@ -8530,11 +8547,19 @@ namespace meta_hpp } inline uvalue uvalue::operator*() const { - return vtable_ != nullptr ? vtable_->deref(storage_) : uvalue{}; + return has_deref_op() ? vtable_->deref(storage_) : uvalue{}; + } + + inline bool uvalue::has_deref_op() const noexcept { + return vtable_ != nullptr && vtable_->deref != nullptr; } inline uvalue uvalue::operator[](std::size_t index) const { - return vtable_ != nullptr ? vtable_->index(storage_, index) : uvalue{}; + return has_index_op() ? vtable_->index(storage_, index) : uvalue{}; + } + + inline bool uvalue::has_index_op() const noexcept { + return vtable_ != nullptr && vtable_->index != nullptr; } template < typename T > diff --git a/develop/untests/meta_utilities/value_tests.cpp b/develop/untests/meta_utilities/value_tests.cpp index 566ca0a..c8bab4d 100644 --- a/develop/untests/meta_utilities/value_tests.cpp +++ b/develop/untests/meta_utilities/value_tests.cpp @@ -385,35 +385,59 @@ TEST_CASE("meta/meta_utilities/value") { SUBCASE("deref") { { int i{42}; - const meta::uvalue v{*meta::uvalue{&i}}; + meta::uvalue u{&i}; + CHECK(u.has_deref_op()); + + const meta::uvalue v{*u}; CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_data() != &i); } { const char i{42}; - const meta::uvalue v{*meta::uvalue{&i}}; + meta::uvalue u{&i}; + CHECK(u.has_deref_op()); + + const meta::uvalue v{*u}; CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_data() != &i); } { const int i{42}; const int* const pi = &i; - const meta::uvalue v{*meta::uvalue{&pi}}; + meta::uvalue u{&pi}; + CHECK(u.has_deref_op()); + + const meta::uvalue v{*u}; CHECK(v.get_type() == meta::resolve_type() ); CHECK(v.get_as() == pi); } { int i{42}; - [[maybe_unused]] void* p1 = &i; - [[maybe_unused]] const void* p2 = &i; - [[maybe_unused]] void* const& p3 = &i; - [[maybe_unused]] const void* const& p4 = &i; + void* p1 = &i; + const void* p2 = &i; + void* const& p3 = &i; + const void* const& p4 = &i; - CHECK_THROWS(std::ignore = *meta::uvalue(p1)); - CHECK_THROWS(std::ignore = *meta::uvalue(p2)); - CHECK_THROWS(std::ignore = *meta::uvalue(p3)); - CHECK_THROWS(std::ignore = *meta::uvalue(p4)); + CHECK_FALSE(meta::uvalue(p1).has_deref_op()); + CHECK_FALSE(meta::uvalue(p2).has_deref_op()); + CHECK_FALSE(meta::uvalue(p3).has_deref_op()); + CHECK_FALSE(meta::uvalue(p4).has_deref_op()); + + CHECK_FALSE(*meta::uvalue(p1)); + CHECK_FALSE(*meta::uvalue(p2)); + CHECK_FALSE(*meta::uvalue(p3)); + CHECK_FALSE(*meta::uvalue(p4)); + } + { + int* p1 = nullptr; + const int* p2 = nullptr; + + CHECK(meta::uvalue{p1}.has_deref_op()); + CHECK(meta::uvalue{p2}.has_deref_op()); + + CHECK_FALSE(*meta::uvalue{p1}); + CHECK_FALSE(*meta::uvalue{p2}); } { ivec2 v{1,2}; @@ -443,55 +467,127 @@ TEST_CASE("meta/meta_utilities/value") { TEST_CASE("meta/meta_utilities/value/arrays") { namespace meta = meta_hpp; + SUBCASE("int") { + meta::uvalue v{42}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK_FALSE(v.has_index_op()); + CHECK_FALSE(v[0]); + } + + SUBCASE("void*") { + int i{42}; + void* p{&i}; + meta::uvalue v{p}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK_FALSE(v.has_index_op()); + CHECK_FALSE(v[0]); + } + + SUBCASE("const void*") { + int i{42}; + const void* p{&i}; + meta::uvalue v{p}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK_FALSE(v.has_index_op()); + CHECK_FALSE(v[0]); + } + SUBCASE("int[3]") { - int arr[3]{1,2,3}; - meta::uvalue v{arr}; - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v[0].get_as() == 1); - CHECK(v[1].get_as() == 2); - CHECK(v[2].get_as() == 3); + { + int arr[3]{1,2,3}; + meta::uvalue v{arr}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.has_index_op()); + + CHECK(v[0].get_as() == 1); + CHECK(v[1].get_as() == 2); + CHECK(v[2].get_as() == 3); + } + { + int* arr = nullptr; + meta::uvalue v{arr}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.has_index_op()); + + CHECK_FALSE(v[0]); + } } SUBCASE("const int[3]") { - const int arr[3]{1,2,3}; - meta::uvalue v{arr}; - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v[0].get_as() == 1); - CHECK(v[1].get_as() == 2); - CHECK(v[2].get_as() == 3); + { + const int arr[3]{1,2,3}; + meta::uvalue v{arr}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.has_index_op()); + + CHECK(v[0].get_as() == 1); + CHECK(v[1].get_as() == 2); + CHECK(v[2].get_as() == 3); + } + { + const int* arr = nullptr; + meta::uvalue v{arr}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.has_index_op()); + + CHECK_FALSE(v[0]); + } } SUBCASE("std::array") { meta::uvalue v{std::array{1,2,3}}; CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.has_index_op()); + CHECK(v[0].get_as() == 1); CHECK(v[1].get_as() == 2); CHECK(v[2].get_as() == 3); + CHECK_FALSE(v[3]); + } + + SUBCASE("std::deque") { + const meta::uvalue v{std::deque{1,2,3}}; + CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.has_index_op()); + + CHECK(v[0].get_as() == 1); + CHECK(v[1].get_as() == 2); + CHECK(v[2].get_as() == 3); + CHECK_FALSE(v[3]); } SUBCASE("std::string") { meta::uvalue v{std::string{"hi!"}}; CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.has_index_op()); + CHECK(v[0].get_as() == 'h'); CHECK(v[1].get_as() == 'i'); CHECK(v[2].get_as() == '!'); + CHECK_FALSE(v[3]); } SUBCASE("std::span") { std::vector arr{1,2,3}; meta::uvalue v{std::span{arr}}; CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.has_index_op()); + CHECK(v[0].get_as() == 1); CHECK(v[1].get_as() == 2); CHECK(v[2].get_as() == 3); + CHECK_FALSE(v[3]); } SUBCASE("std::vector") { const meta::uvalue v{std::vector{1,2,3}}; CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.has_index_op()); + CHECK(v[0].get_as() == 1); CHECK(v[1].get_as() == 2); CHECK(v[2].get_as() == 3); + CHECK_FALSE(v[3]); } } diff --git a/headers/meta.hpp/meta_base/base.hpp b/headers/meta.hpp/meta_base/base.hpp index 2dea187..6162479 100644 --- a/headers/meta.hpp/meta_base/base.hpp +++ b/headers/meta.hpp/meta_base/base.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp index 1785ada..da0bb63 100644 --- a/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp @@ -26,7 +26,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits { uvalue operator()(T* v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; @@ -34,7 +34,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits { uvalue operator()(const T* v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; @@ -42,7 +42,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits> { uvalue operator()(const std::shared_ptr& v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; @@ -50,7 +50,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct deref_traits> { uvalue operator()(const std::unique_ptr& v) const { - return uvalue{*v}; + return v != nullptr ? uvalue{*v} : uvalue{}; } }; } diff --git a/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp index d340c57..a00b687 100644 --- a/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp @@ -27,7 +27,7 @@ namespace meta_hpp::detail struct index_traits { uvalue operator()(T* v, std::size_t i) const { // NOLINTNEXTLINE(*-pointer-arithmetic) - return uvalue{v[i]}; + return v != nullptr ? uvalue{v[i]} : uvalue{}; } }; @@ -36,7 +36,7 @@ namespace meta_hpp::detail struct index_traits { uvalue operator()(const T* v, std::size_t i) const { // NOLINTNEXTLINE(*-pointer-arithmetic) - return uvalue{v[i]}; + return v != nullptr ? uvalue{v[i]} : uvalue{}; } }; @@ -44,7 +44,15 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::array& v, std::size_t i) const { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; + } + }; + + template < typename T, typename Allocator > + requires std::is_copy_constructible_v + struct index_traits> { + uvalue operator()(const std::deque& v, std::size_t i) { + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; @@ -52,7 +60,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::span& v, std::size_t i) const { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; @@ -60,7 +68,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::basic_string& v, std::size_t i) const { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; @@ -68,7 +76,7 @@ namespace meta_hpp::detail requires std::is_copy_constructible_v struct index_traits> { uvalue operator()(const std::vector& v, std::size_t i) { - return uvalue{v[i]}; + return i < v.size() ? uvalue{v[i]} : uvalue{}; } }; } diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index 96a10fa..83ff9ef 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -83,7 +83,10 @@ namespace meta_hpp [[nodiscard]] const void* get_cdata() const noexcept; [[nodiscard]] uvalue operator*() const; + [[nodiscard]] bool has_deref_op() const noexcept; + [[nodiscard]] uvalue operator[](std::size_t index) const; + [[nodiscard]] bool has_index_op() const noexcept; template < typename T > [[nodiscard]] T get_as() &&; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index f20f9b7..a499094 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -180,21 +180,26 @@ namespace meta_hpp self.vtable_ = nullptr; }, - .deref = +[]([[maybe_unused]] const storage_u& from) -> uvalue { - if constexpr ( detail::has_deref_traits ) { - return detail::deref_traits{}(*storage_cast(from)); - } else { - META_HPP_THROW_AS(exception, "value type doesn't have value deref traits"); - } - }, - .index = +[]([[maybe_unused]] const storage_u& from, [[maybe_unused]] std::size_t i) -> uvalue { - if constexpr ( detail::has_index_traits ) { - return detail::index_traits{}(*storage_cast(from), i); + .deref = [](){ + if constexpr ( detail::has_deref_traits ) { + return +[](const storage_u& from) -> uvalue { + return detail::deref_traits{}(*storage_cast(from)); + }; } else { - META_HPP_THROW_AS(exception, "value type doesn't have value index traits"); + return nullptr; } - }, + }(), + + .index = [](){ + if constexpr ( detail::has_index_traits ) { + return +[](const storage_u& from, std::size_t i) -> uvalue { + return detail::index_traits{}(*storage_cast(from), i); + }; + } else { + return nullptr; + } + }(), }; return &table; @@ -318,11 +323,19 @@ namespace meta_hpp } inline uvalue uvalue::operator*() const { - return vtable_ != nullptr ? vtable_->deref(storage_) : uvalue{}; + return has_deref_op() ? vtable_->deref(storage_) : uvalue{}; + } + + inline bool uvalue::has_deref_op() const noexcept { + return vtable_ != nullptr && vtable_->deref != nullptr; } inline uvalue uvalue::operator[](std::size_t index) const { - return vtable_ != nullptr ? vtable_->index(storage_, index) : uvalue{}; + return has_index_op() ? vtable_->index(storage_, index) : uvalue{}; + } + + inline bool uvalue::has_index_op() const noexcept { + return vtable_ != nullptr && vtable_->index != nullptr; } template < typename T >