mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-13 11:17:06 +07:00
@@ -5,7 +5,8 @@ target_compile_options(${PROJECT_NAME}.setup_targets INTERFACE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:
|
||||
/WX /W4 /bigobj>
|
||||
$<$<CXX_COMPILER_ID:GNU>:
|
||||
-Werror -Wall -Wextra -Wpedantic>
|
||||
-Werror -Wall -Wextra -Wpedantic
|
||||
-Wno-inaccessible-base>
|
||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
|
||||
-Werror -Weverything -Wconversion
|
||||
-Wno-c++98-compat
|
||||
@@ -30,3 +31,6 @@ target_link_libraries(${PROJECT_NAME}.setup_targets INTERFACE
|
||||
meta.hpp::disable_exceptions>
|
||||
$<$<BOOL:${BUILD_WITH_NO_RTTI}>:
|
||||
meta.hpp::disable_rtti>)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME}.setup_targets INTERFACE
|
||||
$<$<BOOL:${BUILD_WITH_SANITIZERS}>:META_HPP_SANITIZERS>)
|
||||
|
||||
@@ -52,6 +52,12 @@
|
||||
# define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_SANITIZERS)
|
||||
# define META_HPP_DEV_ASSERT(...) META_HPP_ASSERT(__VA_ARGS__)
|
||||
#else
|
||||
# define META_HPP_DEV_ASSERT(...) (void)0
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_PP_CAT)
|
||||
# define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y)
|
||||
# define META_HPP_PP_CAT_I(x, y) x##y
|
||||
@@ -302,42 +308,42 @@ namespace meta_hpp::detail
|
||||
using copy_cvref_t = typename copy_cvref<From, To>::type;
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail::impl
|
||||
{
|
||||
template < typename F, typename... Args >
|
||||
class defer_impl {
|
||||
public:
|
||||
defer_impl() = delete;
|
||||
defer_impl(defer_impl&&) = delete;
|
||||
defer_impl(const defer_impl&) = delete;
|
||||
defer_impl& operator=(defer_impl&&) = delete;
|
||||
defer_impl& operator=(const defer_impl&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit defer_impl(UF&& f, std::tuple<Args...>&& args)
|
||||
: f_{std::forward<UF>(f)}
|
||||
, args_{std::move(args)} {}
|
||||
|
||||
void dismiss() noexcept {
|
||||
dismissed_ = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
~defer_impl() noexcept {
|
||||
if ( !dismissed_ ) {
|
||||
std::apply(std::move(f_), std::move(args_));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
std::tuple<Args...> args_;
|
||||
bool dismissed_{};
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
template < typename F, typename... Args >
|
||||
class defer_impl {
|
||||
public:
|
||||
defer_impl() = delete;
|
||||
defer_impl(defer_impl&&) = delete;
|
||||
defer_impl(const defer_impl&) = delete;
|
||||
defer_impl& operator=(defer_impl&&) = delete;
|
||||
defer_impl& operator=(const defer_impl&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit defer_impl(UF&& f, std::tuple<Args...>&& args)
|
||||
: f_{std::forward<UF>(f)}
|
||||
, args_{std::move(args)} {}
|
||||
|
||||
void dismiss() noexcept {
|
||||
dismissed_ = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
~defer_impl() noexcept {
|
||||
if ( !dismissed_ ) {
|
||||
std::apply(std::move(f_), std::move(args_));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
std::tuple<Args...> args_;
|
||||
bool dismissed_{};
|
||||
};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
@@ -634,15 +640,15 @@ namespace meta_hpp::detail
|
||||
|
||||
static vtable_t table{
|
||||
.call{[](const fixed_function& self, Args... args) -> R {
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
const Fp& src = *buffer_cast<Fp>(self.buffer_);
|
||||
return std::invoke(src, std::forward<Args>(args)...);
|
||||
}},
|
||||
|
||||
.move{[](fixed_function& from, fixed_function& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_ASSERT(from);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(from);
|
||||
|
||||
Fp& src = *buffer_cast<Fp>(from.buffer_);
|
||||
std::construct_at(buffer_cast<Fp>(to.buffer_), std::move(src));
|
||||
@@ -653,7 +659,7 @@ namespace meta_hpp::detail
|
||||
}},
|
||||
|
||||
.destroy{[](fixed_function& self) {
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
Fp& src = *buffer_cast<Fp>(self.buffer_);
|
||||
std::destroy_at(&src);
|
||||
@@ -666,7 +672,7 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename F, typename Fp = std::decay_t<F> >
|
||||
static void construct(fixed_function& dst, F&& fun) {
|
||||
META_HPP_ASSERT(!dst);
|
||||
META_HPP_DEV_ASSERT(!dst);
|
||||
|
||||
static_assert(sizeof(Fp) <= sizeof(buffer_t));
|
||||
static_assert(alignof(buffer_t) % alignof(Fp) == 0);
|
||||
@@ -1162,6 +1168,32 @@ namespace std
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename SortedContainerL, typename SortedContainerR, typename Compare >
|
||||
bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r, Compare compare) {
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
for ( auto iter_l{begin(l)}, iter_r{begin(r)}; iter_l != end(l) && iter_r != end(r); ) {
|
||||
if ( compare(*iter_l, *iter_r) ) {
|
||||
++iter_l;
|
||||
} else if ( compare(*iter_r, *iter_l) ) {
|
||||
++iter_r;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename SortedContainerL, typename SortedContainerR >
|
||||
bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r) {
|
||||
return is_disjoint(l, r, std::less<>{});
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename T >
|
||||
@@ -1174,6 +1206,38 @@ namespace meta_hpp::detail
|
||||
inline constexpr bool is_in_place_type_v = is_in_place_type<T>::value;
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
template < typename From, typename To >
|
||||
constexpr bool is_virtual_base_of_impl(...) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename From,
|
||||
typename To,
|
||||
decltype(static_cast<const volatile To*>(std::declval<const volatile From*>())) = nullptr >
|
||||
constexpr bool is_virtual_base_of_impl(int) noexcept {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
template < typename Base, typename Derived >
|
||||
struct is_virtual_base_of : std::integral_constant<bool,
|
||||
std::is_base_of_v<Base, Derived> &&
|
||||
impl::is_virtual_base_of_impl<Derived, Base>(0) &&
|
||||
!impl::is_virtual_base_of_impl<Base, Derived>(0)> {};
|
||||
|
||||
// clang-format on
|
||||
|
||||
template < typename Base, typename Derived >
|
||||
inline constexpr bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
class memory_buffer final {
|
||||
@@ -1813,7 +1877,7 @@ namespace meta_hpp::detail
|
||||
namespace impl
|
||||
{
|
||||
template < class_kind Class >
|
||||
struct class_traits_base {
|
||||
struct class_traits_impl {
|
||||
static constexpr std::size_t arity{0};
|
||||
|
||||
using argument_types = type_list<>;
|
||||
@@ -1824,7 +1888,7 @@ namespace meta_hpp::detail
|
||||
};
|
||||
|
||||
template < template < typename... > typename Class, typename... Args >
|
||||
struct class_traits_base<Class<Args...>> {
|
||||
struct class_traits_impl<Class<Args...>> {
|
||||
static constexpr std::size_t arity{sizeof...(Args)};
|
||||
|
||||
using argument_types = type_list<Args...>;
|
||||
@@ -1836,7 +1900,7 @@ namespace meta_hpp::detail
|
||||
}
|
||||
|
||||
template < class_kind Class >
|
||||
struct class_traits : impl::class_traits_base<Class> {
|
||||
struct class_traits : impl::class_traits_impl<Class> {
|
||||
static constexpr std::size_t size{sizeof(Class)};
|
||||
static constexpr std::size_t align{alignof(Class)};
|
||||
|
||||
@@ -1859,7 +1923,7 @@ namespace meta_hpp::detail
|
||||
flags.set(class_flags::is_polymorphic);
|
||||
}
|
||||
|
||||
return flags | impl::class_traits_base<Class>::make_flags();
|
||||
return flags | impl::class_traits_impl<Class>::make_flags();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -2532,10 +2596,26 @@ namespace meta_hpp
|
||||
[[nodiscard]] bool is_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
[[nodiscard]] bool is_direct_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
[[nodiscard]] bool is_virtual_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_virtual_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_direct_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_virtual_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_virtual_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
[[nodiscard]] function get_function(std::string_view name) const noexcept;
|
||||
[[nodiscard]] member get_member(std::string_view name) const noexcept;
|
||||
[[nodiscard]] method get_method(std::string_view name) const noexcept;
|
||||
@@ -2754,11 +2834,39 @@ namespace meta_hpp::detail
|
||||
typedef_map typedefs;
|
||||
variable_set variables;
|
||||
|
||||
using upcast_func_t = void* (*)(void*);
|
||||
using upcast_func_list_t = std::vector<upcast_func_t>;
|
||||
struct upcast_func_t final {
|
||||
using upcast_t = void* (*)(void*);
|
||||
|
||||
upcast_t upcast{};
|
||||
class_type target{};
|
||||
bool is_virtual{};
|
||||
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
};
|
||||
|
||||
struct upcast_func_list_t final {
|
||||
using upcasts_t = std::vector<upcast_func_t>;
|
||||
|
||||
upcasts_t upcasts{};
|
||||
class_set vbases{};
|
||||
bool is_ambiguous{};
|
||||
|
||||
upcast_func_list_t(const upcast_func_t& _upcast);
|
||||
upcast_func_list_t(upcasts_t _upcasts, class_set _vbases);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
|
||||
friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r);
|
||||
};
|
||||
|
||||
using base_upcasts_t = std::map<class_type, upcast_func_t, std::less<>>;
|
||||
using deep_upcasts_t = std::multimap<class_type, upcast_func_list_t, std::less<>>;
|
||||
using deep_upcasts_t = std::map<class_type, upcast_func_list_t, std::less<>>;
|
||||
|
||||
base_upcasts_t base_upcasts;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
@@ -4803,19 +4911,20 @@ namespace meta_hpp::detail::class_bind_impl
|
||||
using derived_classes_db_t = std::map<class_type, class_set, std::less<>>;
|
||||
|
||||
template < class_kind Class, class_kind Base >
|
||||
requires detail::class_bind_base_kind<Class, Base>
|
||||
requires std::is_base_of_v<Base, Class>
|
||||
void update_new_bases_db( //
|
||||
new_bases_db_t& new_bases_db
|
||||
) {
|
||||
new_bases_db.emplace(resolve_type<Base>(), [](void* from) {
|
||||
return static_cast<void*>(static_cast<Base*>(static_cast<Class*>(from)));
|
||||
});
|
||||
new_bases_db.try_emplace( //
|
||||
resolve_type<Base>(),
|
||||
std::in_place_type<Class>,
|
||||
std::in_place_type<Base>);
|
||||
}
|
||||
|
||||
inline void update_deep_upcasts_db( //
|
||||
const class_type& derived_class,
|
||||
const class_type& new_base_class,
|
||||
const upcast_func_list_t& derived_to_new_base,
|
||||
upcast_func_list_t&& derived_to_new_base,
|
||||
deep_upcasts_db_t& deep_upcasts_db
|
||||
) {
|
||||
const class_type_data& derived_class_data = *type_access(derived_class);
|
||||
@@ -4823,26 +4932,27 @@ namespace meta_hpp::detail::class_bind_impl
|
||||
|
||||
const auto [deep_upcasts_db_iter, _] = deep_upcasts_db.try_emplace(derived_class, derived_class_data.deep_upcasts);
|
||||
deep_upcasts_t& derived_deep_upcasts = deep_upcasts_db_iter->second;
|
||||
derived_deep_upcasts.emplace(new_base_class, derived_to_new_base);
|
||||
|
||||
const auto add_derived_deep_upcast = [&derived_deep_upcasts](const class_type& deep_class, upcast_func_list_t&& upcasts) {
|
||||
auto&& [position, emplaced] = derived_deep_upcasts.try_emplace(deep_class, std::move(upcasts));
|
||||
if ( !emplaced ) {
|
||||
position->second.is_ambiguous = is_disjoint(position->second.vbases, upcasts.vbases);
|
||||
}
|
||||
};
|
||||
|
||||
for ( auto&& [new_deep_class, new_base_to_deep] : new_base_class_data.deep_upcasts ) {
|
||||
upcast_func_list_t derived_to_new_deep;
|
||||
derived_to_new_deep.reserve(derived_to_new_base.size() + new_base_to_deep.size());
|
||||
derived_to_new_deep.insert(derived_to_new_deep.end(), derived_to_new_base.begin(), derived_to_new_base.end());
|
||||
derived_to_new_deep.insert(derived_to_new_deep.end(), new_base_to_deep.begin(), new_base_to_deep.end());
|
||||
derived_deep_upcasts.emplace(new_deep_class, std::move(derived_to_new_deep));
|
||||
upcast_func_list_t derived_to_new_deep = derived_to_new_base + new_base_to_deep;
|
||||
add_derived_deep_upcast(new_deep_class, std::move(derived_to_new_deep));
|
||||
}
|
||||
|
||||
for ( const class_type& subderived_class : derived_class_data.derived_classes ) {
|
||||
const class_type_data& subderived_data = *type_access(subderived_class);
|
||||
|
||||
upcast_func_list_t subderived_to_new_base;
|
||||
subderived_to_new_base.reserve(derived_to_new_base.size() + 1);
|
||||
subderived_to_new_base.insert(subderived_to_new_base.end(), subderived_data.base_upcasts.at(derived_class));
|
||||
subderived_to_new_base.insert(subderived_to_new_base.end(), derived_to_new_base.begin(), derived_to_new_base.end());
|
||||
|
||||
update_deep_upcasts_db(subderived_class, new_base_class, subderived_to_new_base, deep_upcasts_db);
|
||||
upcast_func_t subderived_to_derived = subderived_data.base_upcasts.at(derived_class);
|
||||
upcast_func_list_t subderived_to_new_base = subderived_to_derived + derived_to_new_base;
|
||||
update_deep_upcasts_db(subderived_class, new_base_class, std::move(subderived_to_new_base), deep_upcasts_db);
|
||||
}
|
||||
|
||||
add_derived_deep_upcast(new_base_class, std::move(derived_to_new_base));
|
||||
}
|
||||
|
||||
inline void updata_derived_classes_db( //
|
||||
@@ -4896,7 +5006,7 @@ namespace meta_hpp
|
||||
continue;
|
||||
}
|
||||
|
||||
update_deep_upcasts_db(*this, new_base_class, {self_to_new_base}, deep_upcasts_db);
|
||||
update_deep_upcasts_db(*this, new_base_class, self_to_new_base, deep_upcasts_db);
|
||||
updata_derived_classes_db(*this, new_base_class, derived_classes_db);
|
||||
|
||||
new_base_classes.emplace(new_base_class);
|
||||
@@ -5670,8 +5780,13 @@ namespace meta_hpp::detail
|
||||
const class_type& base_class = base.as_class();
|
||||
const class_type& derived_class = derived.as_class();
|
||||
|
||||
if ( base_class && derived_class && base_class.is_base_of(derived_class) ) {
|
||||
return true;
|
||||
if ( base_class && derived_class ) {
|
||||
const class_type_data& derived_data = *type_access(derived_class);
|
||||
const class_type_data::deep_upcasts_t& deep_upcasts = derived_data.deep_upcasts;
|
||||
|
||||
if ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -5689,28 +5804,14 @@ namespace meta_hpp::detail
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* base_ptr = nullptr;
|
||||
const class_type_data& from_data = *type_access(from);
|
||||
const class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts;
|
||||
|
||||
class_type_data& from_data = *type_access(from);
|
||||
class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts;
|
||||
|
||||
for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) {
|
||||
void* new_base_ptr = [ptr, iter]() mutable {
|
||||
for ( class_type_data::upcast_func_t upcast : iter->second ) {
|
||||
ptr = upcast(ptr);
|
||||
}
|
||||
return ptr;
|
||||
}();
|
||||
|
||||
if ( base_ptr == nullptr ) {
|
||||
base_ptr = new_base_ptr;
|
||||
} else if ( base_ptr != new_base_ptr ) {
|
||||
// ambiguous conversions
|
||||
return nullptr;
|
||||
}
|
||||
if ( auto iter{deep_upcasts.find(to)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return iter->second.apply(ptr);
|
||||
}
|
||||
|
||||
return base_ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||
@@ -6000,7 +6101,7 @@ namespace meta_hpp::detail
|
||||
{
|
||||
template < pointer_kind To >
|
||||
[[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const {
|
||||
META_HPP_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
META_HPP_DEV_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
|
||||
using to_raw_type = std::remove_cv_t<To>;
|
||||
|
||||
@@ -6014,21 +6115,27 @@ namespace meta_hpp::detail
|
||||
if ( from_type.is_array() ) {
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
|
||||
return static_cast<To>(pointer_upcast( //
|
||||
void* to_ptr = pointer_upcast( //
|
||||
data_,
|
||||
from_type_array.get_data_type(),
|
||||
to_type_ptr.get_data_type()
|
||||
));
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
return static_cast<To>(to_ptr);
|
||||
}
|
||||
|
||||
if ( from_type.is_pointer() ) {
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
return static_cast<To>(pointer_upcast( //
|
||||
void* to_ptr = pointer_upcast( //
|
||||
*static_cast<void**>(data_),
|
||||
from_type_ptr.get_data_type(),
|
||||
to_type_ptr.get_data_type()
|
||||
));
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
return static_cast<To>(to_ptr);
|
||||
}
|
||||
|
||||
throw_exception(error_code::bad_argument_cast);
|
||||
@@ -6036,7 +6143,7 @@ namespace meta_hpp::detail
|
||||
|
||||
template < non_pointer_kind To >
|
||||
[[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const {
|
||||
META_HPP_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
META_HPP_DEV_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
|
||||
@@ -6050,6 +6157,7 @@ namespace meta_hpp::detail
|
||||
const any_type& to_type = registry.resolve_type<to_raw_type>();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_type, to_type);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
@@ -6089,18 +6197,11 @@ namespace meta_hpp::detail
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename ArgTypeList, typename F >
|
||||
auto call_with_uargs(type_registry& registry, std::span<const uarg> args, F&& f) {
|
||||
META_HPP_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
return [ args, ®istry, &f ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return f(args[Is].cast<type_list_at_t<Is, ArgTypeList>>(registry)...);
|
||||
}
|
||||
(std::make_index_sequence<type_list_arity_v<ArgTypeList>>());
|
||||
}
|
||||
|
||||
template < typename ArgTypeList >
|
||||
bool can_cast_all_uargs(type_registry& registry, std::span<const uarg> args) {
|
||||
META_HPP_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
if ( args.size() != type_list_arity_v<ArgTypeList> ) {
|
||||
return false;
|
||||
}
|
||||
return [ args, ®istry ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return (... && args[Is].can_cast_to<type_list_at_t<Is, ArgTypeList>>(registry));
|
||||
}
|
||||
@@ -6109,12 +6210,23 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename ArgTypeList >
|
||||
bool can_cast_all_uargs(type_registry& registry, std::span<const uarg_base> args) {
|
||||
META_HPP_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
if ( args.size() != type_list_arity_v<ArgTypeList> ) {
|
||||
return false;
|
||||
}
|
||||
return [ args, ®istry ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return (... && args[Is].can_cast_to<type_list_at_t<Is, ArgTypeList>>(registry));
|
||||
}
|
||||
(std::make_index_sequence<type_list_arity_v<ArgTypeList>>());
|
||||
}
|
||||
|
||||
template < typename ArgTypeList, typename F >
|
||||
auto unchecked_call_with_uargs(type_registry& registry, std::span<const uarg> args, F&& f) {
|
||||
META_HPP_DEV_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
return [ args, ®istry, &f ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return f(args[Is].cast<type_list_at_t<Is, ArgTypeList>>(registry)...);
|
||||
}
|
||||
(std::make_index_sequence<type_list_arity_v<ArgTypeList>>());
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
@@ -6185,7 +6297,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a function with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [function_ptr](auto&&... all_args) {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [function_ptr](auto&&... all_args) {
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
function_ptr(META_HPP_FWD(all_args)...);
|
||||
return uvalue{};
|
||||
@@ -6503,7 +6615,7 @@ namespace meta_hpp::detail
|
||||
{
|
||||
template < inst_class_ref_kind Q >
|
||||
decltype(auto) uinst::cast(type_registry& registry) const {
|
||||
META_HPP_ASSERT(can_cast_to<Q>(registry) && "bad instance cast");
|
||||
META_HPP_DEV_ASSERT(can_cast_to<Q>(registry) && "bad instance cast");
|
||||
|
||||
using inst_class_cv = std::remove_reference_t<Q>;
|
||||
using inst_class = std::remove_cv_t<inst_class_cv>;
|
||||
@@ -6512,10 +6624,12 @@ namespace meta_hpp::detail
|
||||
const any_type& to_type = registry.resolve_type<inst_class>();
|
||||
|
||||
if ( from_type.is_class() && to_type.is_class() ) {
|
||||
const class_type& from_class = from_type.as_class();
|
||||
const class_type& to_class = to_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_class, to_class);
|
||||
void* to_ptr = pointer_upcast( //
|
||||
data_,
|
||||
from_type.as_class(),
|
||||
to_type.as_class()
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
@@ -6535,11 +6649,12 @@ namespace meta_hpp::detail
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( from_data_type.is_class() && to_type.is_class() ) {
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
const class_type& to_class = to_type.as_class();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_class);
|
||||
void* to_ptr = pointer_upcast( //
|
||||
*static_cast<void**>(data_),
|
||||
from_data_type.as_class(),
|
||||
to_type.as_class()
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
@@ -6961,7 +7076,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a method with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) {
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
(inst.cast<qualified_type>(registry).*method_ptr)(META_HPP_FWD(all_args)...);
|
||||
return uvalue{};
|
||||
@@ -7126,6 +7241,11 @@ namespace meta_hpp
|
||||
return function.invoke(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
uresult try_invoke(const function& function, Args&&... args) {
|
||||
return function.try_invoke(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < detail::function_pointer_kind Function, typename... Args >
|
||||
uvalue invoke(Function function_ptr, Args&&... args) {
|
||||
using namespace detail;
|
||||
@@ -7133,6 +7253,22 @@ namespace meta_hpp
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_function_invoke<function_policy::as_copy_t>(registry, function_ptr, vargs);
|
||||
}
|
||||
|
||||
template < detail::function_pointer_kind Function, typename... Args >
|
||||
uresult try_invoke(Function function_ptr, Args&&... args) {
|
||||
using namespace detail;
|
||||
type_registry& registry{type_registry::instance()};
|
||||
|
||||
{
|
||||
const std::array<uarg_base, sizeof...(Args)> vargs{uarg_base{registry, std::forward<Args>(args)}...};
|
||||
if ( const uerror err = raw_function_invoke_error<Function>(registry, vargs) ) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_function_invoke<function_policy::as_copy_t>(registry, function_ptr, vargs);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -7142,6 +7278,11 @@ namespace meta_hpp
|
||||
return member.get(std::forward<Instance>(instance));
|
||||
}
|
||||
|
||||
template < typename Instance >
|
||||
uresult try_invoke(const member& member, Instance&& instance) {
|
||||
return member.try_get(std::forward<Instance>(instance));
|
||||
}
|
||||
|
||||
template < detail::member_pointer_kind Member, typename Instance >
|
||||
uvalue invoke(Member member_ptr, Instance&& instance) {
|
||||
using namespace detail;
|
||||
@@ -7149,6 +7290,22 @@ namespace meta_hpp
|
||||
const uinst vinst{registry, std::forward<Instance>(instance)};
|
||||
return raw_member_getter<member_policy::as_copy_t>(registry, member_ptr, vinst);
|
||||
}
|
||||
|
||||
template < detail::member_pointer_kind Member, typename Instance >
|
||||
uresult try_invoke(Member member_ptr, Instance&& instance) {
|
||||
using namespace detail;
|
||||
type_registry& registry{type_registry::instance()};
|
||||
|
||||
{
|
||||
const uinst_base vinst{registry, std::forward<Instance>(instance)};
|
||||
if ( const uerror err = raw_member_getter_error<Member>(registry, vinst) ) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const uinst vinst{registry, std::forward<Instance>(instance)};
|
||||
return raw_member_getter<member_policy::as_copy_t>(registry, member_ptr, vinst);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -7158,6 +7315,11 @@ namespace meta_hpp
|
||||
return method.invoke(std::forward<Instance>(instance), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename Instance, typename... Args >
|
||||
uresult try_invoke(const method& method, Instance&& instance, Args&&... args) {
|
||||
return method.try_invoke(std::forward<Instance>(instance), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < detail::method_pointer_kind Method, typename Instance, typename... Args >
|
||||
uvalue invoke(Method method_ptr, Instance&& instance, Args&&... args) {
|
||||
using namespace detail;
|
||||
@@ -7166,6 +7328,24 @@ namespace meta_hpp
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_method_invoke<method_policy::as_copy_t>(registry, method_ptr, vinst, vargs);
|
||||
}
|
||||
|
||||
template < detail::method_pointer_kind Method, typename Instance, typename... Args >
|
||||
uresult try_invoke(Method method_ptr, Instance&& instance, Args&&... args) {
|
||||
using namespace detail;
|
||||
type_registry& registry{type_registry::instance()};
|
||||
|
||||
{
|
||||
const uinst_base vinst{registry, std::forward<Instance>(instance)};
|
||||
const std::array<uarg_base, sizeof...(Args)> vargs{uarg_base{registry, std::forward<Args>(args)}...};
|
||||
if ( const uerror err = raw_method_invoke_error<Method>(registry, vinst, vargs) ) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const uinst vinst{registry, std::forward<Instance>(instance)};
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_method_invoke<method_policy::as_copy_t>(registry, method_ptr, vinst, vargs);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -7352,7 +7532,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a constructor with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [](auto&&... all_args) -> uvalue {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [](auto&&... all_args) -> uvalue {
|
||||
if constexpr ( as_object ) {
|
||||
return make_uvalue<class_type>(META_HPP_FWD(all_args)...);
|
||||
}
|
||||
@@ -7383,7 +7563,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a constructor with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [mem](auto&&... all_args) {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [mem](auto&&... all_args) {
|
||||
return std::construct_at(static_cast<class_type*>(mem), META_HPP_FWD(all_args)...);
|
||||
});
|
||||
}
|
||||
@@ -8009,6 +8189,69 @@ namespace meta_hpp::detail
|
||||
, argument_types{resolve_types(typename class_traits<Class>::argument_types{})} {}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>)
|
||||
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
|
||||
, target{resolve_type<Base>()}
|
||||
, is_virtual{is_virtual_base_of_v<Base, Derived>} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept {
|
||||
return upcast(ptr);
|
||||
}
|
||||
|
||||
inline const void* class_type_data::upcast_func_t::apply(const void* ptr) const noexcept {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return apply(const_cast<void*>(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast)
|
||||
: upcasts{_upcast} {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
if ( upcast.is_virtual ) {
|
||||
vbases.emplace(upcast.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t _upcasts, class_set _vbases)
|
||||
: upcasts{std::move(_upcasts)}
|
||||
, vbases{std::move(_vbases)} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
ptr = upcast.apply(ptr);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
inline const void* class_type_data::upcast_func_list_t::apply(const void* ptr) const noexcept {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return apply(const_cast<void*>(ptr));
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t operator+( //
|
||||
const class_type_data::upcast_func_list_t& l,
|
||||
const class_type_data::upcast_func_list_t& r
|
||||
) {
|
||||
class_type_data::upcast_func_list_t::upcasts_t new_upcasts;
|
||||
new_upcasts.reserve(l.upcasts.size() + r.upcasts.size());
|
||||
new_upcasts.insert(new_upcasts.end(), l.upcasts.begin(), l.upcasts.end());
|
||||
new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.upcasts.end());
|
||||
|
||||
class_set new_vbases;
|
||||
new_vbases.insert(l.vbases.begin(), l.vbases.end());
|
||||
new_vbases.insert(r.vbases.begin(), r.vbases.end());
|
||||
|
||||
return class_type_data::upcast_func_list_t{std::move(new_upcasts), std::move(new_vbases)};
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
inline class_bitflags class_type::get_flags() const noexcept {
|
||||
@@ -8116,12 +8359,33 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_base_of(const class_type& derived) const noexcept {
|
||||
return is_valid() && derived.is_valid() && derived.data_->deep_upcasts.contains(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
bool class_type::is_direct_base_of() const noexcept {
|
||||
return is_direct_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_direct_base_of(const class_type& derived) const noexcept {
|
||||
return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
bool class_type::is_virtual_base_of() const noexcept {
|
||||
return is_virtual_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept {
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( derived.data_->deep_upcasts.contains(*this) ) {
|
||||
return true;
|
||||
using deep_upcasts_t = detail::class_type_data::deep_upcasts_t;
|
||||
const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts;
|
||||
|
||||
if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) {
|
||||
return !iter->second.is_ambiguous && !iter->second.vbases.empty();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -8133,15 +8397,25 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_derived_from(const class_type& base) const noexcept {
|
||||
if ( !is_valid() || !base.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
return base.is_base_of(*this);
|
||||
}
|
||||
|
||||
if ( data_->deep_upcasts.contains(base) ) {
|
||||
return true;
|
||||
}
|
||||
template < detail::class_kind Base >
|
||||
bool class_type::is_direct_derived_from() const noexcept {
|
||||
return is_direct_derived_from(resolve_type<Base>());
|
||||
}
|
||||
|
||||
return false;
|
||||
inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept {
|
||||
return base.is_direct_base_of(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Base >
|
||||
bool class_type::is_virtual_derived_from() const noexcept {
|
||||
return is_virtual_derived_from(resolve_type<Base>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_derived_from(const class_type& base) const noexcept {
|
||||
return base.is_virtual_base_of(*this);
|
||||
}
|
||||
|
||||
inline function class_type::get_function(std::string_view name) const noexcept {
|
||||
@@ -8870,7 +9144,7 @@ namespace meta_hpp
|
||||
|
||||
template < typename T, typename... Args, typename Tp = std::decay_t<T> >
|
||||
static Tp& do_ctor(uvalue& dst, Args&&... args) {
|
||||
META_HPP_ASSERT(!dst);
|
||||
META_HPP_DEV_ASSERT(!dst);
|
||||
|
||||
if constexpr ( in_internal_v<Tp> ) {
|
||||
std::construct_at(storage_cast<Tp>(dst.storage_), std::forward<Args>(args)...);
|
||||
@@ -8888,7 +9162,7 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
static void do_move(uvalue&& self, uvalue& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
|
||||
auto&& [tag, vtable] = unpack_vtag(self);
|
||||
|
||||
@@ -8907,7 +9181,7 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
static void do_copy(const uvalue& self, uvalue& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
|
||||
auto&& [tag, vtable] = unpack_vtag(self);
|
||||
|
||||
@@ -8969,8 +9243,8 @@ namespace meta_hpp
|
||||
.type = resolve_type<Tp>(),
|
||||
|
||||
.move{[](uvalue&& self, uvalue& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
Tp* src = storage_cast<Tp>(self.storage_);
|
||||
|
||||
@@ -8985,8 +9259,8 @@ namespace meta_hpp
|
||||
}},
|
||||
|
||||
.copy{[](const uvalue& self, uvalue& to) {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
const Tp* src = storage_cast<Tp>(self.storage_);
|
||||
|
||||
@@ -9000,7 +9274,7 @@ namespace meta_hpp
|
||||
}},
|
||||
|
||||
.reset{[](uvalue& self) noexcept {
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
Tp* src = storage_cast<Tp>(self.storage_);
|
||||
|
||||
|
||||
30
develop/untests/meta_base/is_disjoint.cpp
Normal file
30
develop/untests/meta_base/is_disjoint.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
* 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-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
TEST_CASE("meta/meta_base/is_disjoint") {
|
||||
namespace meta = meta_hpp;
|
||||
using meta::detail::is_disjoint;
|
||||
|
||||
CHECK(is_disjoint(std::set<int>{}, std::set<int>{}));
|
||||
|
||||
CHECK(is_disjoint(std::set<int>{1}, std::set<int>{}));
|
||||
CHECK(is_disjoint(std::set<int>{}, std::set<int>{1}));
|
||||
|
||||
CHECK_FALSE(is_disjoint(std::set<int>{1}, std::set<int>{1}));
|
||||
|
||||
CHECK_FALSE(is_disjoint(std::set<int>{1,2}, std::set<int>{1}));
|
||||
CHECK_FALSE(is_disjoint(std::set<int>{1}, std::set<int>{1,2}));
|
||||
|
||||
CHECK_FALSE(is_disjoint(std::set<int>{1,2}, std::set<int>{1,3}));
|
||||
CHECK_FALSE(is_disjoint(std::set<int>{1,3}, std::set<int>{1,2}));
|
||||
|
||||
CHECK(is_disjoint(std::set<int>{1,2}, std::set<int>{3,4}));
|
||||
CHECK(is_disjoint(std::set<int>{2,3}, std::set<int>{1,4,5}));
|
||||
CHECK(is_disjoint(std::set<int>{2,4}, std::set<int>{1,3,5}));
|
||||
}
|
||||
77
develop/untests/meta_base/is_virtual_base_of_tests.cpp
Normal file
77
develop/untests/meta_base/is_virtual_base_of_tests.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
* 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-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct A {};
|
||||
struct B : virtual A {};
|
||||
struct C : virtual A {};
|
||||
struct D : B, C {};
|
||||
struct E {};
|
||||
|
||||
struct I {};
|
||||
struct J : virtual I {};
|
||||
struct K : J {};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_base/is_virtual_base_of") {
|
||||
namespace meta = meta_hpp;
|
||||
using meta::detail::is_virtual_base_of;
|
||||
using meta::detail::is_virtual_base_of_v;
|
||||
|
||||
{
|
||||
static_assert(!is_virtual_base_of_v<A, A>);
|
||||
static_assert(is_virtual_base_of_v<A, B>);
|
||||
static_assert(is_virtual_base_of_v<A, C>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<A, D>);
|
||||
static_assert(!is_virtual_base_of_v<B, D>);
|
||||
static_assert(!is_virtual_base_of_v<C, D>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<A, E>);
|
||||
static_assert(!is_virtual_base_of_v<E, A>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<E, D>);
|
||||
static_assert(!is_virtual_base_of_v<D, E>);
|
||||
}
|
||||
|
||||
{
|
||||
static_assert(!is_virtual_base_of_v<I, I>);
|
||||
static_assert(is_virtual_base_of_v<I, J>);
|
||||
static_assert(is_virtual_base_of_v<I, K>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<J, I>);
|
||||
static_assert(!is_virtual_base_of_v<J, J>);
|
||||
static_assert(!is_virtual_base_of_v<J, K>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<K, I>);
|
||||
static_assert(!is_virtual_base_of_v<K, J>);
|
||||
static_assert(!is_virtual_base_of_v<K, K>);
|
||||
}
|
||||
|
||||
{
|
||||
static_assert(is_virtual_base_of_v<I, J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, const J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, const J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, const J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, volatile J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, volatile J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, volatile J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, const volatile J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, const volatile J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, const volatile J>);
|
||||
}
|
||||
}
|
||||
111
develop/untests/meta_features/ambiguous_tests.cpp
Normal file
111
develop/untests/meta_features/ambiguous_tests.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*******************************************************************************
|
||||
* 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-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct A1 { std::string a1{"a1"}; };
|
||||
struct B1 : A1 { std::string b1{"b1"}; };
|
||||
struct C1 : A1 { std::string c1{"c1"}; };
|
||||
struct D1 : B1, C1 { std::string d1{"d1"}; };
|
||||
|
||||
struct A2 { std::string a2{"a2"}; };
|
||||
struct B2 : virtual A2 { std::string b2{"b2"}; };
|
||||
struct C2 : virtual A2 { std::string c2{"c2"}; };
|
||||
struct D2 : B2, C2 { std::string d2{"d2"}; };
|
||||
|
||||
struct A3 { std::string a3{"a3"}; };
|
||||
struct B3 : virtual A3 { std::string b3{"b3"}; };
|
||||
struct C3 : A3 { std::string c3{"c3"}; };
|
||||
struct D3 : B3, C3 { std::string d3{"d3"}; };
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_features/ambiguous") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
{
|
||||
meta::class_<B1>().base_<A1>();
|
||||
meta::class_<C1>().base_<A1>();
|
||||
meta::class_<D1>().base_<B1, C1>();
|
||||
|
||||
// A1 < B1
|
||||
// < D1
|
||||
// A1 < C1
|
||||
|
||||
static_assert(std::is_invocable_v<void(const A1&), A1&&>);
|
||||
static_assert(std::is_invocable_v<void(const A1&), B1&&>);
|
||||
static_assert(std::is_invocable_v<void(const A1&), C1&&>);
|
||||
static_assert(!std::is_invocable_v<void(const A1&), D1&&>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A1&){}, A1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A1&){}, B1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A1&){}, C1{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A1&){}, D1{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<B1>());
|
||||
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<C1>());
|
||||
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<D1>());
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<B1>().is_virtual_base_of<D1>());
|
||||
CHECK_FALSE(meta::resolve_type<C1>().is_virtual_base_of<D1>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B2>().base_<A2>();
|
||||
meta::class_<C2>().base_<A2>();
|
||||
meta::class_<D2>().base_<B2, C2>();
|
||||
|
||||
// A2 <= B2
|
||||
// < D2
|
||||
// A2 <= C2
|
||||
|
||||
static_assert(std::is_invocable_v<void(const A2&), A2&&>);
|
||||
static_assert(std::is_invocable_v<void(const A2&), B2&&>);
|
||||
static_assert(std::is_invocable_v<void(const A2&), C2&&>);
|
||||
static_assert(std::is_invocable_v<void(const A2&), D2&&>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, A2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, B2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, C2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){}, D2{}));
|
||||
|
||||
CHECK(meta::resolve_type<A2>().is_virtual_base_of<B2>());
|
||||
CHECK(meta::resolve_type<A2>().is_virtual_base_of<C2>());
|
||||
CHECK(meta::resolve_type<A2>().is_virtual_base_of<D2>());
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<B2>().is_virtual_base_of<D2>());
|
||||
CHECK_FALSE(meta::resolve_type<C2>().is_virtual_base_of<D2>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B3>().base_<A3>();
|
||||
meta::class_<C3>().base_<A3>();
|
||||
meta::class_<D3>().base_<B3, C3>();
|
||||
|
||||
// A3 <= B3
|
||||
// < D3
|
||||
// A3 < C3
|
||||
|
||||
static_assert(std::is_invocable_v<void(const A3&), A3&&>);
|
||||
static_assert(std::is_invocable_v<void(const A3&), B3&&>);
|
||||
static_assert(std::is_invocable_v<void(const A3&), C3&&>);
|
||||
static_assert(!std::is_invocable_v<void(const A3&), D3&&>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){}, A3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){}, B3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){}, C3{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A3&){}, D3{}));
|
||||
|
||||
CHECK(meta::resolve_type<A3>().is_virtual_base_of<B3>());
|
||||
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<C3>());
|
||||
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<D3>());
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<B3>().is_virtual_base_of<D3>());
|
||||
CHECK_FALSE(meta::resolve_type<C3>().is_virtual_base_of<D3>());
|
||||
}
|
||||
}
|
||||
99
develop/untests/meta_issues/random_issue_1.cpp
Normal file
99
develop/untests/meta_issues/random_issue_1.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*******************************************************************************
|
||||
* 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-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <meta.hpp/meta_all.hpp>
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct A1 {};
|
||||
struct B1 : A1 {};
|
||||
struct C1 : A1 {};
|
||||
struct D1 : B1, C1 {};
|
||||
|
||||
// A1 <- B1 <- *
|
||||
// D1
|
||||
// A1 <- C1 <- *
|
||||
|
||||
struct A2 {};
|
||||
struct B2 : virtual A2 {};
|
||||
struct C2 : virtual B2 {};
|
||||
struct D2 : virtual B2 {};
|
||||
struct E2 : C2, D2 {};
|
||||
|
||||
// A2 <= B2 <= C2 <- *
|
||||
// E2
|
||||
// A2 <= B2 <= D2 <- *
|
||||
|
||||
struct A3 {};
|
||||
struct B3 : virtual A3 {};
|
||||
struct C3 : A3 {};
|
||||
struct D3 : B3, C3 {};
|
||||
|
||||
// A3 <= B3 <- *
|
||||
// D3
|
||||
// A3 <- C3 <- *
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_issues/random/1") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
{
|
||||
meta::class_<B1>().base_<A1>();
|
||||
meta::class_<C1>().base_<A1>();
|
||||
meta::class_<D1>().base_<B1, C1>();
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const D1&){ return true; }, D1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const C1&){ return true; }, D1{}));
|
||||
CHECK(meta::is_invocable_with(+[](const B1&){ return true; }, D1{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A1&){ return true; }, D1{}));
|
||||
|
||||
CHECK(meta::try_invoke(+[](const D1&){ return true; }, D1{}));
|
||||
CHECK(meta::try_invoke(+[](const C1&){ return true; }, D1{}));
|
||||
CHECK(meta::try_invoke(+[](const B1&){ return true; }, D1{}));
|
||||
CHECK_FALSE(meta::try_invoke(+[](const A1&){ return true; }, D1{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<D1>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B2>().base_<A2>();
|
||||
meta::class_<C2>().base_<B2>();
|
||||
meta::class_<D2>().base_<B2>();
|
||||
meta::class_<E2>().base_<C2, D2>();
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A2&){ return true; }, E2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const B2&){ return true; }, E2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const C2&){ return true; }, E2{}));
|
||||
CHECK(meta::is_invocable_with(+[](const D2&){ return true; }, E2{}));
|
||||
|
||||
CHECK(meta::try_invoke(+[](const A2&){ return true; }, E2{}));
|
||||
CHECK(meta::try_invoke(+[](const B2&){ return true; }, E2{}));
|
||||
CHECK(meta::try_invoke(+[](const C2&){ return true; }, E2{}));
|
||||
CHECK(meta::try_invoke(+[](const D2&){ return true; }, E2{}));
|
||||
|
||||
CHECK(meta::resolve_type<A2>().is_virtual_base_of<E2>());
|
||||
}
|
||||
|
||||
{
|
||||
meta::class_<B3>().base_<A3>();
|
||||
meta::class_<C3>().base_<A3>();
|
||||
meta::class_<D3>().base_<B3, C3>();
|
||||
|
||||
static_assert(std::is_invocable_v<void(A3*), A3*>);
|
||||
static_assert(std::is_invocable_v<void(A3*), B3*>);
|
||||
static_assert(std::is_invocable_v<void(A3*), C3*>);
|
||||
static_assert(!std::is_invocable_v<void(A3*), D3*>);
|
||||
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, A3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, B3{}));
|
||||
CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, C3{}));
|
||||
CHECK_FALSE(meta::is_invocable_with(+[](const A3&){ return true; }, D3{}));
|
||||
|
||||
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<D3>());
|
||||
}
|
||||
}
|
||||
@@ -248,40 +248,62 @@ TEST_CASE("meta/meta_types/class_type") {
|
||||
{
|
||||
CHECK_FALSE(base_clazz_1_type.is_base_of<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_base_of(base_clazz_1_type));
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_base_of<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_base_of(base_clazz_1_type));
|
||||
|
||||
CHECK_FALSE(base_clazz_1_type.is_base_of<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_base_of(base_clazz_2_type));
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_base_of<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_base_of(base_clazz_2_type));
|
||||
|
||||
CHECK(base_clazz_1_type.is_base_of<derived_clazz>());
|
||||
CHECK(base_clazz_1_type.is_base_of(derived_clazz_type));
|
||||
CHECK(base_clazz_1_type.is_direct_base_of<derived_clazz>());
|
||||
CHECK(base_clazz_1_type.is_direct_base_of(derived_clazz_type));
|
||||
|
||||
CHECK(base_clazz_1_type.is_base_of<final_derived_clazz>());
|
||||
CHECK(base_clazz_1_type.is_base_of(final_derived_clazz_type));
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_base_of<final_derived_clazz>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_base_of(final_derived_clazz_type));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(base_clazz_2_type.is_base_of<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_base_of(base_clazz_1_type));
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_base_of<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_base_of(base_clazz_1_type));
|
||||
|
||||
CHECK_FALSE(base_clazz_2_type.is_base_of<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_base_of(base_clazz_2_type));
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_base_of<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_base_of(base_clazz_2_type));
|
||||
|
||||
CHECK(base_clazz_2_type.is_base_of<derived_clazz>());
|
||||
CHECK(base_clazz_2_type.is_base_of(derived_clazz_type));
|
||||
CHECK(base_clazz_2_type.is_direct_base_of<derived_clazz>());
|
||||
CHECK(base_clazz_2_type.is_direct_base_of(derived_clazz_type));
|
||||
|
||||
CHECK(base_clazz_2_type.is_base_of<final_derived_clazz>());
|
||||
CHECK(base_clazz_2_type.is_base_of(final_derived_clazz_type));
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_base_of<final_derived_clazz>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_base_of(final_derived_clazz_type));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(derived_clazz_type.is_base_of<base_clazz_1>());
|
||||
CHECK_FALSE(derived_clazz_type.is_base_of(base_clazz_1_type));
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_base_of<base_clazz_1>());
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_base_of(base_clazz_1_type));
|
||||
|
||||
CHECK_FALSE(derived_clazz_type.is_base_of<base_clazz_2>());
|
||||
CHECK_FALSE(derived_clazz_type.is_base_of(base_clazz_2_type));
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_base_of<base_clazz_2>());
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_base_of(base_clazz_2_type));
|
||||
|
||||
CHECK_FALSE(derived_clazz_type.is_base_of<derived_clazz>());
|
||||
CHECK_FALSE(derived_clazz_type.is_base_of(derived_clazz_type));
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_base_of<derived_clazz>());
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_base_of(derived_clazz_type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,45 +311,69 @@ TEST_CASE("meta/meta_types/class_type") {
|
||||
{
|
||||
CHECK_FALSE(base_clazz_1_type.is_derived_from<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_derived_from(base_clazz_1_type));
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_derived_from<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_derived_from(base_clazz_1_type));
|
||||
|
||||
CHECK_FALSE(base_clazz_1_type.is_derived_from<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_derived_from(base_clazz_2_type));
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_derived_from<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_derived_from(base_clazz_2_type));
|
||||
|
||||
CHECK_FALSE(base_clazz_1_type.is_derived_from<derived_clazz>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_derived_from(derived_clazz_type));
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_derived_from<derived_clazz>());
|
||||
CHECK_FALSE(base_clazz_1_type.is_direct_derived_from(derived_clazz_type));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK_FALSE(base_clazz_2_type.is_derived_from<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_derived_from(base_clazz_1_type));
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_derived_from<base_clazz_1>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_derived_from(base_clazz_1_type));
|
||||
|
||||
CHECK_FALSE(base_clazz_2_type.is_derived_from<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_derived_from(base_clazz_2_type));
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_derived_from<base_clazz_2>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_derived_from(base_clazz_2_type));
|
||||
|
||||
CHECK_FALSE(base_clazz_2_type.is_derived_from<derived_clazz>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_derived_from(derived_clazz_type));
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_derived_from<derived_clazz>());
|
||||
CHECK_FALSE(base_clazz_2_type.is_direct_derived_from(derived_clazz_type));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(derived_clazz_type.is_derived_from<base_clazz_1>());
|
||||
CHECK(derived_clazz_type.is_derived_from(base_clazz_1_type));
|
||||
CHECK(derived_clazz_type.is_direct_derived_from<base_clazz_1>());
|
||||
CHECK(derived_clazz_type.is_direct_derived_from(base_clazz_1_type));
|
||||
|
||||
CHECK(derived_clazz_type.is_derived_from<base_clazz_2>());
|
||||
CHECK(derived_clazz_type.is_derived_from(base_clazz_2_type));
|
||||
CHECK(derived_clazz_type.is_direct_derived_from<base_clazz_2>());
|
||||
CHECK(derived_clazz_type.is_direct_derived_from(base_clazz_2_type));
|
||||
|
||||
CHECK_FALSE(derived_clazz_type.is_derived_from<derived_clazz>());
|
||||
CHECK_FALSE(derived_clazz_type.is_derived_from(derived_clazz_type));
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_derived_from<derived_clazz>());
|
||||
CHECK_FALSE(derived_clazz_type.is_direct_derived_from(derived_clazz_type));
|
||||
}
|
||||
|
||||
{
|
||||
CHECK(final_derived_clazz_type.is_derived_from<base_clazz_1>());
|
||||
CHECK(final_derived_clazz_type.is_derived_from(base_clazz_1_type));
|
||||
CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from<base_clazz_1>());
|
||||
CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from(base_clazz_1_type));
|
||||
|
||||
CHECK(final_derived_clazz_type.is_derived_from<base_clazz_2>());
|
||||
CHECK(final_derived_clazz_type.is_derived_from(base_clazz_2_type));
|
||||
CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from<base_clazz_2>());
|
||||
CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from(base_clazz_2_type));
|
||||
|
||||
CHECK(final_derived_clazz_type.is_derived_from<derived_clazz>());
|
||||
CHECK(final_derived_clazz_type.is_derived_from(derived_clazz_type));
|
||||
CHECK(final_derived_clazz_type.is_direct_derived_from<derived_clazz>());
|
||||
CHECK(final_derived_clazz_type.is_direct_derived_from(derived_clazz_type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,13 @@ TEST_CASE("meta/meta_utilities/invoke") {
|
||||
CHECK(meta::invoke(clazz_function, meta::uvalue{3}).as<int>() == 3);
|
||||
CHECK(meta::invoke(clazz_function, meta::uresult{3}).as<int>() == 3);
|
||||
|
||||
CHECK(meta::try_invoke(&clazz::function, 3)->as<int>() == 3);
|
||||
CHECK(meta::try_invoke(&clazz::function, meta::uvalue{3})->as<int>() == 3);
|
||||
CHECK(meta::try_invoke(&clazz::function, meta::uresult{3})->as<int>() == 3);
|
||||
CHECK(meta::try_invoke(clazz_function, 3)->as<int>() == 3);
|
||||
CHECK(meta::try_invoke(clazz_function, meta::uvalue{3})->as<int>() == 3);
|
||||
CHECK(meta::try_invoke(clazz_function, meta::uresult{3})->as<int>() == 3);
|
||||
|
||||
CHECK(meta::is_invocable_with(clazz_function, 3));
|
||||
CHECK(meta::is_invocable_with(clazz_function, meta::uvalue{3}));
|
||||
CHECK(meta::is_invocable_with(clazz_function, meta::uresult{3}));
|
||||
@@ -61,6 +68,13 @@ TEST_CASE("meta/meta_utilities/invoke") {
|
||||
CHECK(meta::invoke(clazz_member, meta::uvalue{cl}).as<int>() == 1);
|
||||
CHECK(meta::invoke(clazz_member, meta::uresult{cl}).as<int>() == 1);
|
||||
|
||||
CHECK(meta::try_invoke(&clazz::member, cl)->as<int>() == 1);
|
||||
CHECK(meta::try_invoke(&clazz::member, meta::uvalue{cl})->as<int>() == 1);
|
||||
CHECK(meta::try_invoke(&clazz::member, meta::uresult{cl})->as<int>() == 1);
|
||||
CHECK(meta::try_invoke(clazz_member, cl)->as<int>() == 1);
|
||||
CHECK(meta::try_invoke(clazz_member, meta::uvalue{cl})->as<int>() == 1);
|
||||
CHECK(meta::try_invoke(clazz_member, meta::uresult{cl})->as<int>() == 1);
|
||||
|
||||
CHECK(meta::is_invocable_with(clazz_member, cl));
|
||||
CHECK(meta::is_invocable_with(clazz_member, meta::uvalue{cl}));
|
||||
CHECK(meta::is_invocable_with(clazz_member, meta::uresult{cl}));
|
||||
@@ -82,6 +96,13 @@ TEST_CASE("meta/meta_utilities/invoke") {
|
||||
CHECK(meta::invoke(clazz_method, meta::uvalue{cl}, meta::uvalue{2}).as<int>() == 2);
|
||||
CHECK(meta::invoke(clazz_method, meta::uresult{cl}, meta::uresult{2}).as<int>() == 2);
|
||||
|
||||
CHECK(meta::try_invoke(&clazz::method, cl, 2)->as<int>() == 2);
|
||||
CHECK(meta::try_invoke(&clazz::method, meta::uvalue{cl}, meta::uvalue{2})->as<int>() == 2);
|
||||
CHECK(meta::try_invoke(&clazz::method, meta::uresult{cl}, meta::uresult{2})->as<int>() == 2);
|
||||
CHECK(meta::try_invoke(clazz_method, cl, 2)->as<int>() == 2);
|
||||
CHECK(meta::try_invoke(clazz_method, meta::uvalue{cl}, meta::uvalue{2})->as<int>() == 2);
|
||||
CHECK(meta::try_invoke(clazz_method, meta::uresult{cl}, meta::uresult{2})->as<int>() == 2);
|
||||
|
||||
CHECK(meta::is_invocable_with(clazz_method, cl, 2));
|
||||
CHECK(meta::is_invocable_with(clazz_method, meta::uvalue{cl}, meta::uvalue{2}));
|
||||
CHECK(meta::is_invocable_with(clazz_method, meta::uresult{cl}, meta::uresult{2}));
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
#include "meta_base/hashed_string.hpp"
|
||||
#include "meta_base/insert_or_assign.hpp"
|
||||
#include "meta_base/intrusive_ptr.hpp"
|
||||
#include "meta_base/is_disjoint.hpp"
|
||||
#include "meta_base/is_in_place_type.hpp"
|
||||
#include "meta_base/is_virtual_base_of.hpp"
|
||||
#include "meta_base/memory_buffer.hpp"
|
||||
#include "meta_base/noncopyable.hpp"
|
||||
#include "meta_base/nonesuch.hpp"
|
||||
|
||||
@@ -53,6 +53,12 @@
|
||||
# define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT
|
||||
#endif
|
||||
|
||||
#if defined(META_HPP_SANITIZERS)
|
||||
# define META_HPP_DEV_ASSERT(...) META_HPP_ASSERT(__VA_ARGS__)
|
||||
#else
|
||||
# define META_HPP_DEV_ASSERT(...) (void)0
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_PP_CAT)
|
||||
# define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y)
|
||||
# define META_HPP_PP_CAT_I(x, y) x##y
|
||||
|
||||
@@ -8,42 +8,42 @@
|
||||
|
||||
#include "base.hpp"
|
||||
|
||||
namespace meta_hpp::detail::impl
|
||||
{
|
||||
template < typename F, typename... Args >
|
||||
class defer_impl {
|
||||
public:
|
||||
defer_impl() = delete;
|
||||
defer_impl(defer_impl&&) = delete;
|
||||
defer_impl(const defer_impl&) = delete;
|
||||
defer_impl& operator=(defer_impl&&) = delete;
|
||||
defer_impl& operator=(const defer_impl&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit defer_impl(UF&& f, std::tuple<Args...>&& args)
|
||||
: f_{std::forward<UF>(f)}
|
||||
, args_{std::move(args)} {}
|
||||
|
||||
void dismiss() noexcept {
|
||||
dismissed_ = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
~defer_impl() noexcept {
|
||||
if ( !dismissed_ ) {
|
||||
std::apply(std::move(f_), std::move(args_));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
std::tuple<Args...> args_;
|
||||
bool dismissed_{};
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
template < typename F, typename... Args >
|
||||
class defer_impl {
|
||||
public:
|
||||
defer_impl() = delete;
|
||||
defer_impl(defer_impl&&) = delete;
|
||||
defer_impl(const defer_impl&) = delete;
|
||||
defer_impl& operator=(defer_impl&&) = delete;
|
||||
defer_impl& operator=(const defer_impl&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit defer_impl(UF&& f, std::tuple<Args...>&& args)
|
||||
: f_{std::forward<UF>(f)}
|
||||
, args_{std::move(args)} {}
|
||||
|
||||
void dismiss() noexcept {
|
||||
dismissed_ = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
~defer_impl() noexcept {
|
||||
if ( !dismissed_ ) {
|
||||
std::apply(std::move(f_), std::move(args_));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
std::tuple<Args...> args_;
|
||||
bool dismissed_{};
|
||||
};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
|
||||
@@ -126,15 +126,15 @@ namespace meta_hpp::detail
|
||||
|
||||
static vtable_t table{
|
||||
.call{[](const fixed_function& self, Args... args) -> R {
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
const Fp& src = *buffer_cast<Fp>(self.buffer_);
|
||||
return std::invoke(src, std::forward<Args>(args)...);
|
||||
}},
|
||||
|
||||
.move{[](fixed_function& from, fixed_function& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_ASSERT(from);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(from);
|
||||
|
||||
Fp& src = *buffer_cast<Fp>(from.buffer_);
|
||||
std::construct_at(buffer_cast<Fp>(to.buffer_), std::move(src));
|
||||
@@ -145,7 +145,7 @@ namespace meta_hpp::detail
|
||||
}},
|
||||
|
||||
.destroy{[](fixed_function& self) {
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
Fp& src = *buffer_cast<Fp>(self.buffer_);
|
||||
std::destroy_at(&src);
|
||||
@@ -158,7 +158,7 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename F, typename Fp = std::decay_t<F> >
|
||||
static void construct(fixed_function& dst, F&& fun) {
|
||||
META_HPP_ASSERT(!dst);
|
||||
META_HPP_DEV_ASSERT(!dst);
|
||||
|
||||
static_assert(sizeof(Fp) <= sizeof(buffer_t));
|
||||
static_assert(alignof(buffer_t) % alignof(Fp) == 0);
|
||||
|
||||
35
headers/meta.hpp/meta_base/is_disjoint.hpp
Normal file
35
headers/meta.hpp/meta_base/is_disjoint.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*******************************************************************************
|
||||
* 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-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.hpp"
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename SortedContainerL, typename SortedContainerR, typename Compare >
|
||||
bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r, Compare compare) {
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
for ( auto iter_l{begin(l)}, iter_r{begin(r)}; iter_l != end(l) && iter_r != end(r); ) {
|
||||
if ( compare(*iter_l, *iter_r) ) {
|
||||
++iter_l;
|
||||
} else if ( compare(*iter_r, *iter_l) ) {
|
||||
++iter_r;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename SortedContainerL, typename SortedContainerR >
|
||||
bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r) {
|
||||
return is_disjoint(l, r, std::less<>{});
|
||||
}
|
||||
}
|
||||
41
headers/meta.hpp/meta_base/is_virtual_base_of.hpp
Normal file
41
headers/meta.hpp/meta_base/is_virtual_base_of.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* 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-2023, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.hpp"
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
template < typename From, typename To >
|
||||
constexpr bool is_virtual_base_of_impl(...) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
typename From,
|
||||
typename To,
|
||||
decltype(static_cast<const volatile To*>(std::declval<const volatile From*>())) = nullptr >
|
||||
constexpr bool is_virtual_base_of_impl(int) noexcept {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
template < typename Base, typename Derived >
|
||||
struct is_virtual_base_of : std::integral_constant<bool,
|
||||
std::is_base_of_v<Base, Derived> &&
|
||||
impl::is_virtual_base_of_impl<Derived, Base>(0) &&
|
||||
!impl::is_virtual_base_of_impl<Base, Derived>(0)> {};
|
||||
|
||||
// clang-format on
|
||||
|
||||
template < typename Base, typename Derived >
|
||||
inline constexpr bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
|
||||
}
|
||||
@@ -23,19 +23,20 @@ namespace meta_hpp::detail::class_bind_impl
|
||||
using derived_classes_db_t = std::map<class_type, class_set, std::less<>>;
|
||||
|
||||
template < class_kind Class, class_kind Base >
|
||||
requires detail::class_bind_base_kind<Class, Base>
|
||||
requires std::is_base_of_v<Base, Class>
|
||||
void update_new_bases_db( //
|
||||
new_bases_db_t& new_bases_db
|
||||
) {
|
||||
new_bases_db.emplace(resolve_type<Base>(), [](void* from) {
|
||||
return static_cast<void*>(static_cast<Base*>(static_cast<Class*>(from)));
|
||||
});
|
||||
new_bases_db.try_emplace( //
|
||||
resolve_type<Base>(),
|
||||
std::in_place_type<Class>,
|
||||
std::in_place_type<Base>);
|
||||
}
|
||||
|
||||
inline void update_deep_upcasts_db( //
|
||||
const class_type& derived_class,
|
||||
const class_type& new_base_class,
|
||||
const upcast_func_list_t& derived_to_new_base,
|
||||
upcast_func_list_t&& derived_to_new_base,
|
||||
deep_upcasts_db_t& deep_upcasts_db
|
||||
) {
|
||||
const class_type_data& derived_class_data = *type_access(derived_class);
|
||||
@@ -43,26 +44,27 @@ namespace meta_hpp::detail::class_bind_impl
|
||||
|
||||
const auto [deep_upcasts_db_iter, _] = deep_upcasts_db.try_emplace(derived_class, derived_class_data.deep_upcasts);
|
||||
deep_upcasts_t& derived_deep_upcasts = deep_upcasts_db_iter->second;
|
||||
derived_deep_upcasts.emplace(new_base_class, derived_to_new_base);
|
||||
|
||||
const auto add_derived_deep_upcast = [&derived_deep_upcasts](const class_type& deep_class, upcast_func_list_t&& upcasts) {
|
||||
auto&& [position, emplaced] = derived_deep_upcasts.try_emplace(deep_class, std::move(upcasts));
|
||||
if ( !emplaced ) {
|
||||
position->second.is_ambiguous = is_disjoint(position->second.vbases, upcasts.vbases);
|
||||
}
|
||||
};
|
||||
|
||||
for ( auto&& [new_deep_class, new_base_to_deep] : new_base_class_data.deep_upcasts ) {
|
||||
upcast_func_list_t derived_to_new_deep;
|
||||
derived_to_new_deep.reserve(derived_to_new_base.size() + new_base_to_deep.size());
|
||||
derived_to_new_deep.insert(derived_to_new_deep.end(), derived_to_new_base.begin(), derived_to_new_base.end());
|
||||
derived_to_new_deep.insert(derived_to_new_deep.end(), new_base_to_deep.begin(), new_base_to_deep.end());
|
||||
derived_deep_upcasts.emplace(new_deep_class, std::move(derived_to_new_deep));
|
||||
upcast_func_list_t derived_to_new_deep = derived_to_new_base + new_base_to_deep;
|
||||
add_derived_deep_upcast(new_deep_class, std::move(derived_to_new_deep));
|
||||
}
|
||||
|
||||
for ( const class_type& subderived_class : derived_class_data.derived_classes ) {
|
||||
const class_type_data& subderived_data = *type_access(subderived_class);
|
||||
|
||||
upcast_func_list_t subderived_to_new_base;
|
||||
subderived_to_new_base.reserve(derived_to_new_base.size() + 1);
|
||||
subderived_to_new_base.insert(subderived_to_new_base.end(), subderived_data.base_upcasts.at(derived_class));
|
||||
subderived_to_new_base.insert(subderived_to_new_base.end(), derived_to_new_base.begin(), derived_to_new_base.end());
|
||||
|
||||
update_deep_upcasts_db(subderived_class, new_base_class, subderived_to_new_base, deep_upcasts_db);
|
||||
upcast_func_t subderived_to_derived = subderived_data.base_upcasts.at(derived_class);
|
||||
upcast_func_list_t subderived_to_new_base = subderived_to_derived + derived_to_new_base;
|
||||
update_deep_upcasts_db(subderived_class, new_base_class, std::move(subderived_to_new_base), deep_upcasts_db);
|
||||
}
|
||||
|
||||
add_derived_deep_upcast(new_base_class, std::move(derived_to_new_base));
|
||||
}
|
||||
|
||||
inline void updata_derived_classes_db( //
|
||||
@@ -116,7 +118,7 @@ namespace meta_hpp
|
||||
continue;
|
||||
}
|
||||
|
||||
update_deep_upcasts_db(*this, new_base_class, {self_to_new_base}, deep_upcasts_db);
|
||||
update_deep_upcasts_db(*this, new_base_class, self_to_new_base, deep_upcasts_db);
|
||||
updata_derived_classes_db(*this, new_base_class, derived_classes_db);
|
||||
|
||||
new_base_classes.emplace(new_base_class);
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace meta_hpp::detail
|
||||
namespace impl
|
||||
{
|
||||
template < class_kind Class >
|
||||
struct class_traits_base {
|
||||
struct class_traits_impl {
|
||||
static constexpr std::size_t arity{0};
|
||||
|
||||
using argument_types = type_list<>;
|
||||
@@ -38,7 +38,7 @@ namespace meta_hpp::detail
|
||||
};
|
||||
|
||||
template < template < typename... > typename Class, typename... Args >
|
||||
struct class_traits_base<Class<Args...>> {
|
||||
struct class_traits_impl<Class<Args...>> {
|
||||
static constexpr std::size_t arity{sizeof...(Args)};
|
||||
|
||||
using argument_types = type_list<Args...>;
|
||||
@@ -50,7 +50,7 @@ namespace meta_hpp::detail
|
||||
}
|
||||
|
||||
template < class_kind Class >
|
||||
struct class_traits : impl::class_traits_base<Class> {
|
||||
struct class_traits : impl::class_traits_impl<Class> {
|
||||
static constexpr std::size_t size{sizeof(Class)};
|
||||
static constexpr std::size_t align{alignof(Class)};
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace meta_hpp::detail
|
||||
flags.set(class_flags::is_polymorphic);
|
||||
}
|
||||
|
||||
return flags | impl::class_traits_base<Class>::make_flags();
|
||||
return flags | impl::class_traits_impl<Class>::make_flags();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace meta_hpp::detail
|
||||
{
|
||||
template < pointer_kind To >
|
||||
[[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const {
|
||||
META_HPP_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
META_HPP_DEV_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
|
||||
using to_raw_type = std::remove_cv_t<To>;
|
||||
|
||||
@@ -258,21 +258,27 @@ namespace meta_hpp::detail
|
||||
if ( from_type.is_array() ) {
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
|
||||
return static_cast<To>(pointer_upcast( //
|
||||
void* to_ptr = pointer_upcast( //
|
||||
data_,
|
||||
from_type_array.get_data_type(),
|
||||
to_type_ptr.get_data_type()
|
||||
));
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
return static_cast<To>(to_ptr);
|
||||
}
|
||||
|
||||
if ( from_type.is_pointer() ) {
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
return static_cast<To>(pointer_upcast( //
|
||||
void* to_ptr = pointer_upcast( //
|
||||
*static_cast<void**>(data_),
|
||||
from_type_ptr.get_data_type(),
|
||||
to_type_ptr.get_data_type()
|
||||
));
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
return static_cast<To>(to_ptr);
|
||||
}
|
||||
|
||||
throw_exception(error_code::bad_argument_cast);
|
||||
@@ -280,7 +286,7 @@ namespace meta_hpp::detail
|
||||
|
||||
template < non_pointer_kind To >
|
||||
[[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const {
|
||||
META_HPP_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
META_HPP_DEV_ASSERT(can_cast_to<To>(registry) && "bad argument cast");
|
||||
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
|
||||
@@ -294,6 +300,7 @@ namespace meta_hpp::detail
|
||||
const any_type& to_type = registry.resolve_type<to_raw_type>();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_type, to_type);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
@@ -333,18 +340,11 @@ namespace meta_hpp::detail
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename ArgTypeList, typename F >
|
||||
auto call_with_uargs(type_registry& registry, std::span<const uarg> args, F&& f) {
|
||||
META_HPP_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
return [ args, ®istry, &f ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return f(args[Is].cast<type_list_at_t<Is, ArgTypeList>>(registry)...);
|
||||
}
|
||||
(std::make_index_sequence<type_list_arity_v<ArgTypeList>>());
|
||||
}
|
||||
|
||||
template < typename ArgTypeList >
|
||||
bool can_cast_all_uargs(type_registry& registry, std::span<const uarg> args) {
|
||||
META_HPP_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
if ( args.size() != type_list_arity_v<ArgTypeList> ) {
|
||||
return false;
|
||||
}
|
||||
return [ args, ®istry ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return (... && args[Is].can_cast_to<type_list_at_t<Is, ArgTypeList>>(registry));
|
||||
}
|
||||
@@ -353,10 +353,21 @@ namespace meta_hpp::detail
|
||||
|
||||
template < typename ArgTypeList >
|
||||
bool can_cast_all_uargs(type_registry& registry, std::span<const uarg_base> args) {
|
||||
META_HPP_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
if ( args.size() != type_list_arity_v<ArgTypeList> ) {
|
||||
return false;
|
||||
}
|
||||
return [ args, ®istry ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return (... && args[Is].can_cast_to<type_list_at_t<Is, ArgTypeList>>(registry));
|
||||
}
|
||||
(std::make_index_sequence<type_list_arity_v<ArgTypeList>>());
|
||||
}
|
||||
|
||||
template < typename ArgTypeList, typename F >
|
||||
auto unchecked_call_with_uargs(type_registry& registry, std::span<const uarg> args, F&& f) {
|
||||
META_HPP_DEV_ASSERT(args.size() == type_list_arity_v<ArgTypeList>);
|
||||
return [ args, ®istry, &f ]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return f(args[Is].cast<type_list_at_t<Is, ArgTypeList>>(registry)...);
|
||||
}
|
||||
(std::make_index_sequence<type_list_arity_v<ArgTypeList>>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace meta_hpp::detail
|
||||
{
|
||||
template < inst_class_ref_kind Q >
|
||||
decltype(auto) uinst::cast(type_registry& registry) const {
|
||||
META_HPP_ASSERT(can_cast_to<Q>(registry) && "bad instance cast");
|
||||
META_HPP_DEV_ASSERT(can_cast_to<Q>(registry) && "bad instance cast");
|
||||
|
||||
using inst_class_cv = std::remove_reference_t<Q>;
|
||||
using inst_class = std::remove_cv_t<inst_class_cv>;
|
||||
@@ -192,10 +192,12 @@ namespace meta_hpp::detail
|
||||
const any_type& to_type = registry.resolve_type<inst_class>();
|
||||
|
||||
if ( from_type.is_class() && to_type.is_class() ) {
|
||||
const class_type& from_class = from_type.as_class();
|
||||
const class_type& to_class = to_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_class, to_class);
|
||||
void* to_ptr = pointer_upcast( //
|
||||
data_,
|
||||
from_type.as_class(),
|
||||
to_type.as_class()
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
@@ -215,11 +217,12 @@ namespace meta_hpp::detail
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( from_data_type.is_class() && to_type.is_class() ) {
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
const class_type& to_class = to_type.as_class();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_class);
|
||||
void* to_ptr = pointer_upcast( //
|
||||
*static_cast<void**>(data_),
|
||||
from_data_type.as_class(),
|
||||
to_type.as_class()
|
||||
);
|
||||
META_HPP_ASSERT(to_ptr);
|
||||
|
||||
if constexpr ( !std::is_reference_v<Q> ) {
|
||||
return *static_cast<inst_class_cv*>(to_ptr);
|
||||
|
||||
@@ -105,8 +105,13 @@ namespace meta_hpp::detail
|
||||
const class_type& base_class = base.as_class();
|
||||
const class_type& derived_class = derived.as_class();
|
||||
|
||||
if ( base_class && derived_class && base_class.is_base_of(derived_class) ) {
|
||||
return true;
|
||||
if ( base_class && derived_class ) {
|
||||
const class_type_data& derived_data = *type_access(derived_class);
|
||||
const class_type_data::deep_upcasts_t& deep_upcasts = derived_data.deep_upcasts;
|
||||
|
||||
if ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -124,28 +129,14 @@ namespace meta_hpp::detail
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* base_ptr = nullptr;
|
||||
const class_type_data& from_data = *type_access(from);
|
||||
const class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts;
|
||||
|
||||
class_type_data& from_data = *type_access(from);
|
||||
class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts;
|
||||
|
||||
for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) {
|
||||
void* new_base_ptr = [ptr, iter]() mutable {
|
||||
for ( class_type_data::upcast_func_t upcast : iter->second ) {
|
||||
ptr = upcast(ptr);
|
||||
}
|
||||
return ptr;
|
||||
}();
|
||||
|
||||
if ( base_ptr == nullptr ) {
|
||||
base_ptr = new_base_ptr;
|
||||
} else if ( base_ptr != new_base_ptr ) {
|
||||
// ambiguous conversions
|
||||
return nullptr;
|
||||
}
|
||||
if ( auto iter{deep_upcasts.find(to)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return iter->second.apply(ptr);
|
||||
}
|
||||
|
||||
return base_ptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||
|
||||
@@ -24,6 +24,11 @@ namespace meta_hpp
|
||||
return function.invoke(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename... Args >
|
||||
uresult try_invoke(const function& function, Args&&... args) {
|
||||
return function.try_invoke(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < detail::function_pointer_kind Function, typename... Args >
|
||||
uvalue invoke(Function function_ptr, Args&&... args) {
|
||||
using namespace detail;
|
||||
@@ -31,6 +36,22 @@ namespace meta_hpp
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_function_invoke<function_policy::as_copy_t>(registry, function_ptr, vargs);
|
||||
}
|
||||
|
||||
template < detail::function_pointer_kind Function, typename... Args >
|
||||
uresult try_invoke(Function function_ptr, Args&&... args) {
|
||||
using namespace detail;
|
||||
type_registry& registry{type_registry::instance()};
|
||||
|
||||
{
|
||||
const std::array<uarg_base, sizeof...(Args)> vargs{uarg_base{registry, std::forward<Args>(args)}...};
|
||||
if ( const uerror err = raw_function_invoke_error<Function>(registry, vargs) ) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_function_invoke<function_policy::as_copy_t>(registry, function_ptr, vargs);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -40,6 +61,11 @@ namespace meta_hpp
|
||||
return member.get(std::forward<Instance>(instance));
|
||||
}
|
||||
|
||||
template < typename Instance >
|
||||
uresult try_invoke(const member& member, Instance&& instance) {
|
||||
return member.try_get(std::forward<Instance>(instance));
|
||||
}
|
||||
|
||||
template < detail::member_pointer_kind Member, typename Instance >
|
||||
uvalue invoke(Member member_ptr, Instance&& instance) {
|
||||
using namespace detail;
|
||||
@@ -47,6 +73,22 @@ namespace meta_hpp
|
||||
const uinst vinst{registry, std::forward<Instance>(instance)};
|
||||
return raw_member_getter<member_policy::as_copy_t>(registry, member_ptr, vinst);
|
||||
}
|
||||
|
||||
template < detail::member_pointer_kind Member, typename Instance >
|
||||
uresult try_invoke(Member member_ptr, Instance&& instance) {
|
||||
using namespace detail;
|
||||
type_registry& registry{type_registry::instance()};
|
||||
|
||||
{
|
||||
const uinst_base vinst{registry, std::forward<Instance>(instance)};
|
||||
if ( const uerror err = raw_member_getter_error<Member>(registry, vinst) ) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const uinst vinst{registry, std::forward<Instance>(instance)};
|
||||
return raw_member_getter<member_policy::as_copy_t>(registry, member_ptr, vinst);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -56,6 +98,11 @@ namespace meta_hpp
|
||||
return method.invoke(std::forward<Instance>(instance), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename Instance, typename... Args >
|
||||
uresult try_invoke(const method& method, Instance&& instance, Args&&... args) {
|
||||
return method.try_invoke(std::forward<Instance>(instance), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < detail::method_pointer_kind Method, typename Instance, typename... Args >
|
||||
uvalue invoke(Method method_ptr, Instance&& instance, Args&&... args) {
|
||||
using namespace detail;
|
||||
@@ -64,6 +111,24 @@ namespace meta_hpp
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_method_invoke<method_policy::as_copy_t>(registry, method_ptr, vinst, vargs);
|
||||
}
|
||||
|
||||
template < detail::method_pointer_kind Method, typename Instance, typename... Args >
|
||||
uresult try_invoke(Method method_ptr, Instance&& instance, Args&&... args) {
|
||||
using namespace detail;
|
||||
type_registry& registry{type_registry::instance()};
|
||||
|
||||
{
|
||||
const uinst_base vinst{registry, std::forward<Instance>(instance)};
|
||||
const std::array<uarg_base, sizeof...(Args)> vargs{uarg_base{registry, std::forward<Args>(args)}...};
|
||||
if ( const uerror err = raw_method_invoke_error<Method>(registry, vinst, vargs) ) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const uinst vinst{registry, std::forward<Instance>(instance)};
|
||||
const std::array<uarg, sizeof...(Args)> vargs{uarg{registry, std::forward<Args>(args)}...};
|
||||
return raw_method_invoke<method_policy::as_copy_t>(registry, method_ptr, vinst, vargs);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a constructor with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [](auto&&... all_args) -> uvalue {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [](auto&&... all_args) -> uvalue {
|
||||
if constexpr ( as_object ) {
|
||||
return make_uvalue<class_type>(META_HPP_FWD(all_args)...);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a constructor with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [mem](auto&&... all_args) {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [mem](auto&&... all_args) {
|
||||
return std::construct_at(static_cast<class_type*>(mem), META_HPP_FWD(all_args)...);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a function with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [function_ptr](auto&&... all_args) {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [function_ptr](auto&&... all_args) {
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
function_ptr(META_HPP_FWD(all_args)...);
|
||||
return uvalue{};
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace meta_hpp::detail
|
||||
&& "an attempt to call a method with incorrect argument types"
|
||||
);
|
||||
|
||||
return call_with_uargs<argument_types>(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) {
|
||||
return unchecked_call_with_uargs<argument_types>(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) {
|
||||
if constexpr ( std::is_void_v<return_type> ) {
|
||||
(inst.cast<qualified_type>(registry).*method_ptr)(META_HPP_FWD(all_args)...);
|
||||
return uvalue{};
|
||||
|
||||
@@ -180,10 +180,26 @@ namespace meta_hpp
|
||||
[[nodiscard]] bool is_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
[[nodiscard]] bool is_direct_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
[[nodiscard]] bool is_virtual_base_of() const noexcept;
|
||||
[[nodiscard]] bool is_virtual_base_of(const class_type& derived) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_direct_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
template < detail::class_kind Base >
|
||||
[[nodiscard]] bool is_virtual_derived_from() const noexcept;
|
||||
[[nodiscard]] bool is_virtual_derived_from(const class_type& base) const noexcept;
|
||||
|
||||
[[nodiscard]] function get_function(std::string_view name) const noexcept;
|
||||
[[nodiscard]] member get_member(std::string_view name) const noexcept;
|
||||
[[nodiscard]] method get_method(std::string_view name) const noexcept;
|
||||
@@ -402,11 +418,39 @@ namespace meta_hpp::detail
|
||||
typedef_map typedefs;
|
||||
variable_set variables;
|
||||
|
||||
using upcast_func_t = void* (*)(void*);
|
||||
using upcast_func_list_t = std::vector<upcast_func_t>;
|
||||
struct upcast_func_t final {
|
||||
using upcast_t = void* (*)(void*);
|
||||
|
||||
upcast_t upcast{};
|
||||
class_type target{};
|
||||
bool is_virtual{};
|
||||
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
};
|
||||
|
||||
struct upcast_func_list_t final {
|
||||
using upcasts_t = std::vector<upcast_func_t>;
|
||||
|
||||
upcasts_t upcasts{};
|
||||
class_set vbases{};
|
||||
bool is_ambiguous{};
|
||||
|
||||
upcast_func_list_t(const upcast_func_t& _upcast);
|
||||
upcast_func_list_t(upcasts_t _upcasts, class_set _vbases);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
|
||||
friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r);
|
||||
};
|
||||
|
||||
using base_upcasts_t = std::map<class_type, upcast_func_t, std::less<>>;
|
||||
using deep_upcasts_t = std::multimap<class_type, upcast_func_list_t, std::less<>>;
|
||||
using deep_upcasts_t = std::map<class_type, upcast_func_list_t, std::less<>>;
|
||||
|
||||
base_upcasts_t base_upcasts;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
|
||||
@@ -32,6 +32,69 @@ namespace meta_hpp::detail
|
||||
, argument_types{resolve_types(typename class_traits<Class>::argument_types{})} {}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>)
|
||||
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
|
||||
, target{resolve_type<Base>()}
|
||||
, is_virtual{is_virtual_base_of_v<Base, Derived>} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept {
|
||||
return upcast(ptr);
|
||||
}
|
||||
|
||||
inline const void* class_type_data::upcast_func_t::apply(const void* ptr) const noexcept {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return apply(const_cast<void*>(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast)
|
||||
: upcasts{_upcast} {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
if ( upcast.is_virtual ) {
|
||||
vbases.emplace(upcast.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t _upcasts, class_set _vbases)
|
||||
: upcasts{std::move(_upcasts)}
|
||||
, vbases{std::move(_vbases)} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
ptr = upcast.apply(ptr);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
inline const void* class_type_data::upcast_func_list_t::apply(const void* ptr) const noexcept {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return apply(const_cast<void*>(ptr));
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t operator+( //
|
||||
const class_type_data::upcast_func_list_t& l,
|
||||
const class_type_data::upcast_func_list_t& r
|
||||
) {
|
||||
class_type_data::upcast_func_list_t::upcasts_t new_upcasts;
|
||||
new_upcasts.reserve(l.upcasts.size() + r.upcasts.size());
|
||||
new_upcasts.insert(new_upcasts.end(), l.upcasts.begin(), l.upcasts.end());
|
||||
new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.upcasts.end());
|
||||
|
||||
class_set new_vbases;
|
||||
new_vbases.insert(l.vbases.begin(), l.vbases.end());
|
||||
new_vbases.insert(r.vbases.begin(), r.vbases.end());
|
||||
|
||||
return class_type_data::upcast_func_list_t{std::move(new_upcasts), std::move(new_vbases)};
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
inline class_bitflags class_type::get_flags() const noexcept {
|
||||
@@ -139,12 +202,33 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_base_of(const class_type& derived) const noexcept {
|
||||
return is_valid() && derived.is_valid() && derived.data_->deep_upcasts.contains(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
bool class_type::is_direct_base_of() const noexcept {
|
||||
return is_direct_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_direct_base_of(const class_type& derived) const noexcept {
|
||||
return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
bool class_type::is_virtual_base_of() const noexcept {
|
||||
return is_virtual_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept {
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( derived.data_->deep_upcasts.contains(*this) ) {
|
||||
return true;
|
||||
using deep_upcasts_t = detail::class_type_data::deep_upcasts_t;
|
||||
const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts;
|
||||
|
||||
if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) {
|
||||
return !iter->second.is_ambiguous && !iter->second.vbases.empty();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -156,15 +240,25 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_derived_from(const class_type& base) const noexcept {
|
||||
if ( !is_valid() || !base.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
return base.is_base_of(*this);
|
||||
}
|
||||
|
||||
if ( data_->deep_upcasts.contains(base) ) {
|
||||
return true;
|
||||
}
|
||||
template < detail::class_kind Base >
|
||||
bool class_type::is_direct_derived_from() const noexcept {
|
||||
return is_direct_derived_from(resolve_type<Base>());
|
||||
}
|
||||
|
||||
return false;
|
||||
inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept {
|
||||
return base.is_direct_base_of(*this);
|
||||
}
|
||||
|
||||
template < detail::class_kind Base >
|
||||
bool class_type::is_virtual_derived_from() const noexcept {
|
||||
return is_virtual_derived_from(resolve_type<Base>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_derived_from(const class_type& base) const noexcept {
|
||||
return base.is_virtual_base_of(*this);
|
||||
}
|
||||
|
||||
inline function class_type::get_function(std::string_view name) const noexcept {
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace meta_hpp
|
||||
|
||||
template < typename T, typename... Args, typename Tp = std::decay_t<T> >
|
||||
static Tp& do_ctor(uvalue& dst, Args&&... args) {
|
||||
META_HPP_ASSERT(!dst);
|
||||
META_HPP_DEV_ASSERT(!dst);
|
||||
|
||||
if constexpr ( in_internal_v<Tp> ) {
|
||||
std::construct_at(storage_cast<Tp>(dst.storage_), std::forward<Args>(args)...);
|
||||
@@ -91,7 +91,7 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
static void do_move(uvalue&& self, uvalue& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
|
||||
auto&& [tag, vtable] = unpack_vtag(self);
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
static void do_copy(const uvalue& self, uvalue& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
|
||||
auto&& [tag, vtable] = unpack_vtag(self);
|
||||
|
||||
@@ -172,8 +172,8 @@ namespace meta_hpp
|
||||
.type = resolve_type<Tp>(),
|
||||
|
||||
.move{[](uvalue&& self, uvalue& to) noexcept {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
Tp* src = storage_cast<Tp>(self.storage_);
|
||||
|
||||
@@ -188,8 +188,8 @@ namespace meta_hpp
|
||||
}},
|
||||
|
||||
.copy{[](const uvalue& self, uvalue& to) {
|
||||
META_HPP_ASSERT(!to);
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(!to);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
const Tp* src = storage_cast<Tp>(self.storage_);
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace meta_hpp
|
||||
}},
|
||||
|
||||
.reset{[](uvalue& self) noexcept {
|
||||
META_HPP_ASSERT(self);
|
||||
META_HPP_DEV_ASSERT(self);
|
||||
|
||||
Tp* src = storage_cast<Tp>(self.storage_);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user