Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright (c) 2018-2025 Jean-Louis Leroy
0002 // Distributed under the Boost Software License, Version 1.0.
0003 // See accompanying file LICENSE_1_0.txt
0004 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_OPENMETHOD_POLICY_VPTR_VECTOR_HPP
0007 #define BOOST_OPENMETHOD_POLICY_VPTR_VECTOR_HPP
0008 
0009 #include <boost/openmethod/preamble.hpp>
0010 
0011 #include <variant>
0012 #include <vector>
0013 
0014 namespace boost::openmethod {
0015 
0016 namespace detail {
0017 
0018 template<class Registry>
0019 inline std::vector<vptr_type> vptr_vector_vptrs;
0020 
0021 template<class Registry>
0022 inline std::vector<const vptr_type*> vptr_vector_indirect_vptrs;
0023 
0024 } // namespace detail
0025 
0026 namespace policies {
0027 
0028 //! Stores v-table pointers in a vector.
0029 //!
0030 //! `vptr_vector` stores v-table pointers in a global vector. If `Registry`
0031 //! contains a @ref type_hash policy, it is used to convert `type_id`s to
0032 //! indices. Otherwise, `type_id`s are used directly as indices.
0033 //!
0034 //! If the registry contains the @ref indirect_vptr policy, stores pointers to
0035 //! pointers to v-tables in the vector.
0036 struct vptr_vector : vptr {
0037   public:
0038     //! A VptrFn metafunction.
0039     //!
0040     //! Keeps track of v-table pointers using a `std::vector`.
0041     //!
0042     //! If `Registry` contains a @ref type_hash policy, it is used to convert
0043     //! `type_id`s to indices; otherwise, `type_id`s are used as indices.
0044     //!
0045     //! If `Registry` contains the @ref indirect_vptr policy, stores pointers to
0046     //! pointers to v-tables in the map.
0047     //!
0048     //! @tparam Registry The registry containing this policy.
0049     template<class Registry>
0050     struct fn {
0051         using type_hash =
0052             typename Registry::template policy<policies::type_hash>;
0053         static constexpr auto has_type_hash = !std::is_same_v<type_hash, void>;
0054 
0055         //! Stores the v-table pointers.
0056         //!
0057         //! If `Registry` contains a @ref type_hash policy, its `initialize`
0058         //! function is called. Its result determines the size of the vector.
0059         //! The v-table pointers are copied into the vector.
0060         //!
0061         //! @tparam Context An @ref InitializeContext.
0062         //! @tparam Options... Zero or more option types.
0063         //! @param ctx A Context object.
0064         //! @param options A tuple of option objects.
0065         template<class Context, class... Options>
0066         static auto initialize(
0067             const Context& ctx, const std::tuple<Options...>& options) -> void {
0068             std::size_t size;
0069             (void)options;
0070 
0071             if constexpr (has_type_hash) {
0072                 auto [_, max_value] = type_hash::initialize(ctx, options);
0073                 size = max_value + 1;
0074             } else {
0075                 size = 0;
0076 
0077                 for (auto iter = ctx.classes_begin(); iter != ctx.classes_end();
0078                      ++iter) {
0079                     for (auto type_iter = iter->type_id_begin();
0080                          type_iter != iter->type_id_end(); ++type_iter) {
0081                         size = (std::max)(size, std::size_t(*type_iter));
0082                     }
0083                 }
0084 
0085                 ++size;
0086             }
0087 
0088             if constexpr (Registry::has_indirect_vptr) {
0089                 detail::vptr_vector_indirect_vptrs<Registry>.resize(size);
0090             } else {
0091                 detail::vptr_vector_vptrs<Registry>.resize(size);
0092             }
0093 
0094             for (auto iter = ctx.classes_begin(); iter != ctx.classes_end();
0095                  ++iter) {
0096                 for (auto type_iter = iter->type_id_begin();
0097                      type_iter != iter->type_id_end(); ++type_iter) {
0098                     std::size_t index;
0099 
0100                     if constexpr (has_type_hash) {
0101                         index = type_hash::hash(*type_iter);
0102                     } else {
0103                         index = std::size_t(*type_iter);
0104                     }
0105 
0106                     if constexpr (Registry::has_indirect_vptr) {
0107                         detail::vptr_vector_indirect_vptrs<Registry>[index] =
0108                             &iter->vptr();
0109                     } else {
0110                         detail::vptr_vector_vptrs<Registry>[index] =
0111                             iter->vptr();
0112                     }
0113                 }
0114             }
0115         }
0116 
0117         //! Returns a *reference* to a v-table pointer for an object.
0118         //!
0119         //! Acquires the dynamic @ref type_id of `arg`, using the registry's
0120         //! @ref rtti policy.
0121         //!
0122         //! If the registry has a @ref type_hash policy, uses it to convert the
0123         //! type id to an index; otherwise, uses the type_id as the index.
0124         //!
0125         //! If the registry contains the @ref runtime_checks policy, verifies
0126         //! that the index falls within the limits of the vector. If it does
0127         //! not, and if the registry contains a @ref error_handler policy, calls
0128         //! its @ref error function with a @ref missing_class value, then
0129         //! terminates the program with @ref abort.
0130         //!
0131         //! @tparam Class A registered class.
0132         //! @param arg A reference to a const object of type `Class`.
0133         //! @return A reference to a the v-table pointer for `Class`.
0134         template<class Class>
0135         static auto dynamic_vptr(const Class& arg) -> const vptr_type& {
0136             auto dynamic_type = Registry::rtti::dynamic_type(arg);
0137             std::size_t index;
0138             if constexpr (has_type_hash) {
0139                 index = type_hash::hash(dynamic_type);
0140             } else {
0141                 index = std::size_t(dynamic_type);
0142 
0143                 if constexpr (Registry::has_runtime_checks) {
0144                     std::size_t max_index = 0;
0145 
0146                     if constexpr (Registry::has_indirect_vptr) {
0147                         max_index =
0148                             detail::vptr_vector_indirect_vptrs<Registry>.size();
0149                     } else {
0150                         max_index = detail::vptr_vector_vptrs<Registry>.size();
0151                     }
0152 
0153                     if (index >= max_index) {
0154                         if constexpr (Registry::has_error_handler) {
0155                             missing_class error;
0156                             error.type = dynamic_type;
0157                             Registry::error_handler::error(error);
0158                         }
0159 
0160                         abort();
0161                     }
0162                 }
0163             }
0164 
0165             if constexpr (Registry::has_indirect_vptr) {
0166                 return *detail::vptr_vector_indirect_vptrs<Registry>[index];
0167             } else {
0168                 return detail::vptr_vector_vptrs<Registry>[index];
0169             }
0170         }
0171 
0172         //! Releases the memory allocated by `initialize`.
0173         //!
0174         //! @tparam Options... Zero or more option types, deduced from the function
0175         //! arguments.
0176         //! @param options Zero or more option objects.
0177         template<class... Options>
0178         static auto finalize(const std::tuple<Options...>&) -> void {
0179             using namespace policies;
0180 
0181             if constexpr (Registry::has_indirect_vptr) {
0182                 detail::vptr_vector_indirect_vptrs<Registry>.clear();
0183             } else {
0184                 detail::vptr_vector_vptrs<Registry>.clear();
0185             }
0186         };
0187     };
0188 };
0189 
0190 } // namespace policies
0191 } // namespace boost::openmethod
0192 
0193 #endif