LCOV - code coverage report
Current view: top level - boost/capy/core - polystore.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 85.4 % 89 76
Test Date: 2026-01-22 22:47:31 Functions: 69.9 % 186 130

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/capy
       8              : //
       9              : 
      10              : #ifndef BOOST_CAPY_POLYSTORE_HPP
      11              : #define BOOST_CAPY_POLYSTORE_HPP
      12              : 
      13              : #include <boost/capy/detail/config.hpp>
      14              : #include <boost/capy/detail/except.hpp>
      15              : #include <boost/core/typeinfo.hpp>
      16              : #include <boost/core/detail/static_assert.hpp>
      17              : #include <cstring>
      18              : #include <memory>
      19              : #include <type_traits>
      20              : #include <unordered_map>
      21              : #include <vector>
      22              : 
      23              : #if ! defined( BOOST_NO_TYPEID )
      24              : #include <typeindex>
      25              : #endif
      26              : 
      27              : namespace boost {
      28              : namespace capy {
      29              : 
      30              : namespace detail {
      31              : 
      32              : #if defined( BOOST_NO_TYPEID )
      33              : 
      34              : struct typeindex
      35              : {
      36              :     typeindex(
      37              :         core::typeinfo const& ti) noexcept
      38              :         : n_(std::strlen(ti.name()))
      39              :         , ti_(&ti)
      40              :     { 
      41              :     }
      42              : 
      43              :     std::size_t hash_code() const noexcept
      44              :     {
      45              :         constexpr std::size_t offset_basis =
      46              :             (sizeof(std::size_t) == 8)
      47              :                 ? 1469598103934665603ull
      48              :                 : 2166136261u;
      49              :         constexpr std::size_t prime =
      50              :             (sizeof(std::size_t) == 8)
      51              :                 ? 1099511628211ull
      52              :                 : 16777619u;
      53              :         auto const s = ti_->name();
      54              :         std::size_t h = offset_basis;
      55              :         for(std::size_t i = 0; i < n_; ++i)
      56              :             h = (h ^ static_cast<unsigned char>(s[i])) * prime;
      57              :         return h;
      58              :     }
      59              : 
      60              :     bool operator==(typeindex const& other) const noexcept
      61              :     {
      62              :         return n_ == other.n_ && *ti_ == *other.ti_;
      63              :     }
      64              : 
      65              : private:
      66              :     std::size_t n_;
      67              :     core::typeinfo const* ti_;
      68              : };
      69              : 
      70              : } // detail
      71              : } // capy
      72              : } // boost
      73              : namespace std {
      74              : template<>
      75              : struct hash< boost::capy::detail::typeindex >
      76              : {
      77              :     std::size_t operator()(
      78              :         boost::capy::detail::typeindex const& t) const noexcept
      79              :     {
      80              :         return t.hash_code();
      81              :     }
      82              : };
      83              : } // std
      84              : namespace boost {
      85              : namespace capy {
      86              : namespace detail {
      87              : 
      88              : #else
      89              : 
      90              : using typeindex = std::type_index;
      91              : 
      92              : #endif
      93              : 
      94              : //------------------------------------------------
      95              : //
      96              : // call_traits
      97              : //
      98              : //------------------------------------------------
      99              : 
     100              : template<class... Ts>
     101              : struct type_list {};
     102              : 
     103              : template<class T>
     104              : struct call_traits : std::false_type {};
     105              : 
     106              : template<class R, class... Args>
     107              : struct call_traits<R(*)(Args...)> : std::true_type
     108              : {
     109              :     using return_type = R;
     110              :     using arg_types = type_list<Args...>;
     111              : };
     112              : 
     113              : template<class R, class... Args>
     114              : struct call_traits<R(&)(Args...)> : std::true_type
     115              : {
     116              :     using return_type = R;
     117              :     using arg_types = type_list<Args...>;
     118              : };
     119              : 
     120              : template<class C, class R, class... Args>
     121              : struct call_traits<R(C::*)(Args...)> : std::true_type
     122              : {
     123              :     using class_type = C;
     124              :     using return_type = R;
     125              :     using arg_types = type_list<Args...>;
     126              : };
     127              : 
     128              : template<class C, class R, class... Args>
     129              : struct call_traits<R(C::*)(Args...) const> : std::true_type
     130              : {
     131              :     using class_type = C;
     132              :     using return_type = R;
     133              :     using arg_types = type_list<Args...>;
     134              : };
     135              : 
     136              : template<class R, class... Args>
     137              : struct call_traits<R(*)(Args...) noexcept> : std::true_type
     138              : {
     139              :     using return_type = R;
     140              :     using arg_types = type_list<Args...>;
     141              : };
     142              : 
     143              : template<class R, class... Args>
     144              : struct call_traits<R(&)(Args...) noexcept> : std::true_type
     145              : {
     146              :     using return_type = R;
     147              :     using arg_types = type_list<Args...>;
     148              : };
     149              : 
     150              : template<class C, class R, class... Args>
     151              : struct call_traits<R(C::*)(Args...) noexcept> : std::true_type
     152              : {
     153              :     using class_type = C;
     154              :     using return_type = R;
     155              :     using arg_types = type_list<Args...>;
     156              : };
     157              : 
     158              : template<class C, class R, class... Args>
     159              : struct call_traits<R(C::*)(Args...) const noexcept> : std::true_type
     160              : {
     161              :     using class_type = C;
     162              :     using return_type = R;
     163              :     using arg_types = type_list<Args...>;
     164              : };
     165              : 
     166              : template<class F>
     167              :     requires requires { &F::operator(); } &&
     168              :              std::is_member_function_pointer_v<decltype(&F::operator())>
     169              : struct call_traits<F> : call_traits<decltype(&F::operator())> {};
     170              : 
     171              : } // detail
     172              : 
     173              : /** A container of type-erased objects
     174              : 
     175              :     Objects are stored and retrieved by their type.
     176              :     Each type may be stored at most once. Types
     177              :     may specify a nested `key_type` to be used
     178              :     as the unique identifier instead of the type
     179              :     itself. In this case, a reference to the type
     180              :     must be convertible to a reference to the key type.
     181              : 
     182              :     @par Example
     183              :     @code
     184              :     struct A
     185              :     {
     186              :         int i = 1;
     187              :     };
     188              :     struct B
     189              :     {
     190              :         char c = '2';
     191              :     };
     192              :     struct C
     193              :     {
     194              :         double d;
     195              :     };
     196              :     struct D : C
     197              :     {
     198              :         using key_type = C;
     199              :         D()
     200              :         {
     201              :             d = 3.14;
     202              :         }
     203              :     };
     204              :     polystore ps;
     205              :     A& a = ps.emplace<A>();
     206              :     B& b = ps.insert(B{});
     207              :     C& c = ps.emplace<C>();
     208              :     assert(ps.get<A>().i == 1);
     209              :     assert(ps.get<B>().c == '2');
     210              :     assert(ps.get<C>().d == 3.14);
     211              :     invoke(ps, [](A& a){ a.i = 0; });
     212              :     invoke(ps, [](A const&, B& b){ b.c = 0; });
     213              :     assert(ps.get<A>().i == 0);
     214              :     assert(ps.get<B>().c == 0);
     215              :     @endcode
     216              : */
     217              : class polystore
     218              : {
     219              :     template<class T, class = void>
     220              :     struct get_key : std::false_type
     221              :     {
     222              :     };
     223              : 
     224              :     template<class T>
     225              :     struct get_key<T, typename std::enable_if<
     226              :         ! std::is_same<T, typename T::key_type>::value>::type>
     227              :         : std::true_type
     228              :     {
     229              :         using type = typename T::key_type;
     230              :     };
     231              : 
     232              : public:
     233              :     /** Destructor
     234              : 
     235              :         All objects stored in the container are destroyed in
     236              :         the reverse order of construction.
     237              :     */
     238              :     BOOST_CAPY_DECL
     239              :     ~polystore();
     240              : 
     241              :     /** Constructor
     242              :         The moved-from container will be empty.
     243              :     */
     244              :     BOOST_CAPY_DECL
     245              :     polystore(polystore&& other) noexcept;
     246              : 
     247              :     /** Assignment operator
     248              :         The moved-from container will be empty.
     249              :         @return A reference to `*this`.
     250              :     */
     251              :     BOOST_CAPY_DECL
     252              :     polystore& operator=(polystore&& other) noexcept;
     253              : 
     254              :     /** Constructor
     255              :         The container is initially empty.
     256              :     */
     257           10 :     polystore() = default;
     258              : 
     259              :     /** Return a pointer to the object associated with type `T`, or `nullptr`
     260              : 
     261              :         If no object associated with `T` exists in the container,
     262              :         `nullptr` is returned.
     263              : 
     264              :         @par Thread Safety
     265              :         `const` member function calls are thread-safe.
     266              :         Calls to non-`const` member functions must not run concurrently
     267              :         with other member functions on the same object.
     268              : 
     269              :         @tparam T The type of object to find.
     270              :         @return A pointer to the associated object, or `nullptr` if none exists.
     271              :     */
     272              :     template<class T>
     273           66 :     T* find() const noexcept
     274              :     {
     275           66 :         return static_cast<T*>(find(BOOST_CORE_TYPEID(T)));
     276              :     }
     277              : 
     278              :     /** Assign the pointer for the object associated with `T`, or `nullptr`.
     279              :         
     280              :         If no object of type `T` is stored, @p t is set to `nullptr`.
     281              : 
     282              :         @par Thread Safety
     283              :         `const` member functions are thread-safe. Non-`const` functions
     284              :         must not run concurrently with any other member function on the
     285              :         same instance.
     286              : 
     287              :         @param t The pointer to assign.
     288              :         @return `true` if an object of type `T` is present, otherwise `false`.
     289              :     */
     290              :     template<class T>
     291              :     bool find(T*& t) const noexcept
     292              :     {
     293              :         t = find<T>();
     294              :         return t != nullptr;
     295              :     }
     296              : 
     297              :     /** Return a reference to the object associated with type T
     298              : 
     299              :         If no such object exists in the container, an exception is thrown.
     300              : 
     301              :         @par Exception Safety
     302              :         Strong guarantee.
     303              : 
     304              :         @par Thread Safety
     305              :         Calls to `const` member functions are thread-safe.  
     306              :         Calls to non-`const` member functions must not run concurrently
     307              :         with other member functions on the same object.
     308              : 
     309              :         @throws std::bad_typeid
     310              :         If no object associated with type `T` is present.
     311              :         @tparam T The type of object to retrieve.
     312              :         @return A reference to the associated object.
     313              :     */
     314              :     template<class T>
     315           34 :     T& get() const
     316              :     {
     317           34 :         if(auto t = find<T>())
     318           33 :             return *t;
     319            1 :         detail::throw_bad_typeid();
     320              :     }
     321              : 
     322              :     /** Construct and insert an anonymous object into the container
     323              : 
     324              :         A new object of type `T` is constructed in place using the provided
     325              :         arguments and inserted into the container without associating it
     326              :         with any key. A reference to the stored object is returned.
     327              : 
     328              :         @par Exception Safety
     329              :         Strong guarantee.
     330              : 
     331              :         @par Thread Safety
     332              :         Not thread-safe.
     333              : 
     334              :         @tparam T The type of object to construct and insert.
     335              :         @param args Arguments forwarded to the constructor of `T`.
     336              :         @return A reference to the inserted object.
     337              :     */
     338              :     template<class T, class... Args>
     339            2 :     T& emplace_anon(Args&&... args)
     340              :     {
     341            4 :         return *static_cast<T*>(insert_impl(
     342            4 :             make_any<T>(std::forward<Args>(args)...)));
     343              :     }
     344              : 
     345              :     /** Insert an anonymous object by moving or copying it into the container
     346              : 
     347              :         A new object of type `T` is inserted into the container without
     348              :         associating it with any key. The object is move-constructed or
     349              :         copy-constructed from the provided argument, and a reference to
     350              :         the stored object is returned.
     351              : 
     352              :         @par Exception Safety
     353              :         Strong guarantee.
     354              : 
     355              :         @par Thread Safety
     356              :         Not thread-safe.
     357              : 
     358              :         @tparam T The type of object to insert.
     359              :         @param t The object to insert.
     360              :         @return A reference to the inserted object.
     361              :     */
     362              :     template<class T>
     363              :     T& insert_anon(T&& t)
     364              :     {
     365              :         return emplace_anon<typename
     366              :             std::remove_cv<T>::type>(
     367              :                 std::forward<T>(t));
     368              :     }
     369              : 
     370              :     /** Construct and insert an object with a nested key type
     371              : 
     372              :         A new object of type `T` is constructed in place using the provided
     373              :         arguments and inserted into the container. The type `T` must define
     374              :         a nested type `key_type`, which is used as the key for insertion.
     375              :         No additional key types may be specified. The type `T&` must be
     376              :         convertible to a reference to `key_type`.
     377              : 
     378              :         @par Constraints
     379              :         `T::key_type` must name a type.
     380              : 
     381              :         @par Exception Safety
     382              :         Strong guarantee.
     383              : 
     384              :         @par Thread Safety
     385              :         Not thread-safe.
     386              : 
     387              :         @throws std::invalid_argument On duplicate insertion.
     388              :         @tparam T The type of object to construct and insert.
     389              :         @param args Arguments forwarded to the constructor of `T`.
     390              :         @return A reference to the inserted object.
     391              :     */
     392              :     template<class T, class... Keys, class... Args>
     393            3 :     auto emplace(Args&&... args) ->
     394              :         typename std::enable_if<get_key<T>::value, T&>::type
     395              :     {
     396              :         // Can't have Keys with nested key_type
     397              :         BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0);
     398              :         // T& must be convertible to key_type&
     399              :         BOOST_CORE_STATIC_ASSERT(std::is_convertible<
     400              :             T&, typename get_key<T>::type&>::value);
     401            3 :         auto p = make_any<T>(std::forward<Args>(args)...);
     402            3 :         keyset<T, typename get_key<T>::type> ks(
     403            3 :             *static_cast<T*>(p->get()));
     404            6 :         return *static_cast<T*>(insert_impl(
     405            7 :             std::move(p), ks.kn, ks.N));
     406            3 :     }
     407              : 
     408              :     /** Construct and insert an object into the container
     409              : 
     410              :         A new object of type `T` is constructed in place using the provided
     411              :         arguments and inserted into the container. The type `T` must not
     412              :         already exist in the container, nor may any of the additional key
     413              :         types refer to an existing object. The type `T&` must be convertible
     414              :         to a reference to each specified key type.
     415              : 
     416              :         @par Constraints
     417              :         `T::key_type` must not name a type.
     418              : 
     419              :         @par Exception Safety
     420              :         Strong guarantee.
     421              : 
     422              :         @par Thread Safety
     423              :         Not thread-safe.
     424              : 
     425              :         @throws std::invalid_argument On duplicate insertion.
     426              :         @tparam T The type of object to construct and insert.
     427              :         @tparam Keys Optional key types associated with the object.
     428              :         @param args Arguments forwarded to the constructor of `T`.
     429              :         @return A reference to the inserted object.
     430              :     */
     431              :     template<class T, class... Keys, class... Args>
     432            9 :     auto emplace(Args&&... args) ->
     433              :         typename std::enable_if<! get_key<T>::value, T&>::type
     434              :     {
     435              :         // T& must be convertible to each of Keys&
     436              :         BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...));
     437            9 :         auto p = make_any<T>(std::forward<Args>(args)...);
     438            9 :         keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
     439           18 :         return *static_cast<T*>(insert_impl(
     440           21 :             std::move(p), ks.kn, ks.N));
     441            9 :     }
     442              : 
     443              :     /** Return an existing object, creating it if necessary
     444              : 
     445              :         If an object of the exact type `T` already exists in the container,
     446              :         a reference to that object is returned. Otherwise, a new object is
     447              :         constructed in place using the provided arguments, and a reference
     448              :         to the newly created object is returned. The type `T` must not
     449              :         already exist in the container, nor may any of the additional key
     450              :         types refer to an existing object. The type `T` must be convertible
     451              :         to a reference to each additional key type.
     452              : 
     453              :         @par Exception Safety
     454              :         Strong guarantee.
     455              : 
     456              :         @par Thread Safety
     457              :         Not thread-safe.
     458              : 
     459              :         @throws std::invalid_argument On duplicate insertion.
     460              :         @tparam T The type of object to return or create.
     461              :         @tparam Keys Optional key types associated with the object.
     462              :         @param args Arguments forwarded to the constructor of `T`.
     463              :         @return A reference to the existing or newly created object.
     464              :     */
     465              :     template<class T, class... Keys, class... Args>
     466            2 :     auto try_emplace(Args&&... args) ->
     467              :         typename std::enable_if<get_key<T>::value, T&>::type
     468              :     {
     469              :         // Can't have Keys with nested key_type
     470              :         BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0);
     471              :         // T& must be convertible to key_type&
     472              :         BOOST_CORE_STATIC_ASSERT(std::is_convertible<
     473              :             T&, typename get_key<T>::type&>::value);
     474            2 :         if(auto t = find<T>())
     475            1 :             return *t;
     476            1 :         auto p = make_any<T>(std::forward<Args>(args)...);
     477            1 :         keyset<T, typename get_key<T>::type> ks(
     478            1 :             *static_cast<T*>(p->get()));
     479            2 :         return *static_cast<T*>(insert_impl(
     480            2 :             std::move(p), ks.kn, ks.N));
     481            1 :     }
     482              : 
     483              :     /** Return an existing object, creating it if necessary
     484              : 
     485              :         If an object of the exact type `T` already exists in the container,
     486              :         a reference to that object is returned. Otherwise, a new object is
     487              :         constructed in place using the provided arguments, and a reference
     488              :         to the newly created object is returned. The type `T` must not
     489              :         already exist in the container, nor may any of the additional key
     490              :         types refer to an existing object. The type `T` must be convertible
     491              :         to a reference to each additional key type.
     492              : 
     493              :         @par Exception Safety
     494              :         Strong guarantee.
     495              : 
     496              :         @par Thread Safety
     497              :         `const` member function calls are thread-safe.
     498              :         Calls to non-`const` member functions must not run concurrently
     499              :         with other member functions on the same object.
     500              : 
     501              :         @throws std::invalid_argument On duplicate insertion.
     502              :         @tparam T The type of object to return or create.
     503              :         @tparam Keys Optional key types associated with the object.
     504              :         @param args Arguments forwarded to the constructor of `T`.
     505              :         @return A reference to the existing or newly created object.
     506              :     */
     507              :     template<class T, class... Keys, class... Args>
     508            2 :     auto try_emplace(Args&&... args) ->
     509              :         typename std::enable_if<! get_key<T>::value, T&>::type
     510              :     {
     511              :         // T& must be convertible to each of Keys&
     512              :         BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...));
     513            2 :         if(auto t = find<T>())
     514            1 :             return *t;
     515            1 :         auto p = make_any<T>(std::forward<Args>(args)...);
     516            1 :         keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
     517            2 :         return *static_cast<T*>(insert_impl(
     518            2 :             std::move(p), ks.kn, ks.N));
     519            1 :     }
     520              : 
     521              :     /** Insert an object by moving or copying it into the container
     522              : 
     523              :         If an object of the same type `T` already exists in the container,
     524              :         or if any of the additional key types would refer to an existing
     525              :         object, an exception is thrown. Otherwise, the object is inserted
     526              :         by move or copy construction, and a reference to the stored object
     527              :         is returned. The type `T` must be convertible to a reference to each
     528              :         additional key type.
     529              : 
     530              :         @par Exception Safety
     531              :         Strong guarantee.
     532              : 
     533              :         @par Thread Safety
     534              :         Not thread-safe.
     535              : 
     536              :         @throws std::invalid_argument On duplicate insertion.
     537              :         @tparam T The type of object to insert.
     538              :         @tparam Keys Optional key types associated with the object.
     539              :         @param t The object to insert.
     540              :         @return A reference to the inserted object.
     541              :     */
     542              :     template<class T, class... Keys>
     543            1 :     T& insert(T&& t)
     544              :     {
     545              :         return emplace<typename
     546            1 :             std::remove_cv<T>::type, Keys...>(
     547            1 :                 std::forward<T>(t));
     548              :     }
     549              : 
     550              :     /** Return an existing object or create a new one
     551              : 
     552              :         If an object of the exact type `T` already exists in the container,
     553              :         a reference to that object is returned. Otherwise, a new object of
     554              :         type `T` is default-constructed in the container, and a reference
     555              :         to the newly created object is returned. This function ignores
     556              :         nested key types and cannot be used to specify additional keys.
     557              : 
     558              :         @par Constraints
     559              :         `T` must be default-constructible.
     560              : 
     561              :         @par Exception Safety
     562              :         Strong guarantee.
     563              : 
     564              :         @par Thread Safety
     565              :         Not thread-safe.
     566              : 
     567              :         @tparam T The type of object to retrieve or create.
     568              :         @return A reference to the stored object.
     569              :     */
     570              :     template<class T>
     571            2 :     T& use()
     572              :     {
     573              :         // T must be default constructible
     574              :         BOOST_CORE_STATIC_ASSERT(
     575              :             std::is_default_constructible<T>::value);
     576            2 :         if(auto t = find<T>())
     577            0 :             return *t;
     578            2 :         return emplace<T>();
     579              :     }
     580              : 
     581              : protected:
     582              :     struct any;
     583              :     class elements;
     584              : 
     585              :     /** Remove and destroy all objects in the container.
     586              : 
     587              :         All stored objects are destroyed in the reverse order
     588              :         of construction. The container is left empty.
     589              :     */
     590              :     BOOST_CAPY_DECL
     591              :     void
     592              :     clear() noexcept;
     593              : 
     594              :     /** Return a range of all stored elements
     595              :         @par Thread Safety
     596              :         `const` member function calls are thread-safe.
     597              :         Calls to non-`const` member functions must not run concurrently
     598              :         with other member functions on the same object.
     599              :         @return An object representing the range of stored elements.
     600              :     */
     601              :     BOOST_CAPY_DECL
     602              :     elements
     603              :     get_elements() noexcept;
     604              : 
     605              : private:
     606              :     template<class T, class = void>
     607              :     struct has_start : std::false_type {};
     608              : 
     609              :     template<class T>
     610              :     struct has_start<T, typename std::enable_if<
     611              :         std::is_same<decltype(std::declval<T>().start()),
     612              :             void>::value>::type> : std::true_type {};
     613              : 
     614              :     template<class T, class = void>
     615              :     struct has_stop : std::false_type {};
     616              : 
     617              :     template<class T>
     618              :     struct has_stop<T, typename std::enable_if<
     619              :         std::is_same<decltype(std::declval<T>().stop()),
     620              :             void>::value>::type> : std::true_type {};
     621              : 
     622              :     struct key
     623              :     {
     624              :         detail::typeindex ti =
     625              :             detail::typeindex(BOOST_CORE_TYPEID(void));
     626              :         void* p = nullptr;
     627              : 
     628            6 :         key() = default;
     629           22 :         key(detail::typeindex const& ti_,
     630           22 :             void* p_) noexcept : ti(ti_) , p(p_) {}
     631              :     };
     632              : 
     633              :     template<class T, class... Key>
     634              :     struct keyset;
     635              : 
     636              :     template<class T>
     637              :     struct keyset<T>
     638              :     {
     639              :         static constexpr std::size_t N = 1;
     640              :         key kn[1];
     641              : 
     642            8 :         explicit keyset(T& t) noexcept
     643            8 :             : kn{ key(detail::typeindex(BOOST_CORE_TYPEID(T)), &t) }
     644              :         {
     645            8 :         }
     646              :     };
     647              : 
     648              :     template<class T, class... Keys>
     649              :     struct keyset
     650              :     {
     651              :         static constexpr std::size_t N = 1 + sizeof...(Keys);
     652              :         key kn[N + 1];
     653              : 
     654            6 :         explicit keyset(T& t) noexcept
     655           20 :             : kn{
     656            6 :                 key(detail::typeindex(BOOST_CORE_TYPEID(T)),
     657            6 :                     std::addressof(t)),
     658            8 :                 key(detail::typeindex(BOOST_CORE_TYPEID(Keys)),
     659            4 :                     &static_cast<Keys&>(t))..., }
     660              :         {
     661            6 :         }
     662              :     };
     663              : 
     664              :     template<class T> struct any_impl;
     665              : 
     666              :     using any_ptr = std::unique_ptr<any>;
     667              : 
     668              :     template<class T, class... Args>
     669              :     auto
     670           16 :     make_any(Args&&... args) ->
     671              :         std::unique_ptr<any_impl<T>>
     672              :     {
     673           17 :         return std::unique_ptr<any_impl<T>>(new
     674           17 :             any_impl<T>(std::forward<Args>(args)...));
     675              :     }
     676              : 
     677              :     void destroy() noexcept;
     678              :     BOOST_CAPY_DECL any& get(std::size_t i);
     679              :     BOOST_CAPY_DECL void* find(
     680              :         core::typeinfo const& ti) const noexcept;
     681              :     BOOST_CAPY_DECL void* insert_impl(any_ptr,
     682              :         key const* = nullptr, std::size_t = 0);
     683              : 
     684              :     std::vector<any_ptr> v_;
     685              :     std::unordered_map<
     686              :         detail::typeindex, void*> m_;
     687              : };
     688              : 
     689              : //------------------------------------------------
     690              : 
     691              : struct BOOST_CAPY_DECL
     692              :     polystore::any
     693              : {
     694           16 :     virtual ~any() = default;
     695              :     virtual void start() = 0;
     696              :     virtual void stop() = 0;
     697              : private:
     698              :     friend class polystore;
     699              :     virtual void* get() noexcept = 0;
     700              : };
     701              : 
     702              : //------------------------------------------------
     703              : 
     704              : class polystore::elements
     705              : {
     706              : public:
     707            0 :     std::size_t size() const noexcept
     708              :     {
     709            0 :         return n_;
     710              :     }
     711              : 
     712            0 :     any& operator[](
     713              :         std::size_t i) noexcept
     714              :     {
     715            0 :         return ps_.get(i);
     716              :     }
     717              : 
     718              : private:
     719              :     friend class polystore;
     720              : 
     721            0 :     elements(
     722              :         std::size_t n,
     723              :         polystore& ps)
     724            0 :         : n_(n)
     725            0 :         , ps_(ps)
     726              :     {
     727            0 :     }
     728              : 
     729              :     std::size_t n_;
     730              :     polystore& ps_;
     731              : };
     732              : 
     733              : //------------------------------------------------
     734              : 
     735              : template<class T>
     736              : struct polystore::any_impl : polystore::any
     737              : {
     738              :     T t;
     739              : 
     740              :     template<class... Args>
     741           16 :     explicit any_impl(Args&&... args)
     742           16 :         : t(std::forward<Args>(args)...)
     743              :     {
     744           16 :     }
     745           30 :     void* get() noexcept override { return std::addressof(t); }
     746            0 :     void start() override { do_start(has_start<T>{}); }
     747            0 :     void stop() override { do_stop(has_stop<T>{}); }
     748              :     void do_start(std::true_type) { t.start(); }
     749            0 :     void do_start(std::false_type) {}
     750              :     void do_stop(std::true_type) { t.stop(); }
     751            0 :     void do_stop(std::false_type) {}
     752              : };
     753              : 
     754              : //------------------------------------------------
     755              : 
     756              : namespace detail {
     757              : 
     758              : template<class T> struct arg;
     759              : template<class T> struct arg<T const&> : arg<T&> {};
     760              : template<class T> struct arg<T const*> : arg<T*> {};
     761              : template<class T> struct arg<T&>
     762              : {
     763            8 :     T& operator()(polystore& ps) const
     764              :     {
     765            8 :         return ps.get<T>();
     766              :     }
     767              : };
     768              : template<class T> struct arg<T*>
     769              : {
     770            5 :     T* operator()(polystore& ps) const
     771              :     {
     772            5 :         return ps.find<T>();
     773              :     }
     774              : };
     775              : 
     776              : template<class F, class... Args>
     777              : auto
     778           10 : invoke(polystore& ps, F&& f,
     779              :     type_list<Args...> const&) ->
     780              :         typename call_traits<std::decay_t<F>>::return_type
     781              : {
     782           10 :     return std::forward<F>(f)(arg<Args>()(ps)...);
     783              : }
     784              : 
     785              : } // detail
     786              : 
     787              : /** Invoke a callable, injecting stored objects as arguments
     788              :     The callable is invoked with zero or more arguments.
     789              :     For each argument type, if an object of that type
     790              :     (or key type) is stored in the container, a reference
     791              :     to that object is passed to the callable.
     792              :     @par Example
     793              :     @code
     794              :     struct A { int i = 1; };
     795              :     polystore ps;
     796              :     ps.emplace<A>();
     797              :     ps.invoke([](A& a){ assert(a.i == 1; });
     798              :     @endcode
     799              :     @param f The callable to invoke.
     800              :     @return The result of the invocation.
     801              :     @throws std::bad_typeid if any reference argument
     802              :         types are not found in the container.
     803              : */
     804              : template<class F>
     805              : auto
     806           10 : invoke(polystore& ps, F&& f) ->
     807              :     typename detail::call_traits<std::decay_t<F>>::return_type
     808              : {
     809           20 :     return detail::invoke(ps, std::forward<F>(f),
     810           20 :         typename detail::call_traits<std::decay_t<F>>::arg_types{});
     811              : }
     812              : 
     813              : } // capy
     814              : } // boost
     815              : 
     816              : #endif
        

Generated by: LCOV version 2.3