File indexing completed on 2026-08-17 08:52:04
0001
0002
0003
0004
0005
0006 #ifndef BOOST_OPENMETHOD_CORE_HPP
0007 #define BOOST_OPENMETHOD_CORE_HPP
0008
0009 #include <stdint.h>
0010 #include <algorithm>
0011 #include <cstdlib>
0012 #include <tuple>
0013 #include <type_traits>
0014 #include <utility>
0015
0016 #include <boost/assert.hpp>
0017 #include <boost/config.hpp>
0018 #include <boost/mp11/algorithm.hpp>
0019 #include <boost/mp11/bind.hpp>
0020 #include <boost/mp11/integral.hpp>
0021 #include <boost/mp11/list.hpp>
0022
0023 #include <boost/openmethod/preamble.hpp>
0024 #include <boost/openmethod/default_registry.hpp>
0025
0026 #ifndef BOOST_OPENMETHOD_DEFAULT_REGISTRY
0027 #define BOOST_OPENMETHOD_DEFAULT_REGISTRY ::boost::openmethod::default_registry
0028 #endif
0029
0030 #ifdef _MSC_VER
0031 #pragma warning(push)
0032 #pragma warning(disable : 4100)
0033 #pragma warning(disable : 4646)
0034 #pragma warning(disable : 4702)
0035 #endif
0036
0037
0038 namespace boost::openmethod {
0039
0040 #ifdef __MRDOCS__
0041 #define BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
0042 #define BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
0043 #define BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0044 #else
0045 #define BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS namespace detail {
0046 #define BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS }
0047 #define BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS detail::
0048 #endif
0049
0050 namespace detail {
0051 using sfinae = void;
0052 }
0053
0054 template<
0055 class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY,
0056 typename = detail::sfinae>
0057 class virtual_ptr;
0058
0059
0060
0061
0062 namespace detail {
0063
0064 using macro_default_registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY;
0065
0066 template<typename...>
0067 struct extract_registry;
0068
0069 template<>
0070 struct extract_registry<> {
0071 using registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY;
0072 using others = mp11::mp_list<>;
0073 };
0074
0075 template<typename Type>
0076 struct extract_registry<Type> {
0077 using registry = std::conditional_t<
0078 is_registry<Type>, Type, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
0079 using others = std::conditional_t<
0080 is_registry<Type>, mp11::mp_list<>, mp11::mp_list<Type>>;
0081 };
0082
0083 template<typename Type1, typename Type2, typename... MoreTypes>
0084 struct extract_registry<Type1, Type2, MoreTypes...> {
0085 static_assert(!is_registry<Type1>, "policy must be the last in the list");
0086 using registry = typename extract_registry<Type2, MoreTypes...>::registry;
0087 using others = mp11::mp_push_front<
0088 typename extract_registry<Type2, MoreTypes...>::others, Type1>;
0089 };
0090
0091 template<class Registry, class... Class>
0092 struct init_type_ids;
0093
0094 template<class Registry, class... Class>
0095 struct init_type_ids<Registry, mp11::mp_list<Class...>> {
0096 static auto fn(type_id* ids) {
0097 (..., (*ids++ = Registry::rtti::template static_type<Class>()));
0098 return ids;
0099 }
0100 };
0101
0102 template<class Base, class Derived>
0103 struct is_unambiguous_accessible_base_of : std::is_base_of<Base, Derived> {
0104 static_assert(
0105 std::is_base_of_v<Base, Derived> ==
0106 std::is_convertible_v<Derived&, Base&>,
0107 "class must be an accessible unambiguous base, repeated inheritance is "
0108 "not "
0109 "supported");
0110 };
0111
0112
0113
0114
0115
0116
0117
0118 template<typename... Cs>
0119 using inheritance_map = mp11::mp_list<boost::mp11::mp_push_front<
0120 boost::mp11::mp_filter_q<
0121 boost::mp11::mp_bind_back<is_unambiguous_accessible_base_of, Cs>,
0122 mp11::mp_list<Cs...>>,
0123 Cs>...>;
0124
0125
0126
0127
0128 template<typename B, typename D, typename = void>
0129 struct requires_dynamic_cast_ref_aux : std::true_type {};
0130
0131 template<typename B, typename D>
0132 struct requires_dynamic_cast_ref_aux<
0133 B, D, std::void_t<decltype(static_cast<D>(std::declval<B>()))>>
0134 : std::false_type {};
0135
0136 template<class B, class D>
0137 constexpr bool requires_dynamic_cast =
0138 detail::requires_dynamic_cast_ref_aux<B, D>::value;
0139
0140 template<class Registry, class D, class B>
0141 auto optimal_cast(B&& obj) -> decltype(auto) {
0142 if constexpr (requires_dynamic_cast<B, D>) {
0143 return Registry::rtti::template dynamic_cast_ref<D>(
0144 std::forward<B>(obj));
0145 } else {
0146 return static_cast<D>(obj);
0147 }
0148 }
0149
0150
0151
0152
0153 template<typename T>
0154 struct is_virtual : std::false_type {};
0155
0156 template<typename T>
0157 struct is_virtual<virtual_<T>> : std::true_type {};
0158
0159 template<typename T>
0160 struct remove_virtual_aux {
0161 using type = T;
0162 };
0163
0164 template<typename T>
0165 struct remove_virtual_aux<virtual_<T>> {
0166 using type = T;
0167 };
0168
0169 template<typename T>
0170 using remove_virtual_ = typename remove_virtual_aux<T>::type;
0171
0172 template<typename T, class Registry, typename = void>
0173 struct virtual_type_aux {
0174 using type = void;
0175 };
0176
0177 template<typename T, class Registry>
0178 struct virtual_type_aux<
0179 T, Registry,
0180 std::void_t<typename virtual_traits<T, Registry>::virtual_type>> {
0181 using type = typename virtual_traits<T, Registry>::virtual_type;
0182 };
0183
0184 template<typename T, class Registry>
0185 using virtual_type = typename virtual_type_aux<T, Registry>::type;
0186
0187 template<typename MethodArgList>
0188 using virtual_types = boost::mp11::mp_transform<
0189 remove_virtual_, boost::mp11::mp_filter<detail::is_virtual, MethodArgList>>;
0190
0191 }
0192
0193 BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
0194
0195
0196
0197
0198
0199
0200
0201 template<typename T>
0202 struct StripVirtualDecorator {
0203
0204 using type = T;
0205 };
0206
0207
0208
0209
0210
0211
0212 template<typename T>
0213 struct StripVirtualDecorator<virtual_<T>> {
0214
0215 using type = T;
0216 };
0217
0218 BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240 template<typename T, class Registry>
0241 struct virtual_traits;
0242
0243
0244
0245
0246
0247 template<class Class, class Registry>
0248 struct virtual_traits<Class&, Registry> {
0249
0250 using virtual_type = std::remove_cv_t<Class>;
0251
0252
0253
0254
0255 static auto peek(const Class& arg) -> const Class& {
0256 return arg;
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 template<typename Derived>
0268 static auto cast(Class& obj) -> Derived {
0269 static_assert(std::is_lvalue_reference_v<Derived>);
0270 return detail::optimal_cast<Registry, Derived>(obj);
0271 }
0272 };
0273
0274
0275
0276
0277
0278 template<class Class, class Registry>
0279 struct virtual_traits<Class&&, Registry> {
0280
0281 using virtual_type = Class;
0282
0283
0284
0285
0286 static auto peek(const Class& arg) -> const Class& {
0287 return arg;
0288 }
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298 template<typename Derived>
0299 static auto cast(Class&& obj) -> Derived {
0300 static_assert(std::is_rvalue_reference_v<Derived>);
0301 return detail::optimal_cast<Registry, Derived>(obj);
0302 }
0303 };
0304
0305
0306
0307
0308
0309 template<class Class, class Registry>
0310 struct virtual_traits<Class*, Registry> {
0311
0312 using virtual_type = std::remove_cv_t<Class>;
0313
0314
0315
0316
0317 static auto peek(const Class* arg) -> const Class& {
0318 return *arg;
0319 }
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329 template<typename Derived>
0330 static auto cast(Class* ptr) -> Derived {
0331 static_assert(std::is_pointer_v<Derived>);
0332
0333 if constexpr (detail::requires_dynamic_cast<Class*, Derived>) {
0334 return dynamic_cast<Derived>(ptr);
0335 } else {
0336 return static_cast<Derived>(ptr);
0337 }
0338 }
0339 };
0340
0341 namespace detail {
0342
0343 template<class...>
0344 struct use_class_aux;
0345
0346 template<class Registry, class Class, typename... Bases>
0347 struct use_class_aux<Registry, mp11::mp_list<Class, Bases...>>
0348 : std::conditional_t<
0349 Registry::has_deferred_static_rtti, detail::deferred_class_info,
0350 detail::class_info> {
0351 static type_id bases[sizeof...(Bases)];
0352 use_class_aux() {
0353 this->first_base = bases;
0354 this->last_base = bases + sizeof...(Bases);
0355 this->is_abstract = std::is_abstract_v<Class>;
0356 this->static_vptr = &Registry::template static_vptr<Class>;
0357
0358 if constexpr (!Registry::has_deferred_static_rtti) {
0359 resolve_type_ids();
0360 }
0361
0362 Registry::classes.push_back(*this);
0363 }
0364
0365 void resolve_type_ids() {
0366 this->type = Registry::rtti::template static_type<Class>();
0367 auto iter = bases;
0368 (..., (*iter++ = Registry::rtti::template static_type<Bases>()));
0369 }
0370
0371 ~use_class_aux() {
0372 Registry::classes.remove(*this);
0373 }
0374 };
0375
0376 template<class Registry, class Class, typename... Bases>
0377 type_id use_class_aux<
0378 Registry, mp11::mp_list<Class, Bases...>>::bases[sizeof...(Bases)];
0379
0380 template<class... Classes>
0381 using use_classes_tuple_type = boost::mp11::mp_apply<
0382 std::tuple,
0383 boost::mp11::mp_transform_q<
0384 boost::mp11::mp_bind_front<
0385 detail::use_class_aux,
0386 typename detail::extract_registry<Classes...>::registry>,
0387 boost::mp11::mp_apply<
0388 detail::inheritance_map,
0389 typename detail::extract_registry<Classes...>::others>>>;
0390
0391 }
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 template<class... Classes>
0414 class use_classes {
0415 detail::use_classes_tuple_type<Classes...> tuple;
0416 };
0417
0418
0419
0420
0421 namespace detail {
0422
0423 void boost_openmethod_vptr(...);
0424
0425 template<typename, class, typename = void>
0426 struct is_smart_ptr_aux : std::false_type {};
0427
0428 template<typename Class, class Registry>
0429 struct is_smart_ptr_aux<
0430 Class, Registry,
0431 std::void_t<
0432 typename virtual_traits<Class, Registry>::template rebind<Class>>>
0433 : std::true_type {};
0434
0435 template<class Class, class Other, class Registry, typename = void>
0436 struct same_smart_ptr_aux : std::false_type {};
0437
0438 template<class Class, class Other, class Registry>
0439 struct same_smart_ptr_aux<
0440 Class, Other, Registry,
0441 std::void_t<typename virtual_traits<Class, Registry>::template rebind<
0442 typename Other::element_type>>>
0443 : std::is_same<
0444 Other,
0445 typename virtual_traits<Class, Registry>::template rebind<
0446 typename Other::element_type>> {};
0447
0448 }
0449
0450 BOOST_OPENMETHOD_OPEN_NAMESPACE_DETAIL_UNLESS_MRDOCS
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463 template<class Class, class Registry>
0464 constexpr bool IsPolymorphic = Registry::rtti::template is_polymorphic<Class>;
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475 template<typename Class, class Registry>
0476 constexpr bool IsSmartPtr = detail::is_smart_ptr_aux<Class, Registry>::value;
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486 template<class Class, class Other, class Registry>
0487 constexpr bool SameSmartPtr =
0488 detail::same_smart_ptr_aux<Class, Other, Registry>::value;
0489
0490 BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
0491
0492 template<class Registry, typename Arg>
0493 inline auto final_virtual_ptr(Arg&& obj);
0494
0495 namespace detail {
0496
0497 template<class Class, class Registry>
0498 struct is_virtual<virtual_ptr<Class, Registry, void>> : std::true_type {};
0499
0500 template<class Class, class Registry>
0501 struct is_virtual<virtual_ptr<Class, Registry, void>&> : std::true_type {};
0502
0503 template<class Class, class Registry>
0504 struct is_virtual<const virtual_ptr<Class, Registry, void>&> : std::true_type {
0505 };
0506
0507 template<typename>
0508 struct is_virtual_ptr_aux : std::false_type {};
0509
0510 template<class Class, class Registry>
0511 struct is_virtual_ptr_aux<virtual_ptr<Class, Registry, void>> : std::true_type {
0512 };
0513
0514 template<class Class, class Registry>
0515 struct is_virtual_ptr_aux<const virtual_ptr<Class, Registry, void>&>
0516 : std::true_type {};
0517
0518 template<typename T>
0519 constexpr bool is_virtual_ptr = detail::is_virtual_ptr_aux<T>::value;
0520
0521 template<class Class, class Registry>
0522 constexpr bool has_vptr_fn = std::is_same_v<
0523 decltype(boost_openmethod_vptr(
0524 std::declval<const Class&>(), std::declval<Registry*>())),
0525 vptr_type>;
0526
0527 template<class Registry, class ArgType>
0528 decltype(auto) acquire_vptr(const ArgType& arg) {
0529 Registry::require_initialized();
0530
0531 if constexpr (detail::has_vptr_fn<ArgType, Registry>) {
0532 return boost_openmethod_vptr(arg, static_cast<Registry*>(nullptr));
0533 } else {
0534 return Registry::template policy<policies::vptr>::dynamic_vptr(arg);
0535 }
0536 }
0537
0538 template<bool Indirect>
0539 inline auto box_vptr(const vptr_type& vp) {
0540 if constexpr (Indirect) {
0541 return &vp;
0542 } else {
0543 return vp;
0544 }
0545 }
0546
0547 inline auto unbox_vptr(vptr_type vp) {
0548 return vp;
0549 }
0550
0551 inline auto unbox_vptr(const vptr_type* vpp) {
0552 return *vpp;
0553 }
0554
0555 inline vptr_type null_vptr = nullptr;
0556
0557 }
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581 template<class Registry, typename Arg>
0582 inline auto final_virtual_ptr(Arg&& obj) {
0583 using namespace detail;
0584 using VirtualPtr = virtual_ptr<std::remove_reference_t<Arg>, Registry>;
0585 using Traits = virtual_traits<Arg, Registry>;
0586 using Class = typename Traits::virtual_type;
0587
0588 static_assert(!std::is_const_v<Class>);
0589 static_assert(!std::is_volatile_v<Class>);
0590 static_assert(!std::is_reference_v<Class>);
0591 static_assert(!std::is_pointer_v<Class>);
0592
0593 Registry::require_initialized();
0594
0595 if constexpr (
0596 Registry::has_runtime_checks &&
0597 Registry::rtti::template is_polymorphic<Class>) {
0598
0599
0600 auto static_type = Registry::rtti::template static_type<Class>();
0601 auto dynamic_type = Registry::rtti::dynamic_type(Traits::peek(obj));
0602
0603 if (dynamic_type != static_type) {
0604 if constexpr (is_not_void<typename Registry::error_handler>) {
0605 final_error error;
0606 error.static_type = static_type;
0607 error.dynamic_type = dynamic_type;
0608 Registry::error_handler::error(error);
0609 }
0610
0611 abort();
0612 }
0613 }
0614
0615 const vptr_type& vptr = Registry::template static_vptr<Class>;
0616 BOOST_ASSERT(vptr);
0617
0618 return VirtualPtr(
0619 std::forward<Arg>(obj),
0620 detail::box_vptr<VirtualPtr::use_indirect_vptrs>(vptr));
0621 }
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631 template<class Arg>
0632 inline auto final_virtual_ptr(Arg&& obj) {
0633 return final_virtual_ptr<BOOST_OPENMETHOD_DEFAULT_REGISTRY, Arg>(
0634 std::forward<Arg>(obj));
0635 }
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664 template<class Class, class Registry, typename>
0665 class virtual_ptr {
0666
0667 using traits = virtual_traits<Class&, Registry>;
0668
0669 #ifndef __MRDOCS__
0670 template<class, class, typename>
0671 friend class virtual_ptr;
0672 template<class, typename Arg>
0673 friend auto final_virtual_ptr(Arg&& obj);
0674 #endif
0675
0676 static constexpr bool is_smart_ptr = false;
0677 static constexpr bool use_indirect_vptrs = Registry::has_indirect_vptr;
0678
0679 std::conditional_t<use_indirect_vptrs, const vptr_type*, vptr_type> vp;
0680 Class* obj;
0681
0682 template<
0683 class Other,
0684 typename = std::enable_if_t<std::is_constructible_v<Class*, Other*>>>
0685 virtual_ptr(Other& other, decltype(vp) vp) : vp(vp), obj(&other) {
0686 }
0687
0688 public:
0689
0690
0691
0692 using element_type = Class;
0693
0694
0695
0696
0697
0698 virtual_ptr() = default;
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720 explicit virtual_ptr(std::nullptr_t)
0721 : vp(detail::box_vptr<use_indirect_vptrs>(detail::null_vptr)),
0722 obj(nullptr) {
0723 }
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761 template<
0762 class Other,
0763 typename = std::enable_if_t<
0764 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0765 IsPolymorphic<Other, Registry> &&
0766 std::is_constructible_v<Class*, Other*>>>
0767 virtual_ptr(Other& other)
0768 : vp(detail::box_vptr<use_indirect_vptrs>(
0769 detail::acquire_vptr<Registry>(other))),
0770 obj(&other) {
0771 }
0772
0773
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788
0789
0790
0791
0792
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811 template<
0812 class Other,
0813 typename = std::enable_if_t<
0814 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0815 IsPolymorphic<Class, Registry> &&
0816 std::is_constructible_v<Class*, Other*>>>
0817 virtual_ptr(Other* other)
0818 : vp(detail::box_vptr<use_indirect_vptrs>(
0819 detail::acquire_vptr<Registry>(*other))),
0820 obj(other) {
0821 }
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872
0873
0874
0875
0876 template<
0877 class Other,
0878 typename = std::enable_if_t<std::is_constructible_v<
0879 Class*, typename virtual_ptr<Other, Registry>::element_type*>>>
0880 virtual_ptr(const virtual_ptr<Other, Registry>& other)
0881 : vp(other.vp), obj(other.get()) {
0882 }
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923 template<
0924 class Other,
0925 typename = std::enable_if_t<
0926 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0927 IsPolymorphic<Class, Registry> &&
0928 std::is_assignable_v<Class*&, Other*>>>
0929 virtual_ptr& operator=(Other& other) {
0930 obj = &other;
0931 vp = detail::box_vptr<use_indirect_vptrs>(
0932 detail::acquire_vptr<Registry>(other));
0933 return *this;
0934 }
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961
0962
0963
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973 template<
0974 class Other,
0975 typename = std::enable_if_t<
0976 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
0977 IsPolymorphic<Class, Registry> &&
0978 std::is_assignable_v<Class*&, Other*>>>
0979 virtual_ptr& operator=(Other* other) {
0980 obj = other;
0981 vp = detail::box_vptr<use_indirect_vptrs>(
0982 detail::acquire_vptr<Registry>(*other));
0983 return *this;
0984 }
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041 template<
1042 class Other,
1043 typename = std::enable_if_t<std::is_assignable_v<
1044 Class*&, typename virtual_ptr<Other, Registry>::element_type*>>>
1045 virtual_ptr& operator=(const virtual_ptr<Other, Registry>& other) {
1046 obj = other.get();
1047 vp = other.vp;
1048 return *this;
1049 }
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070 virtual_ptr& operator=(std::nullptr_t) {
1071 obj = nullptr;
1072 vp = detail::box_vptr<use_indirect_vptrs>(detail::null_vptr);
1073 return *this;
1074 }
1075
1076
1077
1078
1079 auto get() const -> Class* {
1080 return obj;
1081 }
1082
1083
1084
1085
1086 auto operator->() const {
1087 return get();
1088 }
1089
1090
1091
1092
1093 auto operator*() const -> element_type& {
1094 return *get();
1095 }
1096
1097
1098
1099
1100 auto pointer() const -> element_type* {
1101 return obj;
1102 }
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114 template<
1115 class Other,
1116 typename = std::enable_if_t<
1117 std::is_base_of_v<element_type, Other> ||
1118 std::is_base_of_v<Other, element_type>>>
1119 auto cast() const -> decltype(auto) {
1120 return virtual_ptr<Other, Registry>(
1121 traits::template cast<Other&>(*obj), vp);
1122 }
1123
1124
1125
1126
1127
1128
1129
1130
1131 template<class Other>
1132 static auto final(Other&& obj) {
1133 return final_virtual_ptr<Registry>(std::forward<Other>(obj));
1134 }
1135
1136
1137
1138 auto vptr() const {
1139 return detail::unbox_vptr(this->vp);
1140 }
1141 };
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151 template<class SmartPtr, class Registry>
1152 class virtual_ptr<
1153 SmartPtr, Registry,
1154 std::enable_if_t<
1155 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS IsSmartPtr<SmartPtr, Registry>>> {
1156
1157 #ifndef __MRDOCS__
1158 template<class, class, typename>
1159 friend class virtual_ptr;
1160 template<class, typename Arg>
1161 friend auto final_virtual_ptr(Arg&& obj);
1162 #endif
1163
1164 static constexpr bool is_smart_ptr = true;
1165 static constexpr bool use_indirect_vptrs = Registry::has_indirect_vptr;
1166
1167 using traits = virtual_traits<SmartPtr, Registry>;
1168
1169 std::conditional_t<use_indirect_vptrs, const vptr_type*, vptr_type> vp;
1170 SmartPtr obj;
1171
1172 template<
1173 class Other,
1174 typename = std::enable_if_t<std::is_constructible_v<SmartPtr*, Other*>>>
1175 virtual_ptr(Other& other, decltype(vp) vp) : vp(vp), obj(&other) {
1176 }
1177
1178 template<typename Arg>
1179 virtual_ptr(Arg&& obj, decltype(vp) vp)
1180 : vp(vp), obj(std::forward<Arg>(obj)) {
1181 }
1182
1183 public:
1184
1185 using element_type = typename SmartPtr::element_type;
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203 virtual_ptr()
1204 : vp(detail::box_vptr<use_indirect_vptrs>(detail::null_vptr)) {
1205 }
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224 explicit virtual_ptr(std::nullptr_t)
1225 : vp(detail::box_vptr<use_indirect_vptrs>(detail::null_vptr)) {
1226 }
1227
1228 virtual_ptr(const virtual_ptr& other) = default;
1229
1230 virtual_ptr(virtual_ptr&& other)
1231 : vp(std::exchange(
1232 other.vp,
1233 detail::box_vptr<use_indirect_vptrs>(detail::null_vptr))),
1234 obj(std::move(other.obj)) {
1235 }
1236 #ifdef __MRDOCS__
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262 template<
1263 class Other,
1264 typename = std::enable_if_t<
1265 SameSmartPtr<SmartPtr, Other, Registry> &&
1266 IsPolymorphic<typename Other::element_type, Registry> &&
1267 std::is_constructible_v<SmartPtr, const Other&>>>
1268 #else
1269 template<
1270 class Other,
1271 typename = std::enable_if_t<
1272 detail::SameSmartPtr<SmartPtr, Other, Registry> &&
1273 detail::IsPolymorphic<typename Other::element_type, Registry> &&
1274 std::is_constructible_v<SmartPtr, const Other&>>>
1275 #endif
1276 virtual_ptr(const Other& other)
1277 : vp(detail::box_vptr<use_indirect_vptrs>(
1278 other ? detail::acquire_vptr<Registry>(*other)
1279 : detail::null_vptr)),
1280 obj(other) {
1281 }
1282
1283 #if __MRDOCS__
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309 template<
1310 class Other,
1311 typename = std::enable_if_t<
1312 SameSmartPtr<SmartPtr, Other, Registry> &&
1313 IsPolymorphic<typename Other::element_type, Registry> &&
1314 std::is_constructible_v<SmartPtr, Other&>>>
1315 #else
1316 template<
1317 class Other,
1318 typename = std::enable_if_t<
1319 detail::SameSmartPtr<SmartPtr, Other, Registry> &&
1320 detail::IsPolymorphic<typename Other::element_type, Registry> &&
1321 std::is_constructible_v<SmartPtr, Other&>>>
1322 #endif
1323 virtual_ptr(Other& other)
1324 : vp(detail::box_vptr<use_indirect_vptrs>(
1325 other ? detail::acquire_vptr<Registry>(*other)
1326 : detail::null_vptr)),
1327 obj(other) {
1328 }
1329
1330 #ifdef __MRDOCS__
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359 template<
1360 class Other,
1361 typename = std::enable_if_t<
1362 SameSmartPtr<SmartPtr, Other, Registry> &&
1363 IsPolymorphic<typename Other::element_type, Registry> &&
1364 std::is_constructible_v<SmartPtr, Other&&>>>
1365 #else
1366 template<
1367 class Other,
1368 typename = std::enable_if_t<
1369 detail::SameSmartPtr<SmartPtr, Other, Registry> &&
1370 detail::IsPolymorphic<typename Other::element_type, Registry> &&
1371 std::is_constructible_v<SmartPtr, Other&&>>>
1372 #endif
1373 virtual_ptr(Other&& other)
1374 : vp(detail::box_vptr<use_indirect_vptrs>(
1375 other ? detail::acquire_vptr<Registry>(*other)
1376 : detail::null_vptr)),
1377 obj(std::move(other)) {
1378 }
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407 template<
1408 class Other,
1409 typename = std::enable_if_t<
1410 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1411 SameSmartPtr<SmartPtr, Other, Registry> &&
1412 std::is_constructible_v<SmartPtr, const Other&>>>
1413 virtual_ptr(const virtual_ptr<Other, Registry>& other)
1414 : vp(other.vp), obj(other.obj) {
1415 }
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447 template<
1448 class Other,
1449 typename = std::enable_if_t<
1450 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1451 SameSmartPtr<SmartPtr, Other, Registry> &&
1452 std::is_constructible_v<SmartPtr, Other&&>>>
1453 virtual_ptr(virtual_ptr<Other, Registry>&& other)
1454 : vp(std::exchange(
1455 other.vp,
1456 detail::box_vptr<use_indirect_vptrs>(detail::null_vptr))),
1457 obj(std::move(other.obj)) {
1458 }
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481 virtual_ptr& operator=(std::nullptr_t) {
1482 obj = SmartPtr();
1483 vp = detail::box_vptr<use_indirect_vptrs>(detail::null_vptr);
1484 return *this;
1485 }
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 template<
1512 class Other,
1513 typename = std::enable_if_t<
1514 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1515 SameSmartPtr<SmartPtr, Other, Registry> &&
1516 std::is_assignable_v<SmartPtr, const Other&> &&
1517 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1518 IsPolymorphic<typename Other::element_type, Registry>>>
1519 virtual_ptr& operator=(const Other& other) {
1520 obj = other;
1521 vp = detail::box_vptr<use_indirect_vptrs>(
1522 detail::acquire_vptr<Registry>(*other));
1523 return *this;
1524 }
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551 template<
1552 class Other,
1553 typename = std::enable_if_t<
1554 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1555 SameSmartPtr<SmartPtr, Other, Registry> &&
1556 std::is_assignable_v<SmartPtr, Other&&> &&
1557 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1558 IsPolymorphic<typename Other::element_type, Registry>>>
1559 virtual_ptr& operator=(Other&& other) {
1560 vp = detail::box_vptr<use_indirect_vptrs>(
1561 other ? detail::acquire_vptr<Registry>(*other) : detail::null_vptr);
1562 obj = std::move(other);
1563 return *this;
1564 }
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596 template<
1597 class Other,
1598 typename = std::enable_if_t<
1599 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1600 SameSmartPtr<SmartPtr, Other, Registry> &&
1601 std::is_assignable_v<SmartPtr, Other&>>>
1602 virtual_ptr& operator=(virtual_ptr<Other, Registry>& other) {
1603 obj = other.obj;
1604 vp = other.vp;
1605 return *this;
1606 }
1607
1608 virtual_ptr& operator=(const virtual_ptr& other) = default;
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640 template<
1641 class Other,
1642 typename = std::enable_if_t<
1643 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1644 SameSmartPtr<SmartPtr, Other, Registry> &&
1645 std::is_assignable_v<SmartPtr, const Other&>>>
1646 virtual_ptr& operator=(const virtual_ptr<Other, Registry>& other) {
1647 obj = other.obj;
1648 vp = other.vp;
1649 return *this;
1650 }
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685 template<
1686 class Other,
1687 typename = std::enable_if_t<
1688 BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
1689 SameSmartPtr<SmartPtr, Other, Registry> &&
1690 std::is_assignable_v<SmartPtr, Other&&>>>
1691 virtual_ptr& operator=(virtual_ptr<Other, Registry>&& other) {
1692 vp = std::exchange(
1693 other.vp, detail::box_vptr<use_indirect_vptrs>(detail::null_vptr));
1694 obj = std::move(other.obj);
1695
1696 return *this;
1697 }
1698
1699
1700
1701
1702 auto get() const -> element_type* {
1703 return obj.get();
1704 }
1705
1706
1707
1708
1709 auto operator->() const -> element_type* {
1710 return get();
1711 }
1712
1713
1714
1715
1716 auto operator*() const -> element_type& {
1717 return *get();
1718 }
1719
1720
1721
1722
1723 auto pointer() const -> const SmartPtr& {
1724 return obj;
1725 }
1726
1727
1728
1729
1730
1731
1732 template<
1733 class Other,
1734 typename = std::enable_if_t<
1735 std::is_base_of_v<element_type, Other> ||
1736 std::is_base_of_v<Other, element_type>>>
1737 auto cast() & -> decltype(auto) {
1738 using other_smart_ptr = typename traits::template rebind<Other>;
1739
1740 return virtual_ptr<other_smart_ptr, Registry>(
1741 traits::template cast<other_smart_ptr>(obj), vp);
1742 }
1743
1744 template<
1745 class Other,
1746 typename = std::enable_if_t<
1747 std::is_base_of_v<element_type, Other> ||
1748 std::is_base_of_v<Other, element_type>>>
1749 auto cast() const& -> decltype(auto) {
1750 using other_smart_ptr = typename traits::template rebind<Other>;
1751
1752 return virtual_ptr<other_smart_ptr, Registry>(
1753 traits::template cast<other_smart_ptr>(obj), vp);
1754 }
1755
1756 template<class Other>
1757 auto cast() && -> decltype(auto) {
1758 static_assert(
1759 std::is_base_of_v<element_type, Other> ||
1760 std::is_base_of_v<Other, element_type>);
1761
1762 using other_smart_ptr = typename traits::template rebind<Other>;
1763
1764 return virtual_ptr<other_smart_ptr, Registry>(
1765 traits::template cast<other_smart_ptr>(std::move(obj)), vp);
1766 }
1767
1768
1769
1770
1771
1772
1773
1774
1775 template<class Other>
1776 static auto final(Other&& obj) {
1777 return final_virtual_ptr<Registry>(std::forward<Other>(obj));
1778 }
1779
1780
1781
1782 auto vptr() const {
1783 return detail::unbox_vptr(this->vp);
1784 }
1785 };
1786
1787
1788
1789
1790
1791
1792 template<class Class>
1793 virtual_ptr(Class& obj)
1794 -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
1795
1796
1797
1798
1799
1800
1801 template<class Class>
1802 virtual_ptr(Class&& obj)
1803 -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821 template<class Left, class Right, class Registry>
1822 auto operator==(
1823 const virtual_ptr<Left, Registry>& left,
1824 const virtual_ptr<Right, Registry>& right) -> bool {
1825 return left.pointer() == right.pointer();
1826 }
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839 template<class Left, class Right, class Registry>
1840 auto operator!=(
1841 const virtual_ptr<Left, Registry>& left,
1842 const virtual_ptr<Right, Registry>& right) -> bool {
1843 return !(left == right);
1844 }
1845
1846
1847
1848
1849
1850
1851
1852 template<class Class, class Registry>
1853 struct virtual_traits<virtual_ptr<Class, Registry>, Registry> {
1854
1855 using virtual_type =
1856 std::remove_cv_t<typename virtual_ptr<Class, Registry>::element_type>;
1857
1858
1859
1860
1861 static auto peek(const virtual_ptr<Class, Registry>& ptr)
1862 -> const virtual_ptr<Class, Registry>& {
1863 return ptr;
1864 }
1865
1866
1867
1868
1869
1870
1871
1872
1873 template<typename Derived>
1874 static auto
1875 cast(const virtual_ptr<Class, Registry>& ptr) -> decltype(auto) {
1876 return ptr.template cast<typename Derived::element_type>();
1877 }
1878
1879
1880
1881
1882
1883
1884
1885
1886 template<typename Derived>
1887 static auto cast(virtual_ptr<Class, Registry>&& ptr) -> decltype(auto) {
1888 return std::move(ptr).template cast<typename Derived::element_type>();
1889 }
1890 };
1891
1892
1893
1894
1895
1896
1897
1898 template<class Class, class Registry>
1899 struct virtual_traits<const virtual_ptr<Class, Registry>&, Registry> {
1900
1901 using virtual_type =
1902 std::remove_cv_t<typename virtual_ptr<Class, Registry>::element_type>;
1903
1904
1905
1906
1907 static auto peek(const virtual_ptr<Class, Registry>& ptr)
1908 -> const virtual_ptr<Class, Registry>& {
1909 return ptr;
1910 }
1911
1912
1913
1914
1915
1916
1917
1918
1919 template<typename Derived>
1920 static auto
1921 cast(const virtual_ptr<Class, Registry>& ptr) -> decltype(auto) {
1922 return ptr.template cast<
1923 typename std::remove_reference_t<Derived>::element_type>();
1924 }
1925 };
1926
1927
1928
1929
1930 namespace detail {
1931
1932 template<typename P, typename Q, class Registry>
1933 struct select_overrider_virtual_type_aux {
1934 using type = void;
1935 };
1936
1937 template<typename P, typename Q, class Registry>
1938 struct select_overrider_virtual_type_aux<virtual_<P>, Q, Registry> {
1939 using type = virtual_type<Q, Registry>;
1940 };
1941
1942 template<typename P, typename Q, class Registry>
1943 struct select_overrider_virtual_type_aux<
1944 virtual_ptr<P, Registry>, virtual_ptr<Q, Registry>, Registry> {
1945 using type = typename virtual_traits<
1946 virtual_ptr<Q, Registry>, Registry>::virtual_type;
1947 };
1948
1949 template<typename P, typename Q, class Registry>
1950 struct select_overrider_virtual_type_aux<
1951 const virtual_ptr<P, Registry>&, const virtual_ptr<Q, Registry>&,
1952 Registry> {
1953 using type = typename virtual_traits<
1954 const virtual_ptr<Q, Registry>&, Registry>::virtual_type;
1955 };
1956
1957 template<typename P, typename Q, class Registry>
1958 using select_overrider_virtual_type =
1959 typename select_overrider_virtual_type_aux<P, Q, Registry>::type;
1960
1961 template<
1962 typename MethodParameters, typename OverriderParameters, class Registry>
1963 using overrider_virtual_types = boost::mp11::mp_remove<
1964 boost::mp11::mp_transform_q<
1965 boost::mp11::mp_bind_back<select_overrider_virtual_type, Registry>,
1966 MethodParameters, OverriderParameters>,
1967 void>;
1968
1969 template<class Method, class Rtti, std::size_t Index>
1970 struct init_bad_call {
1971 template<typename Arg, typename... Args>
1972 static auto fn(bad_call& error, const Arg& arg, const Args&... args) {
1973 if constexpr (Index == 0u) {
1974 error.method = Rtti::template static_type<Method>();
1975 error.arity = sizeof...(args) + 1;
1976 }
1977
1978 type_id arg_type_id;
1979
1980 if constexpr (is_virtual_ptr<Arg>) {
1981 arg_type_id = Rtti::dynamic_type(*arg);
1982 } else {
1983 arg_type_id = Rtti::dynamic_type(arg);
1984 }
1985
1986 error.types[Index] = arg_type_id;
1987
1988 init_bad_call<Method, Rtti, Index + 1>::fn(error, args...);
1989 }
1990
1991 static auto fn(bad_call&) {
1992 }
1993 };
1994
1995 template<class Method, class Rtti>
1996 struct init_bad_call<Method, Rtti, bad_call::max_types> {
1997 static auto fn(bad_call&) {
1998 }
1999 };
2000
2001 template<class Registry>
2002 using method_base = std::conditional_t<
2003 Registry::has_deferred_static_rtti, deferred_method_info, method_info>;
2004
2005 template<typename T, class Registry>
2006 struct parameter_traits {
2007 static auto peek(const T& value) -> const T& {
2008 return value;
2009 }
2010
2011 template<typename>
2012 static auto cast(T value) -> T {
2013 return value;
2014 }
2015 };
2016
2017 template<typename T, class Registry>
2018 struct parameter_traits<virtual_<T>, Registry> : virtual_traits<T, Registry> {};
2019
2020 template<class Class, class Registry>
2021 struct parameter_traits<virtual_ptr<Class, Registry, void>, Registry>
2022 : virtual_traits<virtual_ptr<Class, Registry, void>, Registry> {};
2023
2024 template<class Class, class Registry>
2025 struct parameter_traits<const virtual_ptr<Class, Registry, void>&, Registry>
2026 : virtual_traits<const virtual_ptr<Class, Registry, void>&, Registry> {};
2027
2028 template<typename...>
2029 constexpr bool false_t = false;
2030
2031 template<typename T, class Registry, typename = void>
2032 struct validate_method_parameter : std::true_type {};
2033
2034 template<typename T, class Registry, typename U>
2035 struct validate_method_parameter<virtual_<T>, Registry, U> : std::false_type {
2036 static_assert(false_t<T>, "virtual_traits not specialized for type");
2037 };
2038
2039 template<typename T, class Registry>
2040 struct validate_method_parameter<
2041 virtual_<T>, Registry,
2042 std::void_t<typename virtual_traits<T, Registry>::virtual_type>>
2043 : std::bool_constant<
2044 has_vptr_fn<virtual_type<T, Registry>, Registry> ||
2045 Registry::rtti::template is_polymorphic<virtual_type<T, Registry>>> {
2046 static_assert(
2047 validate_method_parameter::value,
2048 "virtual_<> parameter is not a polymorphic class and no "
2049 "boost_openmethod_vptr is applicable");
2050 };
2051
2052 template<class Class, class Registry>
2053 struct validate_method_parameter<virtual_ptr<Class, Registry>, Registry, void>
2054 : std::true_type {};
2055
2056 template<class Class, class Registry, class MethodRegistry>
2057 struct validate_method_parameter<
2058 virtual_ptr<Class, Registry>, MethodRegistry, void> : std::false_type {
2059 static_assert(
2060 false_t<Class, Registry, MethodRegistry>, "registry mismatch");
2061 };
2062 }
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139 template<
2140 typename Id, typename Fn,
2141 class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
2142 class method;
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160 template<
2161 typename Id, typename... Parameters, typename ReturnType, class Registry>
2162 class method<Id, ReturnType(Parameters...), Registry>
2163 : public detail::method_base<Registry> {
2164 template<auto Function, typename FunctionType>
2165 struct override_aux;
2166
2167
2168
2169 using RegistryType = Registry;
2170 using rtti = typename Registry::rtti;
2171 using DeclaredParameters = mp11::mp_list<Parameters...>;
2172 using CallParameters =
2173 boost::mp11::mp_transform<detail::remove_virtual_, DeclaredParameters>;
2174 using VirtualParameters =
2175 typename detail::virtual_types<DeclaredParameters>;
2176 using Signature = auto(Parameters...) -> ReturnType;
2177 using FunctionPointer = auto (*)(detail::remove_virtual_<Parameters>...)
2178 -> ReturnType;
2179
2180 public:
2181
2182
2183
2184
2185 static method fn;
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203 auto operator()(typename BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
2204 StripVirtualDecorator<Parameters>::type... args) const
2205 -> ReturnType;
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218 template<auto Fn>
2219 static bool has_next();
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231 template<auto Fn>
2232 static FunctionPointer next;
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263 template<auto... Fn>
2264 class override {
2265 std::tuple<override_aux<Fn, decltype(Fn)>...> impl;
2266 };
2267
2268 private:
2269 static constexpr auto Arity = boost::mp11::mp_count_if<
2270 mp11::mp_list<Parameters...>, detail::is_virtual>::value;
2271
2272
2273 static_assert((
2274 detail::validate_method_parameter<Parameters, Registry>::value && ...));
2275 static_assert(Arity > 0, "method has no virtual parameters");
2276
2277 type_id vp_type_ids[Arity];
2278
2279 std::size_t slots_strides[2 * Arity - 1];
2280
2281
2282
2283
2284
2285
2286
2287
2288 void resolve_type_ids();
2289
2290 template<typename ArgType>
2291 auto vptr(const ArgType& arg) const -> vptr_type;
2292
2293 template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2294 auto resolve_uni(const ArgType& arg, const MoreArgTypes&... more_args) const
2295 -> detail::word;
2296
2297 template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2298 auto resolve_multi_first(
2299 const ArgType& arg,
2300 const MoreArgTypes&... more_args) const -> detail::word;
2301
2302 template<
2303 std::size_t VirtualArg, typename MethodArgList, typename ArgType,
2304 typename... MoreArgTypes>
2305 auto resolve_multi_next(
2306 vptr_type dispatch, const ArgType& arg,
2307 const MoreArgTypes&... more_args) const -> detail::word;
2308
2309 template<typename... ArgType>
2310 FunctionPointer resolve(const ArgType&... args) const;
2311
2312 template<auto, typename>
2313 struct thunk;
2314
2315 template<auto, typename>
2316 struct thunk;
2317
2318 method();
2319 method(const method&) = delete;
2320 method(method&&) = delete;
2321 ~method();
2322
2323 void resolve();
2324
2325 static BOOST_NORETURN auto fn_not_implemented(
2326 detail::remove_virtual_<Parameters>... args) -> ReturnType;
2327 static BOOST_NORETURN auto
2328 fn_ambiguous(detail::remove_virtual_<Parameters>... args) -> ReturnType;
2329
2330 template<
2331 auto Overrider, typename OverriderReturn,
2332 typename... OverriderParameters>
2333 struct thunk<Overrider, OverriderReturn (*)(OverriderParameters...)> {
2334 static auto
2335 fn(detail::remove_virtual_<Parameters>... arg) -> ReturnType;
2336 using OverriderVirtualParameters = detail::overrider_virtual_types<
2337 DeclaredParameters, mp11::mp_list<OverriderParameters...>,
2338 Registry>;
2339 };
2340
2341 template<auto Function, typename FnReturnType>
2342 struct override_impl
2343 : std::conditional_t<
2344 Registry::has_deferred_static_rtti,
2345 detail::deferred_overrider_info, detail::overrider_info> {
2346 explicit override_impl(FunctionPointer* next = nullptr);
2347 void resolve_type_ids();
2348
2349 static type_id vp_type_ids[Arity];
2350 };
2351
2352 template<auto Function, typename FunctionType>
2353 struct override_aux;
2354
2355 template<auto Function, typename FnReturnType, typename... FnParameters>
2356 struct override_aux<Function, FnReturnType (*)(FnParameters...)> {
2357 override_aux() {
2358 (void)&impl;
2359 }
2360
2361 static override_impl<Function, FnReturnType> impl;
2362 };
2363 };
2364
2365 template<
2366 typename Id, typename... Parameters, typename ReturnType, class Registry>
2367 method<Id, ReturnType(Parameters...), Registry>
2368 method<Id, ReturnType(Parameters...), Registry>::fn;
2369
2370 template<
2371 typename Id, typename... Parameters, typename ReturnType, class Registry>
2372 template<auto Fn>
2373 typename method<Id, ReturnType(Parameters...), Registry>::FunctionPointer
2374 method<Id, ReturnType(Parameters...), Registry>::next;
2375
2376 template<
2377 typename Id, typename... Parameters, typename ReturnType, class Registry>
2378 template<auto Function, typename FnReturnType>
2379 type_id method<Id, ReturnType(Parameters...), Registry>::override_impl<
2380 Function, FnReturnType>::vp_type_ids[Arity];
2381
2382 template<
2383 typename Id, typename... Parameters, typename ReturnType, class Registry>
2384 template<auto Function, typename FnReturnType, typename... FnParameters>
2385 typename method<Id, ReturnType(Parameters...), Registry>::
2386 template override_impl<Function, FnReturnType>
2387 method<Id, ReturnType(Parameters...), Registry>::override_aux<
2388 Function, FnReturnType (*)(FnParameters...)>::impl;
2389
2390 template<
2391 typename Id, typename... Parameters, typename ReturnType, class Registry>
2392 method<Id, ReturnType(Parameters...), Registry>::method() {
2393 using namespace policies;
2394
2395 this->slots_strides_ptr = slots_strides;
2396
2397 if constexpr (!Registry::has_deferred_static_rtti) {
2398 resolve_type_ids();
2399 }
2400
2401 this->vp_begin = vp_type_ids;
2402 this->vp_end = vp_type_ids + Arity;
2403 this->not_implemented = reinterpret_cast<void (*)()>(fn_not_implemented);
2404 this->ambiguous = reinterpret_cast<void (*)()>(fn_ambiguous);
2405
2406 Registry::methods.push_back(*this);
2407 }
2408
2409 template<
2410 typename Id, typename... Parameters, typename ReturnType, class Registry>
2411 void method<Id, ReturnType(Parameters...), Registry>::resolve_type_ids() {
2412 using namespace detail;
2413 this->method_type_id = rtti::template static_type<method>();
2414 this->return_type_id =
2415 rtti::template static_type<virtual_type<ReturnType, Registry>>();
2416 init_type_ids<
2417 Registry,
2418 mp11::mp_transform_q<
2419 mp11::mp_bind_back<virtual_type, Registry>,
2420 VirtualParameters>>::fn(this->vp_type_ids);
2421 }
2422
2423 template<
2424 typename Id, typename... Parameters, typename ReturnType, class Registry>
2425 method<Id, ReturnType(Parameters...), Registry>::~method() {
2426 Registry::methods.remove(*this);
2427 }
2428
2429
2430
2431
2432 template<
2433 typename Id, typename... Parameters, typename ReturnType, class Registry>
2434 BOOST_FORCEINLINE auto
2435 method<Id, ReturnType(Parameters...), Registry>::operator()(
2436 typename BOOST_OPENMETHOD_DETAIL_UNLESS_MRDOCS
2437 StripVirtualDecorator<Parameters>::type... args) const -> ReturnType {
2438 using namespace detail;
2439 auto pf = resolve(parameter_traits<Parameters, Registry>::peek(args)...);
2440
2441 return pf(std::forward<typename StripVirtualDecorator<Parameters>::type>(
2442 args)...);
2443 }
2444
2445 template<
2446 typename Id, typename... Parameters, typename ReturnType, class Registry>
2447 template<typename... ArgType>
2448 BOOST_FORCEINLINE
2449 typename method<Id, ReturnType(Parameters...), Registry>::FunctionPointer
2450 method<Id, ReturnType(Parameters...), Registry>::resolve(
2451 const ArgType&... args) const {
2452 using namespace detail;
2453
2454 Registry::require_initialized();
2455
2456 void (*pf)();
2457
2458 if constexpr (Arity == 1) {
2459 pf = resolve_uni<mp11::mp_list<Parameters...>, ArgType...>(args...).pf;
2460 } else {
2461 pf = resolve_multi_first<mp11::mp_list<Parameters...>, ArgType...>(
2462 args...)
2463 .pf;
2464 }
2465
2466 return reinterpret_cast<FunctionPointer>(pf);
2467 }
2468
2469 template<
2470 typename Id, typename... Parameters, typename ReturnType, class Registry>
2471 template<typename ArgType>
2472 BOOST_FORCEINLINE auto method<Id, ReturnType(Parameters...), Registry>::vptr(
2473 const ArgType& arg) const -> vptr_type {
2474 if constexpr (detail::is_virtual_ptr<ArgType>) {
2475 return arg.vptr();
2476 } else {
2477 return detail::acquire_vptr<Registry>(arg);
2478 }
2479 }
2480
2481 template<
2482 typename Id, typename... Parameters, typename ReturnType, class Registry>
2483 template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2484 BOOST_FORCEINLINE auto
2485 method<Id, ReturnType(Parameters...), Registry>::resolve_uni(
2486 const ArgType& arg,
2487 const MoreArgTypes&... more_args) const -> detail::word {
2488
2489 using namespace detail;
2490 using namespace policies;
2491 using namespace boost::mp11;
2492
2493 if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
2494 vptr_type vtbl = vptr<ArgType>(arg);
2495 return vtbl[this->slots_strides[0]];
2496 } else {
2497 return resolve_uni<mp_rest<MethodArgList>>(more_args...);
2498 }
2499 }
2500
2501 template<
2502 typename Id, typename... Parameters, typename ReturnType, class Registry>
2503 template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
2504 BOOST_FORCEINLINE auto
2505 method<Id, ReturnType(Parameters...), Registry>::resolve_multi_first(
2506 const ArgType& arg,
2507 const MoreArgTypes&... more_args) const -> detail::word {
2508
2509 using namespace detail;
2510 using namespace boost::mp11;
2511
2512 if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
2513 vptr_type vtbl = vptr<ArgType>(arg);
2514 std::size_t slot = this->slots_strides[0];
2515
2516
2517
2518
2519
2520 auto dispatch = vtbl[slot].pw;
2521 return resolve_multi_next<1, mp_rest<MethodArgList>, MoreArgTypes...>(
2522 dispatch, more_args...);
2523 } else {
2524 return resolve_multi_first<mp_rest<MethodArgList>, MoreArgTypes...>(
2525 more_args...);
2526 }
2527 }
2528
2529 template<
2530 typename Id, typename... Parameters, typename ReturnType, class Registry>
2531 template<
2532 std::size_t VirtualArg, typename MethodArgList, typename ArgType,
2533 typename... MoreArgTypes>
2534 BOOST_FORCEINLINE auto
2535 method<Id, ReturnType(Parameters...), Registry>::resolve_multi_next(
2536 vptr_type dispatch, const ArgType& arg,
2537 const MoreArgTypes&... more_args) const -> detail::word {
2538
2539 using namespace detail;
2540 using namespace boost::mp11;
2541
2542 if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
2543 vptr_type vtbl = vptr<ArgType>(arg);
2544 std::size_t slot = this->slots_strides[VirtualArg];
2545 std::size_t stride = this->slots_strides[Arity + VirtualArg - 1];
2546 dispatch = dispatch + vtbl[slot].i * stride;
2547 }
2548
2549 if constexpr (VirtualArg + 1 == Arity) {
2550 return *dispatch;
2551 } else {
2552 return resolve_multi_next<
2553 VirtualArg + 1, mp_rest<MethodArgList>, MoreArgTypes...>(
2554 dispatch, more_args...);
2555 }
2556 }
2557
2558
2559
2560
2561 template<
2562 typename Id, typename... Parameters, typename ReturnType, class Registry>
2563 template<auto Fn>
2564 inline auto
2565 method<Id, ReturnType(Parameters...), Registry>::has_next() -> bool {
2566 if (next<Fn> == fn_not_implemented) {
2567 return false;
2568 }
2569
2570 if (next<Fn> == fn_ambiguous) {
2571 return false;
2572 }
2573
2574 return true;
2575 }
2576
2577 template<
2578 typename Id, typename... Parameters, typename ReturnType, class Registry>
2579 BOOST_NORETURN auto
2580 method<Id, ReturnType(Parameters...), Registry>::fn_not_implemented(
2581 detail::remove_virtual_<Parameters>... args) -> ReturnType {
2582 using namespace policies;
2583
2584 if constexpr (Registry::has_error_handler) {
2585 no_overrider error;
2586 detail::init_bad_call<method, rtti, 0u>::fn(
2587 error,
2588 detail::parameter_traits<Parameters, Registry>::peek(args)...);
2589 Registry::error_handler::error(error);
2590 }
2591
2592 abort();
2593 }
2594
2595 template<
2596 typename Id, typename... Parameters, typename ReturnType, class Registry>
2597 BOOST_NORETURN auto
2598 method<Id, ReturnType(Parameters...), Registry>::fn_ambiguous(
2599 detail::remove_virtual_<Parameters>... args) -> ReturnType {
2600 using namespace policies;
2601
2602 if constexpr (Registry::has_error_handler) {
2603 ambiguous_call error;
2604 detail::init_bad_call<method, rtti, 0u>::fn(
2605 error,
2606 detail::parameter_traits<Parameters, Registry>::peek(args)...);
2607 Registry::error_handler::error(error);
2608 }
2609
2610 abort();
2611 }
2612
2613
2614
2615
2616 namespace detail {
2617
2618 template<typename T, typename U>
2619 struct same_reference_category {
2620 static constexpr bool value = (std::is_lvalue_reference<T>::value ==
2621 std::is_lvalue_reference<U>::value) &&
2622 (std::is_rvalue_reference<T>::value ==
2623 std::is_rvalue_reference<U>::value);
2624 };
2625 template<class T1, class T2, typename = void>
2626 struct validate_overrider_parameter : std::false_type {
2627 static_assert(
2628 false_t<T1, T2>, "non-virtual parameter types must match exactly");
2629 };
2630
2631 template<class T1, class T2>
2632 struct validate_overrider_parameter<
2633 T1, T2,
2634 std::enable_if_t<
2635 is_virtual_ptr<T1> && is_virtual_ptr<T2> &&
2636 !same_reference_category<T1, T2>::value>> : std::false_type {
2637 static_assert(
2638 false_t<T1, T2>, "different virtual_ptr<> reference categories");
2639 };
2640
2641 template<class T1, class T2>
2642 struct validate_overrider_parameter<
2643 T1, T2, std::enable_if_t<is_virtual_ptr<T1> && !is_virtual_ptr<T2>>>
2644 : std::false_type {
2645 static_assert(
2646 false_t<T1, T2>,
2647 "virtual_ptr<> is required in overrider in same position as in "
2648 "method");
2649 };
2650
2651 template<class T>
2652 struct validate_overrider_parameter<T, T, void> : std::true_type {};
2653
2654 template<class T1, class T2>
2655 struct validate_overrider_parameter<virtual_<T1>, T2, void> : std::true_type {};
2656
2657 template<class T1, class T2>
2658 struct validate_overrider_parameter<virtual_<T1>, virtual_<T2>, void>
2659 : std::false_type {
2660 static_assert(false_t<T1, T2>, "virtual_<> is not allowed in overriders");
2661 };
2662
2663 template<class T, class R>
2664 struct validate_overrider_parameter<virtual_ptr<T, R>, virtual_ptr<T, R>, void>
2665 : std::true_type {};
2666
2667 template<class T1, class R, class T2, class R2>
2668 struct validate_overrider_parameter<
2669 virtual_ptr<T1, R>, virtual_ptr<T2, R2>, void> : std::true_type {
2670 static_assert(std::is_same_v<R, R2>, "registry mismatch");
2671 using C1 = virtual_type<virtual_ptr<T1, R>, R>;
2672 using C2 = virtual_type<virtual_ptr<T2, R>, R>;
2673 static_assert(
2674 std::is_base_of_v<C1, C2> &&
2675 std::is_convertible_v<virtual_ptr<T2, R>, virtual_ptr<T1, R>>,
2676 "method parameter must be an unambiguous accessible base "
2677 "of corresponding overrider parameter");
2678 };
2679
2680 template<class T1, class R, class T2, class R2>
2681 struct validate_overrider_parameter<
2682 const virtual_ptr<T1, R>&, const virtual_ptr<T2, R2>&, void>
2683 : std::true_type {
2684 static_assert(std::is_same_v<R, R2>, "registry mismatch");
2685 using C1 = virtual_type<const virtual_ptr<T1, R>&, R>;
2686 using C2 = virtual_type<const virtual_ptr<T2, R>&, R>;
2687 static_assert(
2688 std::is_base_of_v<C1, C2> &&
2689 std::is_convertible_v<virtual_ptr<T2, R>, virtual_ptr<T1, R>>,
2690 "method parameter must be an unambiguous accessible base "
2691 "of corresponding overrider parameter");
2692 };
2693
2694 template<class T1, class R, class T2, class R2>
2695 struct validate_overrider_parameter<
2696 virtual_ptr<T1, R>&&, virtual_ptr<T2, R2>&&, void> : std::true_type {
2697 static_assert(std::is_same_v<R, R2>, "registry mismatch");
2698 using C1 = virtual_type<virtual_ptr<T1, R>&&, R>;
2699 using C2 = virtual_type<virtual_ptr<T2, R>&&, R>;
2700 static_assert(
2701 std::is_base_of_v<C1, C2> &&
2702 std::is_convertible_v<virtual_ptr<T2, R>, virtual_ptr<T1, R>>,
2703 "method parameter must be an unambiguous accessible base "
2704 "of corresponding overrider parameter");
2705 };
2706
2707 }
2708
2709 template<
2710 typename Id, typename... Parameters, typename ReturnType, class Registry>
2711 template<
2712 auto Overrider, typename OverriderReturn, typename... OverriderParameters>
2713 auto method<Id, ReturnType(Parameters...), Registry>::
2714 thunk<Overrider, OverriderReturn (*)(OverriderParameters...)>::fn(
2715 detail::remove_virtual_<Parameters>... arg) -> ReturnType {
2716 using namespace detail;
2717 static_assert(
2718 (validate_overrider_parameter<Parameters, OverriderParameters>::value &&
2719 ...),
2720 "virtual_ptr category mismatch");
2721 return Overrider(
2722 detail::parameter_traits<Parameters, Registry>::template cast<
2723 OverriderParameters>(
2724 std::forward<detail::remove_virtual_<Parameters>>(arg))...);
2725 }
2726
2727 template<
2728 typename Id, typename... Parameters, typename ReturnType, class Registry>
2729 template<auto Function, typename FnReturnType>
2730 method<Id, ReturnType(Parameters...), Registry>::override_impl<
2731 Function, FnReturnType>::override_impl(FunctionPointer* p_next) {
2732 using namespace detail;
2733
2734
2735
2736
2737 #ifdef BOOST_CLANG
2738 #pragma clang diagnostic push
2739 #pragma clang diagnostic ignored "-Wuninitialized"
2740 #endif
2741
2742 #ifdef BOOST_GCC
2743 #pragma GCC diagnostic push
2744 #pragma GCC diagnostic ignored "-Wuninitialized"
2745 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
2746 #endif
2747
2748
2749
2750 if (overrider_info::method) {
2751 BOOST_ASSERT(overrider_info::method == &fn);
2752 return;
2753 }
2754
2755 #ifdef BOOST_CLANG
2756 #pragma clang diagnostic pop
2757 #endif
2758
2759 #ifdef BOOST_GCC
2760 #pragma GCC diagnostic pop
2761 #endif
2762
2763 overrider_info::method = &fn;
2764
2765 if constexpr (!Registry::has_deferred_static_rtti) {
2766 resolve_type_ids();
2767 }
2768
2769 this->next = reinterpret_cast<void (**)()>(
2770 p_next ? p_next : &method::next<Function>);
2771
2772 using Thunk = thunk<Function, decltype(Function)>;
2773 this->pf = reinterpret_cast<void (*)()>(Thunk::fn);
2774
2775 this->vp_begin = vp_type_ids;
2776 this->vp_end = vp_type_ids + Arity;
2777
2778 fn.overriders.push_back(*this);
2779 }
2780
2781 template<
2782 typename Id, typename... Parameters, typename ReturnType, class Registry>
2783 template<auto Function, typename FnReturnType>
2784 void method<Id, ReturnType(Parameters...), Registry>::override_impl<
2785 Function, FnReturnType>::resolve_type_ids() {
2786 using namespace detail;
2787
2788 this->return_type = Registry::rtti::template static_type<
2789 virtual_type<FnReturnType, Registry>>();
2790 this->type = Registry::rtti::template static_type<decltype(Function)>();
2791 using Thunk = thunk<Function, decltype(Function)>;
2792 detail::
2793 init_type_ids<Registry, typename Thunk::OverriderVirtualParameters>::fn(
2794 this->vp_type_ids);
2795 }
2796
2797
2798 namespace aliases {
2799
2800 using boost::openmethod::final_virtual_ptr;
2801 using boost::openmethod::virtual_;
2802 using boost::openmethod::virtual_ptr;
2803
2804 }
2805
2806
2807
2808
2809 #ifdef __MRDOCS__
2810
2811
2812
2813
2814
2815
2816
2817
2818 template<typename T, class Registry>
2819 struct VirtualTraits {
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834 using virtual_type = detail::unspecified;
2835
2836
2837
2838
2839
2840
2841
2842
2843 static auto peek(T arg) -> const virtual_type&;
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853 template<typename U>
2854 static auto cast(T arg) -> U;
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866 template<class U>
2867 using rebind = detail::unspecified;
2868 };
2869
2870 #endif
2871
2872 }
2873
2874 #ifdef _MSC_VER
2875 #pragma warning(pop)
2876 #endif
2877
2878 #endif