Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions include/boost/openmethod/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2792,10 +2792,6 @@ using boost::openmethod::virtual_ptr;

#ifdef __MRDOCS__

namespace detail {
struct unspecified;
}

//! Blueprint for a specialization of @ref virtual_traits (exposition only).
//!
//! Specializations of @ref virtual_traits must implement the members listed
Expand Down
88 changes: 62 additions & 26 deletions include/boost/openmethod/initialize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,23 +182,30 @@ struct generic_compiler {

return nullptr;
}

std::deque<class_> classes;

auto classes_begin() const {
return classes.begin();
}

auto classes_end() const {
return classes.end();
}

std::vector<method> methods;
std::size_t class_mark = 0;
bool compilation_done = false;
};

template<class Compiler>
struct trace_stream {
trace_stream(bool trace) : trace(trace) {
}

bool trace;
bool on = false;
std::size_t indentation_level{0};

auto operator++() -> trace_stream& {
if constexpr (Compiler::has_trace) {
if (trace) {
if (on) {
for (std::size_t i = 0; i < indentation_level; ++i) {
Compiler::Registry::output::os << " ";
}
Expand Down Expand Up @@ -296,7 +303,7 @@ struct range;
template<class Compiler, typename T, typename F>
auto write_range(trace_stream<Compiler>& tr, range<T> range, F fn) -> auto& {
if constexpr (Compiler::has_trace) {
if (tr.trace) {
if (tr.on) {
tr << "(";
const char* sep = "";
for (auto value : range) {
Expand All @@ -314,7 +321,7 @@ auto write_range(trace_stream<Compiler>& tr, range<T> range, F fn) -> auto& {
template<class Compiler, typename T>
auto operator<<(trace_stream<Compiler>& tr, const T& value) -> auto& {
if constexpr (Compiler::has_trace) {
if (tr.trace) {
if (tr.on) {
Compiler::Registry::output::os << value;
}
}
Expand All @@ -324,7 +331,7 @@ auto operator<<(trace_stream<Compiler>& tr, const T& value) -> auto& {
template<class Compiler>
auto operator<<(trace_stream<Compiler>& tr, const rflush& rf) -> auto& {
if constexpr (Compiler::has_trace) {
if (tr.trace) {
if (tr.on) {
std::size_t digits = 1;
auto tmp = rf.value / 10;

Expand All @@ -349,7 +356,7 @@ template<class Compiler>
auto operator<<(trace_stream<Compiler>& tr, const boost::dynamic_bitset<>& bits)
-> auto& {
if constexpr (Compiler::has_trace) {
if (tr.trace) {
if (tr.on) {
auto i = bits.size();
while (i != 0) {
--i;
Expand Down Expand Up @@ -388,9 +395,6 @@ template<class... Options>
struct registry<Policies...>::compiler : detail::generic_compiler {
using type_index_type = decltype(rtti::type_index(0));

static constexpr bool use_n2216 =
mp11::mp_contains<mp11::mp_list<Options...>, n2216>::value;

typename detail::aggregate_reports<mp11::mp_list<report>, policy_list>::type
report;

Expand Down Expand Up @@ -425,10 +429,15 @@ struct registry<Policies...>::compiler : detail::generic_compiler {
is_more_specific(const overrider* a, const overrider* b) -> bool;
static auto is_base(const overrider* a, const overrider* b) -> bool;

std::tuple<Options...> opts;
static constexpr bool has_trace =
mp11::mp_contains<mp11::mp_list<Options...>, openmethod::trace>::value;
bool trace = false;
std::tuple<Options...> options;

template<class Option>
static constexpr bool has_option =
mp11::mp_contains<mp11::mp_list<Options...>, Option>::value;

static constexpr bool has_trace = has_option<trace>;
static constexpr bool has_n2216 = has_option<n2216>;

mutable detail::trace_stream<compiler> tr;
using indent = typename detail::trace_stream<compiler>::indent;
};
Expand Down Expand Up @@ -467,11 +476,42 @@ void registry<Policies...>::compiler<Options...>::initialize() {
registry<Policies...>::initialized = true;
}

#ifdef _MSC_VER
namespace detail {

template<bool HasTrace, typename T>
struct msvc_tuple_get;

template<typename T>
struct msvc_tuple_get<true, T> {
template<class Tuple>
static decltype(auto) fn(const Tuple& t) {
return std::get<T>(t);
}
};

template<typename T>
struct msvc_tuple_get<false, T> {
template<class Tuple>
static decltype(auto) fn(const Tuple&) {
return T();
}
};
} // namespace detail
#endif

template<class... Policies>
template<class... Options>
registry<Policies...>::compiler<Options...>::compiler(Options... opts)
: opts(opts...), trace(detail::option<openmethod::trace>(this->opts).on),
tr(trace) {
: options(opts...) {
if constexpr (has_trace) {
#ifdef _MSC_VER
tr.on = detail::msvc_tuple_get<has_trace, trace>::fn(options).on;
#else
// Even with the constexpr has_trace guard, msvc errors on this.
tr.on = std::get<trace>(options).on;
#endif
}
}

template<class... Policies>
Expand Down Expand Up @@ -1148,7 +1188,7 @@ void registry<Policies...>::compiler<Options...>::build_dispatch_table(
m.dispatch_table.push_back(&m.not_implemented);
++m.report.not_implemented;
} else {
if constexpr (!use_n2216) {
if constexpr (!has_option<n2216>) {
if (remaining > 1) {
++tr << "ambiguous\n";
m.dispatch_table.push_back(&m.ambiguous);
Expand Down Expand Up @@ -1209,7 +1249,7 @@ void registry<Policies...>::compiler<Options...>::build_dispatch_table(

select_dominant_overriders(overriders, pick, remaining);

if constexpr (!use_n2216) {
if constexpr (!has_option<n2216>) {
if (remaining > 1) {
++tr << "ambiguous 'next'\n";
overrider->next = &m.ambiguous;
Expand Down Expand Up @@ -1368,7 +1408,7 @@ void registry<Policies...>::compiler<Options...>::write_global_data() {
++tr << rflush(4, dispatch_data_size) << " " << gv_iter << " end\n";

if constexpr (has_vptr) {
vptr::initialize(classes.begin(), classes.end(), opts);
vptr::initialize(*this, options);
}

new_dispatch_data.swap(dispatch_data);
Expand Down Expand Up @@ -1407,7 +1447,7 @@ void registry<Policies...>::compiler<Options...>::select_dominant_overriders(
return;
}

if constexpr (use_n2216) {
if constexpr (has_option<n2216>) {
if (!candidates[pick]->covariant_return_type) {
return;
}
Expand Down Expand Up @@ -1571,10 +1611,6 @@ void registry<Policies...>::compiler<Options...>::print(
//! @endcode
template<class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY, class... Options>
inline auto initialize(Options&&... options) {
static_assert(
(std::is_base_of_v<detail::option_base, Options> && ...),
"invalid option type");

if (detail::odr_check<Registry>::count > 1) {
// Multiple definitions of default_registry detected.
// This indicates an ODR violation.
Expand Down
78 changes: 29 additions & 49 deletions include/boost/openmethod/policies/fast_perfect_hash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ struct fast_perfect_hash : type_hash {

static void check(std::size_t index, type_id type);

template<class ForwardIterator, class... Options>
template<class InitializeContext, class... Options>
static void initialize(
ForwardIterator first, ForwardIterator last,
std::vector<type_id>& buckets, std::tuple<Options...> options);
const InitializeContext& ctx, std::vector<type_id>& buckets,
const std::tuple<Options...>& options);

public:
//! Find the hash factors
Expand All @@ -95,25 +95,18 @@ struct fast_perfect_hash : type_hash {
//! If no suitable values are found, calls the error handler with
//! a @ref hash_error object then calls `abort`.
//!
//! @tparam ForwardIterator An iterator to a range of @ref
//! IdsToVptr objects.
//! @tparam Options... Zero or more option types, deduced from the
//! function arguments.
//! @param first An iterator to the beginning of the range.
//! @param last An iterator to the end of the range.
//! @param options Zero or more option objects.
//! @tparam Context An @ref InitializeContext.
//! @param ctx A Context object.
//! @return A pair containing the minimum and maximum hash values.
template<class ForwardIterator, class... Options>
static auto initialize(
ForwardIterator first, ForwardIterator last,
std::tuple<Options...> options) {
template<class Context, class... Options>
static auto
initialize(const Context& ctx, const std::tuple<Options...>& options) {
if constexpr (Registry::has_runtime_checks) {
initialize(
first, last, detail::fast_perfect_hash_control<Registry>,
options);
ctx, detail::fast_perfect_hash_control<Registry>, options);
} else {
std::vector<type_id> buckets;
initialize(first, last, buckets, options);
initialize(ctx, buckets, options);
}

return std::pair{min_value, max_value};
Expand Down Expand Up @@ -150,7 +143,7 @@ struct fast_perfect_hash : type_hash {
//! arguments.
//! @param options Zero or more option objects.
template<class... Options>
static auto finalize(std::tuple<Options...>) -> void {
static auto finalize(const std::tuple<Options...>&) -> void {
detail::fast_perfect_hash_control<Registry>.clear();
}
};
Expand All @@ -169,21 +162,16 @@ template<class Registry>
std::size_t fast_perfect_hash::fn<Registry>::max_value;

template<class Registry>
template<class ForwardIterator, class... Options>
template<class InitializeContext, class... Options>
void fast_perfect_hash::fn<Registry>::initialize(
ForwardIterator first, ForwardIterator last, std::vector<type_id>& buckets,
std::tuple<Options...> opts) {
using namespace policies;

const auto N = std::distance(first, last);
(void)opts;

if constexpr (
detail::has_option<trace, Options...> && Registry::has_output) {
if (detail::option<trace>(opts).on) {
Registry::output::os << "Finding hash factor for " << N
<< " types\n";
}
const InitializeContext& ctx, std::vector<type_id>& buckets,
const std::tuple<Options...>& options) {
(void)options;

const auto N = std::distance(ctx.classes_begin(), ctx.classes_end());

if constexpr (mp11::mp_contains<mp11::mp_list<Options...>, trace>::value) {
Registry::output::os << "Finding hash factor for " << N << " types\n";
}

std::default_random_engine rnd(13081963);
Expand All @@ -202,13 +190,9 @@ void fast_perfect_hash::fn<Registry>::initialize(
min_value = (std::numeric_limits<std::size_t>::max)();
max_value = (std::numeric_limits<std::size_t>::min)();

if constexpr (
mp11::mp_contains<mp11::mp_list<Options...>, trace>::value &&
Registry::has_output) {
if (detail::option<trace>(opts).on) {
Registry::output::os << " trying with M = " << M << ", "
<< hash_size << " buckets\n";
}
if constexpr (InitializeContext::template has_option<trace>) {
ctx.tr << " trying with M = " << M << ", " << hash_size
<< " buckets\n";
}

std::size_t attempts = 0;
Expand All @@ -221,7 +205,8 @@ void fast_perfect_hash::fn<Registry>::initialize(
++total_attempts;
mult = uniform_dist(rnd) | 1;

for (auto iter = first; iter != last; ++iter) {
for (auto iter = ctx.classes_begin(); iter != ctx.classes_end();
++iter) {
for (auto type_iter = iter->type_id_begin();
type_iter != iter->type_id_end(); ++type_iter) {
auto type = *type_iter;
Expand All @@ -238,15 +223,10 @@ void fast_perfect_hash::fn<Registry>::initialize(
}
}

if constexpr (
mp11::mp_contains<mp11::mp_list<Options...>, trace>::value &&
Registry::has_output) {
if (detail::option<trace>(opts).on) {
Registry::output::os
<< " found " << mult << " after " << total_attempts
<< " attempts; span = [" << min_value << ", "
<< max_value << "]\n";
}
if constexpr (InitializeContext::template has_option<trace>) {
ctx.tr << " found " << mult << " after " << total_attempts
<< " attempts; span = [" << min_value << ", "
<< max_value << "]\n";
}

return;
Expand Down
29 changes: 13 additions & 16 deletions include/boost/openmethod/policies/vptr_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,17 @@ class vptr_map : public vptr {
public:
//! Stores the v-table pointers.
//!
//! @tparam ForwardIterator An iterator to a range of @ref
//! IdsToVptr objects.
//! @tparam Options... Zero or more option types, deduced from the
//! function arguments.
//! @param first An iterator to the beginning of the range.
//! @param last An iterator to the end of the range.
//! @param options Zero or more option objects.
template<class ForwardIterator, class... Options>
static void initialize(
ForwardIterator first, ForwardIterator last,
std::tuple<Options...>) {
//! @tparam Context An @ref InitializeContext.
//! @tparam Options... Zero or more option types.
//! @param ctx A Context object.
//! @param options A tuple of option objects.
template<class Context, class... Options>
static void
initialize(const Context& ctx, const std::tuple<Options...>&) {
decltype(vptrs) new_vptrs;

for (auto iter = first; iter != last; ++iter) {
for (auto iter = ctx.classes_begin(); iter != ctx.classes_end();
++iter) {
for (auto type_iter = iter->type_id_begin();
type_iter != iter->type_id_end(); ++type_iter) {

Expand Down Expand Up @@ -109,11 +106,11 @@ class vptr_map : public vptr {

//! Clears the map.
//!
//! @tparam Options... Zero or more option types, deduced from the
//! function arguments.
//! @param options Zero or more option objects.
//! @tparam Options... Zero or more option types.
//! @param ctx A Context object.
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @param ctx documentation is incorrect for the finalize method. This method does not have a ctx parameter - it only takes options. Remove the @param ctx line.

Suggested change
//! @param ctx A Context object.

Copilot uses AI. Check for mistakes.
//! @param options A tuple of option objects.
template<class... Options>
static auto finalize(std::tuple<Options...>) -> void {
static auto finalize(const std::tuple<Options...>&) -> void {
vptrs.clear();
}
};
Expand Down
Loading
Loading