mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 03:45:30 +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>()); };
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
class value final {
|
||||
public:
|
||||
value() = delete;
|
||||
|
||||
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||
value(value&& other);
|
||||
value(const value& other);
|
||||
|
||||
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||
value& operator=(value&& other);
|
||||
value& operator=(const value& other);
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<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() = default;
|
||||
|
||||
template < detail::decay_non_uvalue_kind T >
|
||||
explicit value(T&& val);
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<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 >
|
||||
template < detail::decay_non_uvalue_kind T >
|
||||
value& operator=(T&& val);
|
||||
|
||||
void swap(value& other) noexcept;
|
||||
|
||||
const any_type& get_type() const noexcept;
|
||||
[[nodiscard]] const any_type& get_type() const noexcept;
|
||||
|
||||
void* data() noexcept;
|
||||
const void* data() const noexcept;
|
||||
const void* cdata() const noexcept;
|
||||
[[nodiscard]] void* data() noexcept;
|
||||
[[nodiscard]] const void* data() const noexcept;
|
||||
[[nodiscard]] const void* cdata() const noexcept;
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<T> >
|
||||
Tp& cast() &;
|
||||
[[nodiscard]] Tp& cast() &;
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<T> >
|
||||
Tp&& cast() &&;
|
||||
[[nodiscard]] Tp&& cast() &&;
|
||||
|
||||
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> >
|
||||
const Tp&& cast() const &&;
|
||||
[[nodiscard]] const Tp&& cast() const &&;
|
||||
|
||||
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> >
|
||||
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);
|
||||
|
||||
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 std::istream& operator>>(std::istream& os, value& v);
|
||||
friend std::istream& operator>>(std::istream& is, value& v);
|
||||
friend std::ostream& operator<<(std::ostream& os, const value& v);
|
||||
private:
|
||||
struct traits;
|
||||
|
||||
@@ -9,50 +9,6 @@
|
||||
#include "../meta_base.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
|
||||
{
|
||||
struct value::traits final {
|
||||
@@ -87,23 +43,23 @@ namespace meta_hpp
|
||||
return v.try_cast<T>();
|
||||
},
|
||||
|
||||
.less = +[](const value& l, const value& r) -> bool {
|
||||
if constexpr ( detail::has_value_type_less_op<T>::value ) {
|
||||
.less = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
|
||||
if constexpr ( detail::has_less_op_kind<T> ) {
|
||||
return l.cast<T>() < r.cast<T>();
|
||||
} else {
|
||||
throw std::logic_error("value type doesn't have less operator");
|
||||
}
|
||||
},
|
||||
|
||||
.equals = +[](const value& l, const value& r) -> bool {
|
||||
if constexpr ( detail::has_value_type_equals_op<T>::value ) {
|
||||
.equals = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
|
||||
if constexpr ( detail::has_equals_op_kind<T> ) {
|
||||
return l.cast<T>() == r.cast<T>();
|
||||
} else {
|
||||
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> ) {
|
||||
dst.emplace<T>(std::move(src).cast<T>());
|
||||
} 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> ) {
|
||||
dst.emplace<T>(src.cast<T>());
|
||||
} else {
|
||||
@@ -119,16 +75,16 @@ namespace meta_hpp
|
||||
}
|
||||
},
|
||||
|
||||
.istream = +[](std::istream& os, value& v) -> std::istream& {
|
||||
if constexpr ( detail::has_value_type_istream_op<T>::value ) {
|
||||
return os >> v.cast<T>();
|
||||
.istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] value& v) -> std::istream& {
|
||||
if constexpr ( detail::has_istream_op_kind<T> ) {
|
||||
return is >> v.cast<T>();
|
||||
} else {
|
||||
throw std::logic_error("value type doesn't have istream operator");
|
||||
}
|
||||
},
|
||||
|
||||
.ostream = +[](std::ostream& os, const value& v) -> std::ostream& {
|
||||
if constexpr ( detail::has_value_type_ostream_op<T>::value ) {
|
||||
.ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const value& v) -> std::ostream& {
|
||||
if constexpr ( detail::has_ostream_op_kind<T> ) {
|
||||
return os << v.cast<T>();
|
||||
} else {
|
||||
throw std::logic_error("value type doesn't have ostream operator");
|
||||
@@ -141,16 +97,18 @@ namespace meta_hpp
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
inline value::value(value&& other) {
|
||||
traits_ = other.traits_;
|
||||
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||
inline value::value(value&& other)
|
||||
: traits_{other.traits_} {
|
||||
traits_->move_ctor(raw_, std::move(other));
|
||||
}
|
||||
|
||||
inline value::value(const value& other) {
|
||||
traits_ = other.traits_;
|
||||
inline value::value(const value& other)
|
||||
: traits_{other.traits_} {
|
||||
traits_->copy_ctor(raw_, other);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
|
||||
inline value& value::operator=(value&& other) {
|
||||
if ( this != &other ) {
|
||||
traits_ = other.traits_;
|
||||
@@ -167,21 +125,15 @@ namespace meta_hpp
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < typename T, typename Tp
|
||||
, 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> >
|
||||
template < detail::decay_non_uvalue_kind T >
|
||||
value::value(T&& val)
|
||||
: raw_{std::forward<T>(val)}
|
||||
, traits_{traits::get<Tp>()} {}
|
||||
, traits_{traits::get<std::decay_t<T>>()} {}
|
||||
|
||||
template < typename T, typename Tp
|
||||
, 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> >
|
||||
template < detail::decay_non_uvalue_kind T >
|
||||
value& value::operator=(T&& val) {
|
||||
raw_ = std::forward<T>(val);
|
||||
traits_ = resolve_type<Tp>();
|
||||
value temp{std::forward<T>(val)};
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -253,38 +205,42 @@ namespace meta_hpp
|
||||
namespace meta_hpp
|
||||
{
|
||||
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() < 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 >
|
||||
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 (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) {
|
||||
return (l.get_type() < r.get_type()) || (l.get_type() == r.get_type() && l.traits_->less(l, 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));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename T >
|
||||
bool operator==(const value& l, const T& r) {
|
||||
const any_type& r_type = resolve_type<T>();
|
||||
return l.get_type() == r_type && std::equal_to<>{}(l.cast<T>(), r);
|
||||
[[nodiscard]] bool operator==(const value& l, const T& r) {
|
||||
return l.get_type() == resolve_type<T>()
|
||||
&& std::equal_to<>{}(l.cast<T>(), r);
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool operator==(const T& l, const value& r) {
|
||||
const any_type& l_type = resolve_type<T>();
|
||||
return l_type == r.get_type() && std::equal_to<>{}(l, r.cast<T>());
|
||||
[[nodiscard]] bool operator==(const T& l, const value& r) {
|
||||
return resolve_type<T>() == r.get_type()
|
||||
&& std::equal_to<>{}(l, r.cast<T>());
|
||||
}
|
||||
|
||||
inline bool operator==(const value& l, const value& r) {
|
||||
return l.get_type() == r.get_type() && l.traits_->equals(l, r);
|
||||
[[nodiscard]] inline bool operator==(const value& l, const value& 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 {};
|
||||
|
||||
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 {};
|
||||
|
||||
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