mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 03:45:30 +07:00
add traits to value
This commit is contained in:
@@ -8,6 +8,34 @@
|
|||||||
|
|
||||||
#include "meta_fwd.hpp"
|
#include "meta_fwd.hpp"
|
||||||
|
|
||||||
|
namespace meta_hpp
|
||||||
|
{
|
||||||
|
class value;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::value_detail
|
||||||
|
{
|
||||||
|
struct traits {
|
||||||
|
bool(*equal)(const value&, const value&){};
|
||||||
|
bool(*not_equal)(const value&, const value&){};
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool value_equal(const value& l, const value& r);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool value_not_equal(const value& l, const value& r);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const traits* get_traits() noexcept {
|
||||||
|
static traits traits{
|
||||||
|
&value_equal<T>,
|
||||||
|
&value_not_equal<T>,
|
||||||
|
};
|
||||||
|
return &traits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
class value {
|
class value {
|
||||||
@@ -25,7 +53,8 @@ namespace meta_hpp
|
|||||||
, typename = std::enable_if_t<!std::is_same_v<U, value>> >
|
, typename = std::enable_if_t<!std::is_same_v<U, value>> >
|
||||||
value(T&& val)
|
value(T&& val)
|
||||||
: raw_{std::forward<T>(val)}
|
: raw_{std::forward<T>(val)}
|
||||||
, fid_{get_type_family_id<U>()} {}
|
, fid_{get_type_family_id<U>()}
|
||||||
|
, traits_{value_detail::get_traits<U>()} {}
|
||||||
|
|
||||||
template < typename T
|
template < typename T
|
||||||
, typename U = std::decay_t<T>
|
, typename U = std::decay_t<T>
|
||||||
@@ -38,12 +67,14 @@ namespace meta_hpp
|
|||||||
template < typename T, typename... Args >
|
template < typename T, typename... Args >
|
||||||
explicit value(std::in_place_type_t<T>, Args&&... args)
|
explicit value(std::in_place_type_t<T>, Args&&... args)
|
||||||
: raw_{std::in_place_type<T>, std::forward<Args>(args)...}
|
: raw_{std::in_place_type<T>, std::forward<Args>(args)...}
|
||||||
, fid_{get_type_family_id<T>()} {}
|
, fid_{get_type_family_id<T>()}
|
||||||
|
, traits_{value_detail::get_traits<T>()} {}
|
||||||
|
|
||||||
template < typename T, typename U, typename... Args >
|
template < typename T, typename U, typename... Args >
|
||||||
explicit value(std::in_place_type_t<T>, std::initializer_list<U> ilist, Args&&... args)
|
explicit value(std::in_place_type_t<T>, std::initializer_list<U> ilist, Args&&... args)
|
||||||
: raw_{std::in_place_type<T>, ilist, std::forward<Args>(args)...}
|
: raw_{std::in_place_type<T>, ilist, std::forward<Args>(args)...}
|
||||||
, fid_{get_type_family_id<T>()} {}
|
, fid_{get_type_family_id<T>()}
|
||||||
|
, traits_{value_detail::get_traits<T>()} {}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
T cast() && {
|
T cast() && {
|
||||||
@@ -80,6 +111,51 @@ namespace meta_hpp
|
|||||||
using std::swap;
|
using std::swap;
|
||||||
swap(raw_, other.raw_);
|
swap(raw_, other.raw_);
|
||||||
swap(fid_, other.fid_);
|
swap(fid_, other.fid_);
|
||||||
|
swap(traits_, other.traits_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T
|
||||||
|
, typename U = std::decay_t<T>
|
||||||
|
, typename = std::enable_if_t<!std::is_same_v<U, value>>
|
||||||
|
, typename = std::enable_if_t<std::is_invocable_v<std::equal_to<>, U, U>> >
|
||||||
|
friend bool operator==(const value& l, T&& r) {
|
||||||
|
return l.fid() == get_type_family_id<U>()
|
||||||
|
&& std::equal_to<>{}(*l.try_cast<U>(), std::forward<T>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T
|
||||||
|
, typename U = std::decay_t<T>
|
||||||
|
, typename = std::enable_if_t<!std::is_same_v<U, value>>
|
||||||
|
, typename = std::enable_if_t<std::is_invocable_v<std::equal_to<>, U, U>> >
|
||||||
|
friend bool operator==(T&& l, const value& r) {
|
||||||
|
return get_type_family_id<U>() == r.fid()
|
||||||
|
&& std::equal_to<>{}(std::forward<T>(l), *r.try_cast<U>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T
|
||||||
|
, typename U = std::decay_t<T>
|
||||||
|
, typename = std::enable_if_t<!std::is_same_v<U, value>>
|
||||||
|
, typename = std::enable_if_t<std::is_invocable_v<std::equal_to<>, U, U>> >
|
||||||
|
friend bool operator!=(const value& l, T&& r) {
|
||||||
|
return l.fid() != get_type_family_id<U>()
|
||||||
|
|| std::not_equal_to<>{}(*l.try_cast<U>(), std::forward<T>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T
|
||||||
|
, typename U = std::decay_t<T>
|
||||||
|
, typename = std::enable_if_t<!std::is_same_v<U, value>>
|
||||||
|
, typename = std::enable_if_t<std::is_invocable_v<std::equal_to<>, U, U>> >
|
||||||
|
friend bool operator!=(T&& l, const value& r) {
|
||||||
|
return get_type_family_id<U>() != r.fid()
|
||||||
|
|| std::not_equal_to<>{}(std::forward<T>(l), *r.try_cast<U>());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const value& l, const value& r) {
|
||||||
|
return l.traits_->equal(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const value& l, const value& r) {
|
||||||
|
return l.traits_->not_equal(l, r);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
bool to_bool() const { return cast<bool>(); }
|
bool to_bool() const { return cast<bool>(); }
|
||||||
@@ -105,9 +181,37 @@ namespace meta_hpp
|
|||||||
private:
|
private:
|
||||||
std::any raw_;
|
std::any raw_;
|
||||||
family_id fid_;
|
family_id fid_;
|
||||||
|
const value_detail::traits* traits_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void swap(value& l, value& r) noexcept {
|
inline void swap(value& l, value& r) noexcept {
|
||||||
l.swap(r);
|
l.swap(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::value_detail
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
bool value_equal(const value& l, const value& r) {
|
||||||
|
if ( l.fid() != r.fid() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if constexpr ( std::is_invocable_v<std::equal_to<>, T, T> ) {
|
||||||
|
return std::equal_to<>{}(*l.try_cast<T>(), *(r.try_cast<T>()));
|
||||||
|
} else {
|
||||||
|
return std::addressof(l) == std::addressof(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
bool value_not_equal(const value& l, const value& r) {
|
||||||
|
if ( l.fid() != r.fid() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if constexpr ( std::is_invocable_v<std::not_equal_to<>, T, T> ) {
|
||||||
|
return std::not_equal_to<>{}(*l.try_cast<T>(), *(r.try_cast<T>()));
|
||||||
|
} else {
|
||||||
|
return std::addressof(l) != std::addressof(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace
|
|||||||
{
|
{
|
||||||
class clazz {};
|
class clazz {};
|
||||||
class clazz2 {};
|
class clazz2 {};
|
||||||
|
|
||||||
|
void func() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("meta/value") {
|
TEST_CASE("meta/value") {
|
||||||
@@ -61,6 +63,110 @@ TEST_CASE("meta/value/fid") {
|
|||||||
CHECK(meta::value{std::in_place_type<std::vector<int>>, {1,2,3,4}}.fid() == meta::get_type_family_id<std::vector<int>>());
|
CHECK(meta::value{std::in_place_type<std::vector<int>>, {1,2,3,4}}.fid() == meta::get_type_family_id<std::vector<int>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("meta/value/equal") {
|
||||||
|
namespace meta = meta_hpp;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
{
|
||||||
|
CHECK(meta::value{1} == 1);
|
||||||
|
CHECK(meta::value{1} != 0);
|
||||||
|
CHECK(meta::value{1} != "hello"s);
|
||||||
|
|
||||||
|
CHECK_FALSE(meta::value{1} != 1);
|
||||||
|
CHECK_FALSE(meta::value{1} == 0);
|
||||||
|
CHECK_FALSE(meta::value{1} == "hello"s);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
CHECK(1 == meta::value{1});
|
||||||
|
CHECK(0 != meta::value{1});
|
||||||
|
CHECK("hello"s != meta::value{1});
|
||||||
|
|
||||||
|
CHECK_FALSE(1 != meta::value{1});
|
||||||
|
CHECK_FALSE(0 == meta::value{1});
|
||||||
|
CHECK_FALSE("hello"s == meta::value{1});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
CHECK(meta::value{1} == i);
|
||||||
|
CHECK(meta::value{1} == std::as_const(i));
|
||||||
|
CHECK_FALSE(meta::value{1} != i);
|
||||||
|
CHECK_FALSE(meta::value{1} != std::as_const(i));
|
||||||
|
|
||||||
|
CHECK(i == meta::value{1});
|
||||||
|
CHECK(std::as_const(i) == meta::value{1});
|
||||||
|
CHECK_FALSE(i != meta::value{1});
|
||||||
|
CHECK_FALSE(std::as_const(i) != meta::value{1});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
CHECK(meta::value{1} == meta::value{1});
|
||||||
|
CHECK(meta::value{1} != meta::value{0});
|
||||||
|
CHECK(meta::value{1} != meta::value{"hello"s});
|
||||||
|
CHECK_FALSE(meta::value{1} != meta::value{1});
|
||||||
|
CHECK_FALSE(meta::value{1} == meta::value{0});
|
||||||
|
CHECK_FALSE(meta::value{1} == meta::value{"hello"s});
|
||||||
|
|
||||||
|
CHECK(meta::value{1} == meta::value{1});
|
||||||
|
CHECK(meta::value{0} != meta::value{1});
|
||||||
|
CHECK(meta::value{"hello"s} != meta::value{1});
|
||||||
|
CHECK_FALSE(meta::value{1} != meta::value{1});
|
||||||
|
CHECK_FALSE(meta::value{0} == meta::value{1});
|
||||||
|
CHECK_FALSE(meta::value{"hello"s} == meta::value{1});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
CHECK(meta::value{std::in_place_type<int>, 1} == meta::value{1});
|
||||||
|
CHECK(meta::value{1} == meta::value{std::in_place_type<int>, 1});
|
||||||
|
|
||||||
|
using vi = std::vector<int>;
|
||||||
|
CHECK(meta::value{std::in_place_type<vi>, {1,2,3}} == meta::value{vi{1,2,3}});
|
||||||
|
CHECK(meta::value{vi{1,2,3}} == meta::value{std::in_place_type<vi>, {1,2,3}});
|
||||||
|
CHECK_FALSE(meta::value{std::in_place_type<vi>, {1,2,3}} == meta::value{vi{1,2,4}});
|
||||||
|
CHECK_FALSE(meta::value{vi{1,2,4}} == meta::value{std::in_place_type<vi>, {1,2,3}});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
meta::value v1{&func};
|
||||||
|
meta::value v2{&func};
|
||||||
|
|
||||||
|
CHECK(v1 == v1);
|
||||||
|
CHECK_FALSE(v1 != v1);
|
||||||
|
|
||||||
|
CHECK(v1 == v2);
|
||||||
|
CHECK_FALSE(v1 != v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
meta::value v1{clazz{}};
|
||||||
|
meta::value v2{clazz{}};
|
||||||
|
|
||||||
|
CHECK(v1 == v1);
|
||||||
|
CHECK_FALSE(v1 != v1);
|
||||||
|
|
||||||
|
CHECK(v1 != v2);
|
||||||
|
CHECK_FALSE(v1 == v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const int rv = 1;
|
||||||
|
|
||||||
|
meta::value v1{&rv};
|
||||||
|
meta::value v2{&rv};
|
||||||
|
|
||||||
|
CHECK(v1 == v1);
|
||||||
|
CHECK_FALSE(v1 != v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
meta::value v1{"hello"s};
|
||||||
|
meta::value{1}.swap(v1);
|
||||||
|
CHECK(v1 == meta::value{1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("meta/value/swap") {
|
TEST_CASE("meta/value/swap") {
|
||||||
namespace meta = meta_hpp;
|
namespace meta = meta_hpp;
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|||||||
Reference in New Issue
Block a user