diff --git a/headers/meta.hpp/meta_uvalue.hpp b/headers/meta.hpp/meta_uvalue.hpp index 8625231..e01ab62 100644 --- a/headers/meta.hpp/meta_uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue.hpp @@ -61,40 +61,15 @@ namespace meta_hpp [[nodiscard]] uvalue operator[](std::size_t index) const; template < typename T > - [[nodiscard]] T get_as() &; - template < typename T > - [[nodiscard]] T get_as() &&; - template < typename T > - [[nodiscard]] T get_as() const &; - template < typename T > - [[nodiscard]] T get_as() const &&; + [[nodiscard]] auto get_as() + -> std::conditional_t, T, T&>; template < typename T > - [[nodiscard]] T& get_as_ref() &; - template < typename T > - [[nodiscard]] T&& get_as_ref() &&; - template < typename T > - [[nodiscard]] const T& get_as_ref() const &; - template < typename T > - [[nodiscard]] const T&& get_as_ref() const &&; + [[nodiscard]] auto get_as() const + -> std::conditional_t, T, const T&>; template < typename T > - [[nodiscard]] bool can_get_as() &; - template < typename T > - [[nodiscard]] bool can_get_as() &&; - template < typename T > - [[nodiscard]] bool can_get_as() const &; - template < typename T > - [[nodiscard]] bool can_get_as() const &&; - - template < typename T > - [[nodiscard]] bool can_get_as_ref() &; - template < typename T > - [[nodiscard]] bool can_get_as_ref() &&; - template < typename T > - [[nodiscard]] bool can_get_as_ref() const &; - template < typename T > - [[nodiscard]] bool can_get_as_ref() const &&; + [[nodiscard]] bool can_get_as() const noexcept; friend bool operator<(const uvalue& l, const uvalue& r); friend bool operator==(const uvalue& l, const uvalue& r); @@ -116,18 +91,3 @@ namespace meta_hpp l.swap(r); } } - -namespace meta_hpp -{ - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as(V&& value) -> T; - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as_ref(V&& value) -> detail::add_cvref_t; - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as(V&& value) noexcept; - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as_ref(V&& value) noexcept; -} diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index 111f258..4fbce14 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -186,7 +186,7 @@ namespace meta_hpp .deref = +[]([[maybe_unused]] const uvalue& v) -> uvalue { if constexpr ( detail::has_deref_traits ) { - return detail::deref_traits{}(v.get_as_ref()); + return detail::deref_traits{}(v.get_as()); } else { detail::throw_exception_with("value type doesn't have value deref traits"); } @@ -194,7 +194,7 @@ namespace meta_hpp .index = +[]([[maybe_unused]] const uvalue& v, [[maybe_unused]] std::size_t i) -> uvalue { if constexpr ( detail::has_index_traits ) { - return detail::index_traits{}(v.get_as_ref(), i); + return detail::index_traits{}(v.get_as(), i); } else { detail::throw_exception_with("value type doesn't have value index traits"); } @@ -202,7 +202,7 @@ namespace meta_hpp .less = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { if constexpr ( detail::has_less_traits ) { - return detail::less_traits{}(l.get_as_ref(), r.get_as_ref()); + return detail::less_traits{}(l.get_as(), r.get_as()); } else { detail::throw_exception_with("value type doesn't have value less traits"); } @@ -210,23 +210,23 @@ namespace meta_hpp .equals = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { if constexpr ( detail::has_equals_traits ) { - return detail::equals_traits{}(l.get_as_ref(), r.get_as_ref()); + return detail::equals_traits{}(l.get_as(), r.get_as()); } else { detail::throw_exception_with("value type doesn't have value equals traits"); } }, .istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] uvalue& v) -> std::istream& { - if constexpr ( detail::has_istream_traits ) { - return detail::istream_traits{}(is, v.get_as_ref()); + if constexpr ( detail::has_istream_traits && !detail::pointer_kind ) { + return detail::istream_traits{}(is, v.get_as()); } else { detail::throw_exception_with("value type doesn't have value istream traits"); } }, .ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const uvalue& v) -> std::ostream& { - if constexpr ( detail::has_ostream_traits ) { - return detail::ostream_traits{}(os, v.get_as_ref()); + if constexpr ( detail::has_ostream_traits && !detail::pointer_kind ) { + return detail::ostream_traits{}(os, v.get_as()); } else { detail::throw_exception_with("value type doesn't have value ostream traits"); } @@ -327,106 +327,15 @@ namespace meta_hpp } template < typename T > - T uvalue::get_as() & { - return meta_hpp::get_as(*this); - } + auto uvalue::get_as() -> std::conditional_t, T, T&> { + static_assert(std::is_same_v>); - template < typename T > - T uvalue::get_as() && { - return meta_hpp::get_as(std::move(*this)); - } - - template < typename T > - T uvalue::get_as() const & { - return meta_hpp::get_as(*this); - } - - template < typename T > - T uvalue::get_as() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::get_as(std::move(*this)); - } - - template < typename T > - T& uvalue::get_as_ref() & { - return meta_hpp::get_as_ref(*this); - } - - template < typename T > - T&& uvalue::get_as_ref() && { - return meta_hpp::get_as_ref(std::move(*this)); - } - - template < typename T > - const T& uvalue::get_as_ref() const & { - return meta_hpp::get_as_ref(*this); - } - - template < typename T > - const T&& uvalue::get_as_ref() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::get_as_ref(std::move(*this)); - } - - // - - template < typename T > - bool uvalue::can_get_as() & { - return meta_hpp::can_get_as(*this); - } - - template < typename T > - bool uvalue::can_get_as() && { - return meta_hpp::can_get_as(std::move(*this)); - } - - template < typename T > - bool uvalue::can_get_as() const & { - return meta_hpp::can_get_as(*this); - } - - template < typename T > - bool uvalue::can_get_as() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::can_get_as(std::move(*this)); - } - - template < typename T > - bool uvalue::can_get_as_ref() & { - return meta_hpp::can_get_as_ref(*this); - } - - template < typename T > - bool uvalue::can_get_as_ref() && { - return meta_hpp::can_get_as_ref(std::move(*this)); - } - - template < typename T > - bool uvalue::can_get_as_ref() const & { - return meta_hpp::can_get_as_ref(*this); - } - - template < typename T > - bool uvalue::can_get_as_ref() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::can_get_as_ref(std::move(*this)); - } -} - -namespace meta_hpp -{ - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as(V&& value) -> T { - using Tp = std::decay_t; - static_assert(std::is_constructible_v>); - - const any_type& from_type = value.get_type(); - const any_type& to_type = resolve_type(); + const any_type& from_type = get_type(); + const any_type& to_type = resolve_type(); if ( from_type == to_type ) { - using to_ptr_t = detail::add_cv_t*; - auto to_ptr = static_cast(value.data()); - return static_cast(*to_ptr); + T* to_ptr = static_cast(data()); + return *to_ptr; } const auto is_a = [](const any_type& base, const any_type& derived){ @@ -438,12 +347,11 @@ namespace meta_hpp const class_type& to_class = to_type.as_class(); const class_type& from_class = from_type.as_class(); - using to_ptr_t = detail::add_cv_t*; - auto to_ptr = static_cast(detail::pointer_upcast(value.data(), from_class, to_class)); - return static_cast(*to_ptr); + T* to_ptr = static_cast(detail::pointer_upcast(data(), from_class, to_class)); + return *to_ptr; } - if constexpr ( std::is_pointer_v ) { + if constexpr ( detail::pointer_kind ) { if ( to_type.is_pointer() && from_type.is_nullptr() ) { return static_cast(nullptr); } @@ -459,11 +367,11 @@ namespace meta_hpp const any_type& from_data_type = from_type_ptr.get_data_type(); if ( to_type_ptr_readonly >= from_type_ptr_readonly ) { - using from_data_ptr_t = detail::add_cv_t*; - auto from_data_ptr = static_cast(value.data()); + void** from_data_ptr = static_cast(data()); if ( to_data_type.is_void() || to_data_type == from_data_type ) { - return static_cast(*from_data_ptr); + void* to_ptr = *from_data_ptr; + return static_cast(to_ptr); } if ( is_a(to_data_type, from_data_type) ) { @@ -480,19 +388,74 @@ namespace meta_hpp detail::throw_exception_with("bad value cast"); } - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as_ref(V&& value) -> detail::add_cvref_t { - static_assert(!std::is_reference_v); - return get_as>(std::forward(value)); + template < typename T > + auto uvalue::get_as() const -> std::conditional_t, T, const T&> { + static_assert(std::is_same_v>); + + const any_type& from_type = get_type(); + const any_type& to_type = resolve_type(); + + if ( from_type == to_type ) { + const T* to_ptr = static_cast(data()); + return *to_ptr; + } + + const auto is_a = [](const any_type& base, const any_type& derived){ + return (base == derived) + || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); + }; + + if ( is_a(to_type, from_type) ) { + const class_type& to_class = to_type.as_class(); + const class_type& from_class = from_type.as_class(); + + const T* to_ptr = static_cast(detail::pointer_upcast(data(), from_class, to_class)); + return *to_ptr; + } + + if constexpr ( detail::pointer_kind ) { + if ( to_type.is_pointer() && from_type.is_nullptr() ) { + return static_cast(nullptr); + } + + if ( to_type.is_pointer() && from_type.is_pointer() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const pointer_type& from_type_ptr = from_type.as_pointer(); + const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_ptr.get_data_type(); + + if ( to_type_ptr_readonly >= from_type_ptr_readonly ) { + void* const* from_data_ptr = static_cast(data()); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + void* to_ptr = *from_data_ptr; + return static_cast(to_ptr); + } + + if ( is_a(to_data_type, from_data_type) ) { + const class_type& to_data_class = to_data_type.as_class(); + const class_type& from_data_class = from_data_type.as_class(); + + void* to_ptr = detail::pointer_upcast(*from_data_ptr, from_data_class, to_data_class); + return static_cast(to_ptr); + } + } + } + } + + detail::throw_exception_with("bad value cast"); } - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as(V&& value) noexcept { - using Tp = std::decay_t; - static_assert(std::is_constructible_v>); + template < typename T > + bool uvalue::can_get_as() const noexcept { + static_assert(std::is_same_v>); - const any_type& from_type = value.get_type(); - const any_type& to_type = resolve_type(); + const any_type& from_type = get_type(); + const any_type& to_type = resolve_type(); if ( from_type == to_type ) { return true; @@ -507,7 +470,7 @@ namespace meta_hpp return true; } - if constexpr ( std::is_pointer_v ) { + if constexpr ( detail::pointer_kind ) { if ( to_type.is_pointer() && from_type.is_nullptr() ) { return true; } @@ -532,12 +495,6 @@ namespace meta_hpp return false; } - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as_ref(V&& value) noexcept { - static_assert(!std::is_reference_v); - return can_get_as>(std::forward(value)); - } } namespace meta_hpp @@ -551,7 +508,7 @@ namespace meta_hpp const any_type& l_type = l.get_type(); const any_type& r_type = resolve_type(); - return (l_type < r_type) || (l_type == r_type && l.get_as_ref() < r); + return (l_type < r_type) || (l_type == r_type && l.get_as() < r); } template < typename T > @@ -563,7 +520,7 @@ namespace meta_hpp const any_type& l_type = resolve_type(); const any_type& r_type = r.get_type(); - return (l_type < r_type) || (l_type == r_type && l < r.get_as_ref()); + return (l_type < r_type) || (l_type == r_type && l < r.get_as()); } [[nodiscard]] inline bool operator<(const uvalue& l, const uvalue& r) { @@ -593,7 +550,7 @@ namespace meta_hpp const any_type& l_type = l.get_type(); const any_type& r_type = resolve_type(); - return l_type == r_type && l.get_as_ref() == r; + return l_type == r_type && l.get_as() == r; } template < typename T > @@ -605,7 +562,7 @@ namespace meta_hpp const any_type& l_type = resolve_type(); const any_type& r_type = r.get_type(); - return l_type == r_type && l == r.get_as_ref(); + return l_type == r_type && l == r.get_as(); } [[nodiscard]] inline bool operator==(const uvalue& l, const uvalue& r) { diff --git a/manuals/meta_examples/uvalue_example.cpp b/manuals/meta_examples/uvalue_example.cpp new file mode 100644 index 0000000..def3347 --- /dev/null +++ b/manuals/meta_examples/uvalue_example.cpp @@ -0,0 +1,83 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2022, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "../meta_manuals.hpp" + +namespace +{ + class shape { + public: + shape() = default; + shape(const shape&) = default; + virtual ~shape() = default; + + virtual int get_area() const = 0; + }; + + class rectangle : public shape { + public: + explicit rectangle(int width, int height) + : width_{width} + , height_{height} {} + + int get_width() const { + return width_; + } + + int get_height() const { + return height_; + } + + int get_area() const override { + return width_ * height_; + } + private: + int width_{}; + int height_{}; + }; +} + +TEST_CASE("meta/meta_examples/uvalue") { + namespace meta = meta_hpp; + + // 'shape' class type registration + meta::class_() + .method_("get_area", &shape::get_area); + + // 'rectangle' class type registration + meta::class_() + .base_() + .constructor_() + .method_("get_width", &rectangle::get_width) + .method_("get_height", &rectangle::get_height); +} + +TEST_CASE("meta/meta_examples/uvalue/usage") { + namespace meta = meta_hpp; + + // the 'uvalue' class allows to store any copyable value inside + // it's widely used as return value types and as containers for storing metadata + + meta::uvalue val{42}; + CHECK(val.get_type() == meta::resolve_type()); + + // we can get a reference to the stored data and even change it + val.get_as() = 21; + CHECK(val.get_as() == 21); + + // uvalue can be copied, assigned, and moved + val = rectangle{10, 20}; + CHECK(val.get_type() == meta::resolve_type()); + + // also, it supports upcasting for registered types + CHECK(val.get_as().get_area() == 200); + + // upcasting is supported for pointers too + rectangle rect{3, 5}; + val = ▭ + CHECK(val.get_as()->get_area() == 15); + CHECK(val.get_type() == meta::resolve_type()); +} diff --git a/singles/headers/meta.hpp/meta_all.hpp b/singles/headers/meta.hpp/meta_all.hpp index 51b5bf2..9be1c5c 100644 --- a/singles/headers/meta.hpp/meta_all.hpp +++ b/singles/headers/meta.hpp/meta_all.hpp @@ -2263,40 +2263,15 @@ namespace meta_hpp [[nodiscard]] uvalue operator[](std::size_t index) const; template < typename T > - [[nodiscard]] T get_as() &; - template < typename T > - [[nodiscard]] T get_as() &&; - template < typename T > - [[nodiscard]] T get_as() const &; - template < typename T > - [[nodiscard]] T get_as() const &&; + [[nodiscard]] auto get_as() + -> std::conditional_t, T, T&>; template < typename T > - [[nodiscard]] T& get_as_ref() &; - template < typename T > - [[nodiscard]] T&& get_as_ref() &&; - template < typename T > - [[nodiscard]] const T& get_as_ref() const &; - template < typename T > - [[nodiscard]] const T&& get_as_ref() const &&; + [[nodiscard]] auto get_as() const + -> std::conditional_t, T, const T&>; template < typename T > - [[nodiscard]] bool can_get_as() &; - template < typename T > - [[nodiscard]] bool can_get_as() &&; - template < typename T > - [[nodiscard]] bool can_get_as() const &; - template < typename T > - [[nodiscard]] bool can_get_as() const &&; - - template < typename T > - [[nodiscard]] bool can_get_as_ref() &; - template < typename T > - [[nodiscard]] bool can_get_as_ref() &&; - template < typename T > - [[nodiscard]] bool can_get_as_ref() const &; - template < typename T > - [[nodiscard]] bool can_get_as_ref() const &&; + [[nodiscard]] bool can_get_as() const noexcept; friend bool operator<(const uvalue& l, const uvalue& r); friend bool operator==(const uvalue& l, const uvalue& r); @@ -2319,21 +2294,6 @@ namespace meta_hpp } } -namespace meta_hpp -{ - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as(V&& value) -> T; - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as_ref(V&& value) -> detail::add_cvref_t; - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as(V&& value) noexcept; - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as_ref(V&& value) noexcept; -} - namespace meta_hpp::detail { template < typename T > @@ -8204,7 +8164,7 @@ namespace meta_hpp .deref = +[]([[maybe_unused]] const uvalue& v) -> uvalue { if constexpr ( detail::has_deref_traits ) { - return detail::deref_traits{}(v.get_as_ref()); + return detail::deref_traits{}(v.get_as()); } else { detail::throw_exception_with("value type doesn't have value deref traits"); } @@ -8212,7 +8172,7 @@ namespace meta_hpp .index = +[]([[maybe_unused]] const uvalue& v, [[maybe_unused]] std::size_t i) -> uvalue { if constexpr ( detail::has_index_traits ) { - return detail::index_traits{}(v.get_as_ref(), i); + return detail::index_traits{}(v.get_as(), i); } else { detail::throw_exception_with("value type doesn't have value index traits"); } @@ -8220,7 +8180,7 @@ namespace meta_hpp .less = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { if constexpr ( detail::has_less_traits ) { - return detail::less_traits{}(l.get_as_ref(), r.get_as_ref()); + return detail::less_traits{}(l.get_as(), r.get_as()); } else { detail::throw_exception_with("value type doesn't have value less traits"); } @@ -8228,23 +8188,23 @@ namespace meta_hpp .equals = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { if constexpr ( detail::has_equals_traits ) { - return detail::equals_traits{}(l.get_as_ref(), r.get_as_ref()); + return detail::equals_traits{}(l.get_as(), r.get_as()); } else { detail::throw_exception_with("value type doesn't have value equals traits"); } }, .istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] uvalue& v) -> std::istream& { - if constexpr ( detail::has_istream_traits ) { - return detail::istream_traits{}(is, v.get_as_ref()); + if constexpr ( detail::has_istream_traits && !detail::pointer_kind ) { + return detail::istream_traits{}(is, v.get_as()); } else { detail::throw_exception_with("value type doesn't have value istream traits"); } }, .ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const uvalue& v) -> std::ostream& { - if constexpr ( detail::has_ostream_traits ) { - return detail::ostream_traits{}(os, v.get_as_ref()); + if constexpr ( detail::has_ostream_traits && !detail::pointer_kind ) { + return detail::ostream_traits{}(os, v.get_as()); } else { detail::throw_exception_with("value type doesn't have value ostream traits"); } @@ -8345,106 +8305,15 @@ namespace meta_hpp } template < typename T > - T uvalue::get_as() & { - return meta_hpp::get_as(*this); - } + auto uvalue::get_as() -> std::conditional_t, T, T&> { + static_assert(std::is_same_v>); - template < typename T > - T uvalue::get_as() && { - return meta_hpp::get_as(std::move(*this)); - } - - template < typename T > - T uvalue::get_as() const & { - return meta_hpp::get_as(*this); - } - - template < typename T > - T uvalue::get_as() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::get_as(std::move(*this)); - } - - template < typename T > - T& uvalue::get_as_ref() & { - return meta_hpp::get_as_ref(*this); - } - - template < typename T > - T&& uvalue::get_as_ref() && { - return meta_hpp::get_as_ref(std::move(*this)); - } - - template < typename T > - const T& uvalue::get_as_ref() const & { - return meta_hpp::get_as_ref(*this); - } - - template < typename T > - const T&& uvalue::get_as_ref() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::get_as_ref(std::move(*this)); - } - - // - - template < typename T > - bool uvalue::can_get_as() & { - return meta_hpp::can_get_as(*this); - } - - template < typename T > - bool uvalue::can_get_as() && { - return meta_hpp::can_get_as(std::move(*this)); - } - - template < typename T > - bool uvalue::can_get_as() const & { - return meta_hpp::can_get_as(*this); - } - - template < typename T > - bool uvalue::can_get_as() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::can_get_as(std::move(*this)); - } - - template < typename T > - bool uvalue::can_get_as_ref() & { - return meta_hpp::can_get_as_ref(*this); - } - - template < typename T > - bool uvalue::can_get_as_ref() && { - return meta_hpp::can_get_as_ref(std::move(*this)); - } - - template < typename T > - bool uvalue::can_get_as_ref() const & { - return meta_hpp::can_get_as_ref(*this); - } - - template < typename T > - bool uvalue::can_get_as_ref() const && { - // NOLINTNEXTLINE(*-move-const-arg) - return meta_hpp::can_get_as_ref(std::move(*this)); - } -} - -namespace meta_hpp -{ - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as(V&& value) -> T { - using Tp = std::decay_t; - static_assert(std::is_constructible_v>); - - const any_type& from_type = value.get_type(); - const any_type& to_type = resolve_type(); + const any_type& from_type = get_type(); + const any_type& to_type = resolve_type(); if ( from_type == to_type ) { - using to_ptr_t = detail::add_cv_t*; - auto to_ptr = static_cast(value.data()); - return static_cast(*to_ptr); + T* to_ptr = static_cast(data()); + return *to_ptr; } const auto is_a = [](const any_type& base, const any_type& derived){ @@ -8456,12 +8325,11 @@ namespace meta_hpp const class_type& to_class = to_type.as_class(); const class_type& from_class = from_type.as_class(); - using to_ptr_t = detail::add_cv_t*; - auto to_ptr = static_cast(detail::pointer_upcast(value.data(), from_class, to_class)); - return static_cast(*to_ptr); + T* to_ptr = static_cast(detail::pointer_upcast(data(), from_class, to_class)); + return *to_ptr; } - if constexpr ( std::is_pointer_v ) { + if constexpr ( detail::pointer_kind ) { if ( to_type.is_pointer() && from_type.is_nullptr() ) { return static_cast(nullptr); } @@ -8477,11 +8345,11 @@ namespace meta_hpp const any_type& from_data_type = from_type_ptr.get_data_type(); if ( to_type_ptr_readonly >= from_type_ptr_readonly ) { - using from_data_ptr_t = detail::add_cv_t*; - auto from_data_ptr = static_cast(value.data()); + void** from_data_ptr = static_cast(data()); if ( to_data_type.is_void() || to_data_type == from_data_type ) { - return static_cast(*from_data_ptr); + void* to_ptr = *from_data_ptr; + return static_cast(to_ptr); } if ( is_a(to_data_type, from_data_type) ) { @@ -8498,19 +8366,74 @@ namespace meta_hpp detail::throw_exception_with("bad value cast"); } - template < typename T, detail::decay_value_kind V > - [[nodiscard]] auto get_as_ref(V&& value) -> detail::add_cvref_t { - static_assert(!std::is_reference_v); - return get_as>(std::forward(value)); + template < typename T > + auto uvalue::get_as() const -> std::conditional_t, T, const T&> { + static_assert(std::is_same_v>); + + const any_type& from_type = get_type(); + const any_type& to_type = resolve_type(); + + if ( from_type == to_type ) { + const T* to_ptr = static_cast(data()); + return *to_ptr; + } + + const auto is_a = [](const any_type& base, const any_type& derived){ + return (base == derived) + || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); + }; + + if ( is_a(to_type, from_type) ) { + const class_type& to_class = to_type.as_class(); + const class_type& from_class = from_type.as_class(); + + const T* to_ptr = static_cast(detail::pointer_upcast(data(), from_class, to_class)); + return *to_ptr; + } + + if constexpr ( detail::pointer_kind ) { + if ( to_type.is_pointer() && from_type.is_nullptr() ) { + return static_cast(nullptr); + } + + if ( to_type.is_pointer() && from_type.is_pointer() ) { + const pointer_type& to_type_ptr = to_type.as_pointer(); + const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const pointer_type& from_type_ptr = from_type.as_pointer(); + const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly); + + const any_type& to_data_type = to_type_ptr.get_data_type(); + const any_type& from_data_type = from_type_ptr.get_data_type(); + + if ( to_type_ptr_readonly >= from_type_ptr_readonly ) { + void* const* from_data_ptr = static_cast(data()); + + if ( to_data_type.is_void() || to_data_type == from_data_type ) { + void* to_ptr = *from_data_ptr; + return static_cast(to_ptr); + } + + if ( is_a(to_data_type, from_data_type) ) { + const class_type& to_data_class = to_data_type.as_class(); + const class_type& from_data_class = from_data_type.as_class(); + + void* to_ptr = detail::pointer_upcast(*from_data_ptr, from_data_class, to_data_class); + return static_cast(to_ptr); + } + } + } + } + + detail::throw_exception_with("bad value cast"); } - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as(V&& value) noexcept { - using Tp = std::decay_t; - static_assert(std::is_constructible_v>); + template < typename T > + bool uvalue::can_get_as() const noexcept { + static_assert(std::is_same_v>); - const any_type& from_type = value.get_type(); - const any_type& to_type = resolve_type(); + const any_type& from_type = get_type(); + const any_type& to_type = resolve_type(); if ( from_type == to_type ) { return true; @@ -8525,7 +8448,7 @@ namespace meta_hpp return true; } - if constexpr ( std::is_pointer_v ) { + if constexpr ( detail::pointer_kind ) { if ( to_type.is_pointer() && from_type.is_nullptr() ) { return true; } @@ -8550,12 +8473,6 @@ namespace meta_hpp return false; } - - template < typename T, detail::decay_value_kind V > - [[nodiscard]] bool can_get_as_ref(V&& value) noexcept { - static_assert(!std::is_reference_v); - return can_get_as>(std::forward(value)); - } } namespace meta_hpp @@ -8569,7 +8486,7 @@ namespace meta_hpp const any_type& l_type = l.get_type(); const any_type& r_type = resolve_type(); - return (l_type < r_type) || (l_type == r_type && l.get_as_ref() < r); + return (l_type < r_type) || (l_type == r_type && l.get_as() < r); } template < typename T > @@ -8581,7 +8498,7 @@ namespace meta_hpp const any_type& l_type = resolve_type(); const any_type& r_type = r.get_type(); - return (l_type < r_type) || (l_type == r_type && l < r.get_as_ref()); + return (l_type < r_type) || (l_type == r_type && l < r.get_as()); } [[nodiscard]] inline bool operator<(const uvalue& l, const uvalue& r) { @@ -8611,7 +8528,7 @@ namespace meta_hpp const any_type& l_type = l.get_type(); const any_type& r_type = resolve_type(); - return l_type == r_type && l.get_as_ref() == r; + return l_type == r_type && l.get_as() == r; } template < typename T > @@ -8623,7 +8540,7 @@ namespace meta_hpp const any_type& l_type = resolve_type(); const any_type& r_type = r.get_type(); - return l_type == r_type && l == r.get_as_ref(); + return l_type == r_type && l == r.get_as(); } [[nodiscard]] inline bool operator==(const uvalue& l, const uvalue& r) { diff --git a/untests/meta_features/diamond_tests.cpp b/untests/meta_features/diamond_tests.cpp index 3800555..b41bfe5 100644 --- a/untests/meta_features/diamond_tests.cpp +++ b/untests/meta_features/diamond_tests.cpp @@ -253,7 +253,7 @@ TEST_CASE("meta/meta_features/diamond") { CHECK_FALSE(a_inst.can_cast_to()); CHECK_FALSE(a_inst.can_cast_to()); - CHECK(&a_inst.cast() == &a_val.get_as_ref()); + CHECK(&a_inst.cast() == &a_val.get_as()); } { meta::uvalue b_val{B{}}; @@ -265,10 +265,10 @@ TEST_CASE("meta/meta_features/diamond") { CHECK_FALSE(b_inst.can_cast_to()); CHECK_FALSE(b_inst.can_cast_to()); - CHECK(&b_inst.cast() == &b_val.get_as_ref()); - CHECK(&b_inst.cast() == &b_val.get_as_ref()); + CHECK(&b_inst.cast() == &b_val.get_as()); + CHECK(&b_inst.cast() == &b_val.get_as()); - CHECK(&b_inst.cast() == &b_val.get_as_ref()); + CHECK(&b_inst.cast() == &b_val.get_as()); } { meta::uvalue c_val{C{}}; @@ -280,8 +280,8 @@ TEST_CASE("meta/meta_features/diamond") { CHECK_FALSE(c_inst.can_cast_to()); CHECK_FALSE(c_inst.can_cast_to()); - CHECK(&c_inst.cast() == &c_val.get_as_ref()); - CHECK(&c_inst.cast() == &c_val.get_as_ref()); + CHECK(&c_inst.cast() == &c_val.get_as()); + CHECK(&c_inst.cast() == &c_val.get_as()); } { meta::uvalue d_val{D{}}; @@ -293,15 +293,15 @@ TEST_CASE("meta/meta_features/diamond") { CHECK(d_inst.can_cast_to()); CHECK_FALSE(d_inst.can_cast_to()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); + CHECK(&d_inst.cast() == &d_val.get_as()); + CHECK(&d_inst.cast() == &d_val.get_as()); + CHECK(&d_inst.cast() == &d_val.get_as()); + CHECK(&d_inst.cast() == &d_val.get_as()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); - CHECK(&d_inst.cast() == &d_val.get_as_ref()); + CHECK(&d_inst.cast() == &d_val.get_as()); + CHECK(&d_inst.cast() == &d_val.get_as()); + CHECK(&d_inst.cast() == &d_val.get_as()); + CHECK(&d_inst.cast() == &d_val.get_as()); } { meta::uvalue e_val{E{}}; @@ -313,7 +313,7 @@ TEST_CASE("meta/meta_features/diamond") { CHECK_FALSE(e_inst.can_cast_to()); CHECK(e_inst.can_cast_to()); - CHECK(&e_inst.cast() == &e_val.get_as_ref()); + CHECK(&e_inst.cast() == &e_val.get_as()); } } diff --git a/untests/meta_states/ctor_tests.cpp b/untests/meta_states/ctor_tests.cpp index 7bb6aca..cdc5e1b 100644 --- a/untests/meta_states/ctor_tests.cpp +++ b/untests/meta_states/ctor_tests.cpp @@ -92,7 +92,7 @@ TEST_CASE("meta/meta_states/ctor") { CHECK_FALSE(clazz_type.create(10, 20)); const meta::uvalue v = clazz_type.create(10); CHECK(v.get_type() == meta::resolve_type>()); - CHECK(v.get_as_ref>().i == 10); + CHECK(v.get_as>().i == 10); CHECK(clazz_type.destroy(nullptr)); CHECK(clazz_type.destroy(meta::uvalue{nullptr})); @@ -112,7 +112,7 @@ TEST_CASE("meta/meta_states/ctor") { CHECK_FALSE(clazz_type.create(10, 20)); const meta::uvalue v = clazz_type.create(20); CHECK(v.get_type() == meta::resolve_type*>()); - CHECK(v.get_as_ref*>()->i == 20); + CHECK(v.get_as*>()->i == 20); CHECK(clazz_type.destroy(v)); CHECK(clazz_type.destroy(nullptr)); @@ -133,7 +133,7 @@ TEST_CASE("meta/meta_states/ctor") { CHECK_FALSE(clazz_type.create(10, 20)); const meta::uvalue v = clazz_type.create(30); CHECK(v.get_type() == meta::resolve_type>>()); - CHECK(v.get_as_ref>>()->i == 30); + CHECK(v.get_as>>()->i == 30); CHECK(clazz_type.destroy(nullptr)); CHECK(clazz_type.destroy(meta::uvalue{nullptr})); diff --git a/untests/meta_states/member_tests.cpp b/untests/meta_states/member_tests.cpp index 075bac3..5c87403 100644 --- a/untests/meta_states/member_tests.cpp +++ b/untests/meta_states/member_tests.cpp @@ -247,14 +247,14 @@ TEST_CASE("meta/meta_states/member") { clazz_1 v; using ref_t = std::reference_wrapper>; CHECK(vm.get(v).get_type() == meta::resolve_type()); - CHECK(vm.get(v).get_as_ref().get() == v.unique_int_member); + CHECK(vm.get(v).get_as().get() == v.unique_int_member); } { const clazz_1 v; using ref_t = std::reference_wrapper>; CHECK(vm.get(v).get_type() == meta::resolve_type()); - CHECK(vm.get(v).get_as_ref().get() == v.unique_int_member); + CHECK(vm.get(v).get_as().get() == v.unique_int_member); } } } diff --git a/untests/meta_states/variable_tests.cpp b/untests/meta_states/variable_tests.cpp index e02fad0..f98b37c 100644 --- a/untests/meta_states/variable_tests.cpp +++ b/untests/meta_states/variable_tests.cpp @@ -186,7 +186,7 @@ TEST_CASE("meta/meta_states/variable") { using ref_t = std::reference_wrapper>; CHECK(vm.get().get_type() == meta::resolve_type()); - CHECK(vm.get().get_as_ref().get() == clazz_1::unique_int_variable); + CHECK(vm.get().get_as().get() == clazz_1::unique_int_variable); { auto nv = std::make_unique(13); @@ -222,7 +222,7 @@ TEST_CASE("meta/meta_states/variable") { using ref_t = std::reference_wrapper>; CHECK(vm.get().get_type() == meta::resolve_type()); - CHECK(vm.get().get_as_ref().get() == clazz_1::const_unique_int_variable); + CHECK(vm.get().get_as().get() == clazz_1::const_unique_int_variable); { auto nv = std::make_unique(12); diff --git a/untests/meta_utilities/value2_tests.cpp b/untests/meta_utilities/value2_tests.cpp index c88ad84..d029645 100644 --- a/untests/meta_utilities/value2_tests.cpp +++ b/untests/meta_utilities/value2_tests.cpp @@ -154,7 +154,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/small") { meta::uvalue v2{std::move(v1)}; CHECK_FALSE(v1); - CHECK(v2.get_as_ref().x == 1); + CHECK(v2.get_as().x == 1); CHECK(ivec2::destructor_counter == 2); CHECK(ivec2::move_constructor_counter == 2); @@ -170,8 +170,8 @@ TEST_CASE("meta/meta_utilities/value2/counters/small") { meta::uvalue v1{ivec2{1,2}}; meta::uvalue v2{std::as_const(v1)}; - CHECK(v1.get_as_ref().x == 1); - CHECK(v2.get_as_ref().y == 2); + CHECK(v1.get_as().x == 1); + CHECK(v2.get_as().y == 2); CHECK(ivec2::destructor_counter == 1); CHECK(ivec2::move_constructor_counter == 1); @@ -191,8 +191,8 @@ TEST_CASE("meta/meta_utilities/value2/counters/small") { CHECK(ivec2::copy_constructor_counter == 0); v1.swap(v2); - CHECK(v1.get_as_ref().x == 3); - CHECK(v2.get_as_ref().x == 1); + CHECK(v1.get_as().x == 3); + CHECK(v2.get_as().x == 1); CHECK(ivec2::destructor_counter == 5); CHECK(ivec2::move_constructor_counter == 5); @@ -241,7 +241,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/big") { meta::uvalue v2{std::move(v1)}; CHECK_FALSE(v1); - CHECK(v2.get_as_ref().x == 1); + CHECK(v2.get_as().x == 1); CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::move_constructor_counter == 1); @@ -257,8 +257,8 @@ TEST_CASE("meta/meta_utilities/value2/counters/big") { meta::uvalue v1{ivec2_big{1,2}}; meta::uvalue v2{std::as_const(v1)}; - CHECK(v1.get_as_ref().x == 1); - CHECK(v2.get_as_ref().y == 2); + CHECK(v1.get_as().x == 1); + CHECK(v2.get_as().y == 2); CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::move_constructor_counter == 1); @@ -278,8 +278,8 @@ TEST_CASE("meta/meta_utilities/value2/counters/big") { CHECK(ivec2_big::copy_constructor_counter == 0); v1.swap(v2); - CHECK(v1.get_as_ref().x == 3); - CHECK(v2.get_as_ref().x == 1); + CHECK(v1.get_as().x == 3); + CHECK(v2.get_as().x == 1); CHECK(ivec2_big::destructor_counter == 2); CHECK(ivec2_big::move_constructor_counter == 2); @@ -312,7 +312,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") { CHECK(ivec2::copy_constructor_counter == 0); v1.swap(v2); - CHECK(v1.get_as_ref().x == 1); + CHECK(v1.get_as().x == 1); CHECK_FALSE(v2); CHECK(ivec2::destructor_counter == 2); @@ -321,7 +321,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") { v1.swap(v2); CHECK_FALSE(v1); - CHECK(v2.get_as_ref().y == 2); + CHECK(v2.get_as().y == 2); CHECK(ivec2::destructor_counter == 3); CHECK(ivec2::move_constructor_counter == 3); @@ -343,7 +343,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") { CHECK(ivec2_big::copy_constructor_counter == 0); v1.swap(v2); - CHECK(v1.get_as_ref().x == 3); + CHECK(v1.get_as().x == 3); CHECK_FALSE(v2); CHECK(ivec2_big::destructor_counter == 1); @@ -352,7 +352,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") { v1.swap(v2); CHECK_FALSE(v1); - CHECK(v2.get_as_ref().y == 4); + CHECK(v2.get_as().y == 4); CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::move_constructor_counter == 1); @@ -378,8 +378,8 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") { CHECK(ivec2_big::copy_constructor_counter == 0); v1.swap(v2); - CHECK(v1.get_as_ref().x == 3); - CHECK(v2.get_as_ref().x == 1); + CHECK(v1.get_as().x == 3); + CHECK(v2.get_as().x == 1); CHECK(ivec2::destructor_counter == 2); CHECK(ivec2::move_constructor_counter == 2); @@ -390,8 +390,8 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") { CHECK(ivec2_big::copy_constructor_counter == 0); v1.swap(v2); - CHECK(v1.get_as_ref().y == 2); - CHECK(v2.get_as_ref().y == 4); + CHECK(v1.get_as().y == 2); + CHECK(v2.get_as().y == 4); CHECK(ivec2::destructor_counter == 3); CHECK(ivec2::move_constructor_counter == 3); diff --git a/untests/meta_utilities/value4_tests.cpp b/untests/meta_utilities/value4_tests.cpp index 3764d4e..621e175 100644 --- a/untests/meta_utilities/value4_tests.cpp +++ b/untests/meta_utilities/value4_tests.cpp @@ -95,126 +95,63 @@ TEST_CASE("meta/meta_utilities/value4/get_type") { } } -TEST_CASE("meta/meta_utilities/value4/get_as_ref") { - namespace meta = meta_hpp; - - static_assert(std::is_same_v(std::declval())), derived&>); - static_assert(std::is_same_v(std::declval())), derived&&>); - static_assert(std::is_same_v(std::declval())), const derived&>); - static_assert(std::is_same_v(std::declval())), const derived&&>); - - static_assert(std::is_same_v(std::declval())), const derived&>); - static_assert(std::is_same_v(std::declval())), const derived&&>); - static_assert(std::is_same_v(std::declval())), const derived&>); - static_assert(std::is_same_v(std::declval())), const derived&&>); - - static_assert(std::is_same_v(std::declval())), volatile derived&>); - static_assert(std::is_same_v(std::declval())), volatile derived&&>); - static_assert(std::is_same_v(std::declval())), const volatile derived&>); - static_assert(std::is_same_v(std::declval())), const volatile derived&&>); -} - TEST_CASE("meta/meta_utilities/value4/get_as") { namespace meta = meta_hpp; - static_assert(std::is_same_v(std::declval())), derived>); - static_assert(std::is_same_v(std::declval())), derived>); - static_assert(std::is_same_v(std::declval())), derived>); - static_assert(std::is_same_v(std::declval())), derived>); + static_assert(std::is_same_v().get_as()), derived&>); + static_assert(std::is_same_v().get_as()), derived&>); + static_assert(std::is_same_v().get_as()), const derived&>); + static_assert(std::is_same_v().get_as()), const derived&>); - static_assert(std::is_same_v(std::declval())), derived&>); - static_assert(std::is_same_v(std::declval())), derived&>); - static_assert(std::is_same_v(std::declval())), derived&>); - static_assert(std::is_same_v(std::declval())), derived&>); + static_assert(std::is_same_v().get_as()), derived*>); + static_assert(std::is_same_v().get_as()), derived*>); + static_assert(std::is_same_v().get_as()), derived*>); + static_assert(std::is_same_v().get_as()), derived*>); - static_assert(std::is_same_v(std::declval())), const derived&>); - static_assert(std::is_same_v(std::declval())), const derived&>); - static_assert(std::is_same_v(std::declval())), const derived&>); - static_assert(std::is_same_v(std::declval())), const derived&>); + static_assert(std::is_same_v().get_as()), const derived*>); + static_assert(std::is_same_v().get_as()), const derived*>); + static_assert(std::is_same_v().get_as()), const derived*>); + static_assert(std::is_same_v().get_as()), const derived*>); SUBCASE("derived to derived") { { meta::uvalue v{derived{}}; - CHECK(get_as(v).l == 168); - CHECK(get_as(v).l == 168); - // CHECK(get_as(v).l == 168); - CHECK(get_as(v).l == 168); - // CHECK(get_as(v).l == 168); - - CHECK_THROWS(std::ignore = get_as(v)); - CHECK_THROWS(std::ignore = get_as(v)); - CHECK_THROWS(std::ignore = get_as(v)); + CHECK(v.get_as().l == 168); + CHECK_THROWS(std::ignore = v.get_as()); } { meta::uvalue v{derived{}}; - CHECK(get_as(std::move(v)).l == 168); - // CHECK(get_as(std::move(v)).l == 168); - CHECK(get_as(std::move(v)).l == 168); - CHECK(get_as(std::move(v)).l == 168); - CHECK(get_as(std::move(v)).l == 168); - - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK_THROWS(std::ignore = get_as(std::move(v))); + CHECK(std::move(v).get_as().l == 168); + CHECK_THROWS(std::ignore = std::move(v).get_as()); } { const meta::uvalue v{derived{}}; - CHECK(get_as(v).l == 168); - // CHECK(get_as(v).l == 168); - // CHECK(get_as(v).l == 168); - CHECK(get_as(v).l == 168); - // CHECK(get_as(v).l == 168); - - CHECK_THROWS(std::ignore = get_as(v)); - CHECK_THROWS(std::ignore = get_as(v)); + CHECK(v.get_as().l == 168); + CHECK_THROWS(std::ignore = v.get_as()); } { const meta::uvalue v{derived{}}; - CHECK(get_as(std::move(v)).l == 168); - // CHECK(get_as(std::move(v)).l == 168); - // CHECK(get_as(std::move(v)).l == 168); - CHECK(get_as(std::move(v)).l == 168); - CHECK(get_as(std::move(v)).l == 168); - - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK_THROWS(std::ignore = get_as(std::move(v))); + CHECK(std::move(v).get_as().l == 168); + CHECK_THROWS(std::ignore = std::move(v).get_as()); } } SUBCASE("derived to base") { { meta::uvalue v{derived{}}; - CHECK(get_as(v).k == 84); - CHECK(get_as(v).k == 84); - // CHECK(get_as(v).k == 84); - CHECK(get_as(v).k == 84); - // CHECK(get_as(v).k == 84); + CHECK(v.get_as().k == 84); } { meta::uvalue v{derived{}}; - CHECK(get_as(std::move(v)).k == 84); - // CHECK(get_as(std::move(v)).k == 84); - CHECK(get_as(std::move(v)).k == 84); - CHECK(get_as(std::move(v)).k == 84); - CHECK(get_as(std::move(v)).k == 84); + CHECK(std::move(v).get_as().k == 84); } { const meta::uvalue v{derived{}}; - CHECK(get_as(v).k == 84); - // CHECK(get_as(v).k == 84); - // CHECK(get_as(v).k == 84); - CHECK(get_as(v).k == 84); - // CHECK(get_as(v).k == 84); + CHECK(v.get_as().k == 84); } { const meta::uvalue v{derived{}}; - CHECK(get_as(std::move(v)).k == 84); - // CHECK(get_as(std::move(v)).k == 84); - // CHECK(get_as(std::move(v)).k == 84); - CHECK(get_as(std::move(v)).k == 84); - CHECK(get_as(std::move(v)).k == 84); + CHECK(std::move(v).get_as().k == 84); } } @@ -222,43 +159,43 @@ TEST_CASE("meta/meta_utilities/value4/get_as") { { derived d{}; meta::uvalue v{&d}; - CHECK(get_as(v) == &d); - CHECK(get_as(v) == &d); - CHECK(get_as(std::move(v)) == &d); - CHECK(get_as(std::move(v)) == &d); + CHECK(v.get_as() == &d); + CHECK(v.get_as() == &d); + CHECK(std::move(v).get_as() == &d); + CHECK(std::move(v).get_as() == &d); } { const derived d{}; meta::uvalue v{&d}; - CHECK_THROWS(std::ignore = get_as(v)); - CHECK(get_as(v) == &d); - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK(get_as(std::move(v)) == &d); + CHECK_THROWS(std::ignore = v.get_as()); + CHECK(v.get_as() == &d); + CHECK_THROWS(std::ignore = std::move(v).get_as()); + CHECK(std::move(v).get_as() == &d); } } SUBCASE("nullptr") { { meta::uvalue v{nullptr}; - CHECK(get_as(v) == nullptr); - CHECK(get_as(v) == nullptr); - CHECK(get_as(v) == nullptr); - CHECK(get_as(v) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); } { const meta::uvalue v{nullptr}; - CHECK(get_as(v) == nullptr); - CHECK(get_as(v) == nullptr); - CHECK(get_as(v) == nullptr); - CHECK(get_as(v) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); - CHECK(get_as(std::move(v)) == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(v.get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); + CHECK(std::move(v).get_as() == nullptr); } } @@ -266,34 +203,34 @@ TEST_CASE("meta/meta_utilities/value4/get_as") { { derived d{}; meta::uvalue v{&d}; - CHECK(get_as(v)->l == 168); - CHECK(get_as(v)->l == 168); + CHECK(v.get_as()->l == 168); + CHECK(v.get_as()->l == 168); - CHECK_THROWS(std::ignore = get_as(v)); - CHECK_THROWS(std::ignore = get_as(v)); + CHECK_THROWS(std::ignore = v.get_as()); + CHECK_THROWS(std::ignore = v.get_as()); } { derived d{}; meta::uvalue v{&d}; - CHECK(get_as(std::move(v))->l == 168); - CHECK(get_as(std::move(v))->l == 168); + CHECK(std::move(v).get_as()->l == 168); + CHECK(std::move(v).get_as()->l == 168); - CHECK_THROWS(std::ignore = get_as(std::move(v))); - CHECK_THROWS(std::ignore = get_as(std::move(v))); + CHECK_THROWS(std::ignore = std::move(v).get_as()); + CHECK_THROWS(std::ignore = std::move(v).get_as()); } { const derived d{}; meta::uvalue v{&d}; - CHECK(get_as(v)->l == 168); + CHECK(v.get_as()->l == 168); - CHECK_THROWS(std::ignore = get_as(v)); + CHECK_THROWS(std::ignore = v.get_as()); } { const derived d{}; meta::uvalue v{&d}; - CHECK(get_as(std::move(v))->l == 168); + CHECK(std::move(v).get_as()->l == 168); - CHECK_THROWS(std::ignore = get_as(std::move(v))); + CHECK_THROWS(std::ignore = std::move(v).get_as()); } } @@ -301,15 +238,15 @@ TEST_CASE("meta/meta_utilities/value4/get_as") { { derived d{}; meta::uvalue v{&d}; - CHECK(get_as(v)->k == 84); - CHECK(get_as(v)->k == 84); + CHECK(v.get_as()->k == 84); + CHECK(v.get_as()->k == 84); } { const derived d{}; meta::uvalue v{&d}; - CHECK_THROWS(std::ignore = get_as(v)); - CHECK(get_as(v)->k == 84); + CHECK_THROWS(std::ignore = v.get_as()); + CHECK(v.get_as()->k == 84); } } } @@ -320,51 +257,23 @@ TEST_CASE("meta/meta_utilities/value4/can_get_as") { SUBCASE("derived to derived") { { meta::uvalue v{derived{}}; - CHECK(can_get_as(v)); - CHECK(can_get_as(v)); - // CHECK_FALSE(can_get_as(v)); - CHECK(can_get_as(v)); - // CHECK_FALSE(can_get_as(v)); - - CHECK_FALSE(can_get_as(v)); - CHECK_FALSE(can_get_as(v)); - CHECK_FALSE(can_get_as(v)); + CHECK(v.can_get_as()); + CHECK_FALSE(v.can_get_as()); } { meta::uvalue v{derived{}}; - CHECK(can_get_as(std::move(v))); - // CHECK_FALSE(can_get_as(std::move(v))); - CHECK(can_get_as(std::move(v))); - CHECK(can_get_as(std::move(v))); - CHECK(can_get_as(std::move(v))); - - CHECK_FALSE(can_get_as(std::move(v))); - CHECK_FALSE(can_get_as(std::move(v))); - CHECK_FALSE(can_get_as(std::move(v))); - CHECK_FALSE(can_get_as(std::move(v))); + CHECK(std::move(v).can_get_as()); + CHECK_FALSE(std::move(v).can_get_as()); } { const meta::uvalue v{derived{}}; - CHECK(can_get_as(v)); - // CHECK_FALSE(can_get_as(v)); - // CHECK_FALSE(can_get_as(v)); - CHECK(can_get_as(v)); - // CHECK_FALSE(can_get_as(v)); - - CHECK_FALSE(can_get_as(v)); - CHECK_FALSE(can_get_as(v)); + CHECK(v.can_get_as()); + CHECK_FALSE(v.can_get_as()); } { const meta::uvalue v{derived{}}; - CHECK(can_get_as(std::move(v))); - // CHECK_FALSE(can_get_as(std::move(v))); - // CHECK_FALSE(can_get_as(std::move(v))); - CHECK(can_get_as(std::move(v))); - CHECK(can_get_as(std::move(v))); - - CHECK_FALSE(can_get_as(std::move(v))); - CHECK_FALSE(can_get_as(std::move(v))); - CHECK_FALSE(can_get_as(std::move(v))); + CHECK(std::move(v).can_get_as()); + CHECK_FALSE(std::move(v).can_get_as()); } } } diff --git a/untests/meta_utilities/value_tests.cpp b/untests/meta_utilities/value_tests.cpp index 0b51666..256a005 100644 --- a/untests/meta_utilities/value_tests.cpp +++ b/untests/meta_utilities/value_tests.cpp @@ -105,17 +105,17 @@ TEST_CASE("meta/meta_utilities/value") { SUBCASE("cast types") { static_assert(std::is_same_v< - decltype(std::declval().get_as_ref()), + decltype(std::declval().get_as()), ivec2&>); static_assert(std::is_same_v< - decltype(std::declval().get_as_ref()), - ivec2&&>); + decltype(std::declval().get_as()), + ivec2&>); static_assert(std::is_same_v< - decltype(std::declval().get_as_ref()), + decltype(std::declval().get_as()), const ivec2&>); static_assert(std::is_same_v< - decltype(std::declval().get_as_ref()), - const ivec2&&>); + decltype(std::declval().get_as()), + const ivec2&>); } SUBCASE("ivec2{}") { @@ -133,13 +133,13 @@ TEST_CASE("meta/meta_utilities/value") { CHECK_FALSE(*val); CHECK_FALSE(val[0]); - CHECK_FALSE(val.can_get_as_ref()); - CHECK_FALSE(std::as_const(val).can_get_as_ref()); + CHECK_FALSE(val.can_get_as()); + CHECK_FALSE(std::as_const(val).can_get_as()); - CHECK_THROWS(std::ignore = val.get_as_ref()); - CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref()); + CHECK_THROWS(std::ignore = val.get_as()); + CHECK_THROWS(std::ignore = std::as_const(val).get_as()); + CHECK_THROWS(std::ignore = std::move(val).get_as()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as()); } { @@ -195,20 +195,20 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val == ivec2{1,2}); CHECK(val == meta::uvalue{ivec2{1,2}}); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(std::as_const(val)).get_as_ref() == ivec2{1,2}); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK(std::move(val).get_as() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).get_as() == ivec2{1,2}); - CHECK_THROWS(std::ignore = val.get_as_ref()); - CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref()); + CHECK_THROWS(std::ignore = val.get_as()); + CHECK_THROWS(std::ignore = std::as_const(val).get_as()); + CHECK_THROWS(std::ignore = std::move(val).get_as()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as()); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK_FALSE(val.can_get_as_ref()); - CHECK_FALSE(std::as_const(val).can_get_as_ref()); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK_FALSE(val.can_get_as()); + CHECK_FALSE(std::as_const(val).can_get_as()); } SUBCASE("const ivec2&") { @@ -229,20 +229,20 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val == ivec2{1,2}); CHECK(val == meta::uvalue{ivec2{1,2}}); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(std::as_const(val)).get_as_ref() == ivec2{1,2}); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK(std::move(val).get_as() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).get_as() == ivec2{1,2}); - CHECK_THROWS(std::ignore = val.get_as_ref()); - CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref()); + CHECK_THROWS(std::ignore = val.get_as()); + CHECK_THROWS(std::ignore = std::as_const(val).get_as()); + CHECK_THROWS(std::ignore = std::move(val).get_as()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as()); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK_FALSE(val.can_get_as_ref()); - CHECK_FALSE(std::as_const(val).can_get_as_ref()); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK_FALSE(val.can_get_as()); + CHECK_FALSE(std::as_const(val).can_get_as()); } SUBCASE("ivec2&&") { @@ -257,20 +257,20 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val == ivec2{1,2}); CHECK(val == meta::uvalue{ivec2{1,2}}); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(std::as_const(val)).get_as_ref() == ivec2{1,2}); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK(std::move(val).get_as() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).get_as() == ivec2{1,2}); - CHECK_THROWS(std::ignore = val.get_as_ref()); - CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref()); + CHECK_THROWS(std::ignore = val.get_as()); + CHECK_THROWS(std::ignore = std::as_const(val).get_as()); + CHECK_THROWS(std::ignore = std::move(val).get_as()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as()); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK_FALSE(val.can_get_as_ref()); - CHECK_FALSE(std::as_const(val).can_get_as_ref()); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK_FALSE(val.can_get_as()); + CHECK_FALSE(std::as_const(val).can_get_as()); } SUBCASE("const ivec2&&") { @@ -285,20 +285,20 @@ TEST_CASE("meta/meta_utilities/value") { CHECK(val == ivec2{1,2}); CHECK(val == meta::uvalue{ivec2{1,2}}); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(val).get_as_ref() == ivec2{1,2}); - CHECK(std::move(std::as_const(val)).get_as_ref() == ivec2{1,2}); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK(std::move(val).get_as() == ivec2{1,2}); + CHECK(std::move(std::as_const(val)).get_as() == ivec2{1,2}); - CHECK_THROWS(std::ignore = val.get_as_ref()); - CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(val).get_as_ref()); - CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref()); + CHECK_THROWS(std::ignore = val.get_as()); + CHECK_THROWS(std::ignore = std::as_const(val).get_as()); + CHECK_THROWS(std::ignore = std::move(val).get_as()); + CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as()); - CHECK(val.get_as_ref() == ivec2{1,2}); - CHECK(std::as_const(val).get_as_ref() == ivec2{1,2}); - CHECK_FALSE(val.can_get_as_ref()); - CHECK_FALSE(std::as_const(val).can_get_as_ref()); + CHECK(val.get_as() == ivec2{1,2}); + CHECK(std::as_const(val).get_as() == ivec2{1,2}); + CHECK_FALSE(val.can_get_as()); + CHECK_FALSE(std::as_const(val).can_get_as()); } SUBCASE("value(value&&)") { @@ -473,7 +473,7 @@ TEST_CASE("meta/meta_utilities/value") { const int* const pi = &i; const meta::uvalue v{*meta::uvalue{&pi}}; CHECK(v.get_type() == meta::resolve_type() ); - CHECK(v.get_as_ref() == pi); + CHECK(v.get_as() == pi); } { int i{42}; @@ -572,23 +572,44 @@ TEST_CASE("meta/meta_utilities/value/functions") { namespace meta = meta_hpp; SUBCASE("add") { + { + meta::uvalue v{&ivec2::add}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == &ivec2::add); + CHECK((ivec2{1,2}.*(v.get_as()))(ivec2{3,4}) == ivec2(4,6)); + } { const meta::uvalue v{&ivec2::add}; CHECK(v.get_type() == meta::resolve_type()); - CHECK((ivec2{1,2}.*(v.get_as_ref()))(ivec2{3,4}) == ivec2(4,6)); + CHECK(v.get_as() == &ivec2::add); + CHECK((ivec2{1,2}.*(v.get_as()))(ivec2{3,4}) == ivec2(4,6)); } } SUBCASE("iadd2") { + { + meta::uvalue v{iadd2}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == &iadd2); + CHECK((v.get_as())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6}); + } + { + meta::uvalue v{&iadd2}; + CHECK(v.get_type() == meta::resolve_type()); + CHECK(v.get_as() == &iadd2); + CHECK((v.get_as())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6}); + } { const meta::uvalue v{iadd2}; CHECK(v.get_type() == meta::resolve_type()); - CHECK((v.get_as_ref())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6}); + CHECK(v.get_as() == &iadd2); + CHECK((v.get_as())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6}); } { const meta::uvalue v{&iadd2}; CHECK(v.get_type() == meta::resolve_type()); - CHECK((v.get_as_ref())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6}); + CHECK(v.get_as() == &iadd2); + CHECK((v.get_as())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6}); } } }