mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 03:45:30 +07:00
add value deref function
This commit is contained in:
20
TODO.md
20
TODO.md
@@ -1,14 +1,16 @@
|
||||
# meta.hpp
|
||||
|
||||
- add type names;
|
||||
- add argument names
|
||||
- add variable and member readonly flags
|
||||
- add array value access
|
||||
- add return value policy
|
||||
- add meta exception class;
|
||||
- add conversion of nullptr to any pointers;
|
||||
- add conversion of any pointers to void pointer ( identically cv-qualified );
|
||||
- add enum_type::create, number_type::create, and so on.
|
||||
- add return value policy
|
||||
- add is_invocable_with by dynamic types
|
||||
- add metadata to every type and state
|
||||
- add integral implicit conversions
|
||||
- add meta::invoke function
|
||||
|
||||
* argument names
|
||||
* argument defaults
|
||||
* type conversions
|
||||
* states and types metadata
|
||||
|
||||
? add type names;
|
||||
? add enum_type::create, number_type::create, and so on.
|
||||
? add invoke and is_invocable_with by dynamic types
|
||||
|
||||
@@ -116,6 +116,11 @@ namespace meta_hpp::detail
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T >
|
||||
concept has_deref_op_kind = requires(const T& v) {
|
||||
{ *v } -> convertible_to<std::remove_pointer_t<T>>;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
concept has_less_op_kind = requires(const T& v) {
|
||||
{ v < v } -> convertible_to<bool>;
|
||||
@@ -182,6 +187,10 @@ namespace meta_hpp
|
||||
[[nodiscard]] const void* data() const noexcept;
|
||||
[[nodiscard]] const void* cdata() const noexcept;
|
||||
|
||||
[[nodiscard]] value deref();
|
||||
[[nodiscard]] value deref() const;
|
||||
[[nodiscard]] value cderef() const;
|
||||
|
||||
template < typename T, typename Tp = std::decay_t<T> >
|
||||
[[nodiscard]] Tp& cast() &;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace meta_hpp
|
||||
void* (*const data)(value&) noexcept;
|
||||
const void* (*const cdata)(const value&) noexcept;
|
||||
|
||||
value (*const deref)(value&);
|
||||
value (*const cderef)(const value&);
|
||||
|
||||
bool (*const less)(const value&, const value&);
|
||||
bool (*const equals)(const value&, const value&);
|
||||
|
||||
@@ -32,6 +35,8 @@ namespace meta_hpp
|
||||
|
||||
template < typename T >
|
||||
const value::traits* value::traits::get() noexcept {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
|
||||
static const traits traits{
|
||||
.type = resolve_type<T>(),
|
||||
|
||||
@@ -43,6 +48,22 @@ namespace meta_hpp
|
||||
return v.try_cast<T>();
|
||||
},
|
||||
|
||||
.deref = +[]([[maybe_unused]] value& v) -> value {
|
||||
if constexpr ( detail::has_deref_op_kind<T> ) {
|
||||
return value{*v.cast<T>()};
|
||||
} else {
|
||||
throw std::logic_error("value type doesn't have deref operator");
|
||||
}
|
||||
},
|
||||
|
||||
.cderef = +[]([[maybe_unused]] const value& v) -> value {
|
||||
if constexpr ( detail::has_deref_op_kind<T> ) {
|
||||
return value{*v.cast<T>()};
|
||||
} else {
|
||||
throw std::logic_error("value type doesn't have deref operator");
|
||||
}
|
||||
},
|
||||
|
||||
.less = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
|
||||
if constexpr ( detail::has_less_op_kind<T> ) {
|
||||
return l.cast<T>() < r.cast<T>();
|
||||
@@ -91,6 +112,7 @@ namespace meta_hpp
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return &traits;
|
||||
}
|
||||
}
|
||||
@@ -159,6 +181,18 @@ namespace meta_hpp
|
||||
return traits_->cdata(*this);
|
||||
}
|
||||
|
||||
inline value value::deref() {
|
||||
return traits_->deref(*this);
|
||||
}
|
||||
|
||||
inline value value::deref() const {
|
||||
return traits_->cderef(*this);
|
||||
}
|
||||
|
||||
inline value value::cderef() const {
|
||||
return traits_->cderef(*this);
|
||||
}
|
||||
|
||||
template < typename T, typename Tp >
|
||||
Tp& value::cast() & {
|
||||
if ( get_type() != resolve_type<Tp>() ) {
|
||||
|
||||
@@ -30,6 +30,12 @@ namespace
|
||||
++copy_ctor_counter;
|
||||
}
|
||||
|
||||
ivec2& add(const ivec2& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ivec2& operator=(ivec2&& other) = delete;
|
||||
ivec2& operator=(const ivec2& other) = delete;
|
||||
public:
|
||||
@@ -344,21 +350,85 @@ TEST_CASE("meta/meta_utilities/value") {
|
||||
CHECK_THROWS(std::ignore = operator==(meta::value{empty_class1{}}, meta::value{empty_class1{}}));
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("deref") {
|
||||
{
|
||||
int i{42};
|
||||
const meta::value v{meta::value{&i}.deref()};
|
||||
CHECK(v.get_type() == meta::resolve_type<int>());
|
||||
CHECK(v.data() != &i);
|
||||
}
|
||||
{
|
||||
const char i{42};
|
||||
const meta::value v{meta::value{&i}.deref()};
|
||||
CHECK(v.get_type() == meta::resolve_type<char>());
|
||||
CHECK(v.data() != &i);
|
||||
}
|
||||
{
|
||||
const int i{42};
|
||||
const int* const pi = &i;
|
||||
const meta::value v{meta::value{&pi}.deref()};
|
||||
CHECK(v.get_type() == meta::resolve_type<const int*>() );
|
||||
CHECK(v.cast<const int*>() == pi);
|
||||
}
|
||||
{
|
||||
int i{42};
|
||||
|
||||
void* p1 = &i;
|
||||
const void* p2 = &i;
|
||||
void* const& p3 = &i;
|
||||
const void* const& p4 = &i;
|
||||
|
||||
CHECK_THROWS(std::ignore = meta::value(p1).deref());
|
||||
CHECK_THROWS(std::ignore = meta::value(p2).deref());
|
||||
CHECK_THROWS(std::ignore = meta::value(p3).deref());
|
||||
CHECK_THROWS(std::ignore = meta::value(p4).deref());
|
||||
}
|
||||
{
|
||||
ivec2 v{1,2};
|
||||
meta::value vp{&v};
|
||||
CHECK(ivec2::move_ctor_counter == 0);
|
||||
CHECK(ivec2::copy_ctor_counter == 0);
|
||||
|
||||
meta::value vv1{vp.deref()};
|
||||
CHECK(ivec2::move_ctor_counter == 0);
|
||||
CHECK(ivec2::copy_ctor_counter == 1);
|
||||
|
||||
meta::value vv2{std::move(vp).deref()};
|
||||
CHECK(ivec2::move_ctor_counter == 0);
|
||||
CHECK(ivec2::copy_ctor_counter == 2);
|
||||
|
||||
meta::value vv3{vp.cderef()};
|
||||
CHECK(ivec2::move_ctor_counter == 0);
|
||||
CHECK(ivec2::copy_ctor_counter == 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_utilities/value/functions") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
SUBCASE("add") {
|
||||
{
|
||||
const meta::value v{&ivec2::add};
|
||||
CHECK(v.get_type() == meta::resolve_type<ivec2&(ivec2::*)(const ivec2&)>());
|
||||
CHECK(std::invoke(v.cast<decltype(&ivec2::add)>(), ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
CHECK(std::invoke(*v.try_cast<decltype(&ivec2::add)>(), ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("iadd2") {
|
||||
{
|
||||
const meta::value v{iadd2};
|
||||
CHECK(v.get_type() == meta::resolve_type<ivec2(*)(ivec2, ivec2)>());
|
||||
CHECK(v.cast<decltype(iadd2)>()(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
CHECK(std::invoke(v.cast<decltype(iadd2)>(), ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
CHECK(std::invoke(*v.try_cast<decltype(iadd2)>(), ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
}
|
||||
{
|
||||
const meta::value v{&iadd2};
|
||||
CHECK(v.get_type() == meta::resolve_type<ivec2(*)(ivec2, ivec2)>());
|
||||
CHECK(v.cast<decltype(&iadd2)>()(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
CHECK(std::invoke(v.cast<decltype(&iadd2)>(), ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
CHECK(std::invoke(*v.try_cast<decltype(&iadd2)>(), ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user