diff --git a/CMakeLists.txt b/CMakeLists.txt index d4d87f3..36bbe89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ target_compile_options(${PROJECT_NAME} -Wno-ctad-maybe-unsupported -Wno-exit-time-destructors -Wno-float-equal + -Wno-ignored-qualifiers -Wno-padded -Wno-shadow-field -Wno-shadow-field-in-constructor diff --git a/headers/meta.hpp/meta_utilities.hpp b/headers/meta.hpp/meta_utilities.hpp index ac698ef..52e745f 100644 --- a/headers/meta.hpp/meta_utilities.hpp +++ b/headers/meta.hpp/meta_utilities.hpp @@ -58,6 +58,12 @@ namespace meta_hpp template < typename T, typename Tp = std::decay_t > 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 > @@ -161,10 +167,10 @@ namespace meta_hpp::detail class inst_base { public: enum class ref_types { - ref, - rref, - cref, - crref, + lvalue, + const_lvalue, + rvalue, + const_rvalue, }; public: inst_base() = delete; @@ -187,8 +193,9 @@ namespace meta_hpp::detail explicit inst_base(type_list); explicit inst_base(value& v); - explicit inst_base(value&& v); explicit inst_base(const value& v); + + explicit inst_base(value&& v); explicit inst_base(const value&& v); bool is_const() const noexcept; diff --git a/headers/meta.hpp/meta_utilities/inst.hpp b/headers/meta.hpp/meta_utilities/inst.hpp index b4b7397..754140e 100644 --- a/headers/meta.hpp/meta_utilities/inst.hpp +++ b/headers/meta.hpp/meta_utilities/inst.hpp @@ -15,7 +15,7 @@ namespace meta_hpp::detail (std::is_lvalue_reference_v && std::is_class_v>) , int> > inst_base::inst_base(type_list) - : ref_type_{std::is_const_v> ? ref_types::cref : ref_types::ref} + : ref_type_{std::is_const_v> ? ref_types::const_lvalue : ref_types::lvalue} , raw_type_{resolve_type>()} {} template < typename T, std::enable_if_t< @@ -23,19 +23,11 @@ namespace meta_hpp::detail (std::is_rvalue_reference_v && std::is_class_v>) , int> > inst_base::inst_base(type_list) - : ref_type_{std::is_const_v> ? ref_types::crref : ref_types::rref} + : ref_type_{std::is_const_v> ? ref_types::const_rvalue : ref_types::rvalue} , raw_type_{resolve_type>()} {} inline inst_base::inst_base(value& v) - : ref_type_{ref_types::ref} - , raw_type_{v.get_type().as_class()} { - if ( !v.get_type().is_class() ) { - throw std::logic_error("an attempt to create an instance with a non-class value type"); - } - } - - inline inst_base::inst_base(value&& v) - : ref_type_{ref_types::rref} + : ref_type_{ref_types::lvalue} , raw_type_{v.get_type().as_class()} { if ( !v.get_type().is_class() ) { throw std::logic_error("an attempt to create an instance with a non-class value type"); @@ -43,7 +35,15 @@ namespace meta_hpp::detail } inline inst_base::inst_base(const value& v) - : ref_type_{ref_types::cref} + : ref_type_{ref_types::const_lvalue} + , raw_type_{v.get_type().as_class()} { + if ( !v.get_type().is_class() ) { + throw std::logic_error("an attempt to create an instance with a non-class value type"); + } + } + + inline inst_base::inst_base(value&& v) + : ref_type_{ref_types::rvalue} , raw_type_{v.get_type().as_class()} { if ( !v.get_type().is_class() ) { throw std::logic_error("an attempt to create an instance with a non-class value type"); @@ -51,7 +51,7 @@ namespace meta_hpp::detail } inline inst_base::inst_base(const value&& v) - : ref_type_{ref_types::crref} + : ref_type_{ref_types::const_rvalue} , raw_type_{v.get_type().as_class()} { if ( !v.get_type().is_class() ) { throw std::logic_error("an attempt to create an instance with a non-class value type"); @@ -59,18 +59,18 @@ namespace meta_hpp::detail } inline bool inst_base::is_const() const noexcept { - return ref_type_ == ref_types::cref - || ref_type_ == ref_types::crref; + return ref_type_ == ref_types::const_lvalue + || ref_type_ == ref_types::const_rvalue; } inline bool inst_base::is_lvalue() const noexcept { - return ref_type_ == ref_types::ref - || ref_type_ == ref_types::cref; + return ref_type_ == ref_types::lvalue + || ref_type_ == ref_types::const_lvalue; } inline bool inst_base::is_rvalue() const noexcept { - return ref_type_ == ref_types::rref - || ref_type_ == ref_types::crref; + return ref_type_ == ref_types::rvalue + || ref_type_ == ref_types::const_rvalue; } inline inst_base::ref_types inst_base::get_ref_type() const noexcept { @@ -86,28 +86,30 @@ namespace meta_hpp::detail (std::is_reference_v && std::is_class_v>) , int> > bool inst_base::can_cast_to() const noexcept { - constexpr bool to_const = std::is_const_v>; + using to_raw_type = std::remove_cvref_t; + using to_raw_type_cv = std::remove_reference_t; - if constexpr ( !to_const ) { + if constexpr ( !std::is_const_v ) { if ( is_const() ) { return false; } } - if constexpr ( std::is_lvalue_reference_v ) { - if ( !is_lvalue() ) { + if constexpr ( std::is_reference_v ) { + const auto check_qualifiers = [](ref_types self_ref_type){ + switch ( self_ref_type ) { + case ref_types::lvalue: return std::is_convertible_v; + case ref_types::const_lvalue: return std::is_convertible_v; + case ref_types::rvalue: return std::is_convertible_v; + case ref_types::const_rvalue: return std::is_convertible_v; + } + }; + + if ( !check_qualifiers(get_ref_type()) ) { return false; } } - if constexpr ( std::is_rvalue_reference_v ) { - if ( !is_rvalue() ) { - return false; - } - } - - using to_raw_type = std::remove_cvref_t; - return get_raw_type() == resolve_type() || get_raw_type().is_derived_from(resolve_type()); } @@ -135,7 +137,7 @@ namespace meta_hpp::detail , int> > decltype(auto) inst::cast() const { if ( !can_cast_to() ) { - throw std::logic_error("bad an instance cast"); + throw std::logic_error("bad instance cast"); } if constexpr ( std::is_reference_v ) { diff --git a/untests/meta_utilities/inst_tests.cpp b/untests/meta_utilities/inst_tests.cpp index 9048994..dd20b2c 100644 --- a/untests/meta_utilities/inst_tests.cpp +++ b/untests/meta_utilities/inst_tests.cpp @@ -8,133 +8,202 @@ namespace { - struct ivec2 { - int x{}; - int y{}; - - [[maybe_unused]] ivec2() = default; - [[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {} - [[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {} - - [[maybe_unused]] ivec2(ivec2&& other) noexcept { - x = other.x; - y = other.y; - other.x = 0; - other.y = 0; - } - - [[maybe_unused]] ivec2(const ivec2& other) noexcept { - x = other.x; - y = other.y; - } - - ivec2& operator=(ivec2&&) = delete; - ivec2& operator=(const ivec2&) = delete; + struct clazz { + int m1() { return 1; } + int m2() & { return 1; } + int m3() && { return 1; } + int m4() const { return 1; } + int m5() const & { return 1; } + int m6() const && { return 1; } }; - struct derived_ivec2 : ivec2 { - [[maybe_unused]] derived_ivec2() = default; - [[maybe_unused]] explicit derived_ivec2(int v): ivec2{v, v} {} - [[maybe_unused]] derived_ivec2(int x, int y): ivec2{x, y} {} - }; + struct dclazz : clazz {}; } -TEST_CASE("features/meta_utilities/inst") { +#define META_HPP_CHECK_INVOCABLE(Inst, FName, Qualifiers)\ + {\ + using namespace meta::detail;\ + auto method_ptr = meta::select(&clazz::FName);\ + meta::method m_state{method_state::make("", method_ptr)};\ + \ + if ( std::is_invocable_v ) {\ + CHECK(inst{Inst}.can_cast_to());\ + CHECK(inst_base{type_list{}}.can_cast_to());\ + \ + CHECK(m_state.is_invocable_with());\ + CHECK(m_state.invoke(Inst) == 1);\ + } else {\ + CHECK_FALSE(inst{Inst}.can_cast_to());\ + CHECK_FALSE(inst_base{type_list{}}.can_cast_to());\ + \ + CHECK_FALSE(m_state.is_invocable_with());\ + CHECK_THROWS(m_state.invoke(Inst));\ + }\ + } + +TEST_CASE("features/meta_utilities/inst2") { namespace meta = meta_hpp; - SUBCASE("ref") { + meta::class_() + .base_(); +} + +TEST_CASE("features/meta_utilities/inst2") { + namespace meta = meta_hpp; + + { + // lvalue + auto LV = []() -> clazz& { static clazz v; return v; }; + auto LV2 = []() -> dclazz& { static dclazz v; return v; }; + { - derived_ivec2 v{1,2}; - derived_ivec2& vr = v; - meta::detail::inst a{vr}; - - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::ref); + meta::detail::inst i{LV()}; + CHECK(i.get_raw_type() == meta::resolve_type()); + CHECK(i.get_ref_type() == meta::detail::inst::ref_types::lvalue); } - { - meta::value v{derived_ivec2{1,2}}; - meta::value& vr = v; - meta::detail::inst a{vr}; - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::ref); + META_HPP_CHECK_INVOCABLE(LV(), m1, ); + META_HPP_CHECK_INVOCABLE(LV(), m2, &); + META_HPP_CHECK_INVOCABLE(LV(), m3, &&); + META_HPP_CHECK_INVOCABLE(LV(), m4, const); + META_HPP_CHECK_INVOCABLE(LV(), m5, const &); + META_HPP_CHECK_INVOCABLE(LV(), m6, const &&); - CHECK(a.can_cast_to()); - CHECK(a.can_cast_to()); - CHECK(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - } + META_HPP_CHECK_INVOCABLE(LV2(), m1, ); + META_HPP_CHECK_INVOCABLE(LV2(), m2, &); + META_HPP_CHECK_INVOCABLE(LV2(), m3, &&); + META_HPP_CHECK_INVOCABLE(LV2(), m4, const); + META_HPP_CHECK_INVOCABLE(LV2(), m5, const &); + META_HPP_CHECK_INVOCABLE(LV2(), m6, const &&); } - SUBCASE("cref") { + { + // const lvalue + auto CLV = []() -> const clazz& { static clazz v; return v; }; + auto CLV2 = []() -> const dclazz& { static dclazz v; return v; }; + { - const derived_ivec2 v{1,2}; - const derived_ivec2& vr = v; - meta::detail::inst a{vr}; - - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::cref); + meta::detail::inst i{CLV()}; + CHECK(i.get_raw_type() == meta::resolve_type()); + CHECK(i.get_ref_type() == meta::detail::inst::ref_types::const_lvalue); } - { - const meta::value v{derived_ivec2{1,2}}; - const meta::value& vr = v; - meta::detail::inst a{vr}; - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::cref); + META_HPP_CHECK_INVOCABLE(CLV(), m1, ); + META_HPP_CHECK_INVOCABLE(CLV(), m2, &); + META_HPP_CHECK_INVOCABLE(CLV(), m3, &&); + META_HPP_CHECK_INVOCABLE(CLV(), m4, const); + META_HPP_CHECK_INVOCABLE(CLV(), m5, const &); + META_HPP_CHECK_INVOCABLE(CLV(), m6, const &&); - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - } + META_HPP_CHECK_INVOCABLE(CLV2(), m1, ); + META_HPP_CHECK_INVOCABLE(CLV2(), m2, &); + META_HPP_CHECK_INVOCABLE(CLV2(), m3, &&); + META_HPP_CHECK_INVOCABLE(CLV2(), m4, const); + META_HPP_CHECK_INVOCABLE(CLV2(), m5, const &); + META_HPP_CHECK_INVOCABLE(CLV2(), m6, const &&); } - SUBCASE("rref") { + { + // xvalue + auto XV = []() -> clazz&& { static clazz v; return std::move(v); }; + auto XV2 = []() -> dclazz&& { static dclazz v; return std::move(v); }; + { - derived_ivec2 v{1,2}; - meta::detail::inst a{std::move(v)}; - - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::rref); + meta::detail::inst i{XV()}; + CHECK(i.get_raw_type() == meta::resolve_type()); + CHECK(i.get_ref_type() == meta::detail::inst::ref_types::rvalue); } - { - meta::value v{derived_ivec2{1,2}}; - meta::detail::inst a{std::move(v)}; - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::rref); + META_HPP_CHECK_INVOCABLE(XV(), m1, ); + META_HPP_CHECK_INVOCABLE(XV(), m2, &); + META_HPP_CHECK_INVOCABLE(XV(), m3, &&); + META_HPP_CHECK_INVOCABLE(XV(), m4, const); + META_HPP_CHECK_INVOCABLE(XV(), m5, const &); + META_HPP_CHECK_INVOCABLE(XV(), m6, const &&); - CHECK(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK(a.can_cast_to()); - CHECK(a.can_cast_to()); - } + META_HPP_CHECK_INVOCABLE(XV2(), m1, ); + META_HPP_CHECK_INVOCABLE(XV2(), m2, &); + META_HPP_CHECK_INVOCABLE(XV2(), m3, &&); + META_HPP_CHECK_INVOCABLE(XV2(), m4, const); + META_HPP_CHECK_INVOCABLE(XV2(), m5, const &); + META_HPP_CHECK_INVOCABLE(XV2(), m6, const &&); } - SUBCASE("crref") { + { + // const xvalue + auto CXV = []() -> const clazz&& { static clazz v; return std::move(v); }; + auto CXV2 = []() -> const dclazz&& { static dclazz v; return std::move(v); }; + { - const derived_ivec2 v{1,2}; - meta::detail::inst a{std::move(v)}; - - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::crref); + meta::detail::inst i{CXV()}; + CHECK(i.get_raw_type() == meta::resolve_type()); + CHECK(i.get_ref_type() == meta::detail::inst::ref_types::const_rvalue); } + + META_HPP_CHECK_INVOCABLE(CXV(), m1, ); + META_HPP_CHECK_INVOCABLE(CXV(), m2, &); + META_HPP_CHECK_INVOCABLE(CXV(), m3, &&); + META_HPP_CHECK_INVOCABLE(CXV(), m4, const); + META_HPP_CHECK_INVOCABLE(CXV(), m5, const &); + META_HPP_CHECK_INVOCABLE(CXV(), m6, const &&); + + META_HPP_CHECK_INVOCABLE(CXV2(), m1, ); + META_HPP_CHECK_INVOCABLE(CXV2(), m2, &); + META_HPP_CHECK_INVOCABLE(CXV2(), m3, &&); + META_HPP_CHECK_INVOCABLE(CXV2(), m4, const); + META_HPP_CHECK_INVOCABLE(CXV2(), m5, const &); + META_HPP_CHECK_INVOCABLE(CXV2(), m6, const &&); + } + + { + // prvalue + auto PRV = []() -> clazz { return clazz{}; }; + auto PRV2 = []() -> dclazz { return dclazz{}; }; + { - const meta::value v{derived_ivec2{1,2}}; - meta::detail::inst a{std::move(v)}; - - CHECK(a.get_raw_type() == meta::resolve_type()); - CHECK(a.get_ref_type() == meta::detail::inst::ref_types::crref); - - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK_FALSE(a.can_cast_to()); - CHECK(a.can_cast_to()); + meta::detail::inst i{PRV()}; + CHECK(i.get_raw_type() == meta::resolve_type()); + CHECK(i.get_ref_type() == meta::detail::inst::ref_types::rvalue); } + + META_HPP_CHECK_INVOCABLE(PRV(), m1, ); + META_HPP_CHECK_INVOCABLE(PRV(), m2, &); + META_HPP_CHECK_INVOCABLE(PRV(), m3, &&); + META_HPP_CHECK_INVOCABLE(PRV(), m4, const); + META_HPP_CHECK_INVOCABLE(PRV(), m5, const &); + META_HPP_CHECK_INVOCABLE(PRV(), m6, const &&); + + META_HPP_CHECK_INVOCABLE(PRV2(), m1, ); + META_HPP_CHECK_INVOCABLE(PRV2(), m2, &); + META_HPP_CHECK_INVOCABLE(PRV2(), m3, &&); + META_HPP_CHECK_INVOCABLE(PRV2(), m4, const); + META_HPP_CHECK_INVOCABLE(PRV2(), m5, const &); + META_HPP_CHECK_INVOCABLE(PRV2(), m6, const &&); + } + + { + // const prvalue + auto CPRV = []() -> const clazz { return clazz{}; }; + auto CPRV2 = []() -> const dclazz { return dclazz{}; }; + + { + meta::detail::inst i{CPRV()}; + CHECK(i.get_raw_type() == meta::resolve_type()); + CHECK(i.get_ref_type() == meta::detail::inst::ref_types::const_rvalue); + } + + META_HPP_CHECK_INVOCABLE(CPRV(), m1, ); + META_HPP_CHECK_INVOCABLE(CPRV(), m2, &); + META_HPP_CHECK_INVOCABLE(CPRV(), m3, &&); + META_HPP_CHECK_INVOCABLE(CPRV(), m4, const); + META_HPP_CHECK_INVOCABLE(CPRV(), m5, const &); + META_HPP_CHECK_INVOCABLE(CPRV(), m6, const &&); + + META_HPP_CHECK_INVOCABLE(CPRV2(), m1, ); + META_HPP_CHECK_INVOCABLE(CPRV2(), m2, &); + META_HPP_CHECK_INVOCABLE(CPRV2(), m3, &&); + META_HPP_CHECK_INVOCABLE(CPRV2(), m4, const); + META_HPP_CHECK_INVOCABLE(CPRV2(), m5, const &); + META_HPP_CHECK_INVOCABLE(CPRV2(), m6, const &&); } }