mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-13 11:17:06 +07:00
@@ -9,6 +9,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
@@ -28,6 +30,8 @@
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <version>
|
||||
@@ -40,24 +44,19 @@
|
||||
# define META_HPP_NO_RTTI
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_NO_EXCEPTIONS)
|
||||
# include <exception>
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_NO_RTTI)
|
||||
# include <typeindex>
|
||||
# include <typeinfo>
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_FWD)
|
||||
# define META_HPP_FWD(v) std::forward<decltype(v)>(v)
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_ASSERT)
|
||||
# include <cassert>
|
||||
# define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT
|
||||
#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
|
||||
#endif
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Enum >
|
||||
@@ -303,6 +302,141 @@ 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
|
||||
{
|
||||
template < typename F, typename... Args >
|
||||
class defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
defer() = delete;
|
||||
defer(defer&&) = delete;
|
||||
defer(const defer&) = delete;
|
||||
defer& operator=(defer&&) = delete;
|
||||
defer& operator=(const defer&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit defer(UF&& f, std::tuple<Args...>&& args)
|
||||
: impl::defer_impl<F, Args...>{std::forward<UF>(f), std::move(args)} {}
|
||||
|
||||
~defer() noexcept = default;
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class error_defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
error_defer() = delete;
|
||||
error_defer(error_defer&&) = delete;
|
||||
error_defer(const error_defer&) = delete;
|
||||
error_defer& operator=(error_defer&&) = delete;
|
||||
error_defer& operator=(const error_defer&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit error_defer(UF&& f, std::tuple<Args...>&& args)
|
||||
: impl::defer_impl<F, Args...>{std::forward<UF>(f), std::move(args)}
|
||||
, exceptions_{std::uncaught_exceptions()} {}
|
||||
|
||||
~error_defer() noexcept {
|
||||
if ( exceptions_ == std::uncaught_exceptions() ) {
|
||||
this->dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int exceptions_{};
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class return_defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
return_defer() = delete;
|
||||
return_defer(return_defer&&) = delete;
|
||||
return_defer(const return_defer&) = delete;
|
||||
return_defer& operator=(return_defer&&) = delete;
|
||||
return_defer& operator=(const return_defer&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit return_defer(UF&& f, std::tuple<Args...>&& args)
|
||||
: impl::defer_impl<F, Args...>{std::forward<UF>(f), std::move(args)}
|
||||
, exceptions_{std::uncaught_exceptions()} {}
|
||||
|
||||
~return_defer() noexcept {
|
||||
if ( exceptions_ != std::uncaught_exceptions() ) {
|
||||
this->dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int exceptions_{};
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_defer(F&& f, Args&&... args) {
|
||||
using defer_t = defer<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
return defer_t{std::forward<F>(f), std::make_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_error_defer(F&& f, Args&&... args) {
|
||||
using defer_t = error_defer<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
return defer_t{std::forward<F>(f), std::make_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_return_defer(F&& f, Args&&... args) {
|
||||
using defer_t = return_defer<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
return defer_t{std::forward<F>(f), std::make_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __COUNTER__
|
||||
# define META_HPP_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __COUNTER__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) }
|
||||
# define META_HPP_ERROR_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __COUNTER__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) }
|
||||
# define META_HPP_RETURN_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __COUNTER__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) }
|
||||
#else
|
||||
# define META_HPP_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __LINE__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) }
|
||||
# define META_HPP_ERROR_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __LINE__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) }
|
||||
# define META_HPP_RETURN_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __LINE__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) }
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_NO_EXCEPTIONS)
|
||||
# define META_HPP_TRY try
|
||||
# define META_HPP_CATCH(...) catch ( __VA_ARGS__ )
|
||||
@@ -2375,7 +2509,8 @@ namespace meta_hpp
|
||||
[[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept;
|
||||
[[nodiscard]] const any_type_list& get_argument_types() const noexcept;
|
||||
|
||||
[[nodiscard]] const class_set& get_bases() const noexcept;
|
||||
[[nodiscard]] const class_set& get_base_classes() const noexcept;
|
||||
[[nodiscard]] const class_set& get_derived_classes() const noexcept;
|
||||
[[nodiscard]] const constructor_set& get_constructors() const noexcept;
|
||||
[[nodiscard]] const destructor_set& get_destructors() const noexcept;
|
||||
[[nodiscard]] const function_set& get_functions() const noexcept;
|
||||
@@ -2609,7 +2744,8 @@ namespace meta_hpp::detail
|
||||
const std::size_t align;
|
||||
const any_type_list argument_types;
|
||||
|
||||
class_set bases;
|
||||
class_set base_classes;
|
||||
class_set derived_classes;
|
||||
constructor_set constructors;
|
||||
destructor_set destructors;
|
||||
function_set functions;
|
||||
@@ -2618,13 +2754,14 @@ namespace meta_hpp::detail
|
||||
typedef_map typedefs;
|
||||
variable_set variables;
|
||||
|
||||
struct base_info final {
|
||||
using upcast_fptr = void* (*)(void*);
|
||||
const upcast_fptr upcast;
|
||||
};
|
||||
using upcast_func_t = void* (*)(void*);
|
||||
using upcast_func_list_t = std::vector<upcast_func_t>;
|
||||
|
||||
using base_info_map = std::map<class_type, base_info, std::less<>>;
|
||||
base_info_map bases_info;
|
||||
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<>>;
|
||||
|
||||
base_upcasts_t base_upcasts;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
|
||||
template < class_kind Class >
|
||||
explicit class_type_data(type_list<Class>);
|
||||
@@ -4653,6 +4790,73 @@ namespace meta_hpp
|
||||
: type_bind_base{resolve_type<Array>(), std::move(metadata)} {}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail::class_bind_impl
|
||||
{
|
||||
using base_upcasts_t = class_type_data::base_upcasts_t;
|
||||
using deep_upcasts_t = class_type_data::deep_upcasts_t;
|
||||
|
||||
using upcast_func_t = class_type_data::upcast_func_t;
|
||||
using upcast_func_list_t = class_type_data::upcast_func_list_t;
|
||||
|
||||
using new_bases_db_t = std::map<class_type, upcast_func_t>;
|
||||
using deep_upcasts_db_t = std::map<class_type, deep_upcasts_t, std::less<>>;
|
||||
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>
|
||||
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)));
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
deep_upcasts_db_t& deep_upcasts_db
|
||||
) {
|
||||
const class_type_data& derived_class_data = *type_access(derived_class);
|
||||
const class_type_data& new_base_class_data = *type_access(new_base_class);
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
inline void updata_derived_classes_db( //
|
||||
const class_type& self_class,
|
||||
const class_type& new_base_class,
|
||||
derived_classes_db_t& derived_classes_db
|
||||
) {
|
||||
const class_type_data& base_class_data = *type_access(new_base_class);
|
||||
class_set new_derived_classes{base_class_data.derived_classes};
|
||||
new_derived_classes.emplace(self_class);
|
||||
derived_classes_db.emplace(new_base_class, std::move(new_derived_classes));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < detail::class_kind Class >
|
||||
@@ -4671,28 +4875,47 @@ namespace meta_hpp
|
||||
template < detail::class_kind... Bases >
|
||||
requires(... && detail::class_bind_base_kind<Class, Bases>)
|
||||
class_bind<Class>& class_bind<Class>::base_() {
|
||||
const auto register_base{[this]<detail::class_kind Base>(std::in_place_type_t<Base>) {
|
||||
const class_type& base_type = resolve_type<Base>();
|
||||
using namespace detail;
|
||||
using namespace detail::class_bind_impl;
|
||||
|
||||
auto&& [position, emplaced] = get_data().bases.emplace(base_type);
|
||||
if ( !emplaced ) {
|
||||
return;
|
||||
if ( (... && get_data().base_classes.contains(resolve_type<Bases>())) ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
new_bases_db_t new_bases_db;
|
||||
(update_new_bases_db<Class, Bases>(new_bases_db), ...);
|
||||
|
||||
deep_upcasts_db_t deep_upcasts_db;
|
||||
derived_classes_db_t derived_classes_db;
|
||||
|
||||
class_set new_base_classes{get_data().base_classes};
|
||||
base_upcasts_t new_base_upcasts{get_data().base_upcasts};
|
||||
|
||||
for ( auto&& [new_base_class, self_to_new_base] : new_bases_db ) {
|
||||
if ( new_base_classes.contains(new_base_class) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
META_HPP_TRY {
|
||||
get_data().bases_info.emplace( //
|
||||
base_type,
|
||||
detail::class_type_data::base_info{
|
||||
.upcast{[](void* derived) -> void* { return static_cast<Base*>(static_cast<Class*>(derived)); }}}
|
||||
);
|
||||
}
|
||||
META_HPP_CATCH(...) {
|
||||
get_data().bases.erase(position);
|
||||
META_HPP_RETHROW();
|
||||
}
|
||||
}};
|
||||
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);
|
||||
new_base_upcasts.emplace(new_base_class, self_to_new_base);
|
||||
}
|
||||
|
||||
get_data().base_classes.swap(new_base_classes);
|
||||
get_data().base_upcasts.swap(new_base_upcasts);
|
||||
|
||||
for ( auto&& [derived_class, new_deep_upcasts] : deep_upcasts_db ) {
|
||||
class_type_data& derived_data = *type_access(derived_class);
|
||||
derived_data.deep_upcasts.swap(new_deep_upcasts);
|
||||
}
|
||||
|
||||
for ( auto&& [base_class, new_derived_classes] : derived_classes_db ) {
|
||||
class_type_data& base_data = *type_access(base_class);
|
||||
base_data.derived_classes.swap(new_derived_classes);
|
||||
}
|
||||
|
||||
(register_base(std::in_place_type<Bases>), ...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -5466,37 +5689,34 @@ namespace meta_hpp::detail
|
||||
return ptr;
|
||||
}
|
||||
|
||||
for ( auto&& [base_type, base_info] : type_access(from)->bases_info ) {
|
||||
if ( base_type == to ) {
|
||||
return base_info.upcast(ptr);
|
||||
}
|
||||
void* base_ptr = nullptr;
|
||||
|
||||
if ( base_type.is_derived_from(to) ) {
|
||||
return pointer_upcast(base_info.upcast(ptr), base_type, to);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
}
|
||||
|
||||
template < class_kind To, class_kind From >
|
||||
[[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
|
||||
const class_type& to_class = registry.resolve_type<To>();
|
||||
const class_type& from_class = registry.resolve_type<From>();
|
||||
return static_cast<To*>(pointer_upcast(ptr, from_class, to_class));
|
||||
}
|
||||
|
||||
template < class_kind To, class_kind From >
|
||||
[[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
|
||||
const class_type& to_class = registry.resolve_type<To>();
|
||||
const class_type& from_class = registry.resolve_type<From>();
|
||||
return static_cast<const To*>(pointer_upcast(ptr, from_class, to_class));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
@@ -5513,8 +5733,10 @@ namespace meta_hpp::detail
|
||||
const class_type& to_class = to.as_class();
|
||||
const class_type& from_class = from.as_class();
|
||||
|
||||
if ( to_class && from_class && from_class.is_derived_from(to_class) ) {
|
||||
return pointer_upcast(ptr, from_class, to_class);
|
||||
if ( to_class && from_class ) {
|
||||
if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) {
|
||||
return base_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -5526,6 +5748,27 @@ namespace meta_hpp::detail
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename To, typename From >
|
||||
[[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
|
||||
return static_cast<To*>(pointer_upcast( //
|
||||
ptr,
|
||||
registry.resolve_type<From>(),
|
||||
registry.resolve_type<To>()
|
||||
));
|
||||
}
|
||||
|
||||
template < typename To, typename From >
|
||||
[[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
|
||||
return static_cast<const To*>(pointer_upcast( //
|
||||
ptr,
|
||||
registry.resolve_type<From>(),
|
||||
registry.resolve_type<To>()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
class uarg_base {
|
||||
@@ -7792,8 +8035,12 @@ namespace meta_hpp
|
||||
return data_->argument_types;
|
||||
}
|
||||
|
||||
inline const class_set& class_type::get_bases() const noexcept {
|
||||
return data_->bases;
|
||||
inline const class_set& class_type::get_base_classes() const noexcept {
|
||||
return data_->base_classes;
|
||||
}
|
||||
|
||||
inline const class_set& class_type::get_derived_classes() const noexcept {
|
||||
return data_->derived_classes;
|
||||
}
|
||||
|
||||
inline const constructor_set& class_type::get_constructors() const noexcept {
|
||||
@@ -7873,16 +8120,10 @@ namespace meta_hpp
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( derived.data_->bases.contains(*this) ) {
|
||||
if ( derived.data_->deep_upcasts.contains(*this) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( const class_type& derived_base : derived.data_->bases ) {
|
||||
if ( is_base_of(derived_base) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7896,16 +8137,10 @@ namespace meta_hpp
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( data_->bases.contains(base) ) {
|
||||
if ( data_->deep_upcasts.contains(base) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( const class_type& self_base : data_->bases ) {
|
||||
if ( self_base.is_derived_from(base) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7916,7 +8151,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const function& function = base.get_function(name) ) {
|
||||
return function;
|
||||
}
|
||||
@@ -7932,7 +8167,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const member& member = base.get_member(name) ) {
|
||||
return member;
|
||||
}
|
||||
@@ -7948,7 +8183,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const method& method = base.get_method(name) ) {
|
||||
return method;
|
||||
}
|
||||
@@ -7962,7 +8197,7 @@ namespace meta_hpp
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const any_type& type = base.get_typedef(name) ) {
|
||||
return type;
|
||||
}
|
||||
@@ -7978,7 +8213,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const variable& variable = base.get_variable(name) ) {
|
||||
return variable;
|
||||
}
|
||||
@@ -8050,7 +8285,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const function& function = base.get_function_with(name, first, last) ) {
|
||||
return function;
|
||||
}
|
||||
@@ -8090,7 +8325,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const method& method = base.get_method_with(name, first, last) ) {
|
||||
return method;
|
||||
}
|
||||
|
||||
292
develop/unbench/cast_function_bench.cpp
Normal file
292
develop/unbench/cast_function_bench.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
* 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 <vmath.hpp/vmath_all.hpp>
|
||||
|
||||
#include <rttr/type>
|
||||
#include <rttr/registration>
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace meta = meta_hpp;
|
||||
namespace vmath = vmath_hpp;
|
||||
|
||||
volatile unsigned static_acc{};
|
||||
|
||||
struct base1 {
|
||||
unsigned b1{1};
|
||||
|
||||
base1() = default;
|
||||
virtual ~base1() = default;
|
||||
|
||||
base1(const base1&) = default;
|
||||
base1& operator=(const base1&) = default;
|
||||
|
||||
RTTR_ENABLE()
|
||||
};
|
||||
|
||||
struct base2 : base1 {
|
||||
unsigned b2{2};
|
||||
RTTR_ENABLE(base1)
|
||||
};
|
||||
|
||||
struct base3 : base2 {
|
||||
unsigned b3{3};
|
||||
RTTR_ENABLE(base2)
|
||||
};
|
||||
|
||||
struct base4 : base3 {
|
||||
unsigned b4{4};
|
||||
RTTR_ENABLE(base3)
|
||||
};
|
||||
|
||||
unsigned static_function_1(base1* b1) {
|
||||
unsigned r = b1->b1;
|
||||
static_acc = static_acc + r;
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned static_function_2(base1* b1, base2* b2) {
|
||||
unsigned r = b1->b1 + b2->b2;
|
||||
static_acc = static_acc + r;
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned static_function_3(base1* b1, base2* b2, base3* b3) {
|
||||
unsigned r = b1->b1 + b2->b2 + b3->b3;
|
||||
static_acc = static_acc + r;
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned static_function_4(base1* b1, base2* b2, base3* b3, base4* b4) {
|
||||
unsigned r = b1->b1 + b2->b2 + b3->b3 + b4->b4;
|
||||
static_acc = static_acc + r;
|
||||
return r;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void static_function_reset(const benchmark::State&) {
|
||||
static_acc = 0;
|
||||
}
|
||||
|
||||
const bool registered = [](){
|
||||
meta::class_<base1>();
|
||||
meta::class_<base2>().base_<base1>();
|
||||
meta::class_<base3>().base_<base2>();
|
||||
meta::class_<base4>().base_<base3>();
|
||||
return true;
|
||||
}();
|
||||
|
||||
meta::scope meta_bench_scope = meta::local_scope_("")
|
||||
.function_("cast_function_1", &static_function_1)
|
||||
.function_("cast_function_2", &static_function_2)
|
||||
.function_("cast_function_3", &static_function_3)
|
||||
.function_("cast_function_4", &static_function_4);
|
||||
}
|
||||
|
||||
RTTR_REGISTRATION
|
||||
{
|
||||
using namespace rttr;
|
||||
|
||||
registration::method("cast_function_1", &static_function_1);
|
||||
registration::method("cast_function_2", &static_function_2);
|
||||
registration::method("cast_function_3", &static_function_3);
|
||||
registration::method("cast_function_4", &static_function_4);
|
||||
}
|
||||
|
||||
//
|
||||
// native
|
||||
//
|
||||
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void cast_function_1(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = static_function_1(&b4);
|
||||
META_HPP_ASSERT(r == 1);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void cast_function_2(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = static_function_2(&b4, &b4);
|
||||
META_HPP_ASSERT(r == 3);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void cast_function_3(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = static_function_3(&b4, &b4, &b4);
|
||||
META_HPP_ASSERT(r == 6);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void cast_function_4(benchmark::State &state) {
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = static_function_4(&b4, &b4, &b4, &b4);
|
||||
META_HPP_ASSERT(r == 10);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// meta
|
||||
//
|
||||
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void meta_cast_function_1(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("cast_function_1");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = f(&b4).as<unsigned>();
|
||||
META_HPP_ASSERT(r == 1);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_cast_function_2(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("cast_function_2");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = f(&b4, &b4).as<unsigned>();
|
||||
META_HPP_ASSERT(r == 3);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_cast_function_3(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("cast_function_3");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = f(&b4, &b4, &b4).as<unsigned>();
|
||||
META_HPP_ASSERT(r == 6);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_cast_function_4(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("cast_function_4");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = f(&b4, &b4, &b4, &b4).as<unsigned>();
|
||||
META_HPP_ASSERT(r == 10);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// rttr
|
||||
//
|
||||
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void rttr_cast_function_1(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("cast_function_1");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = m.invoke({},
|
||||
rttr::rttr_cast<base1*>(&b4)).get_value<unsigned>();
|
||||
META_HPP_ASSERT(r == 1);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_cast_function_2(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("cast_function_2");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = m.invoke({},
|
||||
rttr::rttr_cast<base1*>(&b4),
|
||||
rttr::rttr_cast<base2*>(&b4)).get_value<unsigned>();
|
||||
META_HPP_ASSERT(r == 3);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_cast_function_3(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("cast_function_3");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = m.invoke({},
|
||||
rttr::rttr_cast<base1*>(&b4),
|
||||
rttr::rttr_cast<base2*>(&b4),
|
||||
rttr::rttr_cast<base3*>(&b4)).get_value<unsigned>();
|
||||
META_HPP_ASSERT(r == 6);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_cast_function_4(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("cast_function_4");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
base4 b4;
|
||||
for ( auto _ : state ) {
|
||||
unsigned r = m.invoke({},
|
||||
rttr::rttr_cast<base1*>(&b4),
|
||||
rttr::rttr_cast<base2*>(&b4),
|
||||
rttr::rttr_cast<base3*>(&b4),
|
||||
rttr::rttr_cast<base4*>(&b4)).get_value<unsigned>();
|
||||
META_HPP_ASSERT(r == 10);
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(cast_function_1)->Teardown(static_function_reset);
|
||||
BENCHMARK(meta_cast_function_1)->Teardown(static_function_reset);
|
||||
BENCHMARK(rttr_cast_function_1)->Teardown(static_function_reset);
|
||||
|
||||
BENCHMARK(cast_function_2)->Teardown(static_function_reset);
|
||||
BENCHMARK(meta_cast_function_2)->Teardown(static_function_reset);
|
||||
BENCHMARK(rttr_cast_function_2)->Teardown(static_function_reset);
|
||||
|
||||
BENCHMARK(cast_function_3)->Teardown(static_function_reset);
|
||||
BENCHMARK(meta_cast_function_3)->Teardown(static_function_reset);
|
||||
BENCHMARK(rttr_cast_function_3)->Teardown(static_function_reset);
|
||||
|
||||
BENCHMARK(cast_function_4)->Teardown(static_function_reset);
|
||||
BENCHMARK(meta_cast_function_4)->Teardown(static_function_reset);
|
||||
BENCHMARK(rttr_cast_function_4)->Teardown(static_function_reset);
|
||||
@@ -45,28 +45,29 @@ namespace
|
||||
static_angle = static_angle + 0.00001f;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void static_function_reset(const benchmark::State&) {
|
||||
static_acc = 0.f;
|
||||
static_angle = 0.f;
|
||||
}
|
||||
|
||||
meta::scope meta_bench_scope = meta::local_scope_("")
|
||||
.function_("static_function_0", &static_function_0)
|
||||
.function_("static_function_1", &static_function_1)
|
||||
.function_("static_function_2", &static_function_2)
|
||||
.function_("static_function_3", &static_function_3)
|
||||
.function_("static_function_4", &static_function_4);
|
||||
.function_("invoke_function_0", &static_function_0)
|
||||
.function_("invoke_function_1", &static_function_1)
|
||||
.function_("invoke_function_2", &static_function_2)
|
||||
.function_("invoke_function_3", &static_function_3)
|
||||
.function_("invoke_function_4", &static_function_4);
|
||||
}
|
||||
|
||||
RTTR_REGISTRATION
|
||||
{
|
||||
using namespace rttr;
|
||||
|
||||
registration::method("static_function_0", &static_function_0);
|
||||
registration::method("static_function_1", &static_function_1);
|
||||
registration::method("static_function_2", &static_function_2);
|
||||
registration::method("static_function_3", &static_function_3);
|
||||
registration::method("static_function_4", &static_function_4);
|
||||
registration::method("invoke_function_0", &static_function_0);
|
||||
registration::method("invoke_function_1", &static_function_1);
|
||||
registration::method("invoke_function_2", &static_function_2);
|
||||
registration::method("invoke_function_3", &static_function_3);
|
||||
registration::method("invoke_function_4", &static_function_4);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -119,7 +120,7 @@ namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void meta_invoke_function_0(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("static_function_0");
|
||||
meta::function f = meta_bench_scope.get_function("invoke_function_0");
|
||||
for ( auto _ : state ) {
|
||||
f();
|
||||
}
|
||||
@@ -127,7 +128,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_invoke_function_1(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("static_function_1");
|
||||
meta::function f = meta_bench_scope.get_function("invoke_function_1");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -137,7 +138,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_invoke_function_2(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("static_function_2");
|
||||
meta::function f = meta_bench_scope.get_function("invoke_function_2");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -147,7 +148,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_invoke_function_3(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("static_function_3");
|
||||
meta::function f = meta_bench_scope.get_function("invoke_function_3");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -157,7 +158,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void meta_invoke_function_4(benchmark::State &state) {
|
||||
meta::function f = meta_bench_scope.get_function("static_function_4");
|
||||
meta::function f = meta_bench_scope.get_function("invoke_function_4");
|
||||
META_HPP_ASSERT(f.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -174,7 +175,7 @@ namespace
|
||||
{
|
||||
[[maybe_unused]]
|
||||
void rttr_invoke_function_0(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("static_function_0");
|
||||
rttr::method m = rttr::type::get_global_method("invoke_function_0");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -184,7 +185,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_invoke_function_1(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("static_function_1");
|
||||
rttr::method m = rttr::type::get_global_method("invoke_function_1");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -194,7 +195,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_invoke_function_2(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("static_function_2");
|
||||
rttr::method m = rttr::type::get_global_method("invoke_function_2");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -204,7 +205,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_invoke_function_3(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("static_function_3");
|
||||
rttr::method m = rttr::type::get_global_method("invoke_function_3");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
@@ -214,7 +215,7 @@ namespace
|
||||
|
||||
[[maybe_unused]]
|
||||
void rttr_invoke_function_4(benchmark::State &state) {
|
||||
rttr::method m = rttr::type::get_global_method("static_function_4");
|
||||
rttr::method m = rttr::type::get_global_method("invoke_function_4");
|
||||
META_HPP_ASSERT(m.is_valid());
|
||||
|
||||
for ( auto _ : state ) {
|
||||
|
||||
204
develop/untests/meta_features/multiple2_tests.cpp
Normal file
204
develop/untests/meta_features/multiple2_tests.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*******************************************************************************
|
||||
* 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 { std::string a{"a"}; };
|
||||
struct B0 : virtual A { std::string b0{"b0"}; };
|
||||
struct B1 : virtual A { std::string b1{"b1"}; };
|
||||
|
||||
struct C : B0, B1 { std::string c{"c"}; };
|
||||
|
||||
struct D0 : C { std::string d0{"d0"}; };
|
||||
struct E0 : D0 { std::string e0{"e0"}; };
|
||||
|
||||
struct D1 : C { std::string d1{"d1"}; };
|
||||
struct E1 : D1 { std::string e1{"e1"}; };
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_features/multiple2/_") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::class_<C>().base_<B0, B1>();
|
||||
meta::class_<B0>().base_<A>();
|
||||
meta::class_<B1>().base_<A>();
|
||||
|
||||
meta::class_<E0>().base_<D0>();
|
||||
meta::class_<E1>().base_<D1>();
|
||||
|
||||
meta::class_<D0>().base_<C>();
|
||||
meta::class_<D1>().base_<C>();
|
||||
|
||||
// * <- B0 <- * * <- D0 * <- E0
|
||||
// A C
|
||||
// * <- B1 <- * * <- D1 * <- E1
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_features/multiple2") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
const meta::class_type A_type = meta::resolve_type<A>();
|
||||
const meta::class_type B0_type = meta::resolve_type<B0>();
|
||||
const meta::class_type B1_type = meta::resolve_type<B1>();
|
||||
const meta::class_type C_type = meta::resolve_type<C>();
|
||||
const meta::class_type D0_type = meta::resolve_type<D0>();
|
||||
const meta::class_type D1_type = meta::resolve_type<D1>();
|
||||
const meta::class_type E0_type = meta::resolve_type<E0>();
|
||||
const meta::class_type E1_type = meta::resolve_type<E1>();
|
||||
|
||||
REQUIRE(A_type);
|
||||
REQUIRE(B0_type);
|
||||
REQUIRE(B1_type);
|
||||
REQUIRE(C_type);
|
||||
REQUIRE(D0_type);
|
||||
REQUIRE(D1_type);
|
||||
REQUIRE(E0_type);
|
||||
REQUIRE(E1_type);
|
||||
|
||||
SUBCASE("is_base_of") {
|
||||
CHECK(!A_type.is_base_of(A_type));
|
||||
CHECK(A_type.is_base_of(B0_type));
|
||||
CHECK(A_type.is_base_of(B1_type));
|
||||
CHECK(A_type.is_base_of(C_type));
|
||||
CHECK(A_type.is_base_of(D0_type));
|
||||
CHECK(A_type.is_base_of(D1_type));
|
||||
CHECK(A_type.is_base_of(E0_type));
|
||||
CHECK(A_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!B0_type.is_base_of(A_type));
|
||||
CHECK(!B0_type.is_base_of(B0_type));
|
||||
CHECK(!B0_type.is_base_of(B1_type));
|
||||
CHECK(B0_type.is_base_of(C_type));
|
||||
CHECK(B0_type.is_base_of(D0_type));
|
||||
CHECK(B0_type.is_base_of(D1_type));
|
||||
CHECK(B0_type.is_base_of(E0_type));
|
||||
CHECK(B0_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!B1_type.is_base_of(A_type));
|
||||
CHECK(!B1_type.is_base_of(B0_type));
|
||||
CHECK(!B1_type.is_base_of(B1_type));
|
||||
CHECK(B1_type.is_base_of(C_type));
|
||||
CHECK(B1_type.is_base_of(D0_type));
|
||||
CHECK(B1_type.is_base_of(D1_type));
|
||||
CHECK(B1_type.is_base_of(E0_type));
|
||||
CHECK(B1_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!C_type.is_base_of(A_type));
|
||||
CHECK(!C_type.is_base_of(B0_type));
|
||||
CHECK(!C_type.is_base_of(B1_type));
|
||||
CHECK(!C_type.is_base_of(C_type));
|
||||
CHECK(C_type.is_base_of(D0_type));
|
||||
CHECK(C_type.is_base_of(D1_type));
|
||||
CHECK(C_type.is_base_of(E0_type));
|
||||
CHECK(C_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!D0_type.is_base_of(A_type));
|
||||
CHECK(!D0_type.is_base_of(B0_type));
|
||||
CHECK(!D0_type.is_base_of(B1_type));
|
||||
CHECK(!D0_type.is_base_of(C_type));
|
||||
CHECK(!D0_type.is_base_of(D0_type));
|
||||
CHECK(!D0_type.is_base_of(D1_type));
|
||||
CHECK(D0_type.is_base_of(E0_type));
|
||||
CHECK(!D0_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!D1_type.is_base_of(A_type));
|
||||
CHECK(!D1_type.is_base_of(B0_type));
|
||||
CHECK(!D1_type.is_base_of(B1_type));
|
||||
CHECK(!D1_type.is_base_of(C_type));
|
||||
CHECK(!D1_type.is_base_of(D0_type));
|
||||
CHECK(!D1_type.is_base_of(D1_type));
|
||||
CHECK(!D1_type.is_base_of(E0_type));
|
||||
CHECK(D1_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!E0_type.is_base_of(A_type));
|
||||
CHECK(!E0_type.is_base_of(B0_type));
|
||||
CHECK(!E0_type.is_base_of(B1_type));
|
||||
CHECK(!E0_type.is_base_of(C_type));
|
||||
CHECK(!E0_type.is_base_of(D0_type));
|
||||
CHECK(!E0_type.is_base_of(D1_type));
|
||||
CHECK(!E0_type.is_base_of(E0_type));
|
||||
CHECK(!E0_type.is_base_of(E1_type));
|
||||
|
||||
CHECK(!E1_type.is_base_of(A_type));
|
||||
CHECK(!E1_type.is_base_of(B0_type));
|
||||
CHECK(!E1_type.is_base_of(B1_type));
|
||||
CHECK(!E1_type.is_base_of(C_type));
|
||||
CHECK(!E1_type.is_base_of(D0_type));
|
||||
CHECK(!E1_type.is_base_of(D1_type));
|
||||
CHECK(!E1_type.is_base_of(E0_type));
|
||||
CHECK(!E1_type.is_base_of(E1_type));
|
||||
}
|
||||
|
||||
SUBCASE("pointer_upcast") {
|
||||
using meta::detail::type_registry;
|
||||
using meta::detail::pointer_upcast;
|
||||
|
||||
type_registry& r{type_registry::instance()};
|
||||
|
||||
{
|
||||
A a;
|
||||
CHECK(pointer_upcast<A>(r, &a) == &a); CHECK(pointer_upcast<A>(r, &a)->a == "a");
|
||||
CHECK_FALSE(pointer_upcast<B0>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<B1>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &a));
|
||||
}
|
||||
|
||||
{
|
||||
B0 b0;
|
||||
CHECK(pointer_upcast<A>(r, &b0) == &b0); CHECK(pointer_upcast<A>(r, &b0)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &b0) == &b0); CHECK(pointer_upcast<B0>(r, &b0)->b0 == "b0");
|
||||
CHECK_FALSE(pointer_upcast<B1>(r, &b0));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b0));
|
||||
}
|
||||
|
||||
{
|
||||
B1 b1;
|
||||
CHECK(pointer_upcast<A>(r, &b1) == &b1); CHECK(pointer_upcast<A>(r, &b1)->a == "a");
|
||||
CHECK_FALSE(pointer_upcast<B0>(r, &b1));
|
||||
CHECK(pointer_upcast<B1>(r, &b1) == &b1); CHECK(pointer_upcast<B1>(r, &b1)->b1 == "b1");
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b1));
|
||||
}
|
||||
|
||||
{
|
||||
C c;
|
||||
CHECK(pointer_upcast<A>(r, &c) == &c); CHECK(pointer_upcast<A>(r, &c)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &c) == &c); CHECK(pointer_upcast<B0>(r, &c)->b0 == "b0");
|
||||
CHECK(pointer_upcast<B1>(r, &c) == &c); CHECK(pointer_upcast<B1>(r, &c)->b1 == "b1");
|
||||
CHECK(pointer_upcast<C>(r, &c) == &c); CHECK(pointer_upcast<C>(r, &c)->c == "c");
|
||||
CHECK_FALSE(pointer_upcast<D0>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<D1>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E0>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E1>(r, &c));
|
||||
}
|
||||
|
||||
{
|
||||
E0 e0;
|
||||
CHECK(pointer_upcast<A>(r, &e0) == &e0); CHECK(pointer_upcast<A>(r, &e0)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &e0) == &e0); CHECK(pointer_upcast<B0>(r, &e0)->b0 == "b0");
|
||||
CHECK(pointer_upcast<B1>(r, &e0) == &e0); CHECK(pointer_upcast<B1>(r, &e0)->b1 == "b1");
|
||||
CHECK(pointer_upcast<C>(r, &e0) == &e0); CHECK(pointer_upcast<C>(r, &e0)->c == "c");
|
||||
CHECK(pointer_upcast<D0>(r, &e0) == &e0); CHECK(pointer_upcast<D0>(r, &e0)->d0 == "d0");
|
||||
CHECK_FALSE(pointer_upcast<D1>(r, &e0));
|
||||
CHECK(pointer_upcast<E0>(r, &e0) == &e0); CHECK(pointer_upcast<E0>(r, &e0)->e0 == "e0");
|
||||
CHECK_FALSE(pointer_upcast<E1>(r, &e0));
|
||||
}
|
||||
|
||||
{
|
||||
E1 e1;
|
||||
CHECK(pointer_upcast<A>(r, &e1) == &e1); CHECK(pointer_upcast<A>(r, &e1)->a == "a");
|
||||
CHECK(pointer_upcast<B0>(r, &e1) == &e1); CHECK(pointer_upcast<B0>(r, &e1)->b0 == "b0");
|
||||
CHECK(pointer_upcast<B1>(r, &e1) == &e1); CHECK(pointer_upcast<B1>(r, &e1)->b1 == "b1");
|
||||
CHECK(pointer_upcast<C>(r, &e1) == &e1); CHECK(pointer_upcast<C>(r, &e1)->c == "c");
|
||||
CHECK_FALSE(pointer_upcast<D0>(r, &e1));
|
||||
CHECK(pointer_upcast<D1>(r, &e1) == &e1); CHECK(pointer_upcast<D1>(r, &e1)->d1 == "d1");
|
||||
CHECK_FALSE(pointer_upcast<E0>(r, &e1));
|
||||
CHECK(pointer_upcast<E1>(r, &e1) == &e1); CHECK(pointer_upcast<E1>(r, &e1)->e1 == "e1");
|
||||
}
|
||||
}
|
||||
}
|
||||
214
develop/untests/meta_features/multiple_tests.cpp
Normal file
214
develop/untests/meta_features/multiple_tests.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/*******************************************************************************
|
||||
* 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 {
|
||||
A() = default;
|
||||
|
||||
A(A&&) = default;
|
||||
A(const A&) = default;
|
||||
|
||||
A& operator=(A&&) = delete;
|
||||
A& operator=(const A&) = delete;
|
||||
|
||||
virtual ~A() = default;
|
||||
};
|
||||
|
||||
struct B : A {};
|
||||
struct C : A {};
|
||||
struct D : B, C {};
|
||||
struct E : D {};
|
||||
struct F {};
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_features/multiple/_") {
|
||||
namespace meta = meta_hpp;
|
||||
|
||||
meta::class_<D>().base_<B, C>();
|
||||
meta::class_<E>().base_<D>();
|
||||
|
||||
meta::class_<B>().base_<A>();
|
||||
meta::class_<C>().base_<A>();
|
||||
|
||||
// A * <- B <- *
|
||||
// D * <- E
|
||||
// A * <- C <- *
|
||||
}
|
||||
|
||||
TEST_CASE("meta/meta_features/multiple") {
|
||||
namespace meta = meta_hpp;
|
||||
using meta::detail::uarg;
|
||||
using meta::detail::uinst;
|
||||
using meta::detail::type_registry;
|
||||
type_registry& r{type_registry::instance()};
|
||||
|
||||
const meta::class_type A_type = meta::resolve_type<A>();
|
||||
const meta::class_type B_type = meta::resolve_type<B>();
|
||||
const meta::class_type C_type = meta::resolve_type<C>();
|
||||
const meta::class_type D_type = meta::resolve_type<D>();
|
||||
const meta::class_type E_type = meta::resolve_type<E>();
|
||||
const meta::class_type F_type = meta::resolve_type<F>();
|
||||
|
||||
REQUIRE(A_type);
|
||||
REQUIRE(B_type);
|
||||
REQUIRE(C_type);
|
||||
REQUIRE(D_type);
|
||||
REQUIRE(E_type);
|
||||
REQUIRE(F_type);
|
||||
|
||||
SUBCASE("is_base_of") {
|
||||
CHECK(!A_type.is_base_of(A_type));
|
||||
CHECK(A_type.is_base_of(B_type));
|
||||
CHECK(A_type.is_base_of(C_type));
|
||||
CHECK(A_type.is_base_of(D_type));
|
||||
CHECK(A_type.is_base_of(E_type));
|
||||
CHECK(!A_type.is_base_of(F_type));
|
||||
|
||||
CHECK(!B_type.is_base_of(A_type));
|
||||
CHECK(!B_type.is_base_of(B_type));
|
||||
CHECK(!B_type.is_base_of(C_type));
|
||||
CHECK(B_type.is_base_of(D_type));
|
||||
CHECK(B_type.is_base_of(E_type));
|
||||
CHECK(!B_type.is_base_of(F_type));
|
||||
|
||||
CHECK(!C_type.is_base_of(A_type));
|
||||
CHECK(!C_type.is_base_of(B_type));
|
||||
CHECK(!C_type.is_base_of(C_type));
|
||||
CHECK(C_type.is_base_of(D_type));
|
||||
CHECK(C_type.is_base_of(E_type));
|
||||
CHECK(!C_type.is_base_of(F_type));
|
||||
|
||||
CHECK(!D_type.is_base_of(A_type));
|
||||
CHECK(!D_type.is_base_of(B_type));
|
||||
CHECK(!D_type.is_base_of(C_type));
|
||||
CHECK(!D_type.is_base_of(D_type));
|
||||
CHECK(D_type.is_base_of(E_type));
|
||||
CHECK(!D_type.is_base_of(F_type));
|
||||
|
||||
CHECK(!E_type.is_base_of(A_type));
|
||||
CHECK(!E_type.is_base_of(B_type));
|
||||
CHECK(!E_type.is_base_of(C_type));
|
||||
CHECK(!E_type.is_base_of(D_type));
|
||||
CHECK(!E_type.is_base_of(E_type));
|
||||
CHECK(!E_type.is_base_of(F_type));
|
||||
|
||||
CHECK(!F_type.is_base_of(A_type));
|
||||
CHECK(!F_type.is_base_of(B_type));
|
||||
CHECK(!F_type.is_base_of(C_type));
|
||||
CHECK(!F_type.is_base_of(D_type));
|
||||
CHECK(!F_type.is_base_of(E_type));
|
||||
CHECK(!F_type.is_base_of(F_type));
|
||||
}
|
||||
|
||||
SUBCASE("is_derived_from") {
|
||||
CHECK(!A_type.is_derived_from(A_type));
|
||||
CHECK(!A_type.is_derived_from(B_type));
|
||||
CHECK(!A_type.is_derived_from(C_type));
|
||||
CHECK(!A_type.is_derived_from(D_type));
|
||||
CHECK(!A_type.is_derived_from(E_type));
|
||||
CHECK(!A_type.is_derived_from(F_type));
|
||||
|
||||
CHECK(B_type.is_derived_from(A_type));
|
||||
CHECK(!B_type.is_derived_from(B_type));
|
||||
CHECK(!B_type.is_derived_from(C_type));
|
||||
CHECK(!B_type.is_derived_from(D_type));
|
||||
CHECK(!B_type.is_derived_from(E_type));
|
||||
CHECK(!B_type.is_derived_from(F_type));
|
||||
|
||||
CHECK(C_type.is_derived_from(A_type));
|
||||
CHECK(!C_type.is_derived_from(B_type));
|
||||
CHECK(!C_type.is_derived_from(C_type));
|
||||
CHECK(!C_type.is_derived_from(D_type));
|
||||
CHECK(!C_type.is_derived_from(E_type));
|
||||
CHECK(!C_type.is_derived_from(F_type));
|
||||
|
||||
CHECK(D_type.is_derived_from(A_type));
|
||||
CHECK(D_type.is_derived_from(B_type));
|
||||
CHECK(D_type.is_derived_from(C_type));
|
||||
CHECK(!D_type.is_derived_from(D_type));
|
||||
CHECK(!D_type.is_derived_from(E_type));
|
||||
CHECK(!D_type.is_derived_from(F_type));
|
||||
|
||||
CHECK(E_type.is_derived_from(A_type));
|
||||
CHECK(E_type.is_derived_from(B_type));
|
||||
CHECK(E_type.is_derived_from(C_type));
|
||||
CHECK(E_type.is_derived_from(D_type));
|
||||
CHECK(!E_type.is_derived_from(E_type));
|
||||
CHECK(!E_type.is_derived_from(F_type));
|
||||
|
||||
CHECK(!F_type.is_derived_from(A_type));
|
||||
CHECK(!F_type.is_derived_from(B_type));
|
||||
CHECK(!F_type.is_derived_from(C_type));
|
||||
CHECK(!F_type.is_derived_from(D_type));
|
||||
CHECK(!F_type.is_derived_from(F_type));
|
||||
}
|
||||
|
||||
SUBCASE("pointer_upcast") {
|
||||
using meta::detail::pointer_upcast;
|
||||
{
|
||||
A a;
|
||||
CHECK(pointer_upcast<A>(r, &a) == &a);
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &a));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &a));
|
||||
}
|
||||
{
|
||||
const B b;
|
||||
CHECK(pointer_upcast<A>(r, &b) == &b);
|
||||
CHECK(pointer_upcast<B>(r, &b) == &b);
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &b));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &b));
|
||||
}
|
||||
{
|
||||
C c;
|
||||
CHECK(pointer_upcast<A>(r, &c) == &c);
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &c));
|
||||
CHECK(pointer_upcast<C>(r, &c) == &c);
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &c));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &c));
|
||||
}
|
||||
{
|
||||
const D d;
|
||||
CHECK_FALSE(pointer_upcast<A>(r,&d));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<B>(r,&d)) == static_cast<const A*>(static_cast<const B*>(&d)));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<C>(r,&d)) == static_cast<const A*>(static_cast<const C*>(&d)));
|
||||
CHECK(pointer_upcast<B>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<C>(r, &d) == &d);
|
||||
CHECK(pointer_upcast<D>(r, &d) == &d);
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &d));
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &d));
|
||||
}
|
||||
{
|
||||
const E e;
|
||||
CHECK_FALSE(pointer_upcast<A>(r,&e));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<B>(r,&e)) == static_cast<const A*>(static_cast<const B*>(&e)));
|
||||
CHECK(pointer_upcast<A>(r, pointer_upcast<C>(r,&e)) == static_cast<const A*>(static_cast<const C*>(&e)));
|
||||
CHECK(pointer_upcast<B>(r, &e) == &e);
|
||||
CHECK(pointer_upcast<C>(r, &e) == &e);
|
||||
CHECK(pointer_upcast<D>(r, &e) == &e);
|
||||
CHECK(pointer_upcast<E>(r, &e) == &e);
|
||||
CHECK_FALSE(pointer_upcast<F>(r, &e));
|
||||
}
|
||||
{
|
||||
F f;
|
||||
CHECK_FALSE(pointer_upcast<A>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<B>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<C>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<D>(r, &f));
|
||||
CHECK_FALSE(pointer_upcast<E>(r, &f));
|
||||
CHECK(pointer_upcast<F>(r, &f) == &f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,11 +202,18 @@ TEST_CASE("meta/meta_types/class_type") {
|
||||
CHECK(final_derived_clazz_type.get_constructors().size() == 1);
|
||||
}
|
||||
|
||||
SUBCASE("get_bases") {
|
||||
CHECK(base_clazz_1_type.get_bases() == meta::class_set{});
|
||||
CHECK(base_clazz_2_type.get_bases() == meta::class_set{});
|
||||
CHECK(derived_clazz_type.get_bases() == meta::class_set{base_clazz_1_type, base_clazz_2_type});
|
||||
CHECK(final_derived_clazz_type.get_bases() == meta::class_set{derived_clazz_type});
|
||||
SUBCASE("get_base_classes") {
|
||||
CHECK(base_clazz_1_type.get_base_classes() == meta::class_set{});
|
||||
CHECK(base_clazz_2_type.get_base_classes() == meta::class_set{});
|
||||
CHECK(derived_clazz_type.get_base_classes() == meta::class_set{base_clazz_1_type, base_clazz_2_type});
|
||||
CHECK(final_derived_clazz_type.get_base_classes() == meta::class_set{derived_clazz_type});
|
||||
}
|
||||
|
||||
SUBCASE("get_derived_classes") {
|
||||
CHECK(base_clazz_1_type.get_derived_classes() == meta::class_set{derived_clazz_type});
|
||||
CHECK(base_clazz_2_type.get_derived_classes() == meta::class_set{derived_clazz_type});
|
||||
CHECK(derived_clazz_type.get_derived_classes() == meta::class_set{final_derived_clazz_type});
|
||||
CHECK(final_derived_clazz_type.get_derived_classes() == meta::class_set{});
|
||||
}
|
||||
|
||||
SUBCASE("get_functions") {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "meta_base/bitflags.hpp"
|
||||
#include "meta_base/cv_traits.hpp"
|
||||
#include "meta_base/cvref_traits.hpp"
|
||||
#include "meta_base/defer.hpp"
|
||||
#include "meta_base/exceptions.hpp"
|
||||
#include "meta_base/fixed_function.hpp"
|
||||
#include "meta_base/fnv1a_hash.hpp"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
@@ -29,6 +31,8 @@
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <version>
|
||||
@@ -41,20 +45,15 @@
|
||||
# define META_HPP_NO_RTTI
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_NO_EXCEPTIONS)
|
||||
# include <exception>
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_NO_RTTI)
|
||||
# include <typeindex>
|
||||
# include <typeinfo>
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_FWD)
|
||||
# define META_HPP_FWD(v) std::forward<decltype(v)>(v)
|
||||
#endif
|
||||
|
||||
#if !defined(META_HPP_ASSERT)
|
||||
# include <cassert>
|
||||
# define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT
|
||||
#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
|
||||
#endif
|
||||
|
||||
144
headers/meta.hpp/meta_base/defer.hpp
Normal file
144
headers/meta.hpp/meta_base/defer.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*******************************************************************************
|
||||
* 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::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
|
||||
{
|
||||
template < typename F, typename... Args >
|
||||
class defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
defer() = delete;
|
||||
defer(defer&&) = delete;
|
||||
defer(const defer&) = delete;
|
||||
defer& operator=(defer&&) = delete;
|
||||
defer& operator=(const defer&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit defer(UF&& f, std::tuple<Args...>&& args)
|
||||
: impl::defer_impl<F, Args...>{std::forward<UF>(f), std::move(args)} {}
|
||||
|
||||
~defer() noexcept = default;
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class error_defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
error_defer() = delete;
|
||||
error_defer(error_defer&&) = delete;
|
||||
error_defer(const error_defer&) = delete;
|
||||
error_defer& operator=(error_defer&&) = delete;
|
||||
error_defer& operator=(const error_defer&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit error_defer(UF&& f, std::tuple<Args...>&& args)
|
||||
: impl::defer_impl<F, Args...>{std::forward<UF>(f), std::move(args)}
|
||||
, exceptions_{std::uncaught_exceptions()} {}
|
||||
|
||||
~error_defer() noexcept {
|
||||
if ( exceptions_ == std::uncaught_exceptions() ) {
|
||||
this->dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int exceptions_{};
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class return_defer final : public impl::defer_impl<F, Args...> {
|
||||
public:
|
||||
return_defer() = delete;
|
||||
return_defer(return_defer&&) = delete;
|
||||
return_defer(const return_defer&) = delete;
|
||||
return_defer& operator=(return_defer&&) = delete;
|
||||
return_defer& operator=(const return_defer&) = delete;
|
||||
|
||||
template < typename UF >
|
||||
explicit return_defer(UF&& f, std::tuple<Args...>&& args)
|
||||
: impl::defer_impl<F, Args...>{std::forward<UF>(f), std::move(args)}
|
||||
, exceptions_{std::uncaught_exceptions()} {}
|
||||
|
||||
~return_defer() noexcept {
|
||||
if ( exceptions_ != std::uncaught_exceptions() ) {
|
||||
this->dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int exceptions_{};
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_defer(F&& f, Args&&... args) {
|
||||
using defer_t = defer<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
return defer_t{std::forward<F>(f), std::make_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_error_defer(F&& f, Args&&... args) {
|
||||
using defer_t = error_defer<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
return defer_t{std::forward<F>(f), std::make_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_return_defer(F&& f, Args&&... args) {
|
||||
using defer_t = return_defer<std::decay_t<F>, std::decay_t<Args>...>;
|
||||
return defer_t{std::forward<F>(f), std::make_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __COUNTER__
|
||||
# define META_HPP_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __COUNTER__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) }
|
||||
# define META_HPP_ERROR_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __COUNTER__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) }
|
||||
# define META_HPP_RETURN_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __COUNTER__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) }
|
||||
#else
|
||||
# define META_HPP_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __LINE__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) }
|
||||
# define META_HPP_ERROR_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __LINE__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) }
|
||||
# define META_HPP_RETURN_DEFER(...) \
|
||||
auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __LINE__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) }
|
||||
#endif
|
||||
@@ -10,6 +10,73 @@
|
||||
#include "../meta_binds.hpp"
|
||||
#include "../meta_registry.hpp"
|
||||
|
||||
namespace meta_hpp::detail::class_bind_impl
|
||||
{
|
||||
using base_upcasts_t = class_type_data::base_upcasts_t;
|
||||
using deep_upcasts_t = class_type_data::deep_upcasts_t;
|
||||
|
||||
using upcast_func_t = class_type_data::upcast_func_t;
|
||||
using upcast_func_list_t = class_type_data::upcast_func_list_t;
|
||||
|
||||
using new_bases_db_t = std::map<class_type, upcast_func_t>;
|
||||
using deep_upcasts_db_t = std::map<class_type, deep_upcasts_t, std::less<>>;
|
||||
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>
|
||||
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)));
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
deep_upcasts_db_t& deep_upcasts_db
|
||||
) {
|
||||
const class_type_data& derived_class_data = *type_access(derived_class);
|
||||
const class_type_data& new_base_class_data = *type_access(new_base_class);
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
inline void updata_derived_classes_db( //
|
||||
const class_type& self_class,
|
||||
const class_type& new_base_class,
|
||||
derived_classes_db_t& derived_classes_db
|
||||
) {
|
||||
const class_type_data& base_class_data = *type_access(new_base_class);
|
||||
class_set new_derived_classes{base_class_data.derived_classes};
|
||||
new_derived_classes.emplace(self_class);
|
||||
derived_classes_db.emplace(new_base_class, std::move(new_derived_classes));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < detail::class_kind Class >
|
||||
@@ -28,28 +95,47 @@ namespace meta_hpp
|
||||
template < detail::class_kind... Bases >
|
||||
requires(... && detail::class_bind_base_kind<Class, Bases>)
|
||||
class_bind<Class>& class_bind<Class>::base_() {
|
||||
const auto register_base{[this]<detail::class_kind Base>(std::in_place_type_t<Base>) {
|
||||
const class_type& base_type = resolve_type<Base>();
|
||||
using namespace detail;
|
||||
using namespace detail::class_bind_impl;
|
||||
|
||||
auto&& [position, emplaced] = get_data().bases.emplace(base_type);
|
||||
if ( !emplaced ) {
|
||||
return;
|
||||
if ( (... && get_data().base_classes.contains(resolve_type<Bases>())) ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
new_bases_db_t new_bases_db;
|
||||
(update_new_bases_db<Class, Bases>(new_bases_db), ...);
|
||||
|
||||
deep_upcasts_db_t deep_upcasts_db;
|
||||
derived_classes_db_t derived_classes_db;
|
||||
|
||||
class_set new_base_classes{get_data().base_classes};
|
||||
base_upcasts_t new_base_upcasts{get_data().base_upcasts};
|
||||
|
||||
for ( auto&& [new_base_class, self_to_new_base] : new_bases_db ) {
|
||||
if ( new_base_classes.contains(new_base_class) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
META_HPP_TRY {
|
||||
get_data().bases_info.emplace( //
|
||||
base_type,
|
||||
detail::class_type_data::base_info{
|
||||
.upcast{[](void* derived) -> void* { return static_cast<Base*>(static_cast<Class*>(derived)); }}}
|
||||
);
|
||||
}
|
||||
META_HPP_CATCH(...) {
|
||||
get_data().bases.erase(position);
|
||||
META_HPP_RETHROW();
|
||||
}
|
||||
}};
|
||||
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);
|
||||
new_base_upcasts.emplace(new_base_class, self_to_new_base);
|
||||
}
|
||||
|
||||
get_data().base_classes.swap(new_base_classes);
|
||||
get_data().base_upcasts.swap(new_base_upcasts);
|
||||
|
||||
for ( auto&& [derived_class, new_deep_upcasts] : deep_upcasts_db ) {
|
||||
class_type_data& derived_data = *type_access(derived_class);
|
||||
derived_data.deep_upcasts.swap(new_deep_upcasts);
|
||||
}
|
||||
|
||||
for ( auto&& [base_class, new_derived_classes] : derived_classes_db ) {
|
||||
class_type_data& base_data = *type_access(base_class);
|
||||
base_data.derived_classes.swap(new_derived_classes);
|
||||
}
|
||||
|
||||
(register_base(std::in_place_type<Bases>), ...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,37 +124,34 @@ namespace meta_hpp::detail
|
||||
return ptr;
|
||||
}
|
||||
|
||||
for ( auto&& [base_type, base_info] : type_access(from)->bases_info ) {
|
||||
if ( base_type == to ) {
|
||||
return base_info.upcast(ptr);
|
||||
}
|
||||
void* base_ptr = nullptr;
|
||||
|
||||
if ( base_type.is_derived_from(to) ) {
|
||||
return pointer_upcast(base_info.upcast(ptr), base_type, to);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||
// NOLINTNEXTLINE(*-const-cast)
|
||||
return pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
}
|
||||
|
||||
template < class_kind To, class_kind From >
|
||||
[[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
|
||||
const class_type& to_class = registry.resolve_type<To>();
|
||||
const class_type& from_class = registry.resolve_type<From>();
|
||||
return static_cast<To*>(pointer_upcast(ptr, from_class, to_class));
|
||||
}
|
||||
|
||||
template < class_kind To, class_kind From >
|
||||
[[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
|
||||
const class_type& to_class = registry.resolve_type<To>();
|
||||
const class_type& from_class = registry.resolve_type<From>();
|
||||
return static_cast<const To*>(pointer_upcast(ptr, from_class, to_class));
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
@@ -171,8 +168,10 @@ namespace meta_hpp::detail
|
||||
const class_type& to_class = to.as_class();
|
||||
const class_type& from_class = from.as_class();
|
||||
|
||||
if ( to_class && from_class && from_class.is_derived_from(to_class) ) {
|
||||
return pointer_upcast(ptr, from_class, to_class);
|
||||
if ( to_class && from_class ) {
|
||||
if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) {
|
||||
return base_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -183,3 +182,24 @@ namespace meta_hpp::detail
|
||||
return pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename To, typename From >
|
||||
[[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
|
||||
return static_cast<To*>(pointer_upcast( //
|
||||
ptr,
|
||||
registry.resolve_type<From>(),
|
||||
registry.resolve_type<To>()
|
||||
));
|
||||
}
|
||||
|
||||
template < typename To, typename From >
|
||||
[[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
|
||||
return static_cast<const To*>(pointer_upcast( //
|
||||
ptr,
|
||||
registry.resolve_type<From>(),
|
||||
registry.resolve_type<To>()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,8 @@ namespace meta_hpp
|
||||
[[nodiscard]] any_type get_argument_type(std::size_t position) const noexcept;
|
||||
[[nodiscard]] const any_type_list& get_argument_types() const noexcept;
|
||||
|
||||
[[nodiscard]] const class_set& get_bases() const noexcept;
|
||||
[[nodiscard]] const class_set& get_base_classes() const noexcept;
|
||||
[[nodiscard]] const class_set& get_derived_classes() const noexcept;
|
||||
[[nodiscard]] const constructor_set& get_constructors() const noexcept;
|
||||
[[nodiscard]] const destructor_set& get_destructors() const noexcept;
|
||||
[[nodiscard]] const function_set& get_functions() const noexcept;
|
||||
@@ -391,7 +392,8 @@ namespace meta_hpp::detail
|
||||
const std::size_t align;
|
||||
const any_type_list argument_types;
|
||||
|
||||
class_set bases;
|
||||
class_set base_classes;
|
||||
class_set derived_classes;
|
||||
constructor_set constructors;
|
||||
destructor_set destructors;
|
||||
function_set functions;
|
||||
@@ -400,13 +402,14 @@ namespace meta_hpp::detail
|
||||
typedef_map typedefs;
|
||||
variable_set variables;
|
||||
|
||||
struct base_info final {
|
||||
using upcast_fptr = void* (*)(void*);
|
||||
const upcast_fptr upcast;
|
||||
};
|
||||
using upcast_func_t = void* (*)(void*);
|
||||
using upcast_func_list_t = std::vector<upcast_func_t>;
|
||||
|
||||
using base_info_map = std::map<class_type, base_info, std::less<>>;
|
||||
base_info_map bases_info;
|
||||
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<>>;
|
||||
|
||||
base_upcasts_t base_upcasts;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
|
||||
template < class_kind Class >
|
||||
explicit class_type_data(type_list<Class>);
|
||||
|
||||
@@ -58,8 +58,12 @@ namespace meta_hpp
|
||||
return data_->argument_types;
|
||||
}
|
||||
|
||||
inline const class_set& class_type::get_bases() const noexcept {
|
||||
return data_->bases;
|
||||
inline const class_set& class_type::get_base_classes() const noexcept {
|
||||
return data_->base_classes;
|
||||
}
|
||||
|
||||
inline const class_set& class_type::get_derived_classes() const noexcept {
|
||||
return data_->derived_classes;
|
||||
}
|
||||
|
||||
inline const constructor_set& class_type::get_constructors() const noexcept {
|
||||
@@ -139,16 +143,10 @@ namespace meta_hpp
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( derived.data_->bases.contains(*this) ) {
|
||||
if ( derived.data_->deep_upcasts.contains(*this) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( const class_type& derived_base : derived.data_->bases ) {
|
||||
if ( is_base_of(derived_base) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -162,16 +160,10 @@ namespace meta_hpp
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( data_->bases.contains(base) ) {
|
||||
if ( data_->deep_upcasts.contains(base) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( const class_type& self_base : data_->bases ) {
|
||||
if ( self_base.is_derived_from(base) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -182,7 +174,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const function& function = base.get_function(name) ) {
|
||||
return function;
|
||||
}
|
||||
@@ -198,7 +190,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const member& member = base.get_member(name) ) {
|
||||
return member;
|
||||
}
|
||||
@@ -214,7 +206,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const method& method = base.get_method(name) ) {
|
||||
return method;
|
||||
}
|
||||
@@ -228,7 +220,7 @@ namespace meta_hpp
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const any_type& type = base.get_typedef(name) ) {
|
||||
return type;
|
||||
}
|
||||
@@ -244,7 +236,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const variable& variable = base.get_variable(name) ) {
|
||||
return variable;
|
||||
}
|
||||
@@ -316,7 +308,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const function& function = base.get_function_with(name, first, last) ) {
|
||||
return function;
|
||||
}
|
||||
@@ -356,7 +348,7 @@ namespace meta_hpp
|
||||
}
|
||||
}
|
||||
|
||||
for ( const class_type& base : data_->bases ) {
|
||||
for ( const class_type& base : data_->base_classes ) {
|
||||
if ( const method& method = base.get_method_with(name, first, last) ) {
|
||||
return method;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user