mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 04:22:12 +00:00
handle deferred RTTI without UB
This commit is contained in:
committed by
Jean-Louis Leroy
parent
e8c57b44ff
commit
ae60941daf
@@ -42,18 +42,18 @@ struct custom_rtti : bom::policies::rtti {
|
||||
template<typename T>
|
||||
static auto static_type() -> bom::type_id {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return T::static_type;
|
||||
return reinterpret_cast<bom::type_id>(T::static_type);
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto dynamic_type(const T& obj) -> bom::type_id {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return obj.type;
|
||||
return reinterpret_cast<bom::type_id>(obj.type);
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -86,7 +86,7 @@ struct custom_rtti : bom::policies::rtti {
|
||||
template<typename T>
|
||||
static auto static_type() -> bom::type_id {
|
||||
if constexpr (std::is_base_of_v<Animal, T>) {
|
||||
return T::type_info.id;
|
||||
return reinterpret_cast<bom::type_id>(T::type_info.id);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -95,9 +95,9 @@ struct custom_rtti : bom::policies::rtti {
|
||||
template<typename T>
|
||||
static auto dynamic_type(const T& obj) -> bom::type_id {
|
||||
if constexpr (std::is_base_of_v<Animal, T>) {
|
||||
return obj.type;
|
||||
return reinterpret_cast<bom::type_id>(obj.type);
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Registry>::install_global_tables() {
|
||||
|
||||
template<class Registry>
|
||||
auto compiler<Registry>::compile() {
|
||||
resolve_static_type_ids();
|
||||
augment_classes();
|
||||
augment_methods();
|
||||
assign_slots();
|
||||
@@ -306,52 +304,6 @@ template<class Registry>
|
||||
compiler<Registry>::compiler() {
|
||||
}
|
||||
|
||||
template<class Registry>
|
||||
void compiler<Registry>::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<type_id (*)()>(*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<class Registry>
|
||||
void compiler<Registry>::collect_transitive_bases(class_* cls, class_* base) {
|
||||
if (base->mark == class_mark) {
|
||||
@@ -378,6 +330,10 @@ void compiler<Registry>::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<deferred_class_info&>(cr).resolve_type_ids();
|
||||
}
|
||||
|
||||
{
|
||||
indent _(trace);
|
||||
++trace << type_name(cr.type) << ": "
|
||||
@@ -394,11 +350,6 @@ void compiler<Registry>::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<Registry>::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<deferred_method_info&>(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<Registry>::augment_methods() {
|
||||
}
|
||||
|
||||
if (Registry::template policy<policies::rtti>::type_index(
|
||||
meth_info.return_type) !=
|
||||
meth_info.return_type_id) !=
|
||||
Registry::template policy<policies::rtti>::type_index(
|
||||
Registry::template policy<policies::rtti>::template static_type<
|
||||
void>())) {
|
||||
auto covariant_return_iter = class_map.find(
|
||||
Registry::template policy<policies::rtti>::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<Registry>::augment_methods() {
|
||||
auto spec_iter = meth_iter->specs.begin();
|
||||
|
||||
for (auto& overrider_info : meth_info.specs) {
|
||||
if constexpr (Registry::deferred_static_rtti) {
|
||||
static_cast<deferred_overrider_info&>(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<Registry>::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<Registry>::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<Registry>::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<Registry>::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<Registry>::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<Registry>::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<Registry>::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) {
|
||||
|
||||
@@ -35,13 +35,10 @@
|
||||
namespace boost::openmethod {
|
||||
|
||||
// =============================================================================
|
||||
// Registering classes
|
||||
// Helpers
|
||||
|
||||
namespace detail {
|
||||
|
||||
// =============================================================================
|
||||
// Helpers
|
||||
|
||||
template<class Registry, class Class>
|
||||
constexpr bool is_polymorphic = Registry::rtti::template is_polymorphic<Class>;
|
||||
|
||||
@@ -72,67 +69,46 @@ struct extract_registry<Type1, Type2, MoreTypes...> {
|
||||
typename extract_registry<Type2, MoreTypes...>::others, Type1>;
|
||||
};
|
||||
|
||||
template<class Registry, class Class>
|
||||
auto collect_static_type_id() -> type_id {
|
||||
using rtti = typename Registry::rtti;
|
||||
template<class Registry, class... Class>
|
||||
struct init_type_ids;
|
||||
|
||||
if constexpr (Registry::template has_policy<
|
||||
policies::deferred_static_rtti>) {
|
||||
return reinterpret_cast<type_id>(rtti::template static_type<Class>);
|
||||
} else {
|
||||
return rtti::template static_type<Class>();
|
||||
template<class Registry, class... Class>
|
||||
struct init_type_ids<Registry, mp11::mp_list<Class...>> {
|
||||
static auto fn(type_id* ids) {
|
||||
(..., (*ids++ = Registry::rtti::template static_type<Class>()));
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
||||
template<class TypeList, class Registry>
|
||||
struct type_id_list;
|
||||
|
||||
template<typename... T, class Registry>
|
||||
struct type_id_list<mp11::mp_list<T...>, 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<policies::deferred_static_rtti>;
|
||||
static type_id value[values];
|
||||
static type_id* begin;
|
||||
static type_id* end;
|
||||
};
|
||||
|
||||
template<typename... T, class Registry>
|
||||
type_id type_id_list<mp11::mp_list<T...>, Registry>::value[values] = {
|
||||
collect_static_type_id<Registry, T>()...};
|
||||
|
||||
template<typename... T, class Registry>
|
||||
type_id* type_id_list<mp11::mp_list<T...>, Registry>::begin = value;
|
||||
|
||||
template<typename... T, class Registry>
|
||||
type_id* type_id_list<mp11::mp_list<T...>, Registry>::end =
|
||||
value + sizeof...(T);
|
||||
|
||||
template<class Registry>
|
||||
struct type_id_list<mp11::mp_list<>, Registry> {
|
||||
static constexpr type_id* const begin = nullptr;
|
||||
static constexpr auto end = begin;
|
||||
};
|
||||
|
||||
template<class...>
|
||||
struct class_declaration_aux;
|
||||
struct use_class_aux;
|
||||
|
||||
template<class Registry, class Class, typename... Bases>
|
||||
struct class_declaration_aux<Registry, mp11::mp_list<Class, Bases...>>
|
||||
: class_info {
|
||||
class_declaration_aux() {
|
||||
this->type = collect_static_type_id<Registry, Class>();
|
||||
this->first_base =
|
||||
type_id_list<mp11::mp_list<Bases...>, Registry>::begin;
|
||||
this->last_base = type_id_list<mp11::mp_list<Bases...>, Registry>::end;
|
||||
Registry::classes.push_back(*this);
|
||||
struct use_class_aux<Registry, mp11::mp_list<Class, Bases...>>
|
||||
: 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<Class>;
|
||||
this->static_vptr = &Registry::template static_vptr<Class>;
|
||||
|
||||
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<Class>();
|
||||
auto iter = bases;
|
||||
(..., (*iter++ = Registry::rtti::template static_type<Bases>()));
|
||||
}
|
||||
|
||||
~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<Classes...>::registry>,
|
||||
boost::mp11::mp_apply<
|
||||
detail::inheritance_map,
|
||||
@@ -965,7 +941,9 @@ class method;
|
||||
template<
|
||||
typename Name, typename... Parameters, typename ReturnType, class Registry>
|
||||
class method<Name, auto(Parameters...)->ReturnType, 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 method<Name, auto(Parameters...)->ReturnType, Registry>
|
||||
(true && ... &&
|
||||
detail::using_same_registry<Registry, Parameters>::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 method<Name, auto(Parameters...)->ReturnType, 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<typename ArgType>
|
||||
auto vptr(const ArgType& arg) const -> vptr_type;
|
||||
|
||||
@@ -1032,6 +1014,8 @@ class method<Name, auto(Parameters...)->ReturnType, Registry>
|
||||
method(method&&) = delete;
|
||||
~method();
|
||||
|
||||
void resolve(); // perhaps virtual, perhaps not
|
||||
|
||||
public:
|
||||
// Public aliases.
|
||||
using name_type = Name;
|
||||
@@ -1059,16 +1043,20 @@ class method<Name, auto(Parameters...)->ReturnType, Registry>
|
||||
typename... OverriderParameters>
|
||||
struct thunk<Overrider, OverriderReturn (*)(OverriderParameters...)> {
|
||||
static auto fn(detail::remove_virtual<Parameters>... arg) -> ReturnType;
|
||||
using OverriderParameterTypeIds = detail::type_id_list<
|
||||
detail::overrider_virtual_types<
|
||||
DeclaredParameters, mp11::mp_list<OverriderParameters...>,
|
||||
Registry>,
|
||||
using OverriderVirtualParameters = detail::overrider_virtual_types<
|
||||
DeclaredParameters, mp11::mp_list<OverriderParameters...>,
|
||||
Registry>;
|
||||
};
|
||||
|
||||
template<auto Function, typename FnReturnType>
|
||||
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<auto Function, typename FunctionType>
|
||||
@@ -1129,23 +1117,35 @@ constexpr bool is_method = std::is_base_of_v<detail::method_info, T>;
|
||||
template<
|
||||
typename Name, typename... Parameters, typename ReturnType, class Registry>
|
||||
method<Name, auto(Parameters...)->ReturnType, 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<detail::virtual_type, Registry>,
|
||||
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<void (*)()>(not_implemented_handler);
|
||||
method_info::method_type = rtti::template static_type<method>();
|
||||
method_info::return_type = rtti::template static_type<
|
||||
typename virtual_traits<ReturnType, Registry>::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<method>();
|
||||
this->return_type_id = rtti::template static_type<
|
||||
typename virtual_traits<ReturnType, Registry>::virtual_type>();
|
||||
init_type_ids<
|
||||
Registry,
|
||||
mp11::mp_transform_q<
|
||||
mp11::mp_bind_back<virtual_type, Registry>,
|
||||
VirtualParameters>>::fn(this->vp_type_ids);
|
||||
}
|
||||
|
||||
template<
|
||||
typename Name, typename... Parameters, typename ReturnType, class Registry>
|
||||
std::size_t method<Name, auto(Parameters...)->ReturnType, Registry>::
|
||||
@@ -1422,33 +1422,47 @@ auto method<Name, auto(Parameters...)->ReturnType, Registry>::
|
||||
template<
|
||||
typename Name, typename... Parameters, typename ReturnType, class Registry>
|
||||
template<auto Function, typename FnReturnType>
|
||||
method<Name, auto(Parameters...)->ReturnType, Registry>::override_impl<
|
||||
method<Name, ReturnType(Parameters...), Registry>::override_impl<
|
||||
Function, FnReturnType>::override_impl(FunctionPointer* p_next) {
|
||||
using namespace detail;
|
||||
|
||||
// Work around MSVC bug: using &next<Function> as a default value
|
||||
// for 'next' confuses it about Parameters not being expanded.
|
||||
if (!p_next) {
|
||||
p_next = &next<Function>;
|
||||
}
|
||||
|
||||
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<FnReturnType, Registry>::virtual_type>();
|
||||
info.type = Registry::rtti::template static_type<decltype(Function)>();
|
||||
info.next = reinterpret_cast<void (**)()>(p_next);
|
||||
this->method = &fn;
|
||||
|
||||
if constexpr (!Registry::deferred_static_rtti) {
|
||||
resolve_type_ids();
|
||||
}
|
||||
|
||||
this->next = reinterpret_cast<void (**)()>(
|
||||
p_next ? p_next : &method::next<Function>);
|
||||
|
||||
using Thunk = thunk<Function, decltype(Function)>;
|
||||
info.pf = reinterpret_cast<void (*)()>(Thunk::fn);
|
||||
info.vp_begin = Thunk::OverriderParameterTypeIds::begin;
|
||||
info.vp_end = Thunk::OverriderParameterTypeIds::end;
|
||||
fn.specs.push_back(info);
|
||||
this->pf = reinterpret_cast<void (*)()>(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<auto Function, typename FnReturnType>
|
||||
void method<Name, auto(Parameters...)->ReturnType, Registry>::override_impl<
|
||||
Function, FnReturnType>::resolve_type_ids() {
|
||||
using namespace detail;
|
||||
|
||||
this->return_type = Registry::rtti::template static_type<
|
||||
typename virtual_traits<FnReturnType, Registry>::virtual_type>();
|
||||
this->type = Registry::rtti::template static_type<decltype(Function)>();
|
||||
using Thunk = thunk<Function, decltype(Function)>;
|
||||
detail::
|
||||
init_type_ids<Registry, typename Thunk::OverriderVirtualParameters>::fn(
|
||||
this->vp_type_ids);
|
||||
}
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
@@ -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<std::size_t>::max)();
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using type_id = std::uintptr_t;
|
||||
|
||||
using vptr_type = const detail::word*;
|
||||
|
||||
using type_id = const void*;
|
||||
|
||||
template<typename T>
|
||||
struct virtual_;
|
||||
|
||||
@@ -119,6 +130,10 @@ struct class_info : static_list<class_info>::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<method_info>::static_link {
|
||||
type_id* vp_end;
|
||||
static_list<overrider_info> 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<method_info>::static_link {
|
||||
}
|
||||
};
|
||||
|
||||
struct deferred_method_info : method_info {
|
||||
virtual void resolve_type_ids() = 0;
|
||||
};
|
||||
|
||||
struct overrider_info : static_list<overrider_info>::static_link {
|
||||
~overrider_info() {
|
||||
method->specs.remove(*this);
|
||||
@@ -151,6 +170,10 @@ struct overrider_info : static_list<overrider_info>::static_link {
|
||||
void (*pf)();
|
||||
};
|
||||
|
||||
struct deferred_overrider_info : overrider_info {
|
||||
virtual void resolve_type_ids() = 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
@@ -26,7 +26,7 @@ struct fast_perfect_hash : type_hash {
|
||||
template<class Registry>
|
||||
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<detail::uintptr>(type)) >>
|
||||
hash_shift;
|
||||
|
||||
if constexpr (Registry::template has_policy<runtime_checks>) {
|
||||
check(index, type);
|
||||
@@ -97,7 +99,7 @@ void fast_perfect_hash::fn<Registry>::initialize(
|
||||
++M;
|
||||
}
|
||||
|
||||
std::uniform_int_distribution<type_id> uniform_dist;
|
||||
std::uniform_int_distribution<std::size_t> 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<Registry>::initialize(
|
||||
buckets.resize(hash_size);
|
||||
|
||||
while (attempts < 100000) {
|
||||
std::fill(buckets.begin(), buckets.end(), static_cast<type_id>(-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<Registry>::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<type_id>(-1)) {
|
||||
if (detail::uintptr(buckets[index]) !=
|
||||
detail::uintptr_max) {
|
||||
goto collision;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,14 +26,12 @@ struct std_rtti : rtti {
|
||||
|
||||
template<class Class>
|
||||
static auto static_type() -> type_id {
|
||||
auto tip = &typeid(Class);
|
||||
return reinterpret_cast<type_id>(tip);
|
||||
return &typeid(Class);
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
static auto dynamic_type(const Class& obj) -> type_id {
|
||||
auto tip = &typeid(obj);
|
||||
return reinterpret_cast<type_id>(tip);
|
||||
return &typeid(obj);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
|
||||
@@ -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<type_hash>) {
|
||||
index =
|
||||
Registry::template policy<type_hash>::hash(index);
|
||||
index = Registry::template policy<type_hash>::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<class Class>
|
||||
static auto dynamic_vptr(const Class& arg) -> const vptr_type& {
|
||||
auto index = Registry::template policy<rtti>::dynamic_type(arg);
|
||||
auto dynamic_type =
|
||||
Registry::template policy<rtti>::dynamic_type(arg);
|
||||
std::size_t index;
|
||||
|
||||
if constexpr (Registry::template has_policy<type_hash>) {
|
||||
index = Registry::template policy<type_hash>::hash(index);
|
||||
index =
|
||||
Registry::template policy<type_hash>::hash(dynamic_type);
|
||||
} else {
|
||||
index = std::size_t(dynamic_type);
|
||||
}
|
||||
|
||||
if constexpr (Registry::template has_policy<indirect_vptr>) {
|
||||
|
||||
@@ -185,6 +185,8 @@ struct registry : detail::registry_base {
|
||||
using rtti = policy<policies::rtti>;
|
||||
using error_handler = policy<policies::error_handler>;
|
||||
static constexpr auto runtime_checks = has_policy<policies::runtime_checks>;
|
||||
static constexpr auto deferred_static_rtti =
|
||||
has_policy<policies::deferred_static_rtti>;
|
||||
static constexpr auto trace = has_policy<policies::trace>;
|
||||
};
|
||||
|
||||
|
||||
@@ -149,12 +149,12 @@ static_assert(detail::is_registry<default_registry>);
|
||||
struct not_a_policy {};
|
||||
static_assert(!detail::is_registry<not_a_policy>);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_type_id_list) {
|
||||
auto iter = type_id_list<mp11::mp_list<a&, b&>, default_registry>::begin;
|
||||
auto last = type_id_list<mp11::mp_list<a&, b&>, 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<default_registry, mp11::mp_list<a&, b&>>::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<Animal, Dog, Bulldog, Cat, Dolphin>::tuple_type,
|
||||
std::tuple<
|
||||
class_declaration_aux<
|
||||
default_registry, mp11::mp_list<Animal, Animal>>,
|
||||
class_declaration_aux<
|
||||
default_registry, mp11::mp_list<Dog, Animal, Dog>>,
|
||||
class_declaration_aux<
|
||||
use_class_aux<default_registry, mp11::mp_list<Animal, Animal>>,
|
||||
use_class_aux<default_registry, mp11::mp_list<Dog, Animal, Dog>>,
|
||||
use_class_aux<
|
||||
default_registry, mp11::mp_list<Bulldog, Animal, Dog, Bulldog>>,
|
||||
class_declaration_aux<
|
||||
default_registry, mp11::mp_list<Cat, Animal, Cat>>,
|
||||
class_declaration_aux<
|
||||
use_class_aux<default_registry, mp11::mp_list<Cat, Animal, Cat>>,
|
||||
use_class_aux<
|
||||
default_registry, mp11::mp_list<Dolphin, Animal, Dolphin>>>>);
|
||||
|
||||
} // namespace test_use_classes
|
||||
|
||||
@@ -49,29 +49,31 @@ struct custom_rtti : policies::rtti {
|
||||
template<typename T>
|
||||
static auto static_type() {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return reinterpret_cast<type_id>(T::static_type);
|
||||
return T::static_type;
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto dynamic_type(const T& obj) {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return reinterpret_cast<type_id>(obj.type);
|
||||
return obj.type;
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Stream>
|
||||
static void type_name(type_id type, Stream& stream) {
|
||||
stream << (type == 0 ? "?" : reinterpret_cast<const char*>(type));
|
||||
stream
|
||||
<< (type == nullptr ? "?"
|
||||
: reinterpret_cast<const char*>(type));
|
||||
}
|
||||
|
||||
static auto type_index(type_id type) {
|
||||
return std::string_view(
|
||||
(type == 0 ? "?" : reinterpret_cast<const char*>(type)));
|
||||
(type == nullptr ? "?" : reinterpret_cast<const char*>(type)));
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -140,31 +142,31 @@ struct custom_rtti : policies::rtti {
|
||||
template<class T>
|
||||
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
|
||||
|
||||
static constexpr auto invalid_type =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
inline static auto invalid_type_id = type_id(0xFFFFFF);
|
||||
|
||||
template<typename T>
|
||||
static auto static_type() {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return T::static_type;
|
||||
return type_id(T::static_type);
|
||||
} else {
|
||||
return invalid_type;
|
||||
return invalid_type_id;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto dynamic_type(const T& obj) {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return obj.type;
|
||||
return type_id(obj.type);
|
||||
} else {
|
||||
return invalid_type;
|
||||
return invalid_type_id;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Stream>
|
||||
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<class T>
|
||||
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
|
||||
|
||||
static constexpr auto invalid_type =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
|
||||
template<typename T>
|
||||
static auto static_type() {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return T::static_type;
|
||||
return type_id(T::static_type);
|
||||
} else {
|
||||
return invalid_type;
|
||||
return type_id(0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto dynamic_type(const T& obj) {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return obj.type;
|
||||
return type_id(obj.type);
|
||||
} else {
|
||||
return invalid_type;
|
||||
return type_id(0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Stream>
|
||||
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<Animal> 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<typename T>
|
||||
static auto static_type() {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return T::static_type;
|
||||
return type_id(T::static_type);
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto dynamic_type(const T& obj) {
|
||||
if constexpr (is_polymorphic<T>) {
|
||||
return obj.type;
|
||||
return type_id(obj.type);
|
||||
} else {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Stream>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user