mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-16 14:09:02 +07:00
cleanup value class
This commit is contained in:
@@ -31,69 +31,128 @@ namespace meta_hpp::detail
|
|||||||
requires { static_cast<To>(std::declval<From>()); };
|
requires { static_cast<To>(std::declval<From>()); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::detail
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
concept value_kind =
|
||||||
|
std::same_as<T, value>;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept decay_value_kind =
|
||||||
|
value_kind<std::decay_t<T>>;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept uvalue_kind =
|
||||||
|
std::same_as<T, arg> ||
|
||||||
|
std::same_as<T, inst> ||
|
||||||
|
std::same_as<T, value>;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept decay_uvalue_kind =
|
||||||
|
uvalue_kind<std::decay_t<T>>;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept decay_non_uvalue_kind =
|
||||||
|
(!decay_uvalue_kind<T>);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept arg_lvalue_ref_kind =
|
||||||
|
(std::is_lvalue_reference_v<T>);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept arg_rvalue_ref_kind =
|
||||||
|
(!std::is_reference_v<T>) ||
|
||||||
|
(std::is_rvalue_reference_v<T>);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept inst_class_ref_kind =
|
||||||
|
(std::is_class_v<T>) ||
|
||||||
|
(std::is_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept inst_class_lvalue_ref_kind =
|
||||||
|
(std::is_lvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept inst_class_rvalue_ref_kind =
|
||||||
|
(std::is_class_v<T>) ||
|
||||||
|
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::detail
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
concept has_less_op_kind = requires(const T& v) {
|
||||||
|
{ v < v } -> convertible_to<bool>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept has_equals_op_kind = requires(const T& v) {
|
||||||
|
{ v == v } -> convertible_to<bool>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept has_istream_op_kind = requires(std::istream& is, T& v) {
|
||||||
|
{ is >> v } -> convertible_to<std::istream&>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept has_ostream_op_kind = requires(std::ostream& os, const T& v) {
|
||||||
|
{ os << v } -> convertible_to<std::ostream&>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
class value final {
|
class value final {
|
||||||
public:
|
public:
|
||||||
value() = delete;
|
value() = delete;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||||
value(value&& other);
|
value(value&& other);
|
||||||
value(const value& other);
|
value(const value& other);
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||||
value& operator=(value&& other);
|
value& operator=(value&& other);
|
||||||
value& operator=(const value& other);
|
value& operator=(const value& other);
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T>
|
~value() = default;
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int> = 0
|
template < detail::decay_non_uvalue_kind T >
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> = 0 >
|
|
||||||
explicit value(T&& val);
|
explicit value(T&& val);
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T>
|
template < detail::decay_non_uvalue_kind T >
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int> = 0
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int> = 0
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> = 0 >
|
|
||||||
value& operator=(T&& val);
|
value& operator=(T&& val);
|
||||||
|
|
||||||
void swap(value& other) noexcept;
|
void swap(value& other) noexcept;
|
||||||
|
|
||||||
const any_type& get_type() const noexcept;
|
[[nodiscard]] const any_type& get_type() const noexcept;
|
||||||
|
|
||||||
void* data() noexcept;
|
[[nodiscard]] void* data() noexcept;
|
||||||
const void* data() const noexcept;
|
[[nodiscard]] const void* data() const noexcept;
|
||||||
const void* cdata() const noexcept;
|
[[nodiscard]] const void* cdata() const noexcept;
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T> >
|
template < typename T, typename Tp = std::decay_t<T> >
|
||||||
Tp& cast() &;
|
[[nodiscard]] Tp& cast() &;
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T> >
|
template < typename T, typename Tp = std::decay_t<T> >
|
||||||
Tp&& cast() &&;
|
[[nodiscard]] Tp&& cast() &&;
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T> >
|
template < typename T, typename Tp = std::decay_t<T> >
|
||||||
const Tp& cast() const &;
|
[[nodiscard]] const Tp& cast() const &;
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T> >
|
template < typename T, typename Tp = std::decay_t<T> >
|
||||||
const Tp&& cast() const &&;
|
[[nodiscard]] const Tp&& cast() const &&;
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T> >
|
template < typename T, typename Tp = std::decay_t<T> >
|
||||||
Tp* try_cast() noexcept;
|
[[nodiscard]] Tp* try_cast() noexcept;
|
||||||
|
|
||||||
template < typename T, typename Tp = std::decay_t<T> >
|
template < typename T, typename Tp = std::decay_t<T> >
|
||||||
const Tp* try_cast() const noexcept;
|
[[nodiscard]] const Tp* try_cast() const noexcept;
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
friend bool operator<(const value& l, const T& r);
|
|
||||||
template < typename T >
|
|
||||||
friend bool operator<(const T& l, const value& r);
|
|
||||||
friend bool operator<(const value& l, const value& r);
|
friend bool operator<(const value& l, const value& r);
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
friend bool operator==(const value& l, const T& r);
|
|
||||||
template < typename T >
|
|
||||||
friend bool operator==(const T& l, const value& r);
|
|
||||||
friend bool operator==(const value& l, const value& r);
|
friend bool operator==(const value& l, const value& r);
|
||||||
|
friend std::istream& operator>>(std::istream& is, value& v);
|
||||||
friend std::istream& operator>>(std::istream& os, value& v);
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const value& v);
|
friend std::ostream& operator<<(std::ostream& os, const value& v);
|
||||||
private:
|
private:
|
||||||
struct traits;
|
struct traits;
|
||||||
|
|||||||
@@ -9,50 +9,6 @@
|
|||||||
#include "../meta_base.hpp"
|
#include "../meta_base.hpp"
|
||||||
#include "../meta_utilities.hpp"
|
#include "../meta_utilities.hpp"
|
||||||
|
|
||||||
namespace meta_hpp::detail
|
|
||||||
{
|
|
||||||
template < typename T, typename = void >
|
|
||||||
struct has_value_type_less_op : std::false_type {};
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
struct has_value_type_less_op<T, std::void_t<decltype(
|
|
||||||
std::declval<const T&>() < std::declval<const T&>()
|
|
||||||
)>> : std::true_type {};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace meta_hpp::detail
|
|
||||||
{
|
|
||||||
template < typename T, typename = void >
|
|
||||||
struct has_value_type_equals_op : std::false_type {};
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
struct has_value_type_equals_op<T, std::void_t<decltype(
|
|
||||||
std::declval<const T&>() == std::declval<const T&>()
|
|
||||||
)>> : std::true_type {};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace meta_hpp::detail
|
|
||||||
{
|
|
||||||
template < typename T, typename = void >
|
|
||||||
struct has_value_type_istream_op : std::false_type {};
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
struct has_value_type_istream_op<T, std::void_t<decltype(
|
|
||||||
std::declval<std::istream&>() >> std::declval<T&>()
|
|
||||||
)>> : std::true_type {};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace meta_hpp::detail
|
|
||||||
{
|
|
||||||
template < typename T, typename = void >
|
|
||||||
struct has_value_type_ostream_op : std::false_type {};
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
struct has_value_type_ostream_op<T, std::void_t<decltype(
|
|
||||||
std::declval<std::ostream&>() << std::declval<const T&>()
|
|
||||||
)>> : std::true_type {};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
struct value::traits final {
|
struct value::traits final {
|
||||||
@@ -87,23 +43,23 @@ namespace meta_hpp
|
|||||||
return v.try_cast<T>();
|
return v.try_cast<T>();
|
||||||
},
|
},
|
||||||
|
|
||||||
.less = +[](const value& l, const value& r) -> bool {
|
.less = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
|
||||||
if constexpr ( detail::has_value_type_less_op<T>::value ) {
|
if constexpr ( detail::has_less_op_kind<T> ) {
|
||||||
return l.cast<T>() < r.cast<T>();
|
return l.cast<T>() < r.cast<T>();
|
||||||
} else {
|
} else {
|
||||||
throw std::logic_error("value type doesn't have less operator");
|
throw std::logic_error("value type doesn't have less operator");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.equals = +[](const value& l, const value& r) -> bool {
|
.equals = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
|
||||||
if constexpr ( detail::has_value_type_equals_op<T>::value ) {
|
if constexpr ( detail::has_equals_op_kind<T> ) {
|
||||||
return l.cast<T>() == r.cast<T>();
|
return l.cast<T>() == r.cast<T>();
|
||||||
} else {
|
} else {
|
||||||
throw std::logic_error("value type doesn't have equality operator");
|
throw std::logic_error("value type doesn't have equality operator");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.move_ctor = +[](std::any& dst, value&& src) {
|
.move_ctor = +[]([[maybe_unused]] std::any& dst, [[maybe_unused]] value&& src) {
|
||||||
if constexpr ( std::is_move_constructible_v<T> ) {
|
if constexpr ( std::is_move_constructible_v<T> ) {
|
||||||
dst.emplace<T>(std::move(src).cast<T>());
|
dst.emplace<T>(std::move(src).cast<T>());
|
||||||
} else {
|
} else {
|
||||||
@@ -111,7 +67,7 @@ namespace meta_hpp
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.copy_ctor = +[](std::any& dst, const value& src) {
|
.copy_ctor = +[]([[maybe_unused]] std::any& dst, [[maybe_unused]] const value& src) {
|
||||||
if constexpr ( std::is_copy_constructible_v<T> ) {
|
if constexpr ( std::is_copy_constructible_v<T> ) {
|
||||||
dst.emplace<T>(src.cast<T>());
|
dst.emplace<T>(src.cast<T>());
|
||||||
} else {
|
} else {
|
||||||
@@ -119,16 +75,16 @@ namespace meta_hpp
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.istream = +[](std::istream& os, value& v) -> std::istream& {
|
.istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] value& v) -> std::istream& {
|
||||||
if constexpr ( detail::has_value_type_istream_op<T>::value ) {
|
if constexpr ( detail::has_istream_op_kind<T> ) {
|
||||||
return os >> v.cast<T>();
|
return is >> v.cast<T>();
|
||||||
} else {
|
} else {
|
||||||
throw std::logic_error("value type doesn't have istream operator");
|
throw std::logic_error("value type doesn't have istream operator");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.ostream = +[](std::ostream& os, const value& v) -> std::ostream& {
|
.ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const value& v) -> std::ostream& {
|
||||||
if constexpr ( detail::has_value_type_ostream_op<T>::value ) {
|
if constexpr ( detail::has_ostream_op_kind<T> ) {
|
||||||
return os << v.cast<T>();
|
return os << v.cast<T>();
|
||||||
} else {
|
} else {
|
||||||
throw std::logic_error("value type doesn't have ostream operator");
|
throw std::logic_error("value type doesn't have ostream operator");
|
||||||
@@ -141,16 +97,18 @@ namespace meta_hpp
|
|||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
inline value::value(value&& other) {
|
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||||
traits_ = other.traits_;
|
inline value::value(value&& other)
|
||||||
|
: traits_{other.traits_} {
|
||||||
traits_->move_ctor(raw_, std::move(other));
|
traits_->move_ctor(raw_, std::move(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline value::value(const value& other) {
|
inline value::value(const value& other)
|
||||||
traits_ = other.traits_;
|
: traits_{other.traits_} {
|
||||||
traits_->copy_ctor(raw_, other);
|
traits_->copy_ctor(raw_, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||||
inline value& value::operator=(value&& other) {
|
inline value& value::operator=(value&& other) {
|
||||||
if ( this != &other ) {
|
if ( this != &other ) {
|
||||||
traits_ = other.traits_;
|
traits_ = other.traits_;
|
||||||
@@ -167,21 +125,15 @@ namespace meta_hpp
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T, typename Tp
|
template < detail::decay_non_uvalue_kind T >
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int>
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int>
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> >
|
|
||||||
value::value(T&& val)
|
value::value(T&& val)
|
||||||
: raw_{std::forward<T>(val)}
|
: raw_{std::forward<T>(val)}
|
||||||
, traits_{traits::get<Tp>()} {}
|
, traits_{traits::get<std::decay_t<T>>()} {}
|
||||||
|
|
||||||
template < typename T, typename Tp
|
template < detail::decay_non_uvalue_kind T >
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, value>, int>
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::arg>, int>
|
|
||||||
, std::enable_if_t<!std::is_same_v<Tp, detail::inst>, int> >
|
|
||||||
value& value::operator=(T&& val) {
|
value& value::operator=(T&& val) {
|
||||||
raw_ = std::forward<T>(val);
|
value temp{std::forward<T>(val)};
|
||||||
traits_ = resolve_type<Tp>();
|
swap(temp);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,38 +205,42 @@ namespace meta_hpp
|
|||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
template < typename T >
|
template < typename T >
|
||||||
bool operator<(const value& l, const T& r) {
|
[[nodiscard]] bool operator<(const value& l, const T& r) {
|
||||||
const any_type& r_type = resolve_type<T>();
|
const any_type& r_type = resolve_type<T>();
|
||||||
return (l.get_type() < r_type) || (l.get_type() == r_type && std::less<>{}(l.cast<T>(), r));
|
return (l.get_type() < r_type)
|
||||||
|
|| (l.get_type() == r_type && std::less<>{}(l.cast<T>(), r));
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
bool operator<(const T& l, const value& r) {
|
[[nodiscard]] bool operator<(const T& l, const value& r) {
|
||||||
const any_type& l_type = resolve_type<T>();
|
const any_type& l_type = resolve_type<T>();
|
||||||
return (l_type < r.get_type()) || (l_type == r.get_type() && std::less<>{}(l, r.cast<T>()));
|
return (l_type < r.get_type())
|
||||||
|
|| (l_type == r.get_type() && std::less<>{}(l, r.cast<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator<(const value& l, const value& r) {
|
[[nodiscard]] inline bool operator<(const value& l, const value& r) {
|
||||||
return (l.get_type() < r.get_type()) || (l.get_type() == r.get_type() && l.traits_->less(l, r));
|
return (l.get_type() < r.get_type())
|
||||||
|
|| (l.get_type() == r.get_type() && l.traits_->less(l, r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
template < typename T >
|
template < typename T >
|
||||||
bool operator==(const value& l, const T& r) {
|
[[nodiscard]] bool operator==(const value& l, const T& r) {
|
||||||
const any_type& r_type = resolve_type<T>();
|
return l.get_type() == resolve_type<T>()
|
||||||
return l.get_type() == r_type && std::equal_to<>{}(l.cast<T>(), r);
|
&& std::equal_to<>{}(l.cast<T>(), r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
bool operator==(const T& l, const value& r) {
|
[[nodiscard]] bool operator==(const T& l, const value& r) {
|
||||||
const any_type& l_type = resolve_type<T>();
|
return resolve_type<T>() == r.get_type()
|
||||||
return l_type == r.get_type() && std::equal_to<>{}(l, r.cast<T>());
|
&& std::equal_to<>{}(l, r.cast<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const value& l, const value& r) {
|
[[nodiscard]] inline bool operator==(const value& l, const value& r) {
|
||||||
return l.get_type() == r.get_type() && l.traits_->equals(l, r);
|
return l.get_type() == r.get_type()
|
||||||
|
&& l.traits_->equals(l, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ TEST_CASE("meta/meta_utilities/value") {
|
|||||||
class empty_class2 {};
|
class empty_class2 {};
|
||||||
|
|
||||||
CHECK(operator<(meta::value{empty_class1{}}, meta::value{empty_class2{}}));
|
CHECK(operator<(meta::value{empty_class1{}}, meta::value{empty_class2{}}));
|
||||||
CHECK_THROWS(operator<(meta::value{empty_class1{}}, meta::value{empty_class1{}}));
|
CHECK_THROWS(std::ignore = operator<(meta::value{empty_class1{}}, meta::value{empty_class1{}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ TEST_CASE("meta/meta_utilities/value") {
|
|||||||
class empty_class2 {};
|
class empty_class2 {};
|
||||||
|
|
||||||
CHECK_FALSE(operator==(meta::value{empty_class1{}}, meta::value{empty_class2{}}));
|
CHECK_FALSE(operator==(meta::value{empty_class1{}}, meta::value{empty_class2{}}));
|
||||||
CHECK_THROWS(operator==(meta::value{empty_class1{}}, meta::value{empty_class1{}}));
|
CHECK_THROWS(std::ignore = operator==(meta::value{empty_class1{}}, meta::value{empty_class1{}}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user