diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 1659c32..16085b9 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -10461,20 +10461,99 @@ namespace meta_hpp::detail template < typename T > concept has_copy_traits // - = requires(const T& v) { copy_traits{}(v); }; + = requires(const T& v) { copy_traits>{}(v); }; } namespace meta_hpp::detail { template < typename T > - requires requires(const T& v) { uvalue{v}; } + requires(!std::is_class_v) && requires(T v) { uvalue{v}; } struct copy_traits { - uvalue operator()(const T& v) const { + uvalue operator()(T v) const { + return uvalue{v}; + } + }; + + template < typename T, std::size_t Size > + requires has_copy_traits + struct copy_traits> { + using value_t = std::array; + + uvalue operator()(const value_t& v) const { + return uvalue{v}; + } + }; + + template < typename T, typename Traits, typename Allocator > + requires has_copy_traits + struct copy_traits> { + using value_t = std::basic_string; + + uvalue operator()(const value_t& v) const { + return uvalue{v}; + } + }; + + template < typename T, typename Traits > + requires has_copy_traits + struct copy_traits> { + using value_t = std::basic_string_view; + + uvalue operator()(const value_t& v) const { + return uvalue{v}; + } + }; + + template < typename T, typename Allocator > + requires has_copy_traits + struct copy_traits> { + using value_t = std::vector; + + uvalue operator()(const value_t& v) const { + return uvalue{v}; + } + }; + + template < typename T > + struct copy_traits> { + using value_t = std::shared_ptr; + + uvalue operator()(const value_t& v) const { + return uvalue{v}; + } + }; + + template < typename T > + struct copy_traits> { + using value_t = std::reference_wrapper; + + uvalue operator()(const value_t& v) const { + return uvalue{v}; + } + }; + + template < typename... Ts > + requires(... && has_copy_traits) + struct copy_traits> { + using value_t = std::tuple; + + uvalue operator()(const value_t& v) const { return uvalue{v}; } }; } +#define META_HPP_DECLARE_COPY_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct copy_traits { \ + uvalue operator()(const T& v) const { \ + return uvalue{v}; \ + } \ + }; \ + } + namespace meta_hpp::detail { template < typename T > @@ -10482,13 +10561,13 @@ namespace meta_hpp::detail template < typename T > concept has_deref_traits // - = requires(const T& v) { deref_traits{}(v); }; + = requires(const T& v) { deref_traits>{}(v); }; } namespace meta_hpp::detail { template < typename T > - requires std::is_copy_constructible_v + requires has_copy_traits && (!std::is_function_v) struct deref_traits { uvalue operator()(T* v) const { return v != nullptr ? uvalue{*v} : uvalue{}; @@ -10496,22 +10575,37 @@ namespace meta_hpp::detail }; template < typename T > - requires std::is_copy_constructible_v + requires has_copy_traits struct deref_traits> { - uvalue operator()(const std::shared_ptr& v) const { + using value_t = std::shared_ptr; + + uvalue operator()(const value_t& v) const { return v != nullptr ? uvalue{*v} : uvalue{}; } }; template < typename T, typename Deleter > - requires std::is_copy_constructible_v + requires has_copy_traits struct deref_traits> { - uvalue operator()(const std::unique_ptr& v) const { + using value_t = std::unique_ptr; + + uvalue operator()(const value_t& v) const { return v != nullptr ? uvalue{*v} : uvalue{}; } }; } +#define META_HPP_DECLARE_DEREF_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct deref_traits { \ + uvalue operator()(const T& v) const { \ + return uvalue{*v}; \ + } \ + }; \ + } + namespace meta_hpp::detail { template < typename T > @@ -10519,17 +10613,17 @@ namespace meta_hpp::detail template < typename T > concept has_equals_traits // - = requires(const T& v) { equals_traits{}(v, v); }; + = requires(const T& v) { equals_traits>{}(v, v); }; } namespace meta_hpp::detail { template < typename T > - requires requires(const T& v) { - { v == v } -> std::convertible_to; - } && (!class_kind || type_list_arity_v::argument_types> == 0) + requires(!std::is_class_v) && requires(T v) { + { v == v } -> std::convertible_to; + } struct equals_traits { - bool operator()(const T& l, const T& r) const { + bool operator()(T l, T r) const { META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() return l == r; META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() @@ -10633,13 +10727,13 @@ namespace meta_hpp::detail template < typename T > concept has_index_traits // - = requires(const T& v, std::size_t i) { index_traits{}(v, i); }; + = requires(const T& v, std::size_t i) { index_traits>{}(v, i); }; } namespace meta_hpp::detail { template < typename T > - requires std::is_copy_constructible_v + requires has_copy_traits && (!std::is_function_v) struct index_traits { uvalue operator()(T* v, std::size_t i) const { // NOLINTNEXTLINE(*-pointer-arithmetic) @@ -10648,7 +10742,7 @@ namespace meta_hpp::detail }; template < typename T, std::size_t Size > - requires std::is_copy_constructible_v + requires has_copy_traits struct index_traits> { uvalue operator()(const std::array& v, std::size_t i) const { return i < v.size() ? uvalue{v[i]} : uvalue{}; @@ -10656,7 +10750,7 @@ namespace meta_hpp::detail }; template < typename T, typename Traits, typename Allocator > - requires std::is_copy_constructible_v + requires has_copy_traits struct index_traits> { uvalue operator()(const std::basic_string& v, std::size_t i) const { return i < v.size() ? uvalue{v[i]} : uvalue{}; @@ -10664,7 +10758,7 @@ namespace meta_hpp::detail }; template < typename T, typename Traits > - requires std::is_copy_constructible_v + requires has_copy_traits struct index_traits> { uvalue operator()(const std::basic_string_view& v, std::size_t i) const { return i < v.size() ? uvalue{v[i]} : uvalue{}; @@ -10672,7 +10766,7 @@ namespace meta_hpp::detail }; template < typename T, std::size_t Extent > - requires std::is_copy_constructible_v + requires has_copy_traits struct index_traits> { uvalue operator()(const std::span& v, std::size_t i) const { return i < v.size() ? uvalue{v[i]} : uvalue{}; @@ -10680,7 +10774,7 @@ namespace meta_hpp::detail }; template < typename T, typename Allocator > - requires std::is_copy_constructible_v + requires has_copy_traits struct index_traits> { uvalue operator()(const std::vector& v, std::size_t i) const { return i < v.size() ? uvalue{v[i]} : uvalue{}; @@ -10688,6 +10782,17 @@ namespace meta_hpp::detail }; } +#define META_HPP_DECLARE_INDEX_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct index_traits { \ + uvalue operator()(const T& v, std::size_t i) const { \ + return uvalue{v[i]}; \ + } \ + }; \ + } + namespace meta_hpp::detail { template < typename T > @@ -10695,17 +10800,17 @@ namespace meta_hpp::detail template < typename T > concept has_less_traits // - = requires(const T& v) { less_traits{}(v, v); }; + = requires(const T& v) { less_traits>{}(v, v); }; } namespace meta_hpp::detail { template < typename T > - requires requires(const T& v) { - { v < v } -> std::convertible_to; - } && (!class_kind || type_list_arity_v::argument_types> == 0) + requires(!std::is_class_v) && requires(T v) { + { v < v } -> std::convertible_to; + } struct less_traits { - bool operator()(const T& l, const T& r) const { + bool operator()(T l, T r) const { META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() return l < r; META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() @@ -10809,7 +10914,7 @@ namespace meta_hpp::detail template < typename T > concept has_unmap_traits // - = requires(const T& v) { unmap_traits{}(v); }; + = requires(const T& v) { unmap_traits>{}(v); }; } namespace meta_hpp::detail diff --git a/develop/untests/meta_utilities/value_tests.cpp b/develop/untests/meta_utilities/value_tests.cpp index e4e7d77..1e33c7b 100644 --- a/develop/untests/meta_utilities/value_tests.cpp +++ b/develop/untests/meta_utilities/value_tests.cpp @@ -115,6 +115,19 @@ namespace struct deref_custom_class { int operator*() const { return 42; } }; + + struct custom_class_without_comparison {}; + + struct custom_class_with_fake_comparison { + std::vector vs; + bool operator==(const custom_class_with_fake_comparison&) const = default; + }; + + struct custom_class_with_comparison { + std::vector vs; + bool operator<(const custom_class_with_comparison& r) const { return vs < r.vs; } + bool operator==(const custom_class_with_comparison& r) const { return vs == r.vs; } + }; } META_HPP_DECLARE_COPY_TRAITS_FOR(ivec2) @@ -124,6 +137,11 @@ META_HPP_DECLARE_DEREF_TRAITS_FOR(deref_custom_class) META_HPP_DECLARE_INDEX_TRAITS_FOR(ivec2) +META_HPP_DECLARE_EQUALS_TRAITS_FOR(ivec2) + +META_HPP_DECLARE_LESS_TRAITS_FOR(custom_class_with_comparison) +META_HPP_DECLARE_EQUALS_TRAITS_FOR(custom_class_with_comparison) + TEST_CASE("meta/meta_utilities/value/_") { namespace meta = meta_hpp; @@ -521,12 +539,23 @@ TEST_CASE("meta/meta_utilities/value") { CHECK_FALSE(meta::uvalue{std::vector>{}}.has_copy_op()); CHECK(meta::uvalue{std::shared_ptr{}}.has_copy_op()); { - using ref_t = std::reference_wrapper>; + using ref_t = std::reference_wrapper>; + using cref_t = std::reference_wrapper>; + std::unique_ptr u = std::make_unique(42); CHECK(meta::uvalue{ref_t{u}}.has_copy_op()); - meta::uvalue v = meta::uvalue{ref_t{u}}.copy(); - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v.as().get().get() == u.get()); + CHECK(meta::uvalue{cref_t{u}}.has_copy_op()); + meta::uvalue v1 = meta::uvalue{ref_t{u}}.copy(); + meta::uvalue v2 = meta::uvalue{cref_t{u}}.copy(); + CHECK(v1.get_type() == meta::resolve_type()); + CHECK(v1.as().get().get() == u.get()); + CHECK(v2.get_type() == meta::resolve_type()); + CHECK(v2.as().get().get() == u.get()); + } + { + ivec2 u = ivec2{42, 21}; + CHECK(meta::uvalue{std::ref(u)}.has_copy_op()); + CHECK(meta::uvalue{std::cref(u)}.has_copy_op()); } CHECK(meta::uvalue{std::make_tuple(42, std::make_shared(42))}.has_copy_op()); CHECK_FALSE(meta::uvalue{std::make_tuple(42, std::make_unique(42))}.has_copy_op()); @@ -669,6 +698,10 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(u.get_type() == meta::resolve_type()); CHECK(u.as() == 42); } + { + CHECK(meta::uvalue{std::unique_ptr{}}.has_deref_op()); + CHECK(meta::uvalue{std::unique_ptr{}}.has_deref_op()); + } } SUBCASE("less/equal") { @@ -858,6 +891,16 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(meta::uvalue{std::cref(v2)}.has_equals_op()); } } + { + meta::uvalue v{custom_class_with_comparison{}}; + CHECK(v.has_less_op()); + CHECK(v.has_equals_op()); + } + { + meta::uvalue v{custom_class_with_fake_comparison{}}; + CHECK_FALSE(v.has_less_op()); + CHECK_FALSE(v.has_equals_op()); + } } } diff --git a/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp index dcd63bd..0d65b3f 100644 --- a/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/copy_traits.hpp @@ -16,15 +16,15 @@ namespace meta_hpp::detail template < typename T > concept has_copy_traits // - = requires(const T& v) { copy_traits{}(v); }; + = requires(const T& v) { copy_traits>{}(v); }; } namespace meta_hpp::detail { template < typename T > - requires(!std::is_class_v && std::is_copy_constructible_v) + requires(!std::is_class_v) && requires(T v) { uvalue{v}; } struct copy_traits { - uvalue operator()(const T& v) const { + uvalue operator()(T v) const { return uvalue{v}; } }; 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 19a0d71..3f9cf5c 100644 --- a/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/deref_traits.hpp @@ -18,13 +18,13 @@ namespace meta_hpp::detail template < typename T > concept has_deref_traits // - = requires(const T& v) { deref_traits{}(v); }; + = requires(const T& v) { deref_traits>{}(v); }; } namespace meta_hpp::detail { template < typename T > - requires has_copy_traits + requires has_copy_traits && (!std::is_function_v) struct deref_traits { uvalue operator()(T* v) const { return v != nullptr ? uvalue{*v} : uvalue{}; diff --git a/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp index 11d1314..dcc6a15 100644 --- a/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp @@ -16,17 +16,17 @@ namespace meta_hpp::detail template < typename T > concept has_equals_traits // - = requires(const T& v) { equals_traits{}(v, v); }; + = requires(const T& v) { equals_traits>{}(v, v); }; } namespace meta_hpp::detail { template < typename T > - requires requires(const T& v) { - { v == v } -> std::convertible_to; - } && (!class_kind || type_list_arity_v::argument_types> == 0) + requires(!std::is_class_v) && requires(T v) { + { v == v } -> std::convertible_to; + } struct equals_traits { - bool operator()(const T& l, const T& r) const { + bool operator()(T l, T r) const { META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() return l == r; META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() 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 7aba1ee..74abc1d 100644 --- a/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/index_traits.hpp @@ -18,13 +18,13 @@ namespace meta_hpp::detail template < typename T > concept has_index_traits // - = requires(const T& v, std::size_t i) { index_traits{}(v, i); }; + = requires(const T& v, std::size_t i) { index_traits>{}(v, i); }; } namespace meta_hpp::detail { template < typename T > - requires has_copy_traits + requires has_copy_traits && (!std::is_function_v) struct index_traits { uvalue operator()(T* v, std::size_t i) const { // NOLINTNEXTLINE(*-pointer-arithmetic) diff --git a/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp index 8d37ddb..05f943c 100644 --- a/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp @@ -16,17 +16,17 @@ namespace meta_hpp::detail template < typename T > concept has_less_traits // - = requires(const T& v) { less_traits{}(v, v); }; + = requires(const T& v) { less_traits>{}(v, v); }; } namespace meta_hpp::detail { template < typename T > - requires requires(const T& v) { - { v < v } -> std::convertible_to; - } && (!class_kind || type_list_arity_v::argument_types> == 0) + requires(!std::is_class_v) && requires(T v) { + { v < v } -> std::convertible_to; + } struct less_traits { - bool operator()(const T& l, const T& r) const { + bool operator()(T l, T r) const { META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() return l < r; META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() diff --git a/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp index 8c9396f..f184e72 100644 --- a/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp +++ b/headers/meta.hpp/meta_detail/value_traits/unmap_traits.hpp @@ -16,7 +16,7 @@ namespace meta_hpp::detail template < typename T > concept has_unmap_traits // - = requires(const T& v) { unmap_traits{}(v); }; + = requires(const T& v) { unmap_traits>{}(v); }; } namespace meta_hpp::detail