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
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 = ®istry::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 }
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
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
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
0154 ~inplace_vptr_base() noexcept {
0155 boost_openmethod_vptr = nullptr;
0156 }
0157 };
0158
0159 #ifdef __MRDOCS__
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 template<class Class, class Base, class... MoreBases>
0184 class inplace_vptr_derived {
0185 protected:
0186
0187 inplace_vptr_derived() noexcept;
0188
0189
0190
0191
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
0201
0202
0203
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
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
0228 ~inplace_vptr_derived() noexcept {
0229 detail::boost_openmethod_update_vptr<Base>(
0230 static_cast<Base*>(static_cast<Class*>(this)));
0231 }
0232 };
0233
0234
0235
0236
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
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
0264
0265
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 }
0280
0281 }
0282
0283 #endif