From 1336ade8b3bc7d5a36c8cc595ef175394cbb1eb3 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Wed, 7 Aug 2024 08:39:17 +0700 Subject: [PATCH] new uvalue ops (less, equals) --- develop/singles/headers/meta.hpp/meta_all.hpp | 317 ++++++++++++++++++ .../untests/meta_utilities/value_tests.cpp | 119 +++++++ headers/meta.hpp/meta_base/base.hpp | 12 + .../value_traits/equals_traits.hpp | 124 +++++++ .../meta_detail/value_traits/less_traits.hpp | 124 +++++++ headers/meta.hpp/meta_uvalue.hpp | 6 + headers/meta.hpp/meta_uvalue/uvalue.hpp | 73 ++++ manuals/api/basics.md | 6 + 8 files changed, 781 insertions(+) create mode 100644 headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp create mode 100644 headers/meta.hpp/meta_detail/value_traits/less_traits.hpp diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 12f7971..c4ce663 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -188,6 +188,18 @@ #define META_HPP_DETAIL_IGNORE_OVERRIDE_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP() +// +// +// + +#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() \ + META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_PUSH() \ + META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wunknown-warning-option") \ + META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wfloat-equal") \ + META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wordered-compare-function-pointers") + +#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP() + namespace meta_hpp::detail { template < typename Enum > @@ -2755,6 +2767,12 @@ namespace meta_hpp [[nodiscard]] uvalue unmap() const; [[nodiscard]] bool has_unmap_op() const noexcept; + [[nodiscard]] bool less(const uvalue& other) const; + [[nodiscard]] bool has_less_op() const noexcept; + + [[nodiscard]] bool equals(const uvalue& other) const; + [[nodiscard]] bool has_equals_op() const noexcept; + template < typename T > [[nodiscard]] bool is() const noexcept; @@ -10474,6 +10492,120 @@ namespace meta_hpp::detail }; } +namespace meta_hpp::detail +{ + template < typename T > + struct equals_traits; + + template < typename T > + concept has_equals_traits // + = 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) + struct equals_traits { + bool operator()(const T& l, const T& r) const { + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() + return l == r; + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() + } + }; + + template < typename T, std::size_t Size > + requires has_equals_traits + struct equals_traits> { + using value_t = std::array; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Traits, typename Allocator > + requires has_equals_traits + struct equals_traits> { + using value_t = std::basic_string; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Traits > + requires has_equals_traits + struct equals_traits> { + using value_t = std::basic_string_view; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Allocator > + requires has_equals_traits + struct equals_traits> { + using value_t = std::vector; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T > + struct equals_traits> { + using value_t = std::shared_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Deleter > + struct equals_traits> { + using value_t = std::unique_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T > + requires has_equals_traits + struct equals_traits> { + using value_t = std::reference_wrapper; + + bool operator()(const value_t& l, const value_t& r) const { + return l.get() == r.get(); + } + }; + + template < typename... Ts > + requires(... && has_equals_traits) + struct equals_traits> { + using value_t = std::tuple; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; +} + +#define META_HPP_DECLARE_EQUALS_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct equals_traits { \ + bool operator()(const T& l, const T& r) const { \ + return l == r; \ + } \ + }; \ + } + namespace meta_hpp::detail { template < typename T > @@ -10536,6 +10668,120 @@ namespace meta_hpp::detail }; } +namespace meta_hpp::detail +{ + template < typename T > + struct less_traits; + + template < typename T > + concept has_less_traits // + = 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) + struct less_traits { + bool operator()(const T& l, const T& r) const { + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() + return l < r; + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() + } + }; + + template < typename T, std::size_t Size > + requires has_less_traits + struct less_traits> { + using value_t = std::array; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Traits, typename Allocator > + requires has_less_traits + struct less_traits> { + using value_t = std::basic_string; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Traits > + requires has_less_traits + struct less_traits> { + using value_t = std::basic_string_view; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Allocator > + requires has_less_traits + struct less_traits> { + using value_t = std::vector; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T > + struct less_traits> { + using value_t = std::shared_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Deleter > + struct less_traits> { + using value_t = std::unique_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T > + requires has_less_traits + struct less_traits> { + using value_t = std::reference_wrapper; + + bool operator()(const value_t& l, const value_t& r) const { + return l.get() < r.get(); + } + }; + + template < typename... Ts > + requires(... && has_less_traits) + struct less_traits> { + using value_t = std::tuple; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; +} + +#define META_HPP_DECLARE_LESS_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct less_traits { \ + bool operator()(const T& l, const T& r) const { \ + return l < r; \ + } \ + }; \ + } + namespace meta_hpp::detail { template < typename T > @@ -10583,6 +10829,9 @@ namespace meta_hpp uvalue (*const deref)(const storage_u& self); uvalue (*const index)(const storage_u& self, std::size_t i); uvalue (*const unmap)(const storage_u& self); + + bool (*const less)(const storage_u& l, const storage_u& r); + bool (*const equals)(const storage_u& l, const storage_u& r); // NOLINTEND(*-avoid-const-or-ref-data-members) template < typename T > @@ -10785,6 +11034,26 @@ namespace meta_hpp return nullptr; } }()}, + + .less{[]() { + if constexpr ( detail::has_less_traits ) { + return +[](const storage_u& l, const storage_u& r) -> bool { + return detail::less_traits{}(*storage_cast(l), *storage_cast(r)); + }; + } else { + return nullptr; + } + }()}, + + .equals{[]() { + if constexpr ( detail::has_equals_traits ) { + return +[](const storage_u& l, const storage_u& r) -> bool { + return detail::equals_traits{}(*storage_cast(l), *storage_cast(r)); + }; + } else { + return nullptr; + } + }()}, }; return &table; @@ -10966,6 +11235,54 @@ namespace meta_hpp return tag != storage_e::nothing && vtable->unmap != nullptr; } + inline bool uvalue::less(const uvalue& other) const { + auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this); + auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other); + + if ( l_tag != r_tag ) { + return false; + } + + if ( l_tag == storage_e::nothing ) { + return false; + } + + if ( l_vtable != r_vtable || l_vtable->less == nullptr ) { + return false; + } + + return l_vtable->less(storage_, other.storage_); + } + + inline bool uvalue::has_less_op() const noexcept { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag == storage_e::nothing || vtable->less != nullptr; + } + + inline bool uvalue::equals(const uvalue& other) const { + auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this); + auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other); + + if ( l_tag != r_tag ) { + return false; + } + + if ( l_tag == storage_e::nothing ) { + return true; + } + + if ( l_vtable != r_vtable || l_vtable->equals == nullptr ) { + return false; + } + + return l_vtable->equals(storage_, other.storage_); + } + + inline bool uvalue::has_equals_op() const noexcept { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag == storage_e::nothing || vtable->equals != nullptr; + } + template < typename T > bool uvalue::is() const noexcept { static_assert(std::is_same_v>); diff --git a/develop/untests/meta_utilities/value_tests.cpp b/develop/untests/meta_utilities/value_tests.cpp index d0da912..c95c385 100644 --- a/develop/untests/meta_utilities/value_tests.cpp +++ b/develop/untests/meta_utilities/value_tests.cpp @@ -615,6 +615,125 @@ TEST_CASE("meta/meta_utilities/value") { CHECK((*v).as() == 42); } } + + SUBCASE("less/equals") { + { + meta::uvalue v1{42}; + meta::uvalue v2{42}; + CHECK(v1.has_less_op()); + CHECK(v2.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v1)); + CHECK(v1.equals(v2)); + CHECK(v2.equals(v1)); + } + { + meta::uvalue v1{42}; + meta::uvalue v2{43}; + CHECK(v1.has_less_op()); + CHECK(v2.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK(v1.less(v2)); + CHECK_FALSE(v2.less(v1)); + CHECK_FALSE(v1.equals(v2)); + CHECK_FALSE(v2.equals(v1)); + } + { + meta::uvalue v1{42}; + meta::uvalue v2{'a'}; + CHECK(v1.has_less_op()); + CHECK(v2.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v1)); + CHECK_FALSE(v1.equals(v2)); + CHECK_FALSE(v2.equals(v1)); + } + { + meta::uvalue v1{ivec2{1,2}}; + meta::uvalue v2{ivec2{1,2}}; + CHECK_FALSE(v1.has_less_op()); + CHECK_FALSE(v2.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v1)); + CHECK(v1.equals(v2)); + CHECK(v2.equals(v1)); + } + { + meta::uvalue v1{ivec2{1,2}}; + meta::uvalue v2{ivec3{1,2,3}}; + CHECK_FALSE(v1.has_less_op()); + CHECK_FALSE(v2.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK_FALSE(v2.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v1)); + CHECK_FALSE(v1.equals(v2)); + CHECK_FALSE(v2.equals(v1)); + } + { + meta::uvalue v{}; + CHECK(v.has_less_op()); + CHECK(v.has_equals_op()); + CHECK_FALSE(v.less(v)); + CHECK_FALSE(v.less(meta::uvalue{42})); + CHECK_FALSE(meta::uvalue{42}.less(meta::uvalue{})); + CHECK(v.equals(v)); + CHECK_FALSE(v.equals(meta::uvalue{42})); + CHECK_FALSE(meta::uvalue{42}.equals(meta::uvalue{})); + } + { + meta::uvalue v1{std::array{ivec2{1,2},ivec2{3,4}}}; + meta::uvalue v2{std::array{ivec2{1,2},ivec2{3,4}}}; + meta::uvalue v3{std::array{ivec2{1,2},ivec2{3,5}}}; + CHECK_FALSE(v1.has_less_op()); + CHECK_FALSE(v2.has_less_op()); + CHECK_FALSE(v3.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK(v3.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v3)); + CHECK(v1.equals(v2)); + CHECK_FALSE(v2.equals(v3)); + } + { + meta::uvalue v1{std::vector{{1,2},{3,4}}}; + meta::uvalue v2{std::vector{{1,2},{3,4}}}; + meta::uvalue v3{std::vector{{1,2},{3,5}}}; + CHECK_FALSE(v1.has_less_op()); + CHECK_FALSE(v2.has_less_op()); + CHECK_FALSE(v3.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK(v3.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v3)); + CHECK(v1.equals(v2)); + CHECK_FALSE(v2.equals(v3)); + } + { + meta::uvalue v1{std::tuple{42, {1,2}}}; + meta::uvalue v2{std::tuple{42, {1,2}}}; + meta::uvalue v3{std::tuple{42, {1,3}}}; + CHECK_FALSE(v1.has_less_op()); + CHECK_FALSE(v2.has_less_op()); + CHECK_FALSE(v3.has_less_op()); + CHECK(v1.has_equals_op()); + CHECK(v2.has_equals_op()); + CHECK(v3.has_equals_op()); + CHECK_FALSE(v1.less(v2)); + CHECK_FALSE(v2.less(v3)); + CHECK(v1.equals(v2)); + CHECK_FALSE(v2.equals(v3)); + } + } } TEST_CASE("meta/meta_utilities/value/arrays") { diff --git a/headers/meta.hpp/meta_base/base.hpp b/headers/meta.hpp/meta_base/base.hpp index ca5f0ba..4725b7e 100644 --- a/headers/meta.hpp/meta_base/base.hpp +++ b/headers/meta.hpp/meta_base/base.hpp @@ -188,3 +188,15 @@ META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wsuggest-override") #define META_HPP_DETAIL_IGNORE_OVERRIDE_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP() + +// +// +// + +#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() \ + META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_PUSH() \ + META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wunknown-warning-option") \ + META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wfloat-equal") \ + META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wordered-compare-function-pointers") + +#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP() diff --git a/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp new file mode 100644 index 0000000..11d1314 --- /dev/null +++ b/headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp @@ -0,0 +1,124 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2024, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "../../meta_base.hpp" +#include "../../meta_uvalue.hpp" + +namespace meta_hpp::detail +{ + template < typename T > + struct equals_traits; + + template < typename T > + concept has_equals_traits // + = 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) + struct equals_traits { + bool operator()(const T& l, const T& r) const { + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() + return l == r; + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() + } + }; + + template < typename T, std::size_t Size > + requires has_equals_traits + struct equals_traits> { + using value_t = std::array; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Traits, typename Allocator > + requires has_equals_traits + struct equals_traits> { + using value_t = std::basic_string; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Traits > + requires has_equals_traits + struct equals_traits> { + using value_t = std::basic_string_view; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Allocator > + requires has_equals_traits + struct equals_traits> { + using value_t = std::vector; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T > + struct equals_traits> { + using value_t = std::shared_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T, typename Deleter > + struct equals_traits> { + using value_t = std::unique_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; + + template < typename T > + requires has_equals_traits + struct equals_traits> { + using value_t = std::reference_wrapper; + + bool operator()(const value_t& l, const value_t& r) const { + return l.get() == r.get(); + } + }; + + template < typename... Ts > + requires(... && has_equals_traits) + struct equals_traits> { + using value_t = std::tuple; + + bool operator()(const value_t& l, const value_t& r) const { + return l == r; + } + }; +} + +#define META_HPP_DECLARE_EQUALS_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct equals_traits { \ + bool operator()(const T& l, const T& r) const { \ + return l == r; \ + } \ + }; \ + } diff --git a/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp b/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp new file mode 100644 index 0000000..8d37ddb --- /dev/null +++ b/headers/meta.hpp/meta_detail/value_traits/less_traits.hpp @@ -0,0 +1,124 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2024, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "../../meta_base.hpp" +#include "../../meta_uvalue.hpp" + +namespace meta_hpp::detail +{ + template < typename T > + struct less_traits; + + template < typename T > + concept has_less_traits // + = 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) + struct less_traits { + bool operator()(const T& l, const T& r) const { + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() + return l < r; + META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() + } + }; + + template < typename T, std::size_t Size > + requires has_less_traits + struct less_traits> { + using value_t = std::array; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Traits, typename Allocator > + requires has_less_traits + struct less_traits> { + using value_t = std::basic_string; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Traits > + requires has_less_traits + struct less_traits> { + using value_t = std::basic_string_view; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Allocator > + requires has_less_traits + struct less_traits> { + using value_t = std::vector; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T > + struct less_traits> { + using value_t = std::shared_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T, typename Deleter > + struct less_traits> { + using value_t = std::unique_ptr; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; + + template < typename T > + requires has_less_traits + struct less_traits> { + using value_t = std::reference_wrapper; + + bool operator()(const value_t& l, const value_t& r) const { + return l.get() < r.get(); + } + }; + + template < typename... Ts > + requires(... && has_less_traits) + struct less_traits> { + using value_t = std::tuple; + + bool operator()(const value_t& l, const value_t& r) const { + return l < r; + } + }; +} + +#define META_HPP_DECLARE_LESS_TRAITS_FOR(T) \ + namespace meta_hpp::detail \ + { \ + template <> \ + struct less_traits { \ + bool operator()(const T& l, const T& r) const { \ + return l < r; \ + } \ + }; \ + } diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index 823cc20..e1e7eff 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -77,6 +77,12 @@ namespace meta_hpp [[nodiscard]] uvalue unmap() const; [[nodiscard]] bool has_unmap_op() const noexcept; + [[nodiscard]] bool less(const uvalue& other) const; + [[nodiscard]] bool has_less_op() const noexcept; + + [[nodiscard]] bool equals(const uvalue& other) const; + [[nodiscard]] bool has_equals_op() const noexcept; + template < typename T > [[nodiscard]] bool is() const noexcept; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index 75fa4c8..147016e 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -12,7 +12,9 @@ #include "../meta_detail/value_traits/copy_traits.hpp" #include "../meta_detail/value_traits/deref_traits.hpp" +#include "../meta_detail/value_traits/equals_traits.hpp" #include "../meta_detail/value_traits/index_traits.hpp" +#include "../meta_detail/value_traits/less_traits.hpp" #include "../meta_detail/value_traits/unmap_traits.hpp" #include "../meta_detail/value_utilities/uarg.hpp" @@ -31,6 +33,9 @@ namespace meta_hpp uvalue (*const deref)(const storage_u& self); uvalue (*const index)(const storage_u& self, std::size_t i); uvalue (*const unmap)(const storage_u& self); + + bool (*const less)(const storage_u& l, const storage_u& r); + bool (*const equals)(const storage_u& l, const storage_u& r); // NOLINTEND(*-avoid-const-or-ref-data-members) template < typename T > @@ -233,6 +238,26 @@ namespace meta_hpp return nullptr; } }()}, + + .less{[]() { + if constexpr ( detail::has_less_traits ) { + return +[](const storage_u& l, const storage_u& r) -> bool { + return detail::less_traits{}(*storage_cast(l), *storage_cast(r)); + }; + } else { + return nullptr; + } + }()}, + + .equals{[]() { + if constexpr ( detail::has_equals_traits ) { + return +[](const storage_u& l, const storage_u& r) -> bool { + return detail::equals_traits{}(*storage_cast(l), *storage_cast(r)); + }; + } else { + return nullptr; + } + }()}, }; return &table; @@ -414,6 +439,54 @@ namespace meta_hpp return tag != storage_e::nothing && vtable->unmap != nullptr; } + inline bool uvalue::less(const uvalue& other) const { + auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this); + auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other); + + if ( l_tag != r_tag ) { + return false; + } + + if ( l_tag == storage_e::nothing ) { + return false; + } + + if ( l_vtable != r_vtable || l_vtable->less == nullptr ) { + return false; + } + + return l_vtable->less(storage_, other.storage_); + } + + inline bool uvalue::has_less_op() const noexcept { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag == storage_e::nothing || vtable->less != nullptr; + } + + inline bool uvalue::equals(const uvalue& other) const { + auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this); + auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other); + + if ( l_tag != r_tag ) { + return false; + } + + if ( l_tag == storage_e::nothing ) { + return true; + } + + if ( l_vtable != r_vtable || l_vtable->equals == nullptr ) { + return false; + } + + return l_vtable->equals(storage_, other.storage_); + } + + inline bool uvalue::has_equals_op() const noexcept { + auto&& [tag, vtable] = vtable_t::unpack_vtag(*this); + return tag == storage_e::nothing || vtable->equals != nullptr; + } + template < typename T > bool uvalue::is() const noexcept { static_assert(std::is_same_v>); diff --git a/manuals/api/basics.md b/manuals/api/basics.md index f30fc42..84bd401 100644 --- a/manuals/api/basics.md +++ b/manuals/api/basics.md @@ -191,6 +191,12 @@ public: uvalue unmap() const; bool has_unmap_op() const noexcept; + bool less(const uvalue& other) const; + bool has_less_op() const noexcept; + + bool equals(const uvalue& other) const; + bool has_equals_op() const noexcept; + template < typename T > bool is() const noexcept;