new uvalue ops (less, equals)

This commit is contained in:
BlackMATov
2024-08-07 08:39:17 +07:00
parent 1390279b63
commit 1336ade8b3
8 changed files with 781 additions and 0 deletions

View File

@@ -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<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v == v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct equals_traits<T> {
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<T>
struct equals_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
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<T>
struct equals_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Traits >
requires has_equals_traits<T>
struct equals_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Allocator >
requires has_equals_traits<T>
struct equals_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
struct equals_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Deleter >
struct equals_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
requires has_equals_traits<T>
struct equals_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() == r.get();
}
};
template < typename... Ts >
requires(... && has_equals_traits<Ts>)
struct equals_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
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<T> { \
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<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v < v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct less_traits<T> {
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<T>
struct less_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
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<T>
struct less_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Traits >
requires has_less_traits<T>
struct less_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Allocator >
requires has_less_traits<T>
struct less_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
struct less_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Deleter >
struct less_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
requires has_less_traits<T>
struct less_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() < r.get();
}
};
template < typename... Ts >
requires(... && has_less_traits<Ts>)
struct less_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
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<T> { \
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<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::less_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(r));
};
} else {
return nullptr;
}
}()},
.equals{[]() {
if constexpr ( detail::has_equals_traits<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::equals_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(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<T, std::decay_t<T>>);

View File

@@ -615,6 +615,125 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK((*v).as<int>() == 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, 2>{ivec2{1,2},ivec2{3,4}}};
meta::uvalue v2{std::array<ivec2, 2>{ivec2{1,2},ivec2{3,4}}};
meta::uvalue v3{std::array<ivec2, 2>{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<ivec2>{{1,2},{3,4}}};
meta::uvalue v2{std::vector<ivec2>{{1,2},{3,4}}};
meta::uvalue v3{std::vector<ivec2>{{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<int, ivec2>{42, {1,2}}};
meta::uvalue v2{std::tuple<int, ivec2>{42, {1,2}}};
meta::uvalue v3{std::tuple<int, ivec2>{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") {

View File

@@ -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()

View File

@@ -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<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v == v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct equals_traits<T> {
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<T>
struct equals_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
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<T>
struct equals_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Traits >
requires has_equals_traits<T>
struct equals_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Allocator >
requires has_equals_traits<T>
struct equals_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
struct equals_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Deleter >
struct equals_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
requires has_equals_traits<T>
struct equals_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() == r.get();
}
};
template < typename... Ts >
requires(... && has_equals_traits<Ts>)
struct equals_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
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<T> { \
bool operator()(const T& l, const T& r) const { \
return l == r; \
} \
}; \
}

View File

@@ -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<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v < v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct less_traits<T> {
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<T>
struct less_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
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<T>
struct less_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Traits >
requires has_less_traits<T>
struct less_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Allocator >
requires has_less_traits<T>
struct less_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
struct less_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Deleter >
struct less_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
requires has_less_traits<T>
struct less_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() < r.get();
}
};
template < typename... Ts >
requires(... && has_less_traits<Ts>)
struct less_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
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<T> { \
bool operator()(const T& l, const T& r) const { \
return l < r; \
} \
}; \
}

View File

@@ -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;

View File

@@ -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<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::less_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(r));
};
} else {
return nullptr;
}
}()},
.equals{[]() {
if constexpr ( detail::has_equals_traits<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::equals_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(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<T, std::decay_t<T>>);

View File

@@ -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;