Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:52:05

0001 #ifndef BOOST_OPENMETHOD_REGISTRY_HPP
0002 #define BOOST_OPENMETHOD_REGISTRY_HPP
0003 
0004 #include <boost/openmethod/detail/static_list.hpp>
0005 
0006 #include <boost/mp11/algorithm.hpp>
0007 #include <boost/mp11/bind.hpp>
0008 
0009 #include <stdlib.h>
0010 #include <vector>
0011 #include <cstdint>
0012 
0013 #ifdef _MSC_VER
0014 #pragma warning(push)
0015 #pragma warning(disable : 4702)
0016 #endif
0017 
0018 namespace boost::openmethod {
0019 
0020 namespace detail {
0021 
0022 union word {
0023     word() {
0024     } // undefined
0025     word(void (*pf)()) : pf(pf) {
0026     }
0027     word(word* pw) : pw(pw) {
0028     }
0029     word(std::size_t i) : i(i) {
0030     }
0031 
0032     void (*pf)();
0033     std::size_t i;
0034     word* pw;
0035 };
0036 
0037 } // namespace detail
0038 
0039 //! Alias to v-table pointer type.
0040 //!
0041 //! `vptr_type` is an alias to the type of a v-table pointer.
0042 using vptr_type = const detail::word*;
0043 
0044 //! Type used to identify a class.
0045 //!
0046 //! `type_id` is the return type of the @ref static_type and @ref dynamic_type
0047 //! functions. It can be used as an actual data pointer (e.g. to a
0048 //! `std::type_info` object), or as an opaque integer type.
0049 using type_id = const void*;
0050 
0051 //! Decorator for virtual parameters.
0052 //!
0053 //! `virtual_` marks a formal parameter of a method as virtual. It is a @em
0054 //! decorator, not an actual type that can be instantiated (it does not have a
0055 //! definition). It is removed from the method's signature.
0056 //!
0057 //! @note `virtual_` can be used @em only in method declarations, @em not in
0058 //! overriders. A parameter in overriders is implicitly virtual if it is in
0059 //! the same position as a virtual parameter in the method's declaration.
0060 //!
0061 //! @par Requirements
0062 //!
0063 //! - @ref virtual_traits must be specialized for `T`.
0064 //!
0065 //! @tparam T A class.
0066 template<typename T>
0067 struct virtual_;
0068 
0069 template<typename T, class Registry>
0070 struct virtual_traits;
0071 
0072 // -----------------------------------------------------------------------------
0073 // Error handling
0074 
0075 //! Base class for all OpenMethod errors.
0076 struct openmethod_error {};
0077 
0078 //! One Definition Rule violation.
0079 //!
0080 //! This error is raised if the definition of @ref default_registry is
0081 //! inconsistent across translation units, due to misuse of
0082 //! {{BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS}}.
0083 struct odr_violation : openmethod_error {
0084     //! Write a description of the error to a stream.
0085     //! @tparam Registry The registry containing this policy.
0086     //! @param stream The stream to write to.
0087     template<class Registry, class Stream>
0088     auto write(Stream& stream) const {
0089         stream << "conflicting definitions of ";
0090         Registry::rtti::type_name(
0091             Registry::rtti::template static_type<Registry>(), stream);
0092     }
0093 };
0094 
0095 namespace detail {
0096 
0097 template<class Registry>
0098 struct odr_check {
0099     static std::size_t count;
0100     template<class R>
0101     static std::size_t inc;
0102 
0103     odr_check() {
0104         [[maybe_unused]] auto _ = &inc<typename Registry::registry_type>;
0105     }
0106 };
0107 
0108 template<class Registry>
0109 std::size_t odr_check<Registry>::count;
0110 
0111 template<class Registry>
0112 template<class R>
0113 std::size_t odr_check<Registry>::inc = count++;
0114 
0115 } // namespace detail
0116 
0117 //! Registry not initialized
0118 struct not_initialized : openmethod_error {
0119     //! Write a short description to an output stream
0120     //! @param os The output stream
0121     //! @tparam Registry The registry
0122     //! @tparam Stream A @ref LightweightOutputStream
0123     template<class Registry, class Stream>
0124     auto write(Stream& os) const {
0125         os << "not initialized";
0126     }
0127 };
0128 
0129 //! Missing class.
0130 //!
0131 //! A class used as a virtual parameter in a method, an overrider or a method
0132 //! call was not registered.
0133 //!
0134 //! @par Examples
0135 //!
0136 //! Missing registration of a class used as a virtual parameter in a method:
0137 //! @code
0138 //! struct Animal { virtual ~Animal() {} };
0139 //! struct Dog : Animal {};
0140 //!
0141 //! BOOST_OPENMETHOD_CLASSES(Animal);
0142 //!
0143 //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
0144 //!
0145 //! initialize(); // throws missing_class;
0146 //! @endcode
0147 //!
0148 //! Missing registration of a class used as a virtual parameter in an overrider:
0149 //! @code
0150 //! BOOST_OPENMETHOD_CLASSES(Animal);
0151 //!
0152 //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
0153 //!
0154 //! BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Dog>), void) { /* ... */ }
0155 //!
0156 //! initialize(); // throws missing_class;
0157 //! @endcode
0158 //!
0159 //! Missing registration of a class used as a virtual parameter in a call:
0160 //! @code
0161 //! struct Bulldog : Dog {};
0162 //!
0163 //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0164 //!
0165 //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
0166 //!
0167 //! BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Dog>), void) { /* ... */ }
0168 //!
0169 //! Bulldog hector;
0170 //! poke(hector); // throws missing_class;
0171 //! @endcode
0172 struct missing_class : openmethod_error {
0173     //! The type_id of the unknown class.
0174     type_id type;
0175 
0176     //! Write a short description to an output stream
0177     //! @param os The output stream
0178     //! @tparam Registry The registry
0179     //! @tparam Stream A @ref LightweightOutputStream
0180     template<class Registry, class Stream>
0181     auto write(Stream& os) const;
0182 };
0183 
0184 //! Missing base.
0185 //!
0186 //! A class used in an overrider virtual parameter was not registered as a
0187 //! derived class of the class in the same position in the method's virtual
0188 //! parameter list.
0189 //!
0190 //! @par Example
0191 //! In the following code, OpenMethod cannot infer that `Dog` is derived from
0192 //! `Animal`, because they are not registered in a same call to @ref
0193 //! BOOST_OPENMETHOD_CLASSES.
0194 //!
0195 //! @code
0196 //! BOOST_OPENMETHOD_CLASSES(Animal);
0197 //! BOOST_OPENMETHOD_CLASSES(Dog);
0198 //!
0199 //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
0200 //!
0201 //! BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Dog>), void) { /* ... */ }
0202 //!
0203 //! initialize(); // throws missing_base;
0204 //! @endcode
0205 //!
0206 //! Fix:
0207 //!
0208 //! @code
0209 //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
0210 //! @endcode
0211 struct missing_base : openmethod_error {
0212     //! The type_id of the base class.
0213     type_id base;
0214     //! The type_id of the derived class.
0215     type_id derived;
0216 
0217     //! Write a short description to an output stream
0218     //! @param os The output stream
0219     //! @tparam Registry The registry
0220     //! @tparam Stream A @ref LightweightOutputStream
0221     template<class Registry, class Stream>
0222     auto write(Stream& os) const;
0223 };
0224 
0225 //! No valid overrider
0226 struct bad_call : openmethod_error {
0227     //! The type_id of method that was called
0228     type_id method;
0229     //! The number of @em virtual arguments in the call
0230     std::size_t arity;
0231     //! The maximum size of `types`
0232     static constexpr std::size_t max_types = 16;
0233     //! The type_ids of the arguments.
0234     type_id types[max_types];
0235 };
0236 
0237 //! No overrider for virtual tuple
0238 //!
0239 //! @see @ref bad_call for data members.
0240 struct no_overrider : bad_call {
0241     //! Write a short description to an output stream
0242     //! @param os The output stream
0243     //! @tparam Registry The registry
0244     //! @tparam Stream A @ref LightweightOutputStream
0245     template<class Registry, class Stream>
0246     auto write(Stream& os) const {
0247         os << "not implemented";
0248     }
0249 };
0250 
0251 //! Ambiguous call
0252 //!
0253 //! @see @ref bad_call for data members.
0254 struct ambiguous_call : bad_call {
0255     //! Write a short description to an output stream
0256     //! @param os The output stream
0257     //! @tparam Registry The registry
0258     //! @tparam Stream A @ref LightweightOutputStream
0259     template<class Registry, class Stream>
0260     auto write(Stream& os) const {
0261         os << "ambiguous";
0262     }
0263 };
0264 
0265 //! Static and dynamic type mismatch in "final" construct
0266 //!
0267 //! If runtime checks are enabled, the "final" construct checks that the static
0268 //! and dynamic types of the object, as reported by the `rtti` policy,  are the
0269 //! same. If they are not, and if the registry contains an @ref error_handler
0270 //! policy, its @ref error function is called with a `final_error` object, then
0271 //! the program is terminated with
0272 //! @ref abort.
0273 struct final_error : openmethod_error {
0274     type_id static_type, dynamic_type;
0275 
0276     //! Write a short description to an output stream
0277     //! @param os The output stream
0278     //! @tparam Registry The registry
0279     //! @tparam Stream A @ref LightweightOutputStream
0280     template<class Registry, class Stream>
0281     auto write(Stream& os) const;
0282 };
0283 
0284 namespace detail {
0285 
0286 struct empty {};
0287 
0288 template<typename Iterator>
0289 struct range {
0290     range(Iterator first, Iterator last) : first(first), last(last) {
0291     }
0292 
0293     Iterator first, last;
0294 
0295     auto begin() const -> Iterator {
0296         return first;
0297     }
0298 
0299     auto end() const -> Iterator {
0300         return last;
0301     }
0302 };
0303 
0304 // -----------------------------------------------------------------------------
0305 // class info
0306 
0307 struct class_info : static_list<class_info>::static_link {
0308     type_id type;
0309     vptr_type* static_vptr;
0310     type_id *first_base, *last_base;
0311     bool is_abstract{false};
0312 
0313     auto vptr() const {
0314         return static_vptr;
0315     }
0316 
0317     auto type_id_begin() const {
0318         return &type;
0319     }
0320 
0321     auto type_id_end() const {
0322         return &type + 1;
0323     }
0324 };
0325 
0326 struct deferred_class_info : class_info {
0327     virtual void resolve_type_ids() = 0;
0328 };
0329 
0330 // -----------
0331 // method info
0332 
0333 struct overrider_info;
0334 
0335 struct method_info : static_list<method_info>::static_link {
0336     type_id* vp_begin;
0337     type_id* vp_end;
0338     static_list<overrider_info> overriders;
0339     void (*not_implemented)();
0340     void (*ambiguous)();
0341     type_id method_type_id;
0342     type_id return_type_id;
0343     std::size_t* slots_strides_ptr;
0344 
0345     auto arity() const {
0346         return std::distance(vp_begin, vp_end);
0347     }
0348 };
0349 
0350 struct deferred_method_info : method_info {
0351     virtual void resolve_type_ids() = 0;
0352 };
0353 
0354 struct overrider_info : static_list<overrider_info>::static_link {
0355     ~overrider_info() {
0356         method->overriders.remove(*this);
0357     }
0358 
0359     method_info* method; // for the destructor, to remove definition
0360     type_id return_type; // for N2216 disambiguation
0361     type_id type;        // of the function, for trace
0362     void (**next)();
0363     type_id *vp_begin, *vp_end;
0364     void (*pf)();
0365 };
0366 
0367 struct deferred_overrider_info : overrider_info {
0368     virtual void resolve_type_ids() = 0;
0369 };
0370 
0371 struct unspecified {};
0372 
0373 } // namespace detail
0374 
0375 #ifdef __MRDOCS__
0376 
0377 //! Blueprint for a lightweight output stream (exposition only).
0378 //!
0379 //! Classes used as output streams in policies must provide the operations
0380 //! described on this page, either as members or as free functions.
0381 struct LightweightOutputStream {
0382     //! Writes a null-terminated string to the stream.
0383     LightweightOutputStream& operator<<(const char* str);
0384 
0385     //! Writes a string view to the stream.
0386     LightweightOutputStream& operator<<(const std::string_view& view);
0387 
0388     //! Writes a pointer value to the stream.
0389     LightweightOutputStream& operator<<(const void* value);
0390 
0391     //! Writes a size_t value to the stream.
0392     LightweightOutputStream& operator<<(std::size_t value);
0393 };
0394 
0395 #endif
0396 
0397 //! N2216 ambiguity resolution.
0398 //!
0399 //! If `n2216` is present in @ref initialize\'s `Options`, additional steps are
0400 //! taken to select a single overrider in presence of ambiguous overriders sets,
0401 //! according to the rules defined in the N2216 paper. If the normal resolution
0402 //! procedure fails to select a single overrider, the following steps are
0403 //! applied, in order:
0404 //!
0405 //! - If the return types of the remaining overriders are all polymorphic and
0406 //!   covariant, and one of the return types is more specialized thjat all the
0407 //!   others, use it.
0408 //!
0409 //! - Otherwise, pick one of the overriders. Which one is used is unspecified,
0410 //!   but remains the same throughtout the program, and across different runs of
0411 //!   the same program.
0412 struct n2216 {};
0413 
0414 //! Enable `initialize` tracing.
0415 //!
0416 //! If `trace` is passed to @ref initialize, tracing code is added to various
0417 //! parts of the initialization process (dispatch table construction, hash
0418 //! factors search, etc). The tracing code is executed only if
0419 //! @ref trace::on is set to `true`.
0420 //!
0421 //! `trace` requires the registry being initialized to have an @ref output
0422 //! policy.
0423 //!
0424 //! The content of the trace is neither specified, nor stable across versions.
0425 //! It is comprehensive, and useful for troubleshooting missing class
0426 //! registrations, missing or ambiguous overriders, etc.
0427 struct trace {
0428     //! Enable trace if `true`.
0429     bool on = true;
0430 
0431     trace(bool on = true) : on(on) {
0432     }
0433 
0434     //! Returns a `trace` object with `on` set to `true` if the environment
0435     //! variable `BOOST_OPENMETHOD_TRACE` is set to the string "1", and false
0436     //! otherwise.
0437     static trace from_env();
0438 };
0439 
0440 inline trace trace::from_env() {
0441 #ifdef _MSC_VER
0442     char* env;
0443     std::size_t len;
0444     auto result = _dupenv_s(&env, &len, "BOOST_OPENMETHOD_TRACE") == 0 && env &&
0445         len == 2 && *env == '1';
0446     free(env);
0447     return trace(result);
0448 #else
0449     auto env = getenv("BOOST_OPENMETHOD_TRACE");
0450     return trace(env && *env++ == '1' && *env++ == 0);
0451 #endif
0452 }
0453 
0454 //! Namespace for policies.
0455 //!
0456 //! Classes with snake case names are "blueprints", i.e. exposition-only classes
0457 //! that describe the requirements for policies of a given category. Classes
0458 //! implementing these blueprints must provide a `fn<Registry>` metafunction
0459 //! that conforms to the blueprint's requirements.
0460 //!
0461 //! @see @ref registry for a complete explanation of registries and policies.
0462 
0463 namespace policies {
0464 
0465 #ifdef __MRDOCS__
0466 
0467 //! Class information for initializing a policy (exposition only).
0468 //!
0469 //! Provides the v-table pointer for a class, identified by one or more type
0470 //! ids, via the members described on this page.
0471 struct InitializeClass {
0472     //! Beginning of a range of type ids for a class.
0473     //!
0474     //! @return A forward iterator to the beginning of a range of type ids for
0475     //! a class.
0476     auto type_id_begin() const -> detail::unspecified;
0477 
0478     //! End of a range of type ids for a class.
0479     //!
0480     //! @return A forward iterator to the end of a range of type ids for a
0481     //! class.
0482     auto type_id_end() const -> detail::unspecified;
0483 
0484     //! Reference to the v-table pointer for the class.
0485     //!
0486     //! @return A reference to the v-table pointer for the class.
0487     auto vptr() const -> const vptr_type&;
0488 };
0489 
0490 //! Context for initializing a policy (exposition only).
0491 //!
0492 //! @ref initialize passes a "context" object, of unspecified type, to the
0493 //! `initialize` functions of the policies that have one. It provides the
0494 //! v-table pointer for the registered classes, via the members described on
0495 //! this page.
0496 struct InitializeContext {
0497     //! Beginning of a range of `InitializeClass` objects.
0498     //!
0499     //! @return A forward iterator to the beginning of a range of @ref
0500     //! InitializeClass objects.
0501     detail::unspecified classes_begin() const;
0502 
0503     //! End of a range of `InitializeClass` objects.
0504     //!
0505     //! @return A forward iterator to the end of a range of @ref
0506     //! InitializeClass objects.
0507     detail::unspecified classes_end() const;
0508 };
0509 
0510 //! Blueprint for @ref rtti metafunctions (exposition only).
0511 template<class Registry>
0512 struct RttiFn {
0513     //! Tests if a class is polymorphic.
0514     //!
0515     //! @tparam Class A class.
0516     template<class Class>
0517     static constexpr bool is_polymorphic = std::is_polymorphic_v<Class>;
0518 
0519     //! Returns the static @ref type_id of a type.
0520     //!
0521     //! @note `Class` is not necessarily a @e registered class. This
0522     //! function is also called to acquire the type_id of non-virtual
0523     //! parameters, library types, etc, for diagnostic and trace purposes.
0524     //!
0525     //! @tparam Class A class.
0526     //! @return The static type_id of Class.
0527     template<class Class>
0528     static auto static_type() -> type_id;
0529 
0530     //! Returns the dynamic @ref type_id of an object.
0531     //!
0532     //! @tparam Class A registered class.
0533     //! @param obj A reference to an instance of `Class`.
0534     //! @return The type_id of `obj`'s class.
0535     template<class Class>
0536     static auto dynamic_type(const Class& obj) -> type_id;
0537 
0538     //! Writes a representation of a @ref type_id to a stream.
0539     //!
0540     //! @tparam Stream A LightweightOutputStream.
0541     //! @param type The `type_id` to write.
0542     //! @param stream The stream to write to.
0543     template<typename Stream>
0544     static auto type_name(type_id type, Stream& stream);
0545 
0546     //! Returns a key that uniquely identifies a class.
0547     //!
0548     //! @param type A `type_id`.
0549     //! @return A unique value that identifies a class with the given
0550     //! `type_id`.
0551     static auto type_index(type_id type);
0552 
0553     //! Casts an object to a type.
0554     //!
0555     //! @tparam D A reference to a subclass of `B`.
0556     //! @tparam B A registered class.
0557     //! @param obj A reference to an instance of `B`.
0558     template<typename D, typename B>
0559     static auto dynamic_cast_ref(B&& obj) -> D;
0560 };
0561 
0562 #endif
0563 
0564 //! Policy for manipulating type information.
0565 //!
0566 //! `rtti` policies are responsible for type information acquisition and dynamic
0567 //! casting.
0568 //!
0569 //! @par Requirements
0570 //!
0571 //! Classes implementing this policy must:
0572 //! @li derive from `rtti`.
0573 //! @li provide a `fn<Registry>` metafunction that conforms to the @ref RttiFn
0574 //! blueprint.
0575 struct rtti {
0576     // Policy category.
0577     using category = rtti;
0578 
0579     //! Default implementations of some `rtti` requirements.
0580     struct defaults {
0581         //! Default implementation for `type_index`.
0582         //!
0583         //! @param type A `type_id`.
0584         //!
0585         //! @return `type` itself.
0586         static auto type_index(type_id type) -> type_id {
0587             return type;
0588         }
0589 
0590         //! Default implementation of `type_name`.
0591         //!
0592         //! Executes `stream << "type_id(" << type << ")"`.
0593         //!
0594         //! @param type A `type_id`.
0595         //! @param stream A stream to write to.
0596         template<typename Stream>
0597         static void type_name(type_id type, Stream& stream) {
0598             stream << "type_id(" << type << ")";
0599         }
0600     };
0601 };
0602 
0603 //! Policy for deferred type id collection.
0604 //!
0605 //! Some custom RTTI systems rely on static constructors to assign type ids.
0606 //! OpenMethod itself relies on static constructors to register classes, methods
0607 //! and overriders. This creates order-of-initialization issues. Deriving a @e
0608 //! rtti policy from this class - instead of just `rtti` - causes the collection
0609 //! of type ids to be deferred until the first call to @ref update.
0610 struct deferred_static_rtti : rtti {};
0611 
0612 #ifdef __MRDOCS__
0613 //! Blueprint for @ref error_handler metafunctions (exposition only).
0614 template<class Registry>
0615 struct ErrorHandlerFn {
0616     //! Called when an error is detected.
0617     //!
0618     //! `error` is a function, or a set of functions, that can be called
0619     //! with an instance of any subclass of `openmethod_error`.
0620     static auto error(const auto& error) -> void;
0621 };
0622 #endif
0623 
0624 //! Policy for error handling.
0625 //!
0626 //! A @e error_handler policy runs code before the library terminates the
0627 //! program due to an error. This can be useful for throwing, logging, cleanup,
0628 //! or other actions.
0629 //!
0630 //! @par Requirements
0631 //!
0632 //! Classes implementing this policy must:
0633 //! @li derive from `error_handler`.
0634 //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
0635 //! ErrorHandlerFn blueprint.
0636 struct error_handler {
0637     // Policy category.
0638     using category = error_handler;
0639 };
0640 
0641 #ifdef __MRDOCS__
0642 
0643 //! Blueprint for `vptr` metafunctions (exposition only).
0644 //!
0645 //! @tparam Registry The registry containing the policy.
0646 template<class Registry>
0647 struct VptrFn {
0648     //! Register the v-table pointers.
0649     //!
0650     //! Called by @ref registry::initialize to let the policy store the v-table
0651     //! pointer associated to each `type_id`.
0652     //!
0653     //! @tparam Context A class that conforms to the @ref InitializeContext
0654     //! blueprint.
0655     template<class Context>
0656     static auto initialize(const Context& ctx) -> void;
0657 
0658     //! Return a *reference* to a v-table pointer for an object.
0659     //!
0660     //! @tparam Class A registered class.
0661     //! @param arg A reference to a const object of type `Class`.
0662     //! @return A reference to a the v-table pointer for `Class`.
0663     template<class Class>
0664     static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
0665 
0666     //! Release the resources allocated by `initialize`.
0667     //!
0668     //! This function is optional.
0669     //!
0670     //! @tparam Options... Zero or more option types, deduced from the
0671     //! function arguments.
0672     //! @param options A tuple of option objects.
0673     template<class... Options>
0674     static auto finalize(const std::tuple<Options...>& options) -> void;
0675 };
0676 
0677 #endif
0678 
0679 //! Policy for v-table pointer acquisition.
0680 //!
0681 //! @par Requirements
0682 //!
0683 //! Classes implementing this policy must:
0684 //! @li derive from `vptr`.
0685 //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
0686 //! VptrFn blueprint.
0687 struct vptr {
0688     // Policy category.
0689     using category = vptr;
0690 };
0691 
0692 //! Policy to add an indirection to pointers to v-tables.
0693 //!
0694 //! If this policy is present, constructs like @ref virtual_ptr, @ref
0695 //! inplace_vptr, @ref vptr_vector, etc use pointers to pointers to v-tables.
0696 //! These indirect pointers remain valid after a call to @ref initialize, after
0697 //! dynamically loading a library that adds classes, methods and overriders to
0698 //! the registry.
0699 struct indirect_vptr final {
0700     // Policy category.
0701     using category = indirect_vptr;
0702     template<class Registry>
0703     struct fn {};
0704 };
0705 
0706 #ifdef __MRDOCS__
0707 //! Blueprint for @ref type_hash metafunctions (exposition only).
0708 //!
0709 //! @tparam Registry The registry containing the policy.
0710 template<class Registry>
0711 struct TypeHashFn {
0712     //! Initialize the hash table.
0713     //!
0714     //! @tparam Context A class that conforms to the @ref InitializeContext
0715     //! blueprint.
0716     //! @return A pair containing the minimum and maximum hash values.
0717     template<class Context>
0718     static auto
0719     initialize(const Context& ctx) -> std::pair<std::size_t, std::size_t>;
0720 
0721     //! Hash a `type_id`.
0722     //!
0723     //! @param type A @ref type_id.
0724     //! @return A hash value for the given `type_id`.
0725     static auto hash(type_id type) -> std::size_t;
0726 
0727     //! Release the resources allocated by `initialize`.
0728     //!
0729     //! This function is optional.
0730     //!
0731     //! @tparam Options... Zero or more option types, deduced from the
0732     //! function arguments.
0733     //! @param options A tuple of option objects.
0734     template<class... Options>
0735     static auto finalize(const std::tuple<Options...>& options) -> void;
0736 };
0737 #endif
0738 
0739 //! Policy for hashing type ids.
0740 //!
0741 //! @par Requirements
0742 //!
0743 //! Classes implementing this policy must:
0744 //! @li derive from `rtti`.
0745 //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
0746 //! TypeHashFn blueprint.
0747 struct type_hash {
0748     // Policy category.
0749     using category = type_hash;
0750 };
0751 
0752 #ifdef __MRDOCS__
0753 
0754 //! Blueprint for @ref output metafunctions (exposition only).
0755 //!
0756 //! @tparam Registry The registry containing the policy.
0757 template<class Registry>
0758 struct OutputFn {
0759     //! A @ref LightweightOutputStream.
0760     inline static LightweightOutputStream os;
0761 };
0762 
0763 #endif
0764 
0765 //! Policy for writing diagnostics and trace.
0766 //!
0767 //! If an `output` policy is present, the default error handler uses it to write
0768 //! error messages to its output stream. @ref registry::initialize can also use
0769 //! it to write trace messages.
0770 //!
0771 //! @par Requirements
0772 //!
0773 //! Classes implementing this policy must:
0774 //! @li derive from `output`.
0775 //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
0776 //! OutputFn blueprint.
0777 struct output {
0778     // Policy category.
0779     using category = output;
0780 };
0781 
0782 //! Policy for post-initialize runtime checks.
0783 //!
0784 //! If this policy is present, performs the following checks:
0785 //! @li Classes of virtual arguments have been registered.
0786 //! @li Dynamic and static types match in "final" constructs (@ref
0787 //! final_virtual_ptr and related functions).
0788 struct runtime_checks final {
0789     // Policy category.
0790     using category = runtime_checks;
0791     template<class Registry>
0792     struct fn {};
0793 };
0794 
0795 } // namespace policies
0796 
0797 namespace detail {
0798 
0799 struct registry_base {};
0800 
0801 template<typename T>
0802 constexpr bool is_registry = std::is_base_of_v<registry_base, T>;
0803 
0804 template<typename T>
0805 constexpr bool is_not_void = !std::is_same_v<T, void>;
0806 
0807 template<
0808     class Registry, class Index,
0809     class Size = mp11::mp_size<typename Registry::policy_list>>
0810 struct get_policy_aux {
0811     using type = typename mp11::mp_at<
0812         typename Registry::policy_list, Index>::template fn<Registry>;
0813 };
0814 
0815 template<class Registry, class Size>
0816 struct get_policy_aux<Registry, Size, Size> {
0817     using type = void;
0818 };
0819 
0820 using class_catalog = detail::static_list<detail::class_info>;
0821 using method_catalog = detail::static_list<detail::method_info>;
0822 
0823 template<class Policies, class...>
0824 struct with_aux;
0825 
0826 template<class Policies>
0827 struct with_aux<Policies> {
0828     using type = Policies;
0829 };
0830 
0831 template<class Policies, class Policy, class... MorePolicies>
0832 struct with_aux<Policies, Policy, MorePolicies...> {
0833     using replace = mp11::mp_replace_if_q<
0834         Policies,
0835         mp11::mp_bind_front_q<
0836             mp11::mp_quote_trait<std::is_base_of>, typename Policy::category>,
0837         Policy>;
0838     using replace_or_add = std::conditional_t<
0839         std::is_same_v<replace, Policies>, mp11::mp_push_back<Policies, Policy>,
0840         replace>;
0841     using type = typename with_aux<replace_or_add, MorePolicies...>::type;
0842 };
0843 
0844 template<class Policies, class...>
0845 struct without_aux;
0846 
0847 template<class Policies>
0848 struct without_aux<Policies> {
0849     using type = Policies;
0850 };
0851 
0852 template<class Policies, class Policy, class... MorePolicies>
0853 struct without_aux<Policies, Policy, MorePolicies...> {
0854     using type = typename without_aux<
0855         mp11::mp_remove_if_q<
0856             Policies,
0857             mp11::mp_bind_front_q<
0858                 mp11::mp_quote_trait<std::is_base_of>,
0859                 typename Policy::category>>,
0860         MorePolicies...>::type;
0861 };
0862 
0863 template<class...>
0864 struct use_class_aux;
0865 
0866 template<typename, class...>
0867 struct initialize_aux;
0868 
0869 } // namespace detail
0870 
0871 //! Methods, classes and policies.
0872 //!
0873 //! Methods exist in the context of a registry. Any class used as a method or
0874 //! overrider parameter, or in as a method call argument, must be registered
0875 //! with the same registry.
0876 //!
0877 //! Before calling a method, its registry must be initialized with the @ref
0878 //! initialize function. This is typically done at the beginning of `main`.
0879 //!
0880 //! Multiple registries can co-exist in the same program. They must be
0881 //! initialized individually. Classes referenced by methods in different
0882 //! registries must be registered with each registry.
0883 //!
0884 //! A registry also contains a set of @ref policies that control how certain
0885 //! operations are performed. For example, the `rtti` policy provides type
0886 //! information, implements dynamic casting, etc. It can be replaced to
0887 //! interface with custom RTII systems (like LLVM's).
0888 //!
0889 //! Policies are implemented as Boost.MP11 quoted metafunctions. A policy class
0890 //! must contain a `fn<Registry>` template that provides a set of static
0891 //! members, specific to the responsibility of the policy. Registries
0892 //! instantiate policies by passing themselves to the nested `fn` class
0893 //! templates.
0894 //!
0895 //! There are two reason for this design.
0896 //!
0897 //! Some policies are "stateful": they contain static _data_ members. Since
0898 //! several registries can co-exist in the same program, each stateful policy
0899 //! needs its own, separate set of static data members. For example, @ref
0900 //! vptr_vector, a "vptr" policy, contains a static vector of vptrs, which
0901 //! cannot be shared with other registries.
0902 //!
0903 //! Also, some policies need access to other policies in the same registry. They
0904 //! can be accessed via the `Registry` template parameter. For example, @ref
0905 //! vptr_vector hashes type_ids before using them as an indexes, if `Registry`
0906 //! cotains a `type_hash` policy. It performs out-of-bounds checks if `Registry`
0907 //! contains the `runtime_checks` policy. If an error is detected, it invokes
0908 //! the @ref error_handler policy if there is  one.
0909 //!
0910 //! @tparam Policy The policies used in the registry.
0911 //!
0912 //! @par Requirements
0913 //!
0914 //! @li `Policy` must contain a `category` alias to its root base class. The
0915 //! registry may contain at most one policy per category.
0916 //!
0917 //! @li `Policy` must contain a `fn<Registry>` metafunction.
0918 //!
0919 //! @see @ref policies
0920 template<class... Policy>
0921 class registry : detail::registry_base {
0922     static detail::class_catalog classes;
0923     static detail::method_catalog methods;
0924 
0925     template<class...>
0926     friend struct detail::use_class_aux;
0927     template<typename Name, typename ReturnType, class Registry>
0928     friend class method;
0929 
0930     static std::vector<detail::word> dispatch_data;
0931     static bool initialized;
0932 
0933   public:
0934     //! The type of this registry.
0935     using registry_type = registry;
0936 
0937     template<class... Options>
0938     struct compiler;
0939 
0940     //! Check that the registry is initialized.
0941     //!
0942     //! Check if `initialize` has been called for this registry, and report an
0943     //! error if not.
0944     //!
0945     //! @par Errors
0946     //!
0947     //! @li @ref not_initialized: The registry is not initialized.
0948     static void require_initialized();
0949 
0950     template<class... Options>
0951     static void finalize(Options... opts);
0952 
0953     //! A pointer to the virtual table for a registered class.
0954     //!
0955     //! `static_vptr` is set by @ref registry::initialize to the address of the
0956     //! class' virtual table. It remains valid until the next call to
0957     //! `initialize` or `finalize`.
0958     //!
0959     //! @tparam Class A registered class.
0960     template<class Class>
0961     static vptr_type static_vptr;
0962 
0963     //! List of policies selected in a registry.
0964     //!
0965     //! `policy_list` is a Boost.Mp11 list containing the policies passed to the
0966     //! @ref registry clas template.
0967     //!
0968     //! @tparam Class A registered class.
0969     using policy_list = mp11::mp_list<Policy...>;
0970 
0971     //! Find a policy by category.
0972     //!
0973     //! `policy` searches for a policy that derives from the specified @ref
0974     //! Category. If none is found, it aliases to `void`. Otherwise, it aliases
0975     //! to the policy's `fn` metafunction, applied to the registry.
0976     //!
0977     //! @tparam A policy.
0978     template<class Category>
0979     using policy = typename detail::get_policy_aux<
0980         registry,
0981         mp11::mp_find_if_q<
0982             policy_list,
0983             mp11::mp_bind_front_q<
0984                 mp11::mp_quote_trait<std::is_base_of>, Category>>>::type;
0985 
0986     //! Add or replace policies.
0987     //!
0988     //! `with` aliases to a registry with additional policies, overwriting any
0989     //! existing policies in the same category as the new ones.
0990     //!
0991     //! @tparam NewPolicies Models of @ref policies::Policy.
0992     template<class... NewPolicies>
0993     using with = boost::mp11::mp_apply<
0994         registry, typename detail::with_aux<policy_list, NewPolicies...>::type>;
0995 
0996     //! Remove policies.
0997     //!
0998     //! `without` aliases to a registry containing the same policies, except those
0999     //! that derive from `Categories`.
1000     //!
1001     //! @tparam Categories Models of @ref policies::PolicyCategory.
1002     template<class... Categories>
1003     using without = boost::mp11::mp_apply<
1004         registry,
1005         typename detail::without_aux<policy_list, Categories...>::type>;
1006 
1007     //! The registry's rtti policy.
1008     using rtti = policy<policies::rtti>;
1009 
1010     //! The registry's vptr policy if it contains one, or `void`.
1011     using vptr = policy<policies::vptr>;
1012 
1013     //! `true` if the registry has a vptr policy.
1014     static constexpr auto has_vptr = !std::is_same_v<vptr, void>;
1015 
1016     //! The registry's error_handler policy if it contains one, or `void`.
1017     using error_handler = policy<policies::error_handler>;
1018 
1019     //! `true` if the registry has an error_handler policy.
1020     static constexpr auto has_error_handler =
1021         !std::is_same_v<error_handler, void>;
1022 
1023     //! The registry's output policy if it contains one, or `void`.
1024     using output = policy<policies::output>;
1025 
1026     //! `true` if the registry has an output policy.
1027     static constexpr auto has_output = !std::is_same_v<output, void>;
1028 
1029     //! `true` if the registry has a deferred_static_rtti policy.
1030     static constexpr auto has_deferred_static_rtti =
1031         !std::is_same_v<policy<policies::deferred_static_rtti>, void>;
1032 
1033     //! `true` if the registry has a runtime_checks policy.
1034     static constexpr auto has_runtime_checks =
1035         !std::is_same_v<policy<policies::runtime_checks>, void>;
1036 
1037     //! `true` if the registry has an indirect_vptr policy.
1038     static constexpr auto has_indirect_vptr =
1039         !std::is_same_v<policy<policies::indirect_vptr>, void>;
1040 };
1041 
1042 template<class... Policies>
1043 detail::class_catalog registry<Policies...>::classes;
1044 
1045 template<class... Policies>
1046 detail::method_catalog registry<Policies...>::methods;
1047 
1048 template<class... Policies>
1049 std::vector<detail::word> registry<Policies...>::dispatch_data;
1050 
1051 template<class... Policies>
1052 bool registry<Policies...>::initialized;
1053 
1054 template<class... Policies>
1055 template<class Class>
1056 vptr_type registry<Policies...>::static_vptr;
1057 
1058 template<class... Policies>
1059 void registry<Policies...>::require_initialized() {
1060     if constexpr (registry::has_runtime_checks) {
1061         if (!initialized) {
1062             if constexpr (registry::has_error_handler) {
1063                 error_handler::error(not_initialized());
1064             }
1065 
1066             abort();
1067         }
1068     }
1069 }
1070 
1071 template<class Registry, class Stream>
1072 auto missing_class::write(Stream& os) const {
1073     os << "unknown class ";
1074     Registry::rtti::type_name(type, os);
1075 }
1076 
1077 template<class Registry, class Stream>
1078 auto missing_base::write(Stream& os) const {
1079     os << "missing base ";
1080     Registry::rtti::type_name(base, os);
1081     os << " -<| ";
1082     Registry::rtti::type_name(derived, os);
1083 }
1084 
1085 template<class Registry, class Stream>
1086 auto final_error::write(Stream& os) const {
1087     os << "invalid call to final construct: static type = ";
1088     Registry::rtti::type_name(static_type, os);
1089     os << ", dynamic type = ";
1090     Registry::rtti::type_name(dynamic_type, os);
1091 }
1092 
1093 } // namespace boost::openmethod
1094 
1095 #ifdef _MSC_VER
1096 #pragma warning(pop)
1097 #endif
1098 
1099 #endif // BOOST_OPENMETHOD_REGISTRY_HPP