new uvalue api

This commit is contained in:
BlackMATov
2022-11-06 01:31:58 +07:00
parent 014315699f
commit f9504306c0
13 changed files with 763 additions and 275 deletions

View File

@@ -35,6 +35,7 @@
#include <vector> #include <vector>
#include "meta_base/bitflags.hpp" #include "meta_base/bitflags.hpp"
#include "meta_base/cv_traits.hpp"
#include "meta_base/cvref_traits.hpp" #include "meta_base/cvref_traits.hpp"
#include "meta_base/fixed_function.hpp" #include "meta_base/fixed_function.hpp"
#include "meta_base/hash_combiner.hpp" #include "meta_base/hash_combiner.hpp"

View File

@@ -0,0 +1,46 @@
/*******************************************************************************
* 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)
******************************************************************************/
#pragma once
#include <type_traits>
namespace meta_hpp::detail
{
template < typename From >
struct cv_traits {
static constexpr bool is_const = std::is_const_v<std::remove_reference_t<From>>;
static constexpr bool is_volatile = std::is_volatile_v<std::remove_reference_t<From>>;
template < bool yesno, template < typename > typename Q, typename V >
using apply_t_if = std::conditional_t<yesno, Q<V>, V>;
template < typename To >
using add_to =
apply_t_if<is_const, std::add_const_t,
apply_t_if<is_volatile, std::add_volatile_t,
To>>;
template < typename To >
using copy_to = add_to<std::remove_cv_t<To>>;
};
template < typename From, typename To >
struct add_cv {
using type = typename cv_traits<From>::template add_to<To>;
};
template < typename From, typename To >
struct copy_cv {
using type = typename cv_traits<From>::template copy_to<To>;
};
template < typename From, typename To >
using add_cv_t = typename add_cv<From, To>::type;
template < typename From, typename To >
using copy_cv_t = typename copy_cv<From, To>::type;
}

View File

@@ -21,12 +21,20 @@ namespace meta_hpp::detail
using apply_t_if = std::conditional_t<yesno, Q<V>, V>; using apply_t_if = std::conditional_t<yesno, Q<V>, V>;
template < typename To > template < typename To >
using copy_to = using add_to =
apply_t_if<is_lvalue, std::add_lvalue_reference_t, apply_t_if<is_lvalue, std::add_lvalue_reference_t,
apply_t_if<is_rvalue, std::add_rvalue_reference_t, apply_t_if<is_rvalue, std::add_rvalue_reference_t,
apply_t_if<is_const, std::add_const_t, apply_t_if<is_const, std::add_const_t,
apply_t_if<is_volatile, std::add_volatile_t, apply_t_if<is_volatile, std::add_volatile_t,
std::remove_cvref_t<To>>>>>; To>>>>;
template < typename To >
using copy_to = add_to<std::remove_cvref_t<To>>;
};
template < typename From, typename To >
struct add_cvref {
using type = typename cvref_traits<From>::template add_to<To>;
}; };
template < typename From, typename To > template < typename From, typename To >
@@ -34,6 +42,9 @@ namespace meta_hpp::detail
using type = typename cvref_traits<From>::template copy_to<To>; using type = typename cvref_traits<From>::template copy_to<To>;
}; };
template < typename From, typename To >
using add_cvref_t = typename add_cvref<From, To>::type;
template < typename From, typename To > template < typename From, typename To >
using copy_cvref_t = typename copy_cvref<From, To>::type; using copy_cvref_t = typename copy_cvref<From, To>::type;
} }

View File

@@ -61,22 +61,40 @@ namespace meta_hpp
[[nodiscard]] uvalue operator[](std::size_t index) const; [[nodiscard]] uvalue operator[](std::size_t index) const;
template < typename T > template < typename T >
[[nodiscard]] std::decay_t<T>& cast() &; [[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 &&;
template < typename T > template < typename T >
[[nodiscard]] std::decay_t<T>&& cast() &&; [[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 &&;
template < typename T > template < typename T >
[[nodiscard]] const std::decay_t<T>& cast() const &; [[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 > template < typename T >
[[nodiscard]] const std::decay_t<T>&& cast() const &&; [[nodiscard]] bool can_get_as_ref() &;
template < typename T > template < typename T >
[[nodiscard]] std::decay_t<T>* try_cast() noexcept; [[nodiscard]] bool can_get_as_ref() &&;
template < typename T > template < typename T >
[[nodiscard]] const std::decay_t<T>* try_cast() const noexcept; [[nodiscard]] bool can_get_as_ref() const &;
template < typename T >
[[nodiscard]] bool can_get_as_ref() const &&;
friend bool operator<(const uvalue& l, const uvalue& r); friend bool operator<(const uvalue& l, const uvalue& r);
friend bool operator==(const uvalue& l, const uvalue& r); friend bool operator==(const uvalue& l, const uvalue& r);
@@ -98,3 +116,18 @@ namespace meta_hpp
l.swap(r); 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<V&&, 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;
}

View File

@@ -186,7 +186,7 @@ namespace meta_hpp
.deref = +[]([[maybe_unused]] const uvalue& v) -> uvalue { .deref = +[]([[maybe_unused]] const uvalue& v) -> uvalue {
if constexpr ( detail::has_deref_traits<Tp> ) { if constexpr ( detail::has_deref_traits<Tp> ) {
return detail::deref_traits<Tp>{}(v.cast<Tp>()); return detail::deref_traits<Tp>{}(v.get_as_ref<Tp>());
} else { } else {
detail::throw_exception_with("value type doesn't have value deref traits"); 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 { .index = +[]([[maybe_unused]] const uvalue& v, [[maybe_unused]] std::size_t i) -> uvalue {
if constexpr ( detail::has_index_traits<Tp> ) { if constexpr ( detail::has_index_traits<Tp> ) {
return detail::index_traits<Tp>{}(v.cast<Tp>(), i); return detail::index_traits<Tp>{}(v.get_as_ref<Tp>(), i);
} else { } else {
detail::throw_exception_with("value type doesn't have value index traits"); 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 { .less = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool {
if constexpr ( detail::has_less_traits<Tp> ) { if constexpr ( detail::has_less_traits<Tp> ) {
return detail::less_traits<Tp>{}(l.cast<Tp>(), r.cast<Tp>()); return detail::less_traits<Tp>{}(l.get_as_ref<Tp>(), r.get_as_ref<Tp>());
} else { } else {
detail::throw_exception_with("value type doesn't have value less traits"); detail::throw_exception_with("value type doesn't have value less traits");
} }
@@ -210,7 +210,7 @@ namespace meta_hpp
.equals = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool { .equals = +[]([[maybe_unused]] const uvalue& l, [[maybe_unused]] const uvalue& r) -> bool {
if constexpr ( detail::has_equals_traits<Tp> ) { if constexpr ( detail::has_equals_traits<Tp> ) {
return detail::equals_traits<Tp>{}(l.cast<Tp>(), r.cast<Tp>()); return detail::equals_traits<Tp>{}(l.get_as_ref<Tp>(), r.get_as_ref<Tp>());
} else { } else {
detail::throw_exception_with("value type doesn't have value equals traits"); detail::throw_exception_with("value type doesn't have value equals traits");
} }
@@ -218,7 +218,7 @@ namespace meta_hpp
.istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] uvalue& v) -> std::istream& { .istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] uvalue& v) -> std::istream& {
if constexpr ( detail::has_istream_traits<Tp> ) { if constexpr ( detail::has_istream_traits<Tp> ) {
return detail::istream_traits<Tp>{}(is, v.cast<Tp>()); return detail::istream_traits<Tp>{}(is, v.get_as_ref<Tp>());
} else { } else {
detail::throw_exception_with("value type doesn't have value istream traits"); detail::throw_exception_with("value type doesn't have value istream traits");
} }
@@ -226,7 +226,7 @@ namespace meta_hpp
.ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const uvalue& v) -> std::ostream& { .ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const uvalue& v) -> std::ostream& {
if constexpr ( detail::has_ostream_traits<Tp> ) { if constexpr ( detail::has_ostream_traits<Tp> ) {
return detail::ostream_traits<Tp>{}(os, v.cast<Tp>()); return detail::ostream_traits<Tp>{}(os, v.get_as_ref<Tp>());
} else { } else {
detail::throw_exception_with("value type doesn't have value ostream traits"); detail::throw_exception_with("value type doesn't have value ostream traits");
} }
@@ -327,85 +327,216 @@ namespace meta_hpp
} }
template < typename T > template < typename T >
std::decay_t<T>& uvalue::cast() & { T uvalue::get_as() & {
using Tp = std::decay_t<T>; return meta_hpp::get_as<T>(*this);
if ( Tp* ptr = try_cast<Tp>() ) {
return *ptr;
}
detail::throw_exception_with("bad value cast");
} }
template < typename T > template < typename T >
std::decay_t<T>&& uvalue::cast() && { T uvalue::get_as() && {
using Tp = std::decay_t<T>; return meta_hpp::get_as<T>(std::move(*this));
if ( Tp* ptr = try_cast<Tp>() ) {
return std::move(*ptr);
}
detail::throw_exception_with("bad value cast");
} }
template < typename T > template < typename T >
const std::decay_t<T>& uvalue::cast() const & { T uvalue::get_as() const & {
using Tp = std::decay_t<T>; return meta_hpp::get_as<T>(*this);
if ( const Tp* ptr = try_cast<const Tp>() ) {
return *ptr;
}
detail::throw_exception_with("bad value cast");
} }
template < typename T > template < typename T >
const std::decay_t<T>&& uvalue::cast() const && { T uvalue::get_as() const && {
using Tp = std::decay_t<T>; // NOLINTNEXTLINE(*-move-const-arg)
return meta_hpp::get_as<T>(std::move(*this));
if ( const Tp* ptr = try_cast<const Tp>() ) {
return std::move(*ptr);
}
detail::throw_exception_with("bad value cast");
} }
template < typename T > template < typename T >
std::decay_t<T>* uvalue::try_cast() noexcept { T& uvalue::get_as_ref() & {
using Tp = std::decay_t<T>; return meta_hpp::get_as_ref<T>(*this);
}
const any_type& from_type = get_type(); template < typename T >
T&& uvalue::get_as_ref() && {
return meta_hpp::get_as_ref<T>(std::move(*this));
}
template < typename T >
const T& uvalue::get_as_ref() const & {
return meta_hpp::get_as_ref<T>(*this);
}
template < typename T >
const T&& uvalue::get_as_ref() const && {
// NOLINTNEXTLINE(*-move-const-arg)
return meta_hpp::get_as_ref<T>(std::move(*this));
}
//
template < typename T >
bool uvalue::can_get_as() & {
return meta_hpp::can_get_as<T>(*this);
}
template < typename T >
bool uvalue::can_get_as() && {
return meta_hpp::can_get_as<T>(std::move(*this));
}
template < typename T >
bool uvalue::can_get_as() const & {
return meta_hpp::can_get_as<T>(*this);
}
template < typename T >
bool uvalue::can_get_as() const && {
// NOLINTNEXTLINE(*-move-const-arg)
return meta_hpp::can_get_as<T>(std::move(*this));
}
template < typename T >
bool uvalue::can_get_as_ref() & {
return meta_hpp::can_get_as_ref<T>(*this);
}
template < typename T >
bool uvalue::can_get_as_ref() && {
return meta_hpp::can_get_as_ref<T>(std::move(*this));
}
template < typename T >
bool uvalue::can_get_as_ref() const & {
return meta_hpp::can_get_as_ref<T>(*this);
}
template < typename T >
bool uvalue::can_get_as_ref() const && {
// NOLINTNEXTLINE(*-move-const-arg)
return meta_hpp::can_get_as_ref<T>(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<T>;
static_assert(std::is_constructible_v<T, detail::add_cvref_t<V&&, Tp>>);
const any_type& from_type = value.get_type();
const any_type& to_type = resolve_type<Tp>(); const any_type& to_type = resolve_type<Tp>();
if ( from_type == to_type ) { if ( from_type == to_type ) {
return static_cast<Tp*>(data()); using to_ptr_t = detail::add_cv_t<V, Tp>*;
auto to_ptr = static_cast<to_ptr_t>(value.data());
return static_cast<T>(*to_ptr);
} }
if ( from_type.is_class() && to_type.is_class() ) { const auto is_a = [](const any_type& base, const any_type& derived){
void* to_ptr = detail::pointer_upcast(data(), from_type.as_class(), to_type.as_class()); return (base == derived)
return static_cast<Tp*>(to_ptr); || (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();
using to_ptr_t = detail::add_cv_t<V, Tp>*;
auto to_ptr = static_cast<to_ptr_t>(detail::pointer_upcast(value.data(), from_class, to_class));
return static_cast<T>(*to_ptr);
} }
return nullptr; if constexpr ( std::is_pointer_v<T> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
return static_cast<T>(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 ) {
using from_data_ptr_t = detail::add_cv_t<V, void*>*;
auto from_data_ptr = static_cast<from_data_ptr_t>(value.data());
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
return static_cast<T>(*from_data_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<T>(to_ptr);
}
}
}
}
detail::throw_exception_with("bad value cast");
} }
template < typename T > template < typename T, detail::decay_value_kind V >
const std::decay_t<T>* uvalue::try_cast() const noexcept { [[nodiscard]] auto get_as_ref(V&& value) -> detail::add_cvref_t<V&&, T> {
using Tp = std::decay_t<T>; static_assert(!std::is_reference_v<T>);
return get_as<detail::add_cvref_t<V&&, T>>(std::forward<V>(value));
}
const any_type& from_type = get_type(); template < typename T, detail::decay_value_kind V >
[[nodiscard]] bool can_get_as(V&& value) noexcept {
using Tp = std::decay_t<T>;
static_assert(std::is_constructible_v<T, detail::add_cvref_t<V&&, Tp>>);
const any_type& from_type = value.get_type();
const any_type& to_type = resolve_type<Tp>(); const any_type& to_type = resolve_type<Tp>();
if ( from_type == to_type ) { if ( from_type == to_type ) {
return static_cast<const Tp*>(data()); return true;
} }
if ( from_type.is_class() && to_type.is_class() ) { const auto is_a = [](const any_type& base, const any_type& derived){
const void* to_ptr = detail::pointer_upcast(data(), from_type.as_class(), to_type.as_class()); return (base == derived)
return static_cast<const Tp*>(to_ptr); || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
};
if ( is_a(to_type, from_type) ) {
return true;
} }
return nullptr; if constexpr ( std::is_pointer_v<T> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
return true;
}
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 ) {
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
return true;
}
}
}
}
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<T>);
return can_get_as<detail::add_cvref_t<V&&, T>>(std::forward<V>(value));
} }
} }
@@ -420,7 +551,7 @@ namespace meta_hpp
const any_type& l_type = l.get_type(); const any_type& l_type = l.get_type();
const any_type& r_type = resolve_type<T>(); const any_type& r_type = resolve_type<T>();
return (l_type < r_type) || (l_type == r_type && l.cast<T>() < r); return (l_type < r_type) || (l_type == r_type && l.get_as_ref<T>() < r);
} }
template < typename T > template < typename T >
@@ -432,7 +563,7 @@ namespace meta_hpp
const any_type& l_type = resolve_type<T>(); const any_type& l_type = resolve_type<T>();
const any_type& r_type = r.get_type(); const any_type& r_type = r.get_type();
return (l_type < r_type) || (l_type == r_type && l < r.cast<T>()); return (l_type < r_type) || (l_type == r_type && l < r.get_as_ref<T>());
} }
[[nodiscard]] inline bool operator<(const uvalue& l, const uvalue& r) { [[nodiscard]] inline bool operator<(const uvalue& l, const uvalue& r) {
@@ -462,7 +593,7 @@ namespace meta_hpp
const any_type& l_type = l.get_type(); const any_type& l_type = l.get_type();
const any_type& r_type = resolve_type<T>(); const any_type& r_type = resolve_type<T>();
return l_type == r_type && l.cast<T>() == r; return l_type == r_type && l.get_as_ref<T>() == r;
} }
template < typename T > template < typename T >
@@ -474,7 +605,7 @@ namespace meta_hpp
const any_type& l_type = resolve_type<T>(); const any_type& l_type = resolve_type<T>();
const any_type& r_type = r.get_type(); const any_type& r_type = r.get_type();
return l_type == r_type && l == r.cast<T>(); return l_type == r_type && l == r.get_as_ref<T>();
} }
[[nodiscard]] inline bool operator==(const uvalue& l, const uvalue& r) { [[nodiscard]] inline bool operator==(const uvalue& l, const uvalue& r) {

View File

@@ -253,7 +253,7 @@ TEST_CASE("meta/meta_features/diamond") {
CHECK_FALSE(a_inst.can_cast_to<D&>()); CHECK_FALSE(a_inst.can_cast_to<D&>());
CHECK_FALSE(a_inst.can_cast_to<E&>()); CHECK_FALSE(a_inst.can_cast_to<E&>());
CHECK(&a_inst.cast<A&>() == a_val.try_cast<A>()); CHECK(&a_inst.cast<A&>() == &a_val.get_as_ref<A>());
} }
{ {
meta::uvalue b_val{B{}}; meta::uvalue b_val{B{}};
@@ -265,10 +265,10 @@ TEST_CASE("meta/meta_features/diamond") {
CHECK_FALSE(b_inst.can_cast_to<D&>()); CHECK_FALSE(b_inst.can_cast_to<D&>());
CHECK_FALSE(b_inst.can_cast_to<E&>()); CHECK_FALSE(b_inst.can_cast_to<E&>());
CHECK(&b_inst.cast<A&>() == b_val.try_cast<B>()); CHECK(&b_inst.cast<A&>() == &b_val.get_as_ref<B>());
CHECK(&b_inst.cast<B&>() == b_val.try_cast<B>()); CHECK(&b_inst.cast<B&>() == &b_val.get_as_ref<B>());
CHECK(&b_inst.cast<A&>() == b_val.try_cast<B>()); CHECK(&b_inst.cast<A&>() == &b_val.get_as_ref<B>());
} }
{ {
meta::uvalue c_val{C{}}; meta::uvalue c_val{C{}};
@@ -280,8 +280,8 @@ TEST_CASE("meta/meta_features/diamond") {
CHECK_FALSE(c_inst.can_cast_to<D&>()); CHECK_FALSE(c_inst.can_cast_to<D&>());
CHECK_FALSE(c_inst.can_cast_to<E&>()); CHECK_FALSE(c_inst.can_cast_to<E&>());
CHECK(&c_inst.cast<A&>() == c_val.try_cast<C>()); CHECK(&c_inst.cast<A&>() == &c_val.get_as_ref<C>());
CHECK(&c_inst.cast<C&>() == c_val.try_cast<C>()); CHECK(&c_inst.cast<C&>() == &c_val.get_as_ref<C>());
} }
{ {
meta::uvalue d_val{D{}}; meta::uvalue d_val{D{}};
@@ -293,15 +293,15 @@ TEST_CASE("meta/meta_features/diamond") {
CHECK(d_inst.can_cast_to<D&>()); CHECK(d_inst.can_cast_to<D&>());
CHECK_FALSE(d_inst.can_cast_to<E&>()); CHECK_FALSE(d_inst.can_cast_to<E&>());
CHECK(&d_inst.cast<A&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<A&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<B&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<B&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<C&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<C&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<D&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<D&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<A&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<A&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<B&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<B&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<C&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<C&>() == &d_val.get_as_ref<D>());
CHECK(&d_inst.cast<D&>() == d_val.try_cast<D>()); CHECK(&d_inst.cast<D&>() == &d_val.get_as_ref<D>());
} }
{ {
meta::uvalue e_val{E{}}; meta::uvalue e_val{E{}};
@@ -313,7 +313,7 @@ TEST_CASE("meta/meta_features/diamond") {
CHECK_FALSE(e_inst.can_cast_to<D&>()); CHECK_FALSE(e_inst.can_cast_to<D&>());
CHECK(e_inst.can_cast_to<E&>()); CHECK(e_inst.can_cast_to<E&>());
CHECK(&e_inst.cast<E&>() == e_val.try_cast<E>()); CHECK(&e_inst.cast<E&>() == &e_val.get_as_ref<E>());
} }
} }

View File

@@ -92,7 +92,7 @@ TEST_CASE("meta/meta_states/ctor") {
CHECK_FALSE(clazz_type.create(10, 20)); CHECK_FALSE(clazz_type.create(10, 20));
const meta::uvalue v = clazz_type.create(10); const meta::uvalue v = clazz_type.create(10);
CHECK(v.get_type() == meta::resolve_type<clazz<1>>()); CHECK(v.get_type() == meta::resolve_type<clazz<1>>());
CHECK(v.cast<clazz<1>>().i == 10); CHECK(v.get_as_ref<clazz<1>>().i == 10);
CHECK(clazz_type.destroy(nullptr)); CHECK(clazz_type.destroy(nullptr));
CHECK(clazz_type.destroy(meta::uvalue{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)); CHECK_FALSE(clazz_type.create(10, 20));
const meta::uvalue v = clazz_type.create(20); const meta::uvalue v = clazz_type.create(20);
CHECK(v.get_type() == meta::resolve_type<clazz<2>*>()); CHECK(v.get_type() == meta::resolve_type<clazz<2>*>());
CHECK(v.cast<clazz<2>*>()->i == 20); CHECK(v.get_as_ref<clazz<2>*>()->i == 20);
CHECK(clazz_type.destroy(v)); CHECK(clazz_type.destroy(v));
CHECK(clazz_type.destroy(nullptr)); CHECK(clazz_type.destroy(nullptr));
@@ -133,7 +133,7 @@ TEST_CASE("meta/meta_states/ctor") {
CHECK_FALSE(clazz_type.create(10, 20)); CHECK_FALSE(clazz_type.create(10, 20));
const meta::uvalue v = clazz_type.create(30); const meta::uvalue v = clazz_type.create(30);
CHECK(v.get_type() == meta::resolve_type<std::shared_ptr<clazz<3>>>()); CHECK(v.get_type() == meta::resolve_type<std::shared_ptr<clazz<3>>>());
CHECK(v.cast<std::shared_ptr<clazz<3>>>()->i == 30); CHECK(v.get_as_ref<std::shared_ptr<clazz<3>>>()->i == 30);
CHECK(clazz_type.destroy(nullptr)); CHECK(clazz_type.destroy(nullptr));
CHECK(clazz_type.destroy(meta::uvalue{nullptr})); CHECK(clazz_type.destroy(meta::uvalue{nullptr}));

View File

@@ -247,14 +247,14 @@ TEST_CASE("meta/meta_states/member") {
clazz_1 v; clazz_1 v;
using ref_t = std::reference_wrapper<std::unique_ptr<int>>; using ref_t = std::reference_wrapper<std::unique_ptr<int>>;
CHECK(vm.get(v).get_type() == meta::resolve_type<ref_t>()); CHECK(vm.get(v).get_type() == meta::resolve_type<ref_t>());
CHECK(vm.get(v).try_cast<ref_t>()->get() == v.unique_int_member); CHECK(vm.get(v).get_as_ref<ref_t>().get() == v.unique_int_member);
} }
{ {
const clazz_1 v; const clazz_1 v;
using ref_t = std::reference_wrapper<const std::unique_ptr<int>>; using ref_t = std::reference_wrapper<const std::unique_ptr<int>>;
CHECK(vm.get(v).get_type() == meta::resolve_type<ref_t>()); CHECK(vm.get(v).get_type() == meta::resolve_type<ref_t>());
CHECK(vm.get(v).try_cast<ref_t>()->get() == v.unique_int_member); CHECK(vm.get(v).get_as_ref<ref_t>().get() == v.unique_int_member);
} }
} }
} }

View File

@@ -186,7 +186,7 @@ TEST_CASE("meta/meta_states/variable") {
using ref_t = std::reference_wrapper<std::unique_ptr<int>>; using ref_t = std::reference_wrapper<std::unique_ptr<int>>;
CHECK(vm.get().get_type() == meta::resolve_type<ref_t>()); CHECK(vm.get().get_type() == meta::resolve_type<ref_t>());
CHECK(vm.get().try_cast<ref_t>()->get() == clazz_1::unique_int_variable); CHECK(vm.get().get_as_ref<ref_t>().get() == clazz_1::unique_int_variable);
{ {
auto nv = std::make_unique<int>(13); auto nv = std::make_unique<int>(13);
@@ -222,7 +222,7 @@ TEST_CASE("meta/meta_states/variable") {
using ref_t = std::reference_wrapper<const std::unique_ptr<int>>; using ref_t = std::reference_wrapper<const std::unique_ptr<int>>;
CHECK(vm.get().get_type() == meta::resolve_type<ref_t>()); CHECK(vm.get().get_type() == meta::resolve_type<ref_t>());
CHECK(vm.get().try_cast<ref_t>()->get() == clazz_1::const_unique_int_variable); CHECK(vm.get().get_as_ref<ref_t>().get() == clazz_1::const_unique_int_variable);
{ {
auto nv = std::make_unique<int>(12); auto nv = std::make_unique<int>(12);

View File

@@ -154,7 +154,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/small") {
meta::uvalue v2{std::move(v1)}; meta::uvalue v2{std::move(v1)};
CHECK_FALSE(v1); CHECK_FALSE(v1);
CHECK(v2.cast<ivec2>().x == 1); CHECK(v2.get_as_ref<ivec2>().x == 1);
CHECK(ivec2::destructor_counter == 2); CHECK(ivec2::destructor_counter == 2);
CHECK(ivec2::move_constructor_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 v1{ivec2{1,2}};
meta::uvalue v2{std::as_const(v1)}; meta::uvalue v2{std::as_const(v1)};
CHECK(v1.cast<ivec2>().x == 1); CHECK(v1.get_as_ref<ivec2>().x == 1);
CHECK(v2.cast<ivec2>().y == 2); CHECK(v2.get_as_ref<ivec2>().y == 2);
CHECK(ivec2::destructor_counter == 1); CHECK(ivec2::destructor_counter == 1);
CHECK(ivec2::move_constructor_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); CHECK(ivec2::copy_constructor_counter == 0);
v1.swap(v2); v1.swap(v2);
CHECK(v1.cast<ivec2>().x == 3); CHECK(v1.get_as_ref<ivec2>().x == 3);
CHECK(v2.cast<ivec2>().x == 1); CHECK(v2.get_as_ref<ivec2>().x == 1);
CHECK(ivec2::destructor_counter == 5); CHECK(ivec2::destructor_counter == 5);
CHECK(ivec2::move_constructor_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)}; meta::uvalue v2{std::move(v1)};
CHECK_FALSE(v1); CHECK_FALSE(v1);
CHECK(v2.cast<ivec2_big>().x == 1); CHECK(v2.get_as_ref<ivec2_big>().x == 1);
CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::destructor_counter == 1);
CHECK(ivec2_big::move_constructor_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 v1{ivec2_big{1,2}};
meta::uvalue v2{std::as_const(v1)}; meta::uvalue v2{std::as_const(v1)};
CHECK(v1.cast<ivec2_big>().x == 1); CHECK(v1.get_as_ref<ivec2_big>().x == 1);
CHECK(v2.cast<ivec2_big>().y == 2); CHECK(v2.get_as_ref<ivec2_big>().y == 2);
CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::destructor_counter == 1);
CHECK(ivec2_big::move_constructor_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); CHECK(ivec2_big::copy_constructor_counter == 0);
v1.swap(v2); v1.swap(v2);
CHECK(v1.cast<ivec2_big>().x == 3); CHECK(v1.get_as_ref<ivec2_big>().x == 3);
CHECK(v2.cast<ivec2_big>().x == 1); CHECK(v2.get_as_ref<ivec2_big>().x == 1);
CHECK(ivec2_big::destructor_counter == 2); CHECK(ivec2_big::destructor_counter == 2);
CHECK(ivec2_big::move_constructor_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); CHECK(ivec2::copy_constructor_counter == 0);
v1.swap(v2); v1.swap(v2);
CHECK(v1.cast<ivec2>().x == 1); CHECK(v1.get_as_ref<ivec2>().x == 1);
CHECK_FALSE(v2); CHECK_FALSE(v2);
CHECK(ivec2::destructor_counter == 2); CHECK(ivec2::destructor_counter == 2);
@@ -321,7 +321,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") {
v1.swap(v2); v1.swap(v2);
CHECK_FALSE(v1); CHECK_FALSE(v1);
CHECK(v2.cast<ivec2>().y == 2); CHECK(v2.get_as_ref<ivec2>().y == 2);
CHECK(ivec2::destructor_counter == 3); CHECK(ivec2::destructor_counter == 3);
CHECK(ivec2::move_constructor_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); CHECK(ivec2_big::copy_constructor_counter == 0);
v1.swap(v2); v1.swap(v2);
CHECK(v1.cast<ivec2_big>().x == 3); CHECK(v1.get_as_ref<ivec2_big>().x == 3);
CHECK_FALSE(v2); CHECK_FALSE(v2);
CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::destructor_counter == 1);
@@ -352,7 +352,7 @@ TEST_CASE("meta/meta_utilities/value2/counters/swap") {
v1.swap(v2); v1.swap(v2);
CHECK_FALSE(v1); CHECK_FALSE(v1);
CHECK(v2.cast<ivec2_big>().y == 4); CHECK(v2.get_as_ref<ivec2_big>().y == 4);
CHECK(ivec2_big::destructor_counter == 1); CHECK(ivec2_big::destructor_counter == 1);
CHECK(ivec2_big::move_constructor_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); CHECK(ivec2_big::copy_constructor_counter == 0);
v1.swap(v2); v1.swap(v2);
CHECK(v1.cast<ivec2_big>().x == 3); CHECK(v1.get_as_ref<ivec2_big>().x == 3);
CHECK(v2.cast<ivec2>().x == 1); CHECK(v2.get_as_ref<ivec2>().x == 1);
CHECK(ivec2::destructor_counter == 2); CHECK(ivec2::destructor_counter == 2);
CHECK(ivec2::move_constructor_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); CHECK(ivec2_big::copy_constructor_counter == 0);
v1.swap(v2); v1.swap(v2);
CHECK(v1.cast<ivec2>().y == 2); CHECK(v1.get_as_ref<ivec2>().y == 2);
CHECK(v2.cast<ivec2_big>().y == 4); CHECK(v2.get_as_ref<ivec2_big>().y == 4);
CHECK(ivec2::destructor_counter == 3); CHECK(ivec2::destructor_counter == 3);
CHECK(ivec2::move_constructor_counter == 3); CHECK(ivec2::move_constructor_counter == 3);

View File

@@ -1,92 +0,0 @@
/*******************************************************************************
* 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_untests.hpp"
namespace
{
struct base0 {
int i{21};
};
struct base1 : virtual base0 {
int j{42};
};
struct base2 : virtual base0 {
int k{84};
};
struct derived : base1, base2 {
int l{168};
};
}
TEST_CASE("meta/meta_utilities/value3") {
namespace meta = meta_hpp;
meta::class_<base0>();
meta::class_<base1>()
.base_<base0>();
meta::class_<base2>()
.base_<base0>();
meta::class_<derived>()
.base_<base1>()
.base_<base2>();
}
TEST_CASE("meta/meta_utilities/value3/cast") {
namespace meta = meta_hpp;
SUBCASE("derived") {
{
meta::uvalue v{derived{}};
CHECK(v.get_type() == meta::resolve_type<derived>());
CHECK(v.cast<base0>().i == 21);
CHECK(v.cast<base1>().j == 42);
CHECK(v.cast<base2>().k == 84);
CHECK(v.cast<derived>().l == 168);
}
{
const meta::uvalue v{derived{}};
CHECK(v.get_type() == meta::resolve_type<derived>());
CHECK(v.cast<base0>().i == 21);
CHECK(v.cast<base1>().j == 42);
CHECK(v.cast<base2>().k == 84);
CHECK(v.cast<derived>().l == 168);
}
}
}
TEST_CASE("meta/meta_utilities/value3/try_cast") {
namespace meta = meta_hpp;
SUBCASE("derived") {
{
meta::uvalue v{derived{}};
CHECK(v.get_type() == meta::resolve_type<derived>());
CHECK((v.try_cast<base0>() && v.try_cast<base0>()->i == 21));
CHECK((v.try_cast<base1>() && v.try_cast<base1>()->j == 42));
CHECK((v.try_cast<base2>() && v.try_cast<base2>()->k == 84));
CHECK((v.try_cast<derived>() && v.try_cast<derived>()->l == 168));
}
{
const meta::uvalue v{derived{}};
CHECK(v.get_type() == meta::resolve_type<derived>());
CHECK((v.try_cast<base0>() && v.try_cast<base0>()->i == 21));
CHECK((v.try_cast<base1>() && v.try_cast<base1>()->j == 42));
CHECK((v.try_cast<base2>() && v.try_cast<base2>()->k == 84));
CHECK((v.try_cast<derived>() && v.try_cast<derived>()->l == 168));
}
}
}

View File

@@ -0,0 +1,370 @@
/*******************************************************************************
* 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_untests.hpp"
namespace
{
struct base0 {
int i{21};
};
struct base1 : virtual base0 {
int j{42};
};
struct base2 : virtual base0 {
int k{84};
};
struct derived : base1, base2 {
int l{168};
};
struct derived2 : base1, base2 {
int m{336};
};
}
TEST_CASE("meta/meta_utilities/value4") {
namespace meta = meta_hpp;
meta::class_<base0>();
meta::class_<base1>()
.base_<base0>();
meta::class_<base2>()
.base_<base0>();
meta::class_<derived>()
.base_<base1>()
.base_<base2>();
meta::class_<derived2>()
.base_<base1>()
.base_<base2>();
}
TEST_CASE("meta/meta_utilities/value4/get_type") {
namespace meta = meta_hpp;
SUBCASE("from ref") {
{
derived d{};
CHECK(meta::uvalue{d}.get_type() == meta::resolve_type<derived>());
}
{
const derived d{};
CHECK(meta::uvalue{d}.get_type() == meta::resolve_type<derived>());
}
{
derived d{};
CHECK(meta::uvalue{std::move(d)}.get_type() == meta::resolve_type<derived>());
}
{
const derived d{};
CHECK(meta::uvalue{std::move(d)}.get_type() == meta::resolve_type<derived>());
}
}
SUBCASE("from ptr") {
{
derived d{};
derived* pd = &d;
CHECK(meta::uvalue{pd}.get_type() == meta::resolve_type<derived*>());
}
{
derived d{};
derived* const pd = &d;
CHECK(meta::uvalue{pd}.get_type() == meta::resolve_type<derived*>());
}
{
derived d{};
const derived* pd = &d;
CHECK(meta::uvalue{pd}.get_type() == meta::resolve_type<const derived*>());
}
{
derived d{};
const derived* const pd = &d;
CHECK(meta::uvalue{pd}.get_type() == meta::resolve_type<const derived*>());
}
}
}
TEST_CASE("meta/meta_utilities/value4/get_as_ref") {
namespace meta = meta_hpp;
static_assert(std::is_same_v<decltype(get_as_ref<derived>(std::declval<meta::uvalue&>())), derived&>);
static_assert(std::is_same_v<decltype(get_as_ref<derived>(std::declval<meta::uvalue&&>())), derived&&>);
static_assert(std::is_same_v<decltype(get_as_ref<derived>(std::declval<const meta::uvalue&>())), const derived&>);
static_assert(std::is_same_v<decltype(get_as_ref<derived>(std::declval<const meta::uvalue&&>())), const derived&&>);
static_assert(std::is_same_v<decltype(get_as_ref<const derived>(std::declval<meta::uvalue&>())), const derived&>);
static_assert(std::is_same_v<decltype(get_as_ref<const derived>(std::declval<meta::uvalue&&>())), const derived&&>);
static_assert(std::is_same_v<decltype(get_as_ref<const derived>(std::declval<const meta::uvalue&>())), const derived&>);
static_assert(std::is_same_v<decltype(get_as_ref<const derived>(std::declval<const meta::uvalue&&>())), const derived&&>);
static_assert(std::is_same_v<decltype(get_as_ref<volatile derived>(std::declval<meta::uvalue&>())), volatile derived&>);
static_assert(std::is_same_v<decltype(get_as_ref<volatile derived>(std::declval<meta::uvalue&&>())), volatile derived&&>);
static_assert(std::is_same_v<decltype(get_as_ref<volatile derived>(std::declval<const meta::uvalue&>())), const volatile derived&>);
static_assert(std::is_same_v<decltype(get_as_ref<volatile derived>(std::declval<const meta::uvalue&&>())), const volatile derived&&>);
}
TEST_CASE("meta/meta_utilities/value4/get_as") {
namespace meta = meta_hpp;
static_assert(std::is_same_v<decltype(get_as<derived>(std::declval<meta::uvalue&>())), derived>);
static_assert(std::is_same_v<decltype(get_as<derived>(std::declval<meta::uvalue&&>())), derived>);
static_assert(std::is_same_v<decltype(get_as<derived>(std::declval<const meta::uvalue&>())), derived>);
static_assert(std::is_same_v<decltype(get_as<derived>(std::declval<const meta::uvalue&&>())), derived>);
static_assert(std::is_same_v<decltype(get_as<derived&>(std::declval<meta::uvalue&>())), derived&>);
static_assert(std::is_same_v<decltype(get_as<derived&>(std::declval<meta::uvalue&&>())), derived&>);
static_assert(std::is_same_v<decltype(get_as<derived&>(std::declval<const meta::uvalue&>())), derived&>);
static_assert(std::is_same_v<decltype(get_as<derived&>(std::declval<const meta::uvalue&&>())), derived&>);
static_assert(std::is_same_v<decltype(get_as<const derived&>(std::declval<meta::uvalue&>())), const derived&>);
static_assert(std::is_same_v<decltype(get_as<const derived&>(std::declval<meta::uvalue&&>())), const derived&>);
static_assert(std::is_same_v<decltype(get_as<const derived&>(std::declval<const meta::uvalue&>())), const derived&>);
static_assert(std::is_same_v<decltype(get_as<const derived&>(std::declval<const meta::uvalue&&>())), const derived&>);
SUBCASE("derived to derived") {
{
meta::uvalue v{derived{}};
CHECK(get_as<derived>(v).l == 168);
CHECK(get_as<derived&>(v).l == 168);
// CHECK(get_as<derived&&>(v).l == 168);
CHECK(get_as<const derived&>(v).l == 168);
// CHECK(get_as<const derived&&>(v).l == 168);
CHECK_THROWS(std::ignore = get_as<derived2>(v));
CHECK_THROWS(std::ignore = get_as<derived2&>(v));
CHECK_THROWS(std::ignore = get_as<const derived2&>(v));
}
{
meta::uvalue v{derived{}};
CHECK(get_as<derived>(std::move(v)).l == 168);
// CHECK(get_as<derived&>(std::move(v)).l == 168);
CHECK(get_as<derived&&>(std::move(v)).l == 168);
CHECK(get_as<const derived&>(std::move(v)).l == 168);
CHECK(get_as<const derived&&>(std::move(v)).l == 168);
CHECK_THROWS(std::ignore = get_as<derived2>(std::move(v)));
CHECK_THROWS(std::ignore = get_as<derived2&&>(std::move(v)));
CHECK_THROWS(std::ignore = get_as<const derived2&>(std::move(v)));
CHECK_THROWS(std::ignore = get_as<const derived2&&>(std::move(v)));
}
{
const meta::uvalue v{derived{}};
CHECK(get_as<derived>(v).l == 168);
// CHECK(get_as<derived&>(v).l == 168);
// CHECK(get_as<derived&&>(v).l == 168);
CHECK(get_as<const derived&>(v).l == 168);
// CHECK(get_as<const derived&&>(v).l == 168);
CHECK_THROWS(std::ignore = get_as<derived2>(v));
CHECK_THROWS(std::ignore = get_as<const derived2&>(v));
}
{
const meta::uvalue v{derived{}};
CHECK(get_as<derived>(std::move(v)).l == 168);
// CHECK(get_as<derived&>(std::move(v)).l == 168);
// CHECK(get_as<derived&&>(std::move(v)).l == 168);
CHECK(get_as<const derived&>(std::move(v)).l == 168);
CHECK(get_as<const derived&&>(std::move(v)).l == 168);
CHECK_THROWS(std::ignore = get_as<derived2>(std::move(v)));
CHECK_THROWS(std::ignore = get_as<const derived2&>(std::move(v)));
CHECK_THROWS(std::ignore = get_as<const derived2&&>(std::move(v)));
}
}
SUBCASE("derived to base") {
{
meta::uvalue v{derived{}};
CHECK(get_as<base2>(v).k == 84);
CHECK(get_as<base2&>(v).k == 84);
// CHECK(get_as<base2&&>(v).k == 84);
CHECK(get_as<const base2&>(v).k == 84);
// CHECK(get_as<const base2&&>(v).k == 84);
}
{
meta::uvalue v{derived{}};
CHECK(get_as<base2>(std::move(v)).k == 84);
// CHECK(get_as<base2&>(std::move(v)).k == 84);
CHECK(get_as<base2&&>(std::move(v)).k == 84);
CHECK(get_as<const base2&>(std::move(v)).k == 84);
CHECK(get_as<const base2&&>(std::move(v)).k == 84);
}
{
const meta::uvalue v{derived{}};
CHECK(get_as<base2>(v).k == 84);
// CHECK(get_as<base2&>(v).k == 84);
// CHECK(get_as<base2&&>(v).k == 84);
CHECK(get_as<const base2&>(v).k == 84);
// CHECK(get_as<const base2&&>(v).k == 84);
}
{
const meta::uvalue v{derived{}};
CHECK(get_as<base2>(std::move(v)).k == 84);
// CHECK(get_as<base2&>(std::move(v)).k == 84);
// CHECK(get_as<base2&&>(std::move(v)).k == 84);
CHECK(get_as<const base2&>(std::move(v)).k == 84);
CHECK(get_as<const base2&&>(std::move(v)).k == 84);
}
}
SUBCASE("voidptr") {
{
derived d{};
meta::uvalue v{&d};
CHECK(get_as<void*>(v) == &d);
CHECK(get_as<const void*>(v) == &d);
CHECK(get_as<void*>(std::move(v)) == &d);
CHECK(get_as<const void*>(std::move(v)) == &d);
}
{
const derived d{};
meta::uvalue v{&d};
CHECK_THROWS(std::ignore = get_as<void*>(v));
CHECK(get_as<const void*>(v) == &d);
CHECK_THROWS(std::ignore = get_as<void*>(std::move(v)));
CHECK(get_as<const void*>(std::move(v)) == &d);
}
}
SUBCASE("nullptr") {
{
meta::uvalue v{nullptr};
CHECK(get_as<void*>(v) == nullptr);
CHECK(get_as<const void*>(v) == nullptr);
CHECK(get_as<derived*>(v) == nullptr);
CHECK(get_as<const derived*>(v) == nullptr);
CHECK(get_as<void*>(std::move(v)) == nullptr);
CHECK(get_as<const void*>(std::move(v)) == nullptr);
CHECK(get_as<derived*>(std::move(v)) == nullptr);
CHECK(get_as<const derived*>(std::move(v)) == nullptr);
}
{
const meta::uvalue v{nullptr};
CHECK(get_as<void*>(v) == nullptr);
CHECK(get_as<const void*>(v) == nullptr);
CHECK(get_as<derived*>(v) == nullptr);
CHECK(get_as<const derived*>(v) == nullptr);
CHECK(get_as<void*>(std::move(v)) == nullptr);
CHECK(get_as<const void*>(std::move(v)) == nullptr);
CHECK(get_as<derived*>(std::move(v)) == nullptr);
CHECK(get_as<const derived*>(std::move(v)) == nullptr);
}
}
SUBCASE("derived* to derived*") {
{
derived d{};
meta::uvalue v{&d};
CHECK(get_as<derived*>(v)->l == 168);
CHECK(get_as<const derived*>(v)->l == 168);
CHECK_THROWS(std::ignore = get_as<derived2*>(v));
CHECK_THROWS(std::ignore = get_as<const derived2*>(v));
}
{
derived d{};
meta::uvalue v{&d};
CHECK(get_as<derived*>(std::move(v))->l == 168);
CHECK(get_as<const derived*>(std::move(v))->l == 168);
CHECK_THROWS(std::ignore = get_as<derived2*>(std::move(v)));
CHECK_THROWS(std::ignore = get_as<const derived2*>(std::move(v)));
}
{
const derived d{};
meta::uvalue v{&d};
CHECK(get_as<const derived*>(v)->l == 168);
CHECK_THROWS(std::ignore = get_as<const derived2*>(v));
}
{
const derived d{};
meta::uvalue v{&d};
CHECK(get_as<const derived*>(std::move(v))->l == 168);
CHECK_THROWS(std::ignore = get_as<const derived2*>(std::move(v)));
}
}
SUBCASE("derived* to base*") {
{
derived d{};
meta::uvalue v{&d};
CHECK(get_as<base2*>(v)->k == 84);
CHECK(get_as<const base2*>(v)->k == 84);
}
{
const derived d{};
meta::uvalue v{&d};
CHECK_THROWS(std::ignore = get_as<base2*>(v));
CHECK(get_as<const base2*>(v)->k == 84);
}
}
}
TEST_CASE("meta/meta_utilities/value4/can_get_as") {
namespace meta = meta_hpp;
SUBCASE("derived to derived") {
{
meta::uvalue v{derived{}};
CHECK(can_get_as<derived>(v));
CHECK(can_get_as<derived&>(v));
// CHECK_FALSE(can_get_as<derived&&>(v));
CHECK(can_get_as<const derived&>(v));
// CHECK_FALSE(can_get_as<const derived&&>(v));
CHECK_FALSE(can_get_as<derived2>(v));
CHECK_FALSE(can_get_as<derived2&>(v));
CHECK_FALSE(can_get_as<const derived2&>(v));
}
{
meta::uvalue v{derived{}};
CHECK(can_get_as<derived>(std::move(v)));
// CHECK_FALSE(can_get_as<derived&>(std::move(v)));
CHECK(can_get_as<derived&&>(std::move(v)));
CHECK(can_get_as<const derived&>(std::move(v)));
CHECK(can_get_as<const derived&&>(std::move(v)));
CHECK_FALSE(can_get_as<derived2>(std::move(v)));
CHECK_FALSE(can_get_as<derived2&&>(std::move(v)));
CHECK_FALSE(can_get_as<const derived2&>(std::move(v)));
CHECK_FALSE(can_get_as<const derived2&&>(std::move(v)));
}
{
const meta::uvalue v{derived{}};
CHECK(can_get_as<derived>(v));
// CHECK_FALSE(can_get_as<derived&>(v));
// CHECK_FALSE(can_get_as<derived&&>(v));
CHECK(can_get_as<const derived&>(v));
// CHECK_FALSE(can_get_as<const derived&&>(v));
CHECK_FALSE(can_get_as<derived2>(v));
CHECK_FALSE(can_get_as<const derived2&>(v));
}
{
const meta::uvalue v{derived{}};
CHECK(can_get_as<derived>(std::move(v)));
// CHECK_FALSE(can_get_as<derived&>(std::move(v)));
// CHECK_FALSE(can_get_as<derived&&>(std::move(v)));
CHECK(can_get_as<const derived&>(std::move(v)));
CHECK(can_get_as<const derived&&>(std::move(v)));
CHECK_FALSE(can_get_as<derived2>(std::move(v)));
CHECK_FALSE(can_get_as<const derived2&>(std::move(v)));
CHECK_FALSE(can_get_as<const derived2&&>(std::move(v)));
}
}
}

View File

@@ -105,28 +105,19 @@ TEST_CASE("meta/meta_utilities/value") {
SUBCASE("cast types") { SUBCASE("cast types") {
static_assert(std::is_same_v< static_assert(std::is_same_v<
decltype(std::declval<meta::uvalue&>().cast<ivec2>()), decltype(std::declval<meta::uvalue&>().get_as_ref<ivec2>()),
ivec2&>); ivec2&>);
static_assert(std::is_same_v< static_assert(std::is_same_v<
decltype(std::declval<meta::uvalue&&>().cast<ivec2>()), decltype(std::declval<meta::uvalue&&>().get_as_ref<ivec2>()),
ivec2&&>); ivec2&&>);
static_assert(std::is_same_v< static_assert(std::is_same_v<
decltype(std::declval<const meta::uvalue&>().cast<ivec2>()), decltype(std::declval<const meta::uvalue&>().get_as_ref<ivec2>()),
const ivec2&>); const ivec2&>);
static_assert(std::is_same_v< static_assert(std::is_same_v<
decltype(std::declval<const meta::uvalue&&>().cast<ivec2>()), decltype(std::declval<const meta::uvalue&&>().get_as_ref<ivec2>()),
const ivec2&&>); const ivec2&&>);
} }
SUBCASE("try_cast types") {
static_assert(std::is_same_v<
decltype(std::declval<meta::uvalue>().try_cast<ivec2>()),
ivec2*>);
static_assert(std::is_same_v<
decltype(std::declval<const meta::uvalue>().try_cast<ivec2>()),
const ivec2*>);
}
SUBCASE("ivec2{}") { SUBCASE("ivec2{}") {
{ {
meta::uvalue val{}; meta::uvalue val{};
@@ -142,13 +133,13 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK_FALSE(*val); CHECK_FALSE(*val);
CHECK_FALSE(val[0]); CHECK_FALSE(val[0]);
CHECK(val.try_cast<ivec2>() == nullptr); CHECK_FALSE(val.can_get_as_ref<ivec2>());
CHECK(std::as_const(val).try_cast<ivec2>() == nullptr); CHECK_FALSE(std::as_const(val).can_get_as_ref<ivec2>());
CHECK_THROWS(std::ignore = val.cast<int>()); CHECK_THROWS(std::ignore = val.get_as_ref<int>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<int>()); CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref<int>());
CHECK_THROWS(std::ignore = std::move(val).cast<int>()); CHECK_THROWS(std::ignore = std::move(val).get_as_ref<int>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<int>()); CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref<int>());
} }
{ {
@@ -204,20 +195,20 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val == ivec2{1,2}); CHECK(val == ivec2{1,2});
CHECK(val == meta::uvalue{ivec2{1,2}}); CHECK(val == meta::uvalue{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(std::as_const(val)).get_as_ref<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>()); CHECK_THROWS(std::ignore = val.get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr); CHECK_FALSE(val.can_get_as_ref<ivec3>());
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr); CHECK_FALSE(std::as_const(val).can_get_as_ref<ivec3>());
} }
SUBCASE("const ivec2&") { SUBCASE("const ivec2&") {
@@ -238,20 +229,20 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val == ivec2{1,2}); CHECK(val == ivec2{1,2});
CHECK(val == meta::uvalue{ivec2{1,2}}); CHECK(val == meta::uvalue{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(std::as_const(val)).get_as_ref<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>()); CHECK_THROWS(std::ignore = val.get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr); CHECK_FALSE(val.can_get_as_ref<ivec3>());
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr); CHECK_FALSE(std::as_const(val).can_get_as_ref<ivec3>());
} }
SUBCASE("ivec2&&") { SUBCASE("ivec2&&") {
@@ -266,20 +257,20 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val == ivec2{1,2}); CHECK(val == ivec2{1,2});
CHECK(val == meta::uvalue{ivec2{1,2}}); CHECK(val == meta::uvalue{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(std::as_const(val)).get_as_ref<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>()); CHECK_THROWS(std::ignore = val.get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr); CHECK_FALSE(val.can_get_as_ref<ivec3>());
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr); CHECK_FALSE(std::as_const(val).can_get_as_ref<ivec3>());
} }
SUBCASE("const ivec2&&") { SUBCASE("const ivec2&&") {
@@ -294,20 +285,20 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(val == ivec2{1,2}); CHECK(val == ivec2{1,2});
CHECK(val == meta::uvalue{ivec2{1,2}}); CHECK(val == meta::uvalue{ivec2{1,2}});
CHECK(val.cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::as_const(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(val).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(std::move(std::as_const(val)).cast<ivec2>() == ivec2{1,2}); CHECK(std::move(std::as_const(val)).get_as_ref<ivec2>() == ivec2{1,2});
CHECK_THROWS(std::ignore = val.cast<ivec3>()); CHECK_THROWS(std::ignore = val.get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::as_const(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::as_const(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(val).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(val).get_as_ref<ivec3>());
CHECK_THROWS(std::ignore = std::move(std::as_const(val)).cast<ivec3>()); CHECK_THROWS(std::ignore = std::move(std::as_const(val)).get_as_ref<ivec3>());
CHECK(*val.try_cast<ivec2>() == ivec2{1,2}); CHECK(val.get_as_ref<ivec2>() == ivec2{1,2});
CHECK(*std::as_const(val).try_cast<ivec2>() == ivec2{1,2}); CHECK(std::as_const(val).get_as_ref<ivec2>() == ivec2{1,2});
CHECK(val.try_cast<ivec3>() == nullptr); CHECK_FALSE(val.can_get_as_ref<ivec3>());
CHECK(std::as_const(val).try_cast<ivec3>() == nullptr); CHECK_FALSE(std::as_const(val).can_get_as_ref<ivec3>());
} }
SUBCASE("value(value&&)") { SUBCASE("value(value&&)") {
@@ -482,7 +473,7 @@ TEST_CASE("meta/meta_utilities/value") {
const int* const pi = &i; const int* const pi = &i;
const meta::uvalue v{*meta::uvalue{&pi}}; const meta::uvalue v{*meta::uvalue{&pi}};
CHECK(v.get_type() == meta::resolve_type<const int*>() ); CHECK(v.get_type() == meta::resolve_type<const int*>() );
CHECK(v.cast<const int*>() == pi); CHECK(v.get_as_ref<const int*>() == pi);
} }
{ {
int i{42}; int i{42};
@@ -584,8 +575,7 @@ TEST_CASE("meta/meta_utilities/value/functions") {
{ {
const meta::uvalue v{&ivec2::add}; const meta::uvalue v{&ivec2::add};
CHECK(v.get_type() == meta::resolve_type<ivec2&(ivec2::*)(const ivec2&)>()); CHECK(v.get_type() == meta::resolve_type<ivec2&(ivec2::*)(const ivec2&)>());
CHECK((ivec2{1,2}.*(v.cast<decltype(&ivec2::add)>()))(ivec2{3,4}) == ivec2(4,6)); CHECK((ivec2{1,2}.*(v.get_as_ref<decltype(&ivec2::add)>()))(ivec2{3,4}) == ivec2(4,6));
CHECK((ivec2{1,2}.*(*v.try_cast<decltype(&ivec2::add)>()))(ivec2{3,4}) == ivec2(4,6));
} }
} }
@@ -593,14 +583,12 @@ TEST_CASE("meta/meta_utilities/value/functions") {
{ {
const meta::uvalue v{iadd2}; const meta::uvalue v{iadd2};
CHECK(v.get_type() == meta::resolve_type<ivec2(*)(ivec2, ivec2)>()); 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((v.get_as_ref<decltype(&iadd2)>())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
CHECK((*v.try_cast<decltype(iadd2)>())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
} }
{ {
const meta::uvalue v{&iadd2}; const meta::uvalue v{&iadd2};
CHECK(v.get_type() == meta::resolve_type<ivec2(*)(ivec2, ivec2)>()); 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((v.get_as_ref<decltype(&iadd2)>())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
CHECK((*v.try_cast<decltype(&iadd2)>())(ivec2{1,2}, ivec2{3,4}) == ivec2{4,6});
} }
} }
} }