LCOV - code coverage report
Current view: top level - boost/capy - polystore.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 85.4 % 89 76
Test Date: 2025-12-15 05:33:30 Functions: 68.6 % 204 140

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

Generated by: LCOV version 2.1