little value fixes

This commit is contained in:
BlackMATov
2022-01-23 23:50:00 +07:00
parent d54194d52e
commit 6e127b41da
4 changed files with 111 additions and 96 deletions

View File

@@ -106,22 +106,20 @@ namespace meta_hpp
public: public:
value() = delete; value() = delete;
// NOLINTNEXTLINE(performance-noexcept-move-constructor) value(value&& other) noexcept = default;
value(value&& other); value(const value& other) = default;
value(const value& other);
// NOLINTNEXTLINE(performance-noexcept-move-constructor) value& operator=(value&& other) noexcept;
value& operator=(value&& other);
value& operator=(const value& other); value& operator=(const value& other);
~value() = default; ~value() = default;
template < detail::decay_non_uvalue_kind T, typename Tp = std::decay_t<T> > template < detail::decay_non_uvalue_kind T >
requires detail::stdex::copy_constructible<Tp> requires detail::stdex::copy_constructible<std::decay_t<T>>
explicit value(T&& val); explicit value(T&& val);
template < detail::decay_non_uvalue_kind T, typename Tp = std::decay_t<T> > template < detail::decay_non_uvalue_kind T >
requires detail::stdex::copy_constructible<Tp> requires detail::stdex::copy_constructible<std::decay_t<T>>
value& operator=(T&& val); value& operator=(T&& val);
void swap(value& other) noexcept; void swap(value& other) noexcept;
@@ -135,23 +133,23 @@ namespace meta_hpp
[[nodiscard]] value operator*() const; [[nodiscard]] value operator*() const;
[[nodiscard]] value operator[](std::size_t index) const; [[nodiscard]] value operator[](std::size_t index) const;
template < typename T, typename Tp = std::decay_t<T> > template < typename T >
[[nodiscard]] Tp& cast() &; [[nodiscard]] std::decay_t<T>& cast() &;
template < typename T, typename Tp = std::decay_t<T> > template < typename T >
[[nodiscard]] Tp&& cast() &&; [[nodiscard]] std::decay_t<T>&& cast() &&;
template < typename T, typename Tp = std::decay_t<T> > template < typename T >
[[nodiscard]] const Tp& cast() const &; [[nodiscard]] const std::decay_t<T>& cast() const &;
template < typename T, typename Tp = std::decay_t<T> > template < typename T >
[[nodiscard]] const Tp&& cast() const &&; [[nodiscard]] const std::decay_t<T>&& cast() const &&;
template < typename T, typename Tp = std::decay_t<T> > template < typename T >
[[nodiscard]] Tp* try_cast() noexcept; [[nodiscard]] std::decay_t<T>* try_cast() noexcept;
template < typename T, typename Tp = std::decay_t<T> > template < typename T >
[[nodiscard]] const Tp* try_cast() const noexcept; [[nodiscard]] const std::decay_t<T>* try_cast() const noexcept;
friend bool operator<(const value& l, const value& r); friend bool operator<(const value& l, const value& r);
friend bool operator==(const value& l, const value& r); friend bool operator==(const value& l, const value& r);

View File

@@ -30,9 +30,6 @@ namespace meta_hpp
bool (*const less)(const value&, const value&); bool (*const less)(const value&, const value&);
bool (*const equals)(const value&, const value&); bool (*const equals)(const value&, const value&);
void (*const move_ctor)(std::any&, value&&);
void (*const copy_ctor)(std::any&, const value&);
std::istream& (*const istream)(std::istream&, value&); std::istream& (*const istream)(std::istream&, value&);
std::ostream& (*const ostream)(std::ostream&, const value&); std::ostream& (*const ostream)(std::ostream&, const value&);
@@ -87,22 +84,6 @@ namespace meta_hpp
} }
}, },
.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 {
throw std::logic_error("value type is not move constructible");
}
},
.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 {
throw std::logic_error("value type is not copy constructible");
}
},
.istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] value& v) -> std::istream& { .istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] value& v) -> std::istream& {
if constexpr ( detail::has_value_istream_traits<T> ) { if constexpr ( detail::has_value_istream_traits<T> ) {
return detail::value_istream_traits<T>{}(is, v.cast<T>()); return detail::value_istream_traits<T>{}(is, v.cast<T>());
@@ -126,42 +107,30 @@ namespace meta_hpp
namespace meta_hpp namespace meta_hpp
{ {
// NOLINTNEXTLINE(performance-noexcept-move-constructor) inline value& value::operator=(value&& other) noexcept {
inline value::value(value&& other)
: traits_{other.traits_} {
traits_->move_ctor(raw_, std::move(other));
}
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 ) { if ( this != &other ) {
traits_ = other.traits_; value temp{std::move(other)};
traits_->move_ctor(raw_, std::move(other)); swap(temp);
} }
return *this; return *this;
} }
inline value& value::operator=(const value& other) { inline value& value::operator=(const value& other) {
if ( this != &other ) { if ( this != &other ) {
traits_ = other.traits_; value temp{other};
traits_->copy_ctor(raw_, other); swap(temp);
} }
return *this; return *this;
} }
template < detail::decay_non_uvalue_kind T, typename Tp > template < detail::decay_non_uvalue_kind T >
requires detail::stdex::copy_constructible<Tp> requires detail::stdex::copy_constructible<std::decay_t<T>>
value::value(T&& val) value::value(T&& val)
: raw_{std::forward<T>(val)} : raw_{std::forward<T>(val)}
, traits_{traits::get<std::decay_t<T>>()} {} , traits_{traits::get<std::decay_t<T>>()} {}
template < detail::decay_non_uvalue_kind T, typename Tp > template < detail::decay_non_uvalue_kind T >
requires detail::stdex::copy_constructible<Tp> requires detail::stdex::copy_constructible<std::decay_t<T>>
value& value::operator=(T&& val) { value& value::operator=(T&& val) {
value temp{std::forward<T>(val)}; value temp{std::forward<T>(val)};
swap(temp); swap(temp);
@@ -198,45 +167,39 @@ namespace meta_hpp
return traits_->index(*this, index); return traits_->index(*this, index);
} }
template < typename T, typename Tp > template < typename T >
Tp& value::cast() & { std::decay_t<T>& value::cast() & {
if ( get_type() != resolve_type<Tp>() ) { using Tp = std::decay_t<T>;
throw std::logic_error("bad value cast");
}
return std::any_cast<Tp&>(raw_); return std::any_cast<Tp&>(raw_);
} }
template < typename T, typename Tp > template < typename T >
Tp&& value::cast() && { std::decay_t<T>&& value::cast() && {
if ( get_type() != resolve_type<Tp>() ) { using Tp = std::decay_t<T>;
throw std::logic_error("bad value cast");
}
return std::move(std::any_cast<Tp&>(raw_)); return std::move(std::any_cast<Tp&>(raw_));
} }
template < typename T, typename Tp > template < typename T >
const Tp& value::cast() const & { const std::decay_t<T>& value::cast() const & {
if ( get_type() != resolve_type<Tp>() ) { using Tp = std::decay_t<T>;
throw std::logic_error("bad value cast");
}
return std::any_cast<const Tp&>(raw_); return std::any_cast<const Tp&>(raw_);
} }
template < typename T, typename Tp > template < typename T >
const Tp&& value::cast() const && { const std::decay_t<T>&& value::cast() const && {
if ( get_type() != resolve_type<Tp>() ) { using Tp = std::decay_t<T>;
throw std::logic_error("bad value cast");
}
return std::move(std::any_cast<const Tp&>(raw_)); return std::move(std::any_cast<const Tp&>(raw_));
} }
template < typename T, typename Tp > template < typename T >
Tp* value::try_cast() noexcept { std::decay_t<T>* value::try_cast() noexcept {
using Tp = std::decay_t<T>;
return std::any_cast<Tp>(&raw_); return std::any_cast<Tp>(&raw_);
} }
template < typename T, typename Tp > template < typename T >
const Tp* value::try_cast() const noexcept { const std::decay_t<T>* value::try_cast() const noexcept {
using Tp = std::decay_t<T>;
return std::any_cast<Tp>(&raw_); return std::any_cast<Tp>(&raw_);
} }
} }

View File

@@ -98,8 +98,8 @@ TEST_CASE("meta/meta_states/ctor") {
} }
CHECK(clazz<1>::ctor_counter == 1); CHECK(clazz<1>::ctor_counter == 1);
CHECK(clazz<1>::dtor_counter == 4); CHECK(clazz<1>::dtor_counter == 2);
CHECK(clazz<1>::move_ctor_counter == 3); CHECK(clazz<1>::move_ctor_counter == 1);
CHECK(clazz<1>::copy_ctor_counter == 0); CHECK(clazz<1>::copy_ctor_counter == 0);
} }

View File

@@ -43,6 +43,16 @@ namespace
static int copy_ctor_counter; static int copy_ctor_counter;
}; };
struct ivec3 {
int x{};
int y{};
int z{};
ivec3() = default;
explicit ivec3(int v): x{v}, y{v}, z{v} {}
ivec3(int x, int y, int z): x{x}, y{y}, z{z} {}
};
int ivec2::move_ctor_counter{0}; int ivec2::move_ctor_counter{0};
int ivec2::copy_ctor_counter{0}; int ivec2::copy_ctor_counter{0};
@@ -72,6 +82,20 @@ TEST_CASE("meta/meta_utilities/value/ivec2") {
.member_("y", &ivec2::y); .member_("y", &ivec2::y);
} }
TEST_CASE("meta/meta_utilities/value/ivec3") {
namespace meta = meta_hpp;
meta::class_<ivec3>()
.ctor_<>()
.ctor_<int>()
.ctor_<int, int, int>()
.ctor_<ivec3&&>()
.ctor_<const ivec3&>()
.member_("x", &ivec3::x)
.member_("y", &ivec3::y)
.member_("z", &ivec3::z);
}
TEST_CASE("meta/meta_utilities/value") { TEST_CASE("meta/meta_utilities/value") {
namespace meta = meta_hpp; namespace meta = meta_hpp;
using namespace std::string_literals; using namespace std::string_literals;
@@ -123,9 +147,18 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr);
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr);
} }
SUBCASE("const ivec2&") { SUBCASE("const ivec2&") {
@@ -148,9 +181,18 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr);
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr);
} }
SUBCASE("ivec2&&") { SUBCASE("ivec2&&") {
@@ -167,9 +209,18 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr);
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr);
} }
SUBCASE("const ivec2&&") { SUBCASE("const ivec2&&") {
@@ -186,9 +237,18 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.cast<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(*val.try_cast<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr);
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr);
} }
SUBCASE("value(value&&)") { SUBCASE("value(value&&)") {
@@ -201,9 +261,6 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val_dst == ivec2{1,2}); CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 2); CHECK(ivec2::move_ctor_counter == 2);
CHECK(ivec2::copy_ctor_counter == 0); CHECK(ivec2::copy_ctor_counter == 0);
CHECK(val_src == ivec2{0,0});
CHECK(val_src.data() != val_dst.data());
} }
SUBCASE("value(const meta::value&)") { SUBCASE("value(const meta::value&)") {
@@ -246,11 +303,8 @@ TEST_CASE("meta/meta_utilities/value") {
val_dst = std::move(val_src2); val_dst = std::move(val_src2);
CHECK(val_dst == ivec2{1,2}); CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 2); CHECK(ivec2::move_ctor_counter == 4);
CHECK(ivec2::copy_ctor_counter == 0); CHECK(ivec2::copy_ctor_counter == 0);
CHECK(val_src2 == ivec2{0,0});
CHECK(val_src2.data() != val_dst.data());
} }
SUBCASE("value& operator=(const meta::value&)") { SUBCASE("value& operator=(const meta::value&)") {
@@ -268,7 +322,7 @@ TEST_CASE("meta/meta_utilities/value") {
val_dst = val_src2; val_dst = val_src2;
CHECK(val_dst == ivec2{1,2}); CHECK(val_dst == ivec2{1,2});
CHECK(ivec2::move_ctor_counter == 1); CHECK(ivec2::move_ctor_counter == 3);
CHECK(ivec2::copy_ctor_counter == 1); CHECK(ivec2::copy_ctor_counter == 1);
CHECK(val_src2 == ivec2{1,2}); CHECK(val_src2 == ivec2{1,2});
@@ -284,7 +338,7 @@ TEST_CASE("meta/meta_utilities/value") {
val1.swap(val2); val1.swap(val2);
CHECK(val1 == ivec2{1,2}); CHECK(val1 == ivec2{1,2});
CHECK(val2 == "world"s); CHECK(val2 == "world"s);
CHECK((ivec2::move_ctor_counter == 2 || ivec2::move_ctor_counter == 3)); CHECK(ivec2::move_ctor_counter == 3);
CHECK(ivec2::copy_ctor_counter == 0); CHECK(ivec2::copy_ctor_counter == 0);
swap(val1, val2); swap(val1, val2);