LCOV - code coverage report
Current view: top level - include/boost/http/core - polystore.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 85.4 % 89 76 13
Test Date: 2026-06-13 19:44:58 Functions: 66.5 % 206 137 69

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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/http
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_HTTP_POLYSTORE_HPP
      11                 : #define BOOST_HTTP_POLYSTORE_HPP
      12                 : 
      13                 : #include <boost/http/detail/config.hpp>
      14                 : #include <boost/http/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 http {
      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                 : } // http
      72                 : } // boost
      73                 : namespace std {
      74                 : template<>
      75                 : struct hash< boost::http::detail::typeindex >
      76                 : {
      77                 :     std::size_t operator()(
      78                 :         boost::http::detail::typeindex const& t) const noexcept
      79                 :     {
      80                 :         return t.hash_code();
      81                 :     }
      82                 : };
      83                 : } // std
      84                 : namespace boost {
      85                 : namespace http {
      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_HTTP_DECL
     239                 :     ~polystore();
     240                 : 
     241                 :     /** Constructor
     242                 :         The moved-from container will be empty.
     243                 :     */
     244                 :     BOOST_HTTP_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_HTTP_DECL
     252                 :     polystore& operator=(polystore&& other) noexcept;
     253                 : 
     254                 :     /** Constructor
     255                 :         The container is initially empty.
     256                 :     */
     257 HIT         234 :     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              69 :     T* find() const noexcept
     274                 :     {
     275              69 :         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              11 :     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              11 :         auto p = make_any<T>(std::forward<Args>(args)...);
     438              11 :         keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
     439              22 :         return *static_cast<T*>(insert_impl(
     440              27 :             std::move(p), ks.kn, ks.N));
     441              11 :     }
     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               3 :     T& insert(T&& t)
     544                 :     {
     545                 :         return emplace<typename
     546               3 :             std::remove_cv<T>::type, Keys...>(
     547               3 :                 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 MIS           0 :             return *t;
     578 HIT           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_HTTP_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_HTTP_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              24 :         key(detail::typeindex const& ti_,
     630              24 :             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              10 :         explicit keyset(T& t) noexcept
     643              10 :             : kn{ key(detail::typeindex(BOOST_CORE_TYPEID(T)), &t) }
     644                 :         {
     645              10 :         }
     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              18 :     make_any(Args&&... args) ->
     671                 :         std::unique_ptr<any_impl<T>>
     672                 :     {
     673              21 :         return std::unique_ptr<any_impl<T>>(new
     674              21 :             any_impl<T>(std::forward<Args>(args)...));
     675                 :     }
     676                 : 
     677                 :     void destroy() noexcept;
     678                 :     BOOST_HTTP_DECL any& get(std::size_t i);
     679                 :     BOOST_HTTP_DECL void* find(
     680                 :         core::typeinfo const& ti) const noexcept;
     681                 :     BOOST_HTTP_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_HTTP_DECL
     692                 :     polystore::any
     693                 : {
     694              18 :     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 MIS           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 HIT          18 :     explicit any_impl(Args&&... args)
     742              18 :         : t(std::forward<Args>(args)...)
     743                 :     {
     744              18 :     }
     745              34 :     void* get() noexcept override { return std::addressof(t); }
     746 MIS           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 HIT           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                 : } // http
     814                 : } // boost
     815                 : 
     816                 : #endif
        

Generated by: LCOV version 2.3