diff --git a/headers/meta.hpp/meta_utilities.hpp b/headers/meta.hpp/meta_utilities.hpp index e97eb99..5e9701c 100644 --- a/headers/meta.hpp/meta_utilities.hpp +++ b/headers/meta.hpp/meta_utilities.hpp @@ -106,22 +106,20 @@ namespace meta_hpp public: value() = delete; - // NOLINTNEXTLINE(performance-noexcept-move-constructor) - value(value&& other); - value(const value& other); + value(value&& other) noexcept = default; + value(const value& other) = default; - // NOLINTNEXTLINE(performance-noexcept-move-constructor) - value& operator=(value&& other); + value& operator=(value&& other) noexcept; value& operator=(const value& other); ~value() = default; - template < detail::decay_non_uvalue_kind T, typename Tp = std::decay_t > - requires detail::stdex::copy_constructible + template < detail::decay_non_uvalue_kind T > + requires detail::stdex::copy_constructible> explicit value(T&& val); - template < detail::decay_non_uvalue_kind T, typename Tp = std::decay_t > - requires detail::stdex::copy_constructible + template < detail::decay_non_uvalue_kind T > + requires detail::stdex::copy_constructible> value& operator=(T&& val); void swap(value& other) noexcept; @@ -135,23 +133,23 @@ namespace meta_hpp [[nodiscard]] value operator*() const; [[nodiscard]] value operator[](std::size_t index) const; - template < typename T, typename Tp = std::decay_t > - [[nodiscard]] Tp& cast() &; + template < typename T > + [[nodiscard]] std::decay_t& cast() &; - template < typename T, typename Tp = std::decay_t > - [[nodiscard]] Tp&& cast() &&; + template < typename T > + [[nodiscard]] std::decay_t&& cast() &&; - template < typename T, typename Tp = std::decay_t > - [[nodiscard]] const Tp& cast() const &; + template < typename T > + [[nodiscard]] const std::decay_t& cast() const &; - template < typename T, typename Tp = std::decay_t > - [[nodiscard]] const Tp&& cast() const &&; + template < typename T > + [[nodiscard]] const std::decay_t&& cast() const &&; - template < typename T, typename Tp = std::decay_t > - [[nodiscard]] Tp* try_cast() noexcept; + template < typename T > + [[nodiscard]] std::decay_t* try_cast() noexcept; - template < typename T, typename Tp = std::decay_t > - [[nodiscard]] const Tp* try_cast() const noexcept; + template < typename T > + [[nodiscard]] const std::decay_t* try_cast() const noexcept; friend bool operator<(const value& l, const value& r); friend bool operator==(const value& l, const value& r); diff --git a/headers/meta.hpp/meta_utilities/value.hpp b/headers/meta.hpp/meta_utilities/value.hpp index b9acae1..753ff6f 100644 --- a/headers/meta.hpp/meta_utilities/value.hpp +++ b/headers/meta.hpp/meta_utilities/value.hpp @@ -30,9 +30,6 @@ namespace meta_hpp bool (*const less)(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::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 ) { - dst.emplace(std::move(src).cast()); - } 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 ) { - dst.emplace(src.cast()); - } else { - throw std::logic_error("value type is not copy constructible"); - } - }, - .istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] value& v) -> std::istream& { if constexpr ( detail::has_value_istream_traits ) { return detail::value_istream_traits{}(is, v.cast()); @@ -126,42 +107,30 @@ namespace meta_hpp namespace meta_hpp { - // 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_} { - traits_->copy_ctor(raw_, other); - } - - // NOLINTNEXTLINE(performance-noexcept-move-constructor) - inline value& value::operator=(value&& other) { + inline value& value::operator=(value&& other) noexcept { if ( this != &other ) { - traits_ = other.traits_; - traits_->move_ctor(raw_, std::move(other)); + value temp{std::move(other)}; + swap(temp); } return *this; } inline value& value::operator=(const value& other) { if ( this != &other ) { - traits_ = other.traits_; - traits_->copy_ctor(raw_, other); + value temp{other}; + swap(temp); } return *this; } - template < detail::decay_non_uvalue_kind T, typename Tp > - requires detail::stdex::copy_constructible + template < detail::decay_non_uvalue_kind T > + requires detail::stdex::copy_constructible> value::value(T&& val) : raw_{std::forward(val)} , traits_{traits::get>()} {} - template < detail::decay_non_uvalue_kind T, typename Tp > - requires detail::stdex::copy_constructible + template < detail::decay_non_uvalue_kind T > + requires detail::stdex::copy_constructible> value& value::operator=(T&& val) { value temp{std::forward(val)}; swap(temp); @@ -198,45 +167,39 @@ namespace meta_hpp return traits_->index(*this, index); } - template < typename T, typename Tp > - Tp& value::cast() & { - if ( get_type() != resolve_type() ) { - throw std::logic_error("bad value cast"); - } + template < typename T > + std::decay_t& value::cast() & { + using Tp = std::decay_t; return std::any_cast(raw_); } - template < typename T, typename Tp > - Tp&& value::cast() && { - if ( get_type() != resolve_type() ) { - throw std::logic_error("bad value cast"); - } + template < typename T > + std::decay_t&& value::cast() && { + using Tp = std::decay_t; return std::move(std::any_cast(raw_)); } - template < typename T, typename Tp > - const Tp& value::cast() const & { - if ( get_type() != resolve_type() ) { - throw std::logic_error("bad value cast"); - } + template < typename T > + const std::decay_t& value::cast() const & { + using Tp = std::decay_t; return std::any_cast(raw_); } - template < typename T, typename Tp > - const Tp&& value::cast() const && { - if ( get_type() != resolve_type() ) { - throw std::logic_error("bad value cast"); - } + template < typename T > + const std::decay_t&& value::cast() const && { + using Tp = std::decay_t; return std::move(std::any_cast(raw_)); } - template < typename T, typename Tp > - Tp* value::try_cast() noexcept { + template < typename T > + std::decay_t* value::try_cast() noexcept { + using Tp = std::decay_t; return std::any_cast(&raw_); } - template < typename T, typename Tp > - const Tp* value::try_cast() const noexcept { + template < typename T > + const std::decay_t* value::try_cast() const noexcept { + using Tp = std::decay_t; return std::any_cast(&raw_); } } diff --git a/untests/meta_states/ctor_tests.cpp b/untests/meta_states/ctor_tests.cpp index 5b5b4f2..ac5f36c 100644 --- a/untests/meta_states/ctor_tests.cpp +++ b/untests/meta_states/ctor_tests.cpp @@ -98,8 +98,8 @@ TEST_CASE("meta/meta_states/ctor") { } CHECK(clazz<1>::ctor_counter == 1); - CHECK(clazz<1>::dtor_counter == 4); - CHECK(clazz<1>::move_ctor_counter == 3); + CHECK(clazz<1>::dtor_counter == 2); + CHECK(clazz<1>::move_ctor_counter == 1); CHECK(clazz<1>::copy_ctor_counter == 0); } diff --git a/untests/meta_utilities/value_tests.cpp b/untests/meta_utilities/value_tests.cpp index 6be5630..38b2e44 100644 --- a/untests/meta_utilities/value_tests.cpp +++ b/untests/meta_utilities/value_tests.cpp @@ -43,6 +43,16 @@ namespace 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::copy_ctor_counter{0}; @@ -72,6 +82,20 @@ TEST_CASE("meta/meta_utilities/value/ivec2") { .member_("y", &ivec2::y); } +TEST_CASE("meta/meta_utilities/value/ivec3") { + namespace meta = meta_hpp; + + meta::class_() + .ctor_<>() + .ctor_() + .ctor_() + .ctor_() + .ctor_() + .member_("x", &ivec3::x) + .member_("y", &ivec3::y) + .member_("z", &ivec3::z); +} + TEST_CASE("meta/meta_utilities/value") { namespace meta = meta_hpp; using namespace std::string_literals; @@ -123,9 +147,18 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val.cast() == ivec2{1,2}); CHECK(std::as_const(val).cast() == ivec2{1,2}); + CHECK(std::move(val).cast() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).cast() == ivec2{1,2}); + + CHECK_THROWS(std::ignore = val.cast()); + CHECK_THROWS(std::ignore = std::as_const(val).cast()); + CHECK_THROWS(std::ignore = std::move(val).cast()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast()); CHECK(*val.try_cast() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast() == ivec2{1,2}); + CHECK(val.try_cast() == nullptr); + CHECK(std::as_const(val).try_cast() == nullptr); } SUBCASE("const ivec2&") { @@ -148,9 +181,18 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val.cast() == ivec2{1,2}); CHECK(std::as_const(val).cast() == ivec2{1,2}); + CHECK(std::move(val).cast() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).cast() == ivec2{1,2}); + + CHECK_THROWS(std::ignore = val.cast()); + CHECK_THROWS(std::ignore = std::as_const(val).cast()); + CHECK_THROWS(std::ignore = std::move(val).cast()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast()); CHECK(*val.try_cast() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast() == ivec2{1,2}); + CHECK(val.try_cast() == nullptr); + CHECK(std::as_const(val).try_cast() == nullptr); } SUBCASE("ivec2&&") { @@ -167,9 +209,18 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val.cast() == ivec2{1,2}); CHECK(std::as_const(val).cast() == ivec2{1,2}); + CHECK(std::move(val).cast() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).cast() == ivec2{1,2}); + + CHECK_THROWS(std::ignore = val.cast()); + CHECK_THROWS(std::ignore = std::as_const(val).cast()); + CHECK_THROWS(std::ignore = std::move(val).cast()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast()); CHECK(*val.try_cast() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast() == ivec2{1,2}); + CHECK(val.try_cast() == nullptr); + CHECK(std::as_const(val).try_cast() == nullptr); } SUBCASE("const ivec2&&") { @@ -186,9 +237,18 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val.cast() == ivec2{1,2}); CHECK(std::as_const(val).cast() == ivec2{1,2}); + CHECK(std::move(val).cast() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).cast() == ivec2{1,2}); + + CHECK_THROWS(std::ignore = val.cast()); + CHECK_THROWS(std::ignore = std::as_const(val).cast()); + CHECK_THROWS(std::ignore = std::move(val).cast()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast()); CHECK(*val.try_cast() == ivec2{1,2}); CHECK(*std::as_const(val).try_cast() == ivec2{1,2}); + CHECK(val.try_cast() == nullptr); + CHECK(std::as_const(val).try_cast() == nullptr); } SUBCASE("value(value&&)") { @@ -201,9 +261,6 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val_dst == ivec2{1,2}); CHECK(ivec2::move_ctor_counter == 2); CHECK(ivec2::copy_ctor_counter == 0); - - CHECK(val_src == ivec2{0,0}); - CHECK(val_src.data() != val_dst.data()); } SUBCASE("value(const meta::value&)") { @@ -246,11 +303,8 @@ TEST_CASE("meta/meta_utilities/value") { val_dst = std::move(val_src2); 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(val_src2 == ivec2{0,0}); - CHECK(val_src2.data() != val_dst.data()); } SUBCASE("value& operator=(const meta::value&)") { @@ -268,7 +322,7 @@ TEST_CASE("meta/meta_utilities/value") { val_dst = val_src2; 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(val_src2 == ivec2{1,2}); @@ -284,7 +338,7 @@ TEST_CASE("meta/meta_utilities/value") { val1.swap(val2); CHECK(val1 == ivec2{1,2}); 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); swap(val1, val2);