Back to home page

EIC code displayed by LXR

 
 

    


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

0001 #ifndef BOOST_OPENMETHOD_INPLACE_VPTR_HPP
0002 #define BOOST_OPENMETHOD_INPLACE_VPTR_HPP
0003 
0004 #include <boost/openmethod/core.hpp>
0005 
0006 // =============================================================================
0007 // inplace_vptr
0008 
0009 namespace boost::openmethod {
0010 
0011 namespace detail {
0012 
0013 void boost_openmethod_registry(...);
0014 void boost_openmethod_bases(...);
0015 
0016 template<class Class>
0017 using inplace_vptr_registry =
0018     decltype(boost_openmethod_registry(std::declval<Class*>()));
0019 
0020 template<class>
0021 struct update_vptr_bases;
0022 
0023 template<class To, class Class>
0024 void boost_openmethod_update_vptr(Class* obj);
0025 
0026 template<class... Bases>
0027 struct update_vptr_bases<mp11::mp_list<Bases...>> {
0028     template<class To, class Class>
0029     static void fn(Class* obj) {
0030         (boost_openmethod_update_vptr<To>(static_cast<Bases*>(obj)), ...);
0031     }
0032 };
0033 
0034 template<class To, class Class>
0035 void boost_openmethod_update_vptr(Class* obj) {
0036     using registry = inplace_vptr_registry<Class>;
0037     using bases = decltype(boost_openmethod_bases(obj));
0038 
0039     if constexpr (mp11::mp_size<bases>::value == 0) {
0040         if constexpr (registry::has_indirect_vptr) {
0041             obj->boost_openmethod_vptr = &registry::template static_vptr<To>;
0042         } else {
0043             obj->boost_openmethod_vptr = registry::template static_vptr<To>;
0044         }
0045     } else {
0046         update_vptr_bases<bases>::template fn<To, Class>(obj);
0047     }
0048 }
0049 
0050 #if defined(__GNUC__) && !defined(__clang__)
0051 #pragma GCC diagnostic ignored "-Wnon-template-friend"
0052 #endif
0053 
0054 template<class... Classes>
0055 inline use_classes<Classes...> inplace_vptr_use_classes;
0056 
0057 class inplace_vptr_base_tag {};
0058 
0059 } // namespace detail
0060 
0061 //! Embed a v-table pointer in a class.
0062 //!
0063 //! `inplace_vptr_base` is a [CRTP
0064 //! mixin](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
0065 //! that embeds a v-table pointer at the root of a class hierarchy. It also
0066 //! declares a @ref boost_openmethod_vptr free function that returns the v-table
0067 //! pointer stored in the object.
0068 //!
0069 //! `inplace_vptr_base` registers the class in `Registry`. It is not necessary
0070 //! to register the class with @ref use_class or
0071 //! {{BOOST_OPENMETHOD_REGISTER}}
0072 //!
0073 //! The v-table pointer is obtained directly from the `Registry`\'s @ref
0074 //! static_vptr variable. No hashing is involved. If all the classes in
0075 //! `Registry` inherit from `inplace_vptr_base`, the registry needs not have a
0076 //! @ref policies::vptr policy, nor any policy it depends on (like @ref
0077 //! policies::type_hash).
0078 //!
0079 //! If `Registry` contains the @ref has_indirect_vptr policy, the v-table
0080 //! pointer is stored as a pointer to a pointer, and remains valid after a call
0081 //! to @ref initialize.
0082 //!
0083 //! The default value of `Registry` can be changed by defining
0084 //! {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}
0085 //!
0086 //! @tparam Class The class in which to embed the v-table pointer.
0087 //! @tparam Registry The @ref registry in which `Class` and its derived classes
0088 //! are registered.
0089 //!
0090 //! @par Example
0091 //! @code
0092 //! #include <boost/openmethod.hpp>
0093 //! #include <boost/openmethod/inplace_vptr.hpp>
0094 //! #include <boost/openmethod/initialize.hpp>
0095 //!
0096 //! using namespace boost::openmethod;
0097 //!
0098 //! struct Animal : inplace_vptr_base<Animal> {};
0099 //!
0100 //! struct Cat : Animal, inplace_vptr_derived<Cat, Animal> {};
0101 //!
0102 //! struct Dog : Animal, inplace_vptr_derived<Dog, Animal> {};
0103 //!
0104 //! BOOST_OPENMETHOD(
0105 //!     poke, (virtual_<Animal&> animal, std::ostream& os), void);
0106 //!
0107 //! BOOST_OPENMETHOD_OVERRIDE(poke, (Cat&, std::ostream& os), void) {
0108 //!     os << "hiss\n";
0109 //! }
0110 //!
0111 //! BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&, std::ostream& os), void) {
0112 //!     os << "bark\n";
0113 //! }
0114 //!
0115 //! int main() {
0116 //!     initialize();
0117 //!
0118 //!     std::unique_ptr<Animal> a = std::make_unique<Cat>();
0119 //!     std::unique_ptr<Animal> b = std::make_unique<Dog>();
0120 //!
0121 //!     poke(*a, std::cout); // hiss
0122 //!     poke(*b, std::cout); // bark
0123 //!
0124 //!     return 0;
0125 //! }
0126 //! @endcode
0127 template<class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
0128 class inplace_vptr_base : protected detail::inplace_vptr_base_tag {
0129     template<class To, class Other>
0130     friend void detail::boost_openmethod_update_vptr(Other*);
0131     friend auto boost_openmethod_registry(Class*) -> Registry;
0132     friend auto boost_openmethod_bases(Class*) -> mp11::mp_list<>;
0133 
0134     std::conditional_t<Registry::has_indirect_vptr, const vptr_type*, vptr_type>
0135         boost_openmethod_vptr = nullptr;
0136 
0137     friend auto
0138     boost_openmethod_vptr(const Class& obj, Registry*) noexcept -> vptr_type {
0139         if constexpr (Registry::has_indirect_vptr) {
0140             return *obj.boost_openmethod_vptr;
0141         } else {
0142             return obj.boost_openmethod_vptr;
0143         }
0144     }
0145 
0146   protected:
0147     //! Set the vptr to `Class`\'s v-table.
0148     inplace_vptr_base() noexcept {
0149         (void)&detail::inplace_vptr_use_classes<Class, Registry>;
0150         detail::boost_openmethod_update_vptr<Class>(static_cast<Class*>(this));
0151     }
0152 
0153     //! Set the vptr to `nullptr`.
0154     ~inplace_vptr_base() noexcept {
0155         boost_openmethod_vptr = nullptr;
0156     }
0157 };
0158 
0159 #ifdef __MRDOCS__
0160 //! Adjust the v-table pointer embedded in a class.
0161 //!
0162 //! `inplace_vptr_derived` is a [CRTP
0163 //! mixin](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
0164 //! that adjusts the v-table pointer in a @ref inplace_vptr_base. It can be used
0165 //! only with classes that have @ref inplace_vptr_base as a direct or indirect
0166 //! base class.
0167 //!
0168 //! `inplace_vptr_derived` registers the class and its bases in `Registry`. It
0169 //! is not necessary to register them with @ref use_class or
0170 //! {{BOOST_OPENMETHOD_REGISTER}}
0171 //!
0172 //! The v-table pointer is obtained directly from the `Registry`\'s @ref
0173 //! static_vptr variable. No hashing is involved. If all the classes in
0174 //! `Registry` inherit from `inplace_vptr_derived`, the registry needs not have a
0175 //! @ref policies::vptr policy, nor any policy it depends on (like @ref
0176 //! policies::type_hash).
0177 //!
0178 //! @see @ref inplace_vptr_base for an example.
0179 //!
0180 //! @tparam Class The class in which to embed the v-table pointer.
0181 //! @tparam Base A direct base class of `Class`.
0182 //! @tparam MoreBases More direct base classes of `Class`.
0183 template<class Class, class Base, class... MoreBases>
0184 class inplace_vptr_derived {
0185   protected:
0186     //! Set the vptr to `Class`\'s v-table.
0187     inplace_vptr_derived() noexcept;
0188 
0189     //! Set the vptr in each base class.
0190     //!
0191     //! For each base, set its vptr to the base's v-table.
0192     ~inplace_vptr_derived() noexcept;
0193 };
0194 
0195 #else
0196 template<class Class, class Base, class... MoreBases>
0197 class inplace_vptr_derived;
0198 #endif
0199 
0200 //! Specialization for a single base class.
0201 //!
0202 //!
0203 //! @see The main template for documentation.
0204 template<class Class, class Base>
0205 class inplace_vptr_derived<Class, Base> {
0206     static_assert(
0207         !detail::is_registry<Base>,
0208         "registry can be specified only for root classes");
0209 
0210     static_assert(
0211         std::is_base_of_v<detail::inplace_vptr_base_tag, Base>,
0212         "class must inherit from inplace_vptr_base");
0213 
0214     template<class To, class Other>
0215     friend void detail::boost_openmethod_update_vptr(Other*);
0216     friend auto boost_openmethod_bases(Class*) -> mp11::mp_list<Base>;
0217 
0218   protected:
0219     //! Set the vptr to `Class`\'s v-table.
0220     inplace_vptr_derived() noexcept {
0221         using namespace detail;
0222         (void)&detail::inplace_vptr_use_classes<
0223             Class, Base, detail::inplace_vptr_registry<Class>>;
0224         boost_openmethod_update_vptr<Class>(static_cast<Class*>(this));
0225     }
0226 
0227     //! Set the vptr in base class.
0228     ~inplace_vptr_derived() noexcept {
0229         detail::boost_openmethod_update_vptr<Base>(
0230             static_cast<Base*>(static_cast<Class*>(this)));
0231     }
0232 };
0233 
0234 //! Specialization for multiple base classes.
0235 //!
0236 //! @see The main template for documentation.
0237 template<class Class, class Base1, class Base2, class... MoreBases>
0238 class inplace_vptr_derived<Class, Base1, Base2, MoreBases...> {
0239     static_assert(
0240         !detail::is_registry<Base1> && !detail::is_registry<Base2> &&
0241             (!detail::is_registry<MoreBases> && ...),
0242         "registry can be specified only for root classes");
0243 
0244     friend auto
0245     boost_openmethod_registry(Class*) -> detail::inplace_vptr_registry<Base1>;
0246     friend auto
0247     boost_openmethod_bases(Class*) -> mp11::mp_list<Base1, Base2, MoreBases...>;
0248     friend auto boost_openmethod_vptr(
0249         const Class& obj,
0250         detail::inplace_vptr_registry<Base1>* registry) -> vptr_type {
0251         return boost_openmethod_vptr(static_cast<const Base1&>(obj), registry);
0252     }
0253 
0254   protected:
0255     //! Set the vptr to `Class`\'s v-table.
0256     inplace_vptr_derived() noexcept {
0257         (void)&detail::inplace_vptr_use_classes<
0258             Class, Base1, Base2, MoreBases...,
0259             detail::inplace_vptr_registry<Base1>>;
0260         detail::boost_openmethod_update_vptr<Class>(static_cast<Class*>(this));
0261     }
0262 
0263     //! Set the vptr in each base class.
0264     //!
0265     //! For each base, set its vptr to the base's v-table.
0266     ~inplace_vptr_derived() noexcept {
0267         auto obj = static_cast<Class*>(this);
0268         detail::boost_openmethod_update_vptr<Base1>(static_cast<Base1*>(obj));
0269         detail::boost_openmethod_update_vptr<Base2>(static_cast<Base2*>(obj));
0270         (detail::boost_openmethod_update_vptr<MoreBases>(
0271              static_cast<MoreBases*>(obj)),
0272          ...);
0273     }
0274 };
0275 
0276 namespace aliases {
0277 using boost::openmethod::inplace_vptr_base;
0278 using boost::openmethod::inplace_vptr_derived;
0279 } // namespace aliases
0280 
0281 } // namespace boost::openmethod
0282 
0283 #endif // BOOST_OPENMETHOD_inplace_vptr_HPP