mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-13 03:08:49 +07:00
new uvalue ops (less, equals)
This commit is contained in:
@@ -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>>);
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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()
|
||||
|
||||
124
headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp
Normal file
124
headers/meta.hpp/meta_detail/value_traits/equals_traits.hpp
Normal 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; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
124
headers/meta.hpp/meta_detail/value_traits/less_traits.hpp
Normal file
124
headers/meta.hpp/meta_detail/value_traits/less_traits.hpp
Normal 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; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>>);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user