From ae60941daf2a8d48f4fc40a8030ad6c21ef831df Mon Sep 17 00:00:00 2001 From: Jean-Louis Leroy Date: Mon, 26 May 2025 18:11:04 -0400 Subject: [PATCH] handle deferred RTTI without UB --- examples/custom_rtti.cpp | 8 +- examples/deferred_custom_rtti.cpp | 6 +- include/boost/openmethod/compiler.hpp | 88 +++----- include/boost/openmethod/core.hpp | 200 ++++++++++-------- include/boost/openmethod/detail/types.hpp | 31 ++- .../openmethod/policies/fast_perfect_hash.hpp | 19 +- .../boost/openmethod/policies/std_rtti.hpp | 6 +- .../boost/openmethod/policies/vptr_vector.hpp | 19 +- include/boost/openmethod/registry.hpp | 2 + test/test_core.cpp | 25 +-- test/test_custom_rtti.cpp | 55 +++-- 11 files changed, 232 insertions(+), 227 deletions(-) diff --git a/examples/custom_rtti.cpp b/examples/custom_rtti.cpp index 0222eb5..cc8d2a5 100644 --- a/examples/custom_rtti.cpp +++ b/examples/custom_rtti.cpp @@ -42,18 +42,18 @@ struct custom_rtti : bom::policies::rtti { template static auto static_type() -> bom::type_id { if constexpr (is_polymorphic) { - return T::static_type; + return reinterpret_cast(T::static_type); } else { - return 0; + return nullptr; } } template static auto dynamic_type(const T& obj) -> bom::type_id { if constexpr (is_polymorphic) { - return obj.type; + return reinterpret_cast(obj.type); } else { - return 0; + return nullptr; } } }; diff --git a/examples/deferred_custom_rtti.cpp b/examples/deferred_custom_rtti.cpp index ec5bb45..2c9af72 100644 --- a/examples/deferred_custom_rtti.cpp +++ b/examples/deferred_custom_rtti.cpp @@ -86,7 +86,7 @@ struct custom_rtti : bom::policies::rtti { template static auto static_type() -> bom::type_id { if constexpr (std::is_base_of_v) { - return T::type_info.id; + return reinterpret_cast(T::type_info.id); } else { return 0; } @@ -95,9 +95,9 @@ struct custom_rtti : bom::policies::rtti { template static auto dynamic_type(const T& obj) -> bom::type_id { if constexpr (std::is_base_of_v) { - return obj.type; + return reinterpret_cast(obj.type); } else { - return 0; + return nullptr; } } diff --git a/include/boost/openmethod/compiler.hpp b/include/boost/openmethod/compiler.hpp index 4ed4533..351ef30 100644 --- a/include/boost/openmethod/compiler.hpp +++ b/include/boost/openmethod/compiler.hpp @@ -239,7 +239,6 @@ struct compiler : detail::generic_compiler { auto initialize(); void install_global_tables(); - void resolve_static_type_ids(); void augment_classes(); void collect_transitive_bases(class_* cls, class_* base); void calculate_transitive_derived(class_& cls); @@ -283,7 +282,6 @@ void compiler::install_global_tables() { template auto compiler::compile() { - resolve_static_type_ids(); augment_classes(); augment_methods(); assign_slots(); @@ -306,52 +304,6 @@ template compiler::compiler() { } -template -void compiler::resolve_static_type_ids() { - if constexpr (Registry::template has_policy< - policies::deferred_static_rtti>) { - using namespace detail; - - auto resolve = [](type_id* p) { - auto pf = reinterpret_cast(*p); - *p = pf(); - }; - - for (auto& ci : Registry::classes) { - resolve(&ci.type); - - if (*ci.last_base == 0) { - for (auto& ti : range{ci.first_base, ci.last_base}) { - resolve(&ti); - } - - *ci.last_base = 1; - } - } - - for (auto& method : Registry::methods) { - for (auto& ti : range{method.vp_begin, method.vp_end}) { - if (*method.vp_end == 0) { - resolve(&ti); - } - - for (auto& overrider : method.specs) { - if (*overrider.vp_end == 0) { - for (auto& ti : - range{overrider.vp_begin, overrider.vp_end}) { - resolve(&ti); - } - - *overrider.vp_end = 1; - } - } - } - - *method.vp_end = 1; - } - } -} - template void compiler::collect_transitive_bases(class_* cls, class_* base) { if (base->mark == class_mark) { @@ -378,6 +330,10 @@ void compiler::augment_classes() { // type_info object per class. However, it guarantees that the // type_index for a class has a unique value. for (auto& cr : Registry::classes) { + if constexpr (Registry::deferred_static_rtti) { + static_cast(cr).resolve_type_ids(); + } + { indent _(trace); ++trace << type_name(cr.type) << ": " @@ -394,11 +350,6 @@ void compiler::augment_classes() { rtc->static_vptr = cr.static_vptr; } - // In the unlikely case that a class does have more than one - // associated ti*, collect them in a vector. We don't use an - // unordered_set because, again, this situation is highly - // unlikely, and, were it to occur, the number of distinct ti*s - // would probably be small. if (std::find( rtc->type_ids.begin(), rtc->type_ids.end(), cr.type) == rtc->type_ids.end()) { @@ -550,7 +501,11 @@ void compiler::augment_methods() { auto meth_iter = methods.begin(); for (auto& meth_info : Registry::methods) { - ++trace << type_name(meth_info.method_type) << " " + if constexpr (Registry::deferred_static_rtti) { + static_cast(meth_info).resolve_type_ids(); + } + + ++trace << type_name(meth_info.method_type_id) << " " << range{meth_info.vp_begin, meth_info.vp_end} << "\n"; indent _(trace); @@ -583,13 +538,13 @@ void compiler::augment_methods() { } if (Registry::template policy::type_index( - meth_info.return_type) != + meth_info.return_type_id) != Registry::template policy::type_index( Registry::template policy::template static_type< void>())) { auto covariant_return_iter = class_map.find( Registry::template policy::type_index( - meth_info.return_type)); + meth_info.return_type_id)); if (covariant_return_iter != class_map.end()) { meth_iter->covariant_return_type = @@ -609,6 +564,11 @@ void compiler::augment_methods() { auto spec_iter = meth_iter->specs.begin(); for (auto& overrider_info : meth_info.specs) { + if constexpr (Registry::deferred_static_rtti) { + static_cast(overrider_info) + .resolve_type_ids(); + } + spec_iter->method_index = meth_iter - methods.begin(); spec_iter->spec_index = spec_iter - meth_iter->specs.begin(); @@ -733,7 +693,7 @@ void compiler::assign_tree_slots(class_& cls, std::size_t base_slot) { for (const auto& mp : cls.used_by_vp) { ++trace << " in " << cls << " for " - << type_name(mp.method->info->method_type) << " parameter " + << type_name(mp.method->info->method_type_id) << " parameter " << mp.param << ": " << next_slot << "\n"; mp.method->slots[mp.param] = next_slot++; } @@ -759,8 +719,8 @@ void compiler::assign_lattice_slots(class_& cls) { if (!cls.used_by_vp.empty()) { for (const auto& mp : cls.used_by_vp) { ++trace << " in " << cls << " for " - << type_name(mp.method->info->method_type) << " parameter " - << mp.param << "\n"; + << type_name(mp.method->info->method_type_id) + << " parameter " << mp.param << "\n"; indent _(trace); @@ -828,7 +788,7 @@ void compiler::build_dispatch_tables() { for (auto& m : methods) { ++trace << "Building dispatch table for " - << type_name(m.info->method_type) << "\n"; + << type_name(m.info->method_type_id) << "\n"; indent _(trace); auto dims = m.arity(); @@ -1119,7 +1079,7 @@ void compiler::write_global_data() { if constexpr (trace_enabled) { ++trace << rflush(4, Registry::dispatch_data.size()) << " " << " method #" << m.dispatch_table[0]->method_index - << " " << type_name(m.info->method_type) << "\n"; + << " " << type_name(m.info->method_type_id) << "\n"; indent _(trace); for (auto& entry : m.dispatch_table) { @@ -1141,7 +1101,7 @@ void compiler::write_global_data() { for (auto& m : methods) { indent _(trace); ++trace << "method #" - << " " << type_name(m.info->method_type) << "\n"; + << " " << type_name(m.info->method_type_id) << "\n"; for (auto& overrider : m.specs) { if (overrider.next) { @@ -1184,7 +1144,7 @@ void compiler::write_global_data() { auto spec = method.dispatch_table[entry.group_index]; trace << "spec #" << spec->spec_index << "\n"; indent _(trace); - ++trace << type_name(method.info->method_type) << "\n"; + ++trace << type_name(method.info->method_type_id) << "\n"; ++trace << spec_name(method, spec); BOOST_ASSERT(gv_iter + 1 <= gv_last); *gv_iter++ = spec->pf; @@ -1192,7 +1152,7 @@ void compiler::write_global_data() { trace << "vp #" << entry.vp_index << " group #" << entry.group_index << "\n"; indent _(trace); - ++trace << type_name(method.info->method_type); + ++trace << type_name(method.info->method_type_id); BOOST_ASSERT(gv_iter + 1 <= gv_last); if (entry.vp_index == 0) { diff --git a/include/boost/openmethod/core.hpp b/include/boost/openmethod/core.hpp index d364b11..0d10e4c 100644 --- a/include/boost/openmethod/core.hpp +++ b/include/boost/openmethod/core.hpp @@ -35,13 +35,10 @@ namespace boost::openmethod { // ============================================================================= -// Registering classes +// Helpers namespace detail { -// ============================================================================= -// Helpers - template constexpr bool is_polymorphic = Registry::rtti::template is_polymorphic; @@ -72,67 +69,46 @@ struct extract_registry { typename extract_registry::others, Type1>; }; -template -auto collect_static_type_id() -> type_id { - using rtti = typename Registry::rtti; +template +struct init_type_ids; - if constexpr (Registry::template has_policy< - policies::deferred_static_rtti>) { - return reinterpret_cast(rtti::template static_type); - } else { - return rtti::template static_type(); +template +struct init_type_ids> { + static auto fn(type_id* ids) { + (..., (*ids++ = Registry::rtti::template static_type())); + return ids; } -} - -template -struct type_id_list; - -template -struct type_id_list, Registry> { - // If using deferred 'static_type', add an extra element in 'value', - // default-initialized to zero, indicating the ids need to be resolved. Set - // to 1 after this is done. - static constexpr std::size_t values = sizeof...(T) + - Registry::template has_policy; - static type_id value[values]; - static type_id* begin; - static type_id* end; -}; - -template -type_id type_id_list, Registry>::value[values] = { - collect_static_type_id()...}; - -template -type_id* type_id_list, Registry>::begin = value; - -template -type_id* type_id_list, Registry>::end = - value + sizeof...(T); - -template -struct type_id_list, Registry> { - static constexpr type_id* const begin = nullptr; - static constexpr auto end = begin; }; template -struct class_declaration_aux; +struct use_class_aux; template -struct class_declaration_aux> - : class_info { - class_declaration_aux() { - this->type = collect_static_type_id(); - this->first_base = - type_id_list, Registry>::begin; - this->last_base = type_id_list, Registry>::end; - Registry::classes.push_back(*this); +struct use_class_aux> + : std::conditional_t< + Registry::deferred_static_rtti, detail::deferred_class_info, + detail::class_info> { + inline static type_id bases[sizeof...(Bases)]; + use_class_aux() { + this->first_base = bases; + this->last_base = bases + sizeof...(Bases); this->is_abstract = std::is_abstract_v; this->static_vptr = &Registry::template static_vptr; + + if constexpr (!Registry::deferred_static_rtti) { + resolve_type_ids(); + } + + Registry::classes.push_back(*this); } - ~class_declaration_aux() { + void resolve_type_ids() { + this->type = Registry::rtti::template static_type(); + auto iter = bases; + (..., (*iter++ = Registry::rtti::template static_type())); + } + + ~use_class_aux() { Registry::classes.remove(*this); } }; @@ -291,7 +267,7 @@ struct use_classes { std::tuple, boost::mp11::mp_transform_q< boost::mp11::mp_bind_front< - detail::class_declaration_aux, + detail::use_class_aux, typename detail::extract_registry::registry>, boost::mp11::mp_apply< detail::inheritance_map, @@ -965,7 +941,9 @@ class method; template< typename Name, typename... Parameters, typename ReturnType, class Registry> class methodReturnType, Registry> - : public detail::method_info { + : public std::conditional_t< + Registry::deferred_static_rtti, detail::deferred_method_info, + detail::method_info> { // Aliases used in implementation only. Everything extracted from template // arguments is capitalized like the arguments themselves. using RegistryType = Registry; @@ -987,6 +965,8 @@ class methodReturnType, Registry> (true && ... && detail::using_same_registry::value)); + inline static type_id vp_type_ids[Arity]; + static std::size_t slots_strides[2 * Arity - 1]; // Slots followed by strides. No stride for first virtual argument. // For 1-method: the offset of the method in the method table, which @@ -996,6 +976,8 @@ class methodReturnType, Registry> // the dispatch table, followed by the offset of the second argument and // the stride in the second dimension, etc. + void resolve_type_ids(); + template auto vptr(const ArgType& arg) const -> vptr_type; @@ -1032,6 +1014,8 @@ class methodReturnType, Registry> method(method&&) = delete; ~method(); + void resolve(); // perhaps virtual, perhaps not + public: // Public aliases. using name_type = Name; @@ -1059,16 +1043,20 @@ class methodReturnType, Registry> typename... OverriderParameters> struct thunk { static auto fn(detail::remove_virtual... arg) -> ReturnType; - using OverriderParameterTypeIds = detail::type_id_list< - detail::overrider_virtual_types< - DeclaredParameters, mp11::mp_list, - Registry>, + using OverriderVirtualParameters = detail::overrider_virtual_types< + DeclaredParameters, mp11::mp_list, Registry>; }; template - struct override_impl { + struct override_impl + : std::conditional_t< + Registry::deferred_static_rtti, detail::deferred_overrider_info, + detail::overrider_info> { explicit override_impl(FunctionPointer* next = nullptr); + void resolve_type_ids(); + + inline static type_id vp_type_ids[Arity]; }; template @@ -1129,23 +1117,35 @@ constexpr bool is_method = std::is_base_of_v; template< typename Name, typename... Parameters, typename ReturnType, class Registry> methodReturnType, Registry>::method() { - method_info::slots_strides_ptr = slots_strides; + this->slots_strides_ptr = slots_strides; - using virtual_type_ids = detail::type_id_list< - boost::mp11::mp_transform_q< - boost::mp11::mp_bind_back, - VirtualParameters>, - Registry>; - method_info::vp_begin = virtual_type_ids::begin; - method_info::vp_end = virtual_type_ids::end; - method_info::not_implemented = + if constexpr (!Registry::deferred_static_rtti) { + resolve_type_ids(); + } + + this->vp_begin = vp_type_ids; + this->vp_end = vp_type_ids + Arity; + this->not_implemented = reinterpret_cast(not_implemented_handler); - method_info::method_type = rtti::template static_type(); - method_info::return_type = rtti::template static_type< - typename virtual_traits::virtual_type>(); + Registry::methods.push_back(*this); } +template< + typename Name, typename... Parameters, typename ReturnType, class Registry> +void method< + Name, auto(Parameters...)->ReturnType, Registry>::resolve_type_ids() { + using namespace detail; + this->method_type_id = rtti::template static_type(); + this->return_type_id = rtti::template static_type< + typename virtual_traits::virtual_type>(); + init_type_ids< + Registry, + mp11::mp_transform_q< + mp11::mp_bind_back, + VirtualParameters>>::fn(this->vp_type_ids); +} + template< typename Name, typename... Parameters, typename ReturnType, class Registry> std::size_t methodReturnType, Registry>:: @@ -1422,33 +1422,47 @@ auto methodReturnType, Registry>:: template< typename Name, typename... Parameters, typename ReturnType, class Registry> template -methodReturnType, Registry>::override_impl< +method::override_impl< Function, FnReturnType>::override_impl(FunctionPointer* p_next) { using namespace detail; - // Work around MSVC bug: using &next as a default value - // for 'next' confuses it about Parameters not being expanded. - if (!p_next) { - p_next = &next; - } - - static overrider_info info; - - if (info.method) { - BOOST_ASSERT(info.method == &fn); + if (this->method) { + BOOST_ASSERT(this->method == &fn); return; } - info.method = &fn; - info.return_type = Registry::rtti::template static_type< - typename virtual_traits::virtual_type>(); - info.type = Registry::rtti::template static_type(); - info.next = reinterpret_cast(p_next); + this->method = &fn; + + if constexpr (!Registry::deferred_static_rtti) { + resolve_type_ids(); + } + + this->next = reinterpret_cast( + p_next ? p_next : &method::next); + using Thunk = thunk; - info.pf = reinterpret_cast(Thunk::fn); - info.vp_begin = Thunk::OverriderParameterTypeIds::begin; - info.vp_end = Thunk::OverriderParameterTypeIds::end; - fn.specs.push_back(info); + this->pf = reinterpret_cast(Thunk::fn); + + this->vp_begin = vp_type_ids; + this->vp_end = vp_type_ids + Arity; + + fn.specs.push_back(*this); +} + +template< + typename Name, typename... Parameters, typename ReturnType, class Registry> +template +void methodReturnType, Registry>::override_impl< + Function, FnReturnType>::resolve_type_ids() { + using namespace detail; + + this->return_type = Registry::rtti::template static_type< + typename virtual_traits::virtual_type>(); + this->type = Registry::rtti::template static_type(); + using Thunk = thunk; + detail:: + init_type_ids::fn( + this->vp_type_ids); } } // namespace boost::openmethod diff --git a/include/boost/openmethod/detail/types.hpp b/include/boost/openmethod/detail/types.hpp index 1e36b33..09f1ede 100644 --- a/include/boost/openmethod/detail/types.hpp +++ b/include/boost/openmethod/detail/types.hpp @@ -29,12 +29,23 @@ union word { word* pw; }; +#if defined(UINTPTR_MAX) +using uintptr = std::uintptr_t; +constexpr uintptr uintptr_max = UINTPTR_MAX; +#else +static_assert( + sizeof(std::size_t) == sizeof(void*), + "This implementation requires that size_t and void* have the same size."); +using uintptr = std::size_t; +constexpr uintptr uintptr_max = (std::numeric_limits::max)(); +#endif + } // namespace detail -using type_id = std::uintptr_t; - using vptr_type = const detail::word*; +using type_id = const void*; + template struct virtual_; @@ -119,6 +130,10 @@ struct class_info : static_list::static_link { } }; +struct deferred_class_info : class_info { + virtual void resolve_type_ids() = 0; +}; + // ----------- // method info @@ -129,8 +144,8 @@ struct method_info : static_list::static_link { type_id* vp_end; static_list specs; void (*not_implemented)(); - type_id method_type; - type_id return_type; + type_id method_type_id; + type_id return_type_id; std::size_t* slots_strides_ptr; auto arity() const { @@ -138,6 +153,10 @@ struct method_info : static_list::static_link { } }; +struct deferred_method_info : method_info { + virtual void resolve_type_ids() = 0; +}; + struct overrider_info : static_list::static_link { ~overrider_info() { method->specs.remove(*this); @@ -151,6 +170,10 @@ struct overrider_info : static_list::static_link { void (*pf)(); }; +struct deferred_overrider_info : overrider_info { + virtual void resolve_type_ids() = 0; +}; + } // namespace detail } // namespace boost::openmethod diff --git a/include/boost/openmethod/policies/fast_perfect_hash.hpp b/include/boost/openmethod/policies/fast_perfect_hash.hpp index 8ec9f33..4696266 100644 --- a/include/boost/openmethod/policies/fast_perfect_hash.hpp +++ b/include/boost/openmethod/policies/fast_perfect_hash.hpp @@ -26,7 +26,7 @@ struct fast_perfect_hash : type_hash { template struct fn { - inline static type_id hash_mult; + inline static std::size_t hash_mult; inline static std::size_t hash_shift; inline static std::size_t hash_min; inline static std::size_t hash_max; @@ -38,8 +38,10 @@ struct fast_perfect_hash : type_hash { }; BOOST_FORCEINLINE - static auto hash(type_id type) -> type_id { - auto index = (hash_mult * type) >> hash_shift; + static auto hash(type_id type) -> std::size_t { + auto index = + (hash_mult * reinterpret_cast(type)) >> + hash_shift; if constexpr (Registry::template has_policy) { check(index, type); @@ -97,7 +99,7 @@ void fast_perfect_hash::fn::initialize( ++M; } - std::uniform_int_distribution uniform_dist; + std::uniform_int_distribution uniform_dist; for (std::size_t pass = 0; pass < 4; ++pass, ++M) { hash_shift = 8 * sizeof(type_id) - M; @@ -117,7 +119,8 @@ void fast_perfect_hash::fn::initialize( buckets.resize(hash_size); while (attempts < 100000) { - std::fill(buckets.begin(), buckets.end(), static_cast(-1)); + std::fill( + buckets.begin(), buckets.end(), type_id(detail::uintptr_max)); ++attempts; ++total_attempts; hash_mult = uniform_dist(rnd) | 1; @@ -126,11 +129,13 @@ void fast_perfect_hash::fn::initialize( for (auto type_iter = iter->type_id_begin(); type_iter != iter->type_id_end(); ++type_iter) { auto type = *type_iter; - auto index = (type * hash_mult) >> hash_shift; + auto index = + (detail::uintptr(type) * hash_mult) >> hash_shift; hash_min = (std::min)(hash_min, index); hash_max = (std::max)(hash_max, index); - if (buckets[index] != static_cast(-1)) { + if (detail::uintptr(buckets[index]) != + detail::uintptr_max) { goto collision; } diff --git a/include/boost/openmethod/policies/std_rtti.hpp b/include/boost/openmethod/policies/std_rtti.hpp index 0179e53..2499cc8 100644 --- a/include/boost/openmethod/policies/std_rtti.hpp +++ b/include/boost/openmethod/policies/std_rtti.hpp @@ -26,14 +26,12 @@ struct std_rtti : rtti { template static auto static_type() -> type_id { - auto tip = &typeid(Class); - return reinterpret_cast(tip); + return &typeid(Class); } template static auto dynamic_type(const Class& obj) -> type_id { - auto tip = &typeid(obj); - return reinterpret_cast(tip); + return &typeid(obj); } template diff --git a/include/boost/openmethod/policies/vptr_vector.hpp b/include/boost/openmethod/policies/vptr_vector.hpp index e50c867..9fae26f 100644 --- a/include/boost/openmethod/policies/vptr_vector.hpp +++ b/include/boost/openmethod/policies/vptr_vector.hpp @@ -44,7 +44,7 @@ struct vptr_vector : extern_vptr { for (auto iter = first; iter != last; ++iter) { for (auto type_iter = iter->type_id_begin(); type_iter != iter->type_id_end(); ++type_iter) { - size = (std::max)(size, *type_iter); + size = (std::max)(size, std::size_t(*type_iter)); } } @@ -60,11 +60,13 @@ struct vptr_vector : extern_vptr { for (auto iter = first; iter != last; ++iter) { for (auto type_iter = iter->type_id_begin(); type_iter != iter->type_id_end(); ++type_iter) { - auto index = *type_iter; + std::size_t index; if constexpr (Registry::template has_policy) { - index = - Registry::template policy::hash(index); + index = Registry::template policy::hash( + *type_iter); + } else { + index = std::size_t(*type_iter); } if constexpr (Registry::template has_policy< @@ -81,10 +83,15 @@ struct vptr_vector : extern_vptr { template static auto dynamic_vptr(const Class& arg) -> const vptr_type& { - auto index = Registry::template policy::dynamic_type(arg); + auto dynamic_type = + Registry::template policy::dynamic_type(arg); + std::size_t index; if constexpr (Registry::template has_policy) { - index = Registry::template policy::hash(index); + index = + Registry::template policy::hash(dynamic_type); + } else { + index = std::size_t(dynamic_type); } if constexpr (Registry::template has_policy) { diff --git a/include/boost/openmethod/registry.hpp b/include/boost/openmethod/registry.hpp index cf6559c..c073c8d 100644 --- a/include/boost/openmethod/registry.hpp +++ b/include/boost/openmethod/registry.hpp @@ -185,6 +185,8 @@ struct registry : detail::registry_base { using rtti = policy; using error_handler = policy; static constexpr auto runtime_checks = has_policy; + static constexpr auto deferred_static_rtti = + has_policy; static constexpr auto trace = has_policy; }; diff --git a/test/test_core.cpp b/test/test_core.cpp index 88ac934..28ec8e3 100644 --- a/test/test_core.cpp +++ b/test/test_core.cpp @@ -149,12 +149,12 @@ static_assert(detail::is_registry); struct not_a_policy {}; static_assert(!detail::is_registry); -BOOST_AUTO_TEST_CASE(test_type_id_list) { - auto iter = type_id_list, default_registry>::begin; - auto last = type_id_list, default_registry>::end; - BOOST_TEST_REQUIRE(last - iter == 2); - BOOST_TEST_REQUIRE(*iter++ == type_id(&typeid(a))); - BOOST_TEST_REQUIRE(*iter++ == type_id(&typeid(b))); +BOOST_AUTO_TEST_CASE(test_init_type_ids) { + type_id ids[2]; + auto last = init_type_ids>::fn(ids); + BOOST_TEST_REQUIRE(last - ids == 2); + BOOST_TEST_REQUIRE(ids[0] == type_id(&typeid(a))); + BOOST_TEST_REQUIRE(ids[1] == type_id(&typeid(b))); } } // namespace test_virtual @@ -263,15 +263,12 @@ static_assert( std::is_same_v< use_classes::tuple_type, std::tuple< - class_declaration_aux< - default_registry, mp11::mp_list>, - class_declaration_aux< - default_registry, mp11::mp_list>, - class_declaration_aux< + use_class_aux>, + use_class_aux>, + use_class_aux< default_registry, mp11::mp_list>, - class_declaration_aux< - default_registry, mp11::mp_list>, - class_declaration_aux< + use_class_aux>, + use_class_aux< default_registry, mp11::mp_list>>>); } // namespace test_use_classes diff --git a/test/test_custom_rtti.cpp b/test/test_custom_rtti.cpp index 73e1f97..f02a3f0 100644 --- a/test/test_custom_rtti.cpp +++ b/test/test_custom_rtti.cpp @@ -49,29 +49,31 @@ struct custom_rtti : policies::rtti { template static auto static_type() { if constexpr (is_polymorphic) { - return reinterpret_cast(T::static_type); + return T::static_type; } else { - return 0; + return nullptr; } } template static auto dynamic_type(const T& obj) { if constexpr (is_polymorphic) { - return reinterpret_cast(obj.type); + return obj.type; } else { - return 0; + return nullptr; } } template static void type_name(type_id type, Stream& stream) { - stream << (type == 0 ? "?" : reinterpret_cast(type)); + stream + << (type == nullptr ? "?" + : reinterpret_cast(type)); } static auto type_index(type_id type) { return std::string_view( - (type == 0 ? "?" : reinterpret_cast(type))); + (type == nullptr ? "?" : reinterpret_cast(type))); } }; }; @@ -140,31 +142,31 @@ struct custom_rtti : policies::rtti { template static constexpr bool is_polymorphic = std::is_base_of_v; - static constexpr auto invalid_type = - (std::numeric_limits::max)(); + inline static auto invalid_type_id = type_id(0xFFFFFF); template static auto static_type() { if constexpr (is_polymorphic) { - return T::static_type; + return type_id(T::static_type); } else { - return invalid_type; + return invalid_type_id; } } template static auto dynamic_type(const T& obj) { if constexpr (is_polymorphic) { - return obj.type; + return type_id(obj.type); } else { - return invalid_type; + return invalid_type_id; } } template static void type_name(type_id type, Stream& stream) { static const char* name[] = {"Animal", "Dog", "Cat"}; - stream << (type == invalid_type ? "?" : name[type]); + stream + << (type == invalid_type_id ? "?" : name[std::size_t(type)]); } static auto type_index(type_id type) { @@ -296,31 +298,28 @@ struct custom_rtti : policies::rtti { template static constexpr bool is_polymorphic = std::is_base_of_v; - static constexpr auto invalid_type = - (std::numeric_limits::max)(); - template static auto static_type() { if constexpr (is_polymorphic) { - return T::static_type; + return type_id(T::static_type); } else { - return invalid_type; + return type_id(0xFFFF); } } template static auto dynamic_type(const T& obj) { if constexpr (is_polymorphic) { - return obj.type; + return type_id(obj.type); } else { - return invalid_type; + return type_id(0xFFFF); } } template static void type_name(type_id type, Stream& stream) { static const char* name[] = {"Animal", "Dog", "Cat"}; - stream << (type == invalid_type ? "?" : name[type]); + stream << (type == type_id(0xFFFF) ? "?" : name[std::size_t(type)]); } static auto type_index(type_id type) { @@ -405,7 +404,7 @@ void call_poke(vptr a, std::ostream& os) { } // namespace using_vptr } // namespace virtual_base -namespace defered_type_id { +namespace deferred_type_id { struct Animal { const char* name; @@ -448,25 +447,25 @@ struct custom_rtti : policies::deferred_static_rtti { template static auto static_type() { if constexpr (is_polymorphic) { - return T::static_type; + return type_id(T::static_type); } else { - return 0; + return nullptr; } } template static auto dynamic_type(const T& obj) { if constexpr (is_polymorphic) { - return obj.type; + return type_id(obj.type); } else { - return 0; + return nullptr; } } template static void type_name(type_id type, Stream& stream) { static const char* name[] = {"Animal", "Dog", "Cat"}; - stream << (type == 0 ? "?" : name[type]); + stream << (type == nullptr ? "?" : name[std::size_t(type)]); } static auto type_index(type_id type) { @@ -522,4 +521,4 @@ BOOST_AUTO_TEST_CASE(custom_rtti_deferred) { } } -} // namespace defered_type_id +} // namespace deferred_type_id