1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_HTTP_POLYSTORE_HPP
10  
#ifndef BOOST_HTTP_POLYSTORE_HPP
11  
#define BOOST_HTTP_POLYSTORE_HPP
11  
#define BOOST_HTTP_POLYSTORE_HPP
12  

12  

13  
#include <boost/http/detail/config.hpp>
13  
#include <boost/http/detail/config.hpp>
14  
#include <boost/http/detail/except.hpp>
14  
#include <boost/http/detail/except.hpp>
15  
#include <boost/core/typeinfo.hpp>
15  
#include <boost/core/typeinfo.hpp>
16  
#include <boost/core/detail/static_assert.hpp>
16  
#include <boost/core/detail/static_assert.hpp>
17  
#include <cstring>
17  
#include <cstring>
18  
#include <memory>
18  
#include <memory>
19  
#include <type_traits>
19  
#include <type_traits>
20  
#include <unordered_map>
20  
#include <unordered_map>
21  
#include <vector>
21  
#include <vector>
22  

22  

23  
#if ! defined( BOOST_NO_TYPEID )
23  
#if ! defined( BOOST_NO_TYPEID )
24  
#include <typeindex>
24  
#include <typeindex>
25  
#endif
25  
#endif
26  

26  

27  
namespace boost {
27  
namespace boost {
28  
namespace http {
28  
namespace http {
29  

29  

30  
namespace detail {
30  
namespace detail {
31  

31  

32  
#if defined( BOOST_NO_TYPEID )
32  
#if defined( BOOST_NO_TYPEID )
33  

33  

34  
struct typeindex
34  
struct typeindex
35  
{
35  
{
36  
    typeindex(
36  
    typeindex(
37  
        core::typeinfo const& ti) noexcept
37  
        core::typeinfo const& ti) noexcept
38  
        : n_(std::strlen(ti.name()))
38  
        : n_(std::strlen(ti.name()))
39  
        , ti_(&ti)
39  
        , ti_(&ti)
40  
    { 
40  
    { 
41  
    }
41  
    }
42  

42  

43  
    std::size_t hash_code() const noexcept
43  
    std::size_t hash_code() const noexcept
44  
    {
44  
    {
45  
        constexpr std::size_t offset_basis =
45  
        constexpr std::size_t offset_basis =
46  
            (sizeof(std::size_t) == 8)
46  
            (sizeof(std::size_t) == 8)
47  
                ? 1469598103934665603ull
47  
                ? 1469598103934665603ull
48  
                : 2166136261u;
48  
                : 2166136261u;
49  
        constexpr std::size_t prime =
49  
        constexpr std::size_t prime =
50  
            (sizeof(std::size_t) == 8)
50  
            (sizeof(std::size_t) == 8)
51  
                ? 1099511628211ull
51  
                ? 1099511628211ull
52  
                : 16777619u;
52  
                : 16777619u;
53  
        auto const s = ti_->name();
53  
        auto const s = ti_->name();
54  
        std::size_t h = offset_basis;
54  
        std::size_t h = offset_basis;
55  
        for(std::size_t i = 0; i < n_; ++i)
55  
        for(std::size_t i = 0; i < n_; ++i)
56  
            h = (h ^ static_cast<unsigned char>(s[i])) * prime;
56  
            h = (h ^ static_cast<unsigned char>(s[i])) * prime;
57  
        return h;
57  
        return h;
58  
    }
58  
    }
59  

59  

60  
    bool operator==(typeindex const& other) const noexcept
60  
    bool operator==(typeindex const& other) const noexcept
61  
    {
61  
    {
62  
        return n_ == other.n_ && *ti_ == *other.ti_;
62  
        return n_ == other.n_ && *ti_ == *other.ti_;
63  
    }
63  
    }
64  

64  

65  
private:
65  
private:
66  
    std::size_t n_;
66  
    std::size_t n_;
67  
    core::typeinfo const* ti_;
67  
    core::typeinfo const* ti_;
68  
};
68  
};
69  

69  

70  
} // detail
70  
} // detail
71  
} // http
71  
} // http
72  
} // boost
72  
} // boost
73  
namespace std {
73  
namespace std {
74  
template<>
74  
template<>
75  
struct hash< boost::http::detail::typeindex >
75  
struct hash< boost::http::detail::typeindex >
76  
{
76  
{
77  
    std::size_t operator()(
77  
    std::size_t operator()(
78  
        boost::http::detail::typeindex const& t) const noexcept
78  
        boost::http::detail::typeindex const& t) const noexcept
79  
    {
79  
    {
80  
        return t.hash_code();
80  
        return t.hash_code();
81  
    }
81  
    }
82  
};
82  
};
83  
} // std
83  
} // std
84  
namespace boost {
84  
namespace boost {
85  
namespace http {
85  
namespace http {
86  
namespace detail {
86  
namespace detail {
87  

87  

88  
#else
88  
#else
89  

89  

90  
using typeindex = std::type_index;
90  
using typeindex = std::type_index;
91  

91  

92  
#endif
92  
#endif
93  

93  

94  
//------------------------------------------------
94  
//------------------------------------------------
95  
//
95  
//
96  
// call_traits
96  
// call_traits
97  
//
97  
//
98  
//------------------------------------------------
98  
//------------------------------------------------
99  

99  

100  
template<class... Ts>
100  
template<class... Ts>
101  
struct type_list {};
101  
struct type_list {};
102  

102  

103  
template<class T>
103  
template<class T>
104  
struct call_traits : std::false_type {};
104  
struct call_traits : std::false_type {};
105  

105  

106  
template<class R, class... Args>
106  
template<class R, class... Args>
107  
struct call_traits<R(*)(Args...)> : std::true_type
107  
struct call_traits<R(*)(Args...)> : std::true_type
108  
{
108  
{
109  
    using return_type = R;
109  
    using return_type = R;
110  
    using arg_types = type_list<Args...>;
110  
    using arg_types = type_list<Args...>;
111  
};
111  
};
112  

112  

113  
template<class R, class... Args>
113  
template<class R, class... Args>
114  
struct call_traits<R(&)(Args...)> : std::true_type
114  
struct call_traits<R(&)(Args...)> : std::true_type
115  
{
115  
{
116  
    using return_type = R;
116  
    using return_type = R;
117  
    using arg_types = type_list<Args...>;
117  
    using arg_types = type_list<Args...>;
118  
};
118  
};
119  

119  

120  
template<class C, class R, class... Args>
120  
template<class C, class R, class... Args>
121  
struct call_traits<R(C::*)(Args...)> : std::true_type
121  
struct call_traits<R(C::*)(Args...)> : std::true_type
122  
{
122  
{
123  
    using class_type = C;
123  
    using class_type = C;
124  
    using return_type = R;
124  
    using return_type = R;
125  
    using arg_types = type_list<Args...>;
125  
    using arg_types = type_list<Args...>;
126  
};
126  
};
127  

127  

128  
template<class C, class R, class... Args>
128  
template<class C, class R, class... Args>
129  
struct call_traits<R(C::*)(Args...) const> : std::true_type
129  
struct call_traits<R(C::*)(Args...) const> : std::true_type
130  
{
130  
{
131  
    using class_type = C;
131  
    using class_type = C;
132  
    using return_type = R;
132  
    using return_type = R;
133  
    using arg_types = type_list<Args...>;
133  
    using arg_types = type_list<Args...>;
134  
};
134  
};
135  

135  

136  
template<class R, class... Args>
136  
template<class R, class... Args>
137  
struct call_traits<R(*)(Args...) noexcept> : std::true_type
137  
struct call_traits<R(*)(Args...) noexcept> : std::true_type
138  
{
138  
{
139  
    using return_type = R;
139  
    using return_type = R;
140  
    using arg_types = type_list<Args...>;
140  
    using arg_types = type_list<Args...>;
141  
};
141  
};
142  

142  

143  
template<class R, class... Args>
143  
template<class R, class... Args>
144  
struct call_traits<R(&)(Args...) noexcept> : std::true_type
144  
struct call_traits<R(&)(Args...) noexcept> : std::true_type
145  
{
145  
{
146  
    using return_type = R;
146  
    using return_type = R;
147  
    using arg_types = type_list<Args...>;
147  
    using arg_types = type_list<Args...>;
148  
};
148  
};
149  

149  

150  
template<class C, class R, class... Args>
150  
template<class C, class R, class... Args>
151  
struct call_traits<R(C::*)(Args...) noexcept> : std::true_type
151  
struct call_traits<R(C::*)(Args...) noexcept> : std::true_type
152  
{
152  
{
153  
    using class_type = C;
153  
    using class_type = C;
154  
    using return_type = R;
154  
    using return_type = R;
155  
    using arg_types = type_list<Args...>;
155  
    using arg_types = type_list<Args...>;
156  
};
156  
};
157  

157  

158  
template<class C, class R, class... Args>
158  
template<class C, class R, class... Args>
159  
struct call_traits<R(C::*)(Args...) const noexcept> : std::true_type
159  
struct call_traits<R(C::*)(Args...) const noexcept> : std::true_type
160  
{
160  
{
161  
    using class_type = C;
161  
    using class_type = C;
162  
    using return_type = R;
162  
    using return_type = R;
163  
    using arg_types = type_list<Args...>;
163  
    using arg_types = type_list<Args...>;
164  
};
164  
};
165  

165  

166  
template<class F>
166  
template<class F>
167  
    requires requires { &F::operator(); } &&
167  
    requires requires { &F::operator(); } &&
168  
             std::is_member_function_pointer_v<decltype(&F::operator())>
168  
             std::is_member_function_pointer_v<decltype(&F::operator())>
169  
struct call_traits<F> : call_traits<decltype(&F::operator())> {};
169  
struct call_traits<F> : call_traits<decltype(&F::operator())> {};
170  

170  

171  
} // detail
171  
} // detail
172  

172  

173  
/** A container of type-erased objects
173  
/** A container of type-erased objects
174  

174  

175  
    Objects are stored and retrieved by their type.
175  
    Objects are stored and retrieved by their type.
176  
    Each type may be stored at most once. Types
176  
    Each type may be stored at most once. Types
177  
    may specify a nested `key_type` to be used
177  
    may specify a nested `key_type` to be used
178  
    as the unique identifier instead of the type
178  
    as the unique identifier instead of the type
179  
    itself. In this case, a reference to the type
179  
    itself. In this case, a reference to the type
180  
    must be convertible to a reference to the key type.
180  
    must be convertible to a reference to the key type.
181  

181  

182  
    @par Example
182  
    @par Example
183  
    @code
183  
    @code
184  
    struct A
184  
    struct A
185  
    {
185  
    {
186  
        int i = 1;
186  
        int i = 1;
187  
    };
187  
    };
188  
    struct B
188  
    struct B
189  
    {
189  
    {
190  
        char c = '2';
190  
        char c = '2';
191  
    };
191  
    };
192  
    struct C
192  
    struct C
193  
    {
193  
    {
194  
        double d;
194  
        double d;
195  
    };
195  
    };
196  
    struct D : C
196  
    struct D : C
197  
    {
197  
    {
198  
        using key_type = C;
198  
        using key_type = C;
199  
        D()
199  
        D()
200  
        {
200  
        {
201  
            d = 3.14;
201  
            d = 3.14;
202  
        }
202  
        }
203  
    };
203  
    };
204  
    polystore ps;
204  
    polystore ps;
205  
    A& a = ps.emplace<A>();
205  
    A& a = ps.emplace<A>();
206  
    B& b = ps.insert(B{});
206  
    B& b = ps.insert(B{});
207  
    C& c = ps.emplace<C>();
207  
    C& c = ps.emplace<C>();
208  
    assert(ps.get<A>().i == 1);
208  
    assert(ps.get<A>().i == 1);
209  
    assert(ps.get<B>().c == '2');
209  
    assert(ps.get<B>().c == '2');
210  
    assert(ps.get<C>().d == 3.14);
210  
    assert(ps.get<C>().d == 3.14);
211  
    invoke(ps, [](A& a){ a.i = 0; });
211  
    invoke(ps, [](A& a){ a.i = 0; });
212  
    invoke(ps, [](A const&, B& b){ b.c = 0; });
212  
    invoke(ps, [](A const&, B& b){ b.c = 0; });
213  
    assert(ps.get<A>().i == 0);
213  
    assert(ps.get<A>().i == 0);
214  
    assert(ps.get<B>().c == 0);
214  
    assert(ps.get<B>().c == 0);
215  
    @endcode
215  
    @endcode
216  
*/
216  
*/
217  
class polystore
217  
class polystore
218  
{
218  
{
219  
    template<class T, class = void>
219  
    template<class T, class = void>
220  
    struct get_key : std::false_type
220  
    struct get_key : std::false_type
221  
    {
221  
    {
222  
    };
222  
    };
223  

223  

224  
    template<class T>
224  
    template<class T>
225  
    struct get_key<T, typename std::enable_if<
225  
    struct get_key<T, typename std::enable_if<
226  
        ! std::is_same<T, typename T::key_type>::value>::type>
226  
        ! std::is_same<T, typename T::key_type>::value>::type>
227  
        : std::true_type
227  
        : std::true_type
228  
    {
228  
    {
229  
        using type = typename T::key_type;
229  
        using type = typename T::key_type;
230  
    };
230  
    };
231  

231  

232  
public:
232  
public:
233  
    /** Destructor
233  
    /** Destructor
234  

234  

235  
        All objects stored in the container are destroyed in
235  
        All objects stored in the container are destroyed in
236  
        the reverse order of construction.
236  
        the reverse order of construction.
237  
    */
237  
    */
238  
    BOOST_HTTP_DECL
238  
    BOOST_HTTP_DECL
239  
    ~polystore();
239  
    ~polystore();
240  

240  

241  
    /** Constructor
241  
    /** Constructor
242  
        The moved-from container will be empty.
242  
        The moved-from container will be empty.
243  
    */
243  
    */
244  
    BOOST_HTTP_DECL
244  
    BOOST_HTTP_DECL
245  
    polystore(polystore&& other) noexcept;
245  
    polystore(polystore&& other) noexcept;
246  

246  

247  
    /** Assignment operator
247  
    /** Assignment operator
248  
        The moved-from container will be empty.
248  
        The moved-from container will be empty.
249  
        @return A reference to `*this`.
249  
        @return A reference to `*this`.
250  
    */
250  
    */
251  
    BOOST_HTTP_DECL
251  
    BOOST_HTTP_DECL
252  
    polystore& operator=(polystore&& other) noexcept;
252  
    polystore& operator=(polystore&& other) noexcept;
253  

253  

254  
    /** Constructor
254  
    /** Constructor
255  
        The container is initially empty.
255  
        The container is initially empty.
256  
    */
256  
    */
257  
    polystore() = default;
257  
    polystore() = default;
258  

258  

259  
    /** Return a pointer to the object associated with type `T`, or `nullptr`
259  
    /** Return a pointer to the object associated with type `T`, or `nullptr`
260  

260  

261  
        If no object associated with `T` exists in the container,
261  
        If no object associated with `T` exists in the container,
262  
        `nullptr` is returned.
262  
        `nullptr` is returned.
263  

263  

264  
        @par Thread Safety
264  
        @par Thread Safety
265  
        `const` member function calls are thread-safe.
265  
        `const` member function calls are thread-safe.
266  
        Calls to non-`const` member functions must not run concurrently
266  
        Calls to non-`const` member functions must not run concurrently
267  
        with other member functions on the same object.
267  
        with other member functions on the same object.
268  

268  

269  
        @tparam T The type of object to find.
269  
        @tparam T The type of object to find.
270  
        @return A pointer to the associated object, or `nullptr` if none exists.
270  
        @return A pointer to the associated object, or `nullptr` if none exists.
271  
    */
271  
    */
272  
    template<class T>
272  
    template<class T>
273  
    T* find() const noexcept
273  
    T* find() const noexcept
274  
    {
274  
    {
275  
        return static_cast<T*>(find(BOOST_CORE_TYPEID(T)));
275  
        return static_cast<T*>(find(BOOST_CORE_TYPEID(T)));
276  
    }
276  
    }
277  

277  

278  
    /** Assign the pointer for the object associated with `T`, or `nullptr`.
278  
    /** Assign the pointer for the object associated with `T`, or `nullptr`.
279  
        
279  
        
280  
        If no object of type `T` is stored, @p t is set to `nullptr`.
280  
        If no object of type `T` is stored, @p t is set to `nullptr`.
281  

281  

282  
        @par Thread Safety
282  
        @par Thread Safety
283  
        `const` member functions are thread-safe. Non-`const` functions
283  
        `const` member functions are thread-safe. Non-`const` functions
284  
        must not run concurrently with any other member function on the
284  
        must not run concurrently with any other member function on the
285  
        same instance.
285  
        same instance.
286  

286  

287  
        @param t The pointer to assign.
287  
        @param t The pointer to assign.
288  
        @return `true` if an object of type `T` is present, otherwise `false`.
288  
        @return `true` if an object of type `T` is present, otherwise `false`.
289  
    */
289  
    */
290  
    template<class T>
290  
    template<class T>
291  
    bool find(T*& t) const noexcept
291  
    bool find(T*& t) const noexcept
292  
    {
292  
    {
293  
        t = find<T>();
293  
        t = find<T>();
294  
        return t != nullptr;
294  
        return t != nullptr;
295  
    }
295  
    }
296  

296  

297  
    /** Return a reference to the object associated with type T
297  
    /** Return a reference to the object associated with type T
298  

298  

299  
        If no such object exists in the container, an exception is thrown.
299  
        If no such object exists in the container, an exception is thrown.
300  

300  

301  
        @par Exception Safety
301  
        @par Exception Safety
302  
        Strong guarantee.
302  
        Strong guarantee.
303  

303  

304  
        @par Thread Safety
304  
        @par Thread Safety
305  
        Calls to `const` member functions are thread-safe.  
305  
        Calls to `const` member functions are thread-safe.  
306  
        Calls to non-`const` member functions must not run concurrently
306  
        Calls to non-`const` member functions must not run concurrently
307  
        with other member functions on the same object.
307  
        with other member functions on the same object.
308  

308  

309  
        @throws std::bad_typeid
309  
        @throws std::bad_typeid
310  
        If no object associated with type `T` is present.
310  
        If no object associated with type `T` is present.
311  
        @tparam T The type of object to retrieve.
311  
        @tparam T The type of object to retrieve.
312  
        @return A reference to the associated object.
312  
        @return A reference to the associated object.
313  
    */
313  
    */
314  
    template<class T>
314  
    template<class T>
315  
    T& get() const
315  
    T& get() const
316  
    {
316  
    {
317  
        if(auto t = find<T>())
317  
        if(auto t = find<T>())
318  
            return *t;
318  
            return *t;
319  
        detail::throw_bad_typeid();
319  
        detail::throw_bad_typeid();
320  
    }
320  
    }
321  

321  

322  
    /** Construct and insert an anonymous object into the container
322  
    /** Construct and insert an anonymous object into the container
323  

323  

324  
        A new object of type `T` is constructed in place using the provided
324  
        A new object of type `T` is constructed in place using the provided
325  
        arguments and inserted into the container without associating it
325  
        arguments and inserted into the container without associating it
326  
        with any key. A reference to the stored object is returned.
326  
        with any key. A reference to the stored object is returned.
327  

327  

328  
        @par Exception Safety
328  
        @par Exception Safety
329  
        Strong guarantee.
329  
        Strong guarantee.
330  

330  

331  
        @par Thread Safety
331  
        @par Thread Safety
332  
        Not thread-safe.
332  
        Not thread-safe.
333  

333  

334  
        @tparam T The type of object to construct and insert.
334  
        @tparam T The type of object to construct and insert.
335  
        @param args Arguments forwarded to the constructor of `T`.
335  
        @param args Arguments forwarded to the constructor of `T`.
336  
        @return A reference to the inserted object.
336  
        @return A reference to the inserted object.
337  
    */
337  
    */
338  
    template<class T, class... Args>
338  
    template<class T, class... Args>
339  
    T& emplace_anon(Args&&... args)
339  
    T& emplace_anon(Args&&... args)
340  
    {
340  
    {
341  
        return *static_cast<T*>(insert_impl(
341  
        return *static_cast<T*>(insert_impl(
342  
            make_any<T>(std::forward<Args>(args)...)));
342  
            make_any<T>(std::forward<Args>(args)...)));
343  
    }
343  
    }
344  

344  

345  
    /** Insert an anonymous object by moving or copying it into the container
345  
    /** Insert an anonymous object by moving or copying it into the container
346  

346  

347  
        A new object of type `T` is inserted into the container without
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
348  
        associating it with any key. The object is move-constructed or
349  
        copy-constructed from the provided argument, and a reference to
349  
        copy-constructed from the provided argument, and a reference to
350  
        the stored object is returned.
350  
        the stored object is returned.
351  

351  

352  
        @par Exception Safety
352  
        @par Exception Safety
353  
        Strong guarantee.
353  
        Strong guarantee.
354  

354  

355  
        @par Thread Safety
355  
        @par Thread Safety
356  
        Not thread-safe.
356  
        Not thread-safe.
357  

357  

358  
        @tparam T The type of object to insert.
358  
        @tparam T The type of object to insert.
359  
        @param t The object to insert.
359  
        @param t The object to insert.
360  
        @return A reference to the inserted object.
360  
        @return A reference to the inserted object.
361  
    */
361  
    */
362  
    template<class T>
362  
    template<class T>
363  
    T& insert_anon(T&& t)
363  
    T& insert_anon(T&& t)
364  
    {
364  
    {
365  
        return emplace_anon<typename
365  
        return emplace_anon<typename
366  
            std::remove_cv<T>::type>(
366  
            std::remove_cv<T>::type>(
367  
                std::forward<T>(t));
367  
                std::forward<T>(t));
368  
    }
368  
    }
369  

369  

370  
    /** Construct and insert an object with a nested key type
370  
    /** Construct and insert an object with a nested key type
371  

371  

372  
        A new object of type `T` is constructed in place using the provided
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
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.
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
375  
        No additional key types may be specified. The type `T&` must be
376  
        convertible to a reference to `key_type`.
376  
        convertible to a reference to `key_type`.
377  

377  

378  
        @par Constraints
378  
        @par Constraints
379  
        `T::key_type` must name a type.
379  
        `T::key_type` must name a type.
380  

380  

381  
        @par Exception Safety
381  
        @par Exception Safety
382  
        Strong guarantee.
382  
        Strong guarantee.
383  

383  

384  
        @par Thread Safety
384  
        @par Thread Safety
385  
        Not thread-safe.
385  
        Not thread-safe.
386  

386  

387  
        @throws std::invalid_argument On duplicate insertion.
387  
        @throws std::invalid_argument On duplicate insertion.
388  
        @tparam T The type of object to construct and insert.
388  
        @tparam T The type of object to construct and insert.
389  
        @param args Arguments forwarded to the constructor of `T`.
389  
        @param args Arguments forwarded to the constructor of `T`.
390  
        @return A reference to the inserted object.
390  
        @return A reference to the inserted object.
391  
    */
391  
    */
392  
    template<class T, class... Keys, class... Args>
392  
    template<class T, class... Keys, class... Args>
393  
    auto emplace(Args&&... args) ->
393  
    auto emplace(Args&&... args) ->
394  
        typename std::enable_if<get_key<T>::value, T&>::type
394  
        typename std::enable_if<get_key<T>::value, T&>::type
395  
    {
395  
    {
396  
        // Can't have Keys with nested key_type
396  
        // Can't have Keys with nested key_type
397  
        BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0);
397  
        BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0);
398  
        // T& must be convertible to key_type&
398  
        // T& must be convertible to key_type&
399  
        BOOST_CORE_STATIC_ASSERT(std::is_convertible<
399  
        BOOST_CORE_STATIC_ASSERT(std::is_convertible<
400  
            T&, typename get_key<T>::type&>::value);
400  
            T&, typename get_key<T>::type&>::value);
401  
        auto p = make_any<T>(std::forward<Args>(args)...);
401  
        auto p = make_any<T>(std::forward<Args>(args)...);
402  
        keyset<T, typename get_key<T>::type> ks(
402  
        keyset<T, typename get_key<T>::type> ks(
403  
            *static_cast<T*>(p->get()));
403  
            *static_cast<T*>(p->get()));
404  
        return *static_cast<T*>(insert_impl(
404  
        return *static_cast<T*>(insert_impl(
405  
            std::move(p), ks.kn, ks.N));
405  
            std::move(p), ks.kn, ks.N));
406  
    }
406  
    }
407  

407  

408  
    /** Construct and insert an object into the container
408  
    /** Construct and insert an object into the container
409  

409  

410  
        A new object of type `T` is constructed in place using the provided
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
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
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
413  
        types refer to an existing object. The type `T&` must be convertible
414  
        to a reference to each specified key type.
414  
        to a reference to each specified key type.
415  

415  

416  
        @par Constraints
416  
        @par Constraints
417  
        `T::key_type` must not name a type.
417  
        `T::key_type` must not name a type.
418  

418  

419  
        @par Exception Safety
419  
        @par Exception Safety
420  
        Strong guarantee.
420  
        Strong guarantee.
421  

421  

422  
        @par Thread Safety
422  
        @par Thread Safety
423  
        Not thread-safe.
423  
        Not thread-safe.
424  

424  

425  
        @throws std::invalid_argument On duplicate insertion.
425  
        @throws std::invalid_argument On duplicate insertion.
426  
        @tparam T The type of object to construct and insert.
426  
        @tparam T The type of object to construct and insert.
427  
        @tparam Keys Optional key types associated with the object.
427  
        @tparam Keys Optional key types associated with the object.
428  
        @param args Arguments forwarded to the constructor of `T`.
428  
        @param args Arguments forwarded to the constructor of `T`.
429  
        @return A reference to the inserted object.
429  
        @return A reference to the inserted object.
430  
    */
430  
    */
431  
    template<class T, class... Keys, class... Args>
431  
    template<class T, class... Keys, class... Args>
432  
    auto emplace(Args&&... args) ->
432  
    auto emplace(Args&&... args) ->
433  
        typename std::enable_if<! get_key<T>::value, T&>::type
433  
        typename std::enable_if<! get_key<T>::value, T&>::type
434  
    {
434  
    {
435  
        // T& must be convertible to each of Keys&
435  
        // T& must be convertible to each of Keys&
436  
        BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...));
436  
        BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...));
437  
        auto p = make_any<T>(std::forward<Args>(args)...);
437  
        auto p = make_any<T>(std::forward<Args>(args)...);
438  
        keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
438  
        keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
439  
        return *static_cast<T*>(insert_impl(
439  
        return *static_cast<T*>(insert_impl(
440  
            std::move(p), ks.kn, ks.N));
440  
            std::move(p), ks.kn, ks.N));
441  
    }
441  
    }
442  

442  

443  
    /** Return an existing object, creating it if necessary
443  
    /** Return an existing object, creating it if necessary
444  

444  

445  
        If an object of the exact type `T` already exists in the container,
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
446  
        a reference to that object is returned. Otherwise, a new object is
447  
        constructed in place using the provided arguments, and a reference
447  
        constructed in place using the provided arguments, and a reference
448  
        to the newly created object is returned. The type `T` must not
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
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
450  
        types refer to an existing object. The type `T` must be convertible
451  
        to a reference to each additional key type.
451  
        to a reference to each additional key type.
452  

452  

453  
        @par Exception Safety
453  
        @par Exception Safety
454  
        Strong guarantee.
454  
        Strong guarantee.
455  

455  

456  
        @par Thread Safety
456  
        @par Thread Safety
457  
        Not thread-safe.
457  
        Not thread-safe.
458  

458  

459  
        @throws std::invalid_argument On duplicate insertion.
459  
        @throws std::invalid_argument On duplicate insertion.
460  
        @tparam T The type of object to return or create.
460  
        @tparam T The type of object to return or create.
461  
        @tparam Keys Optional key types associated with the object.
461  
        @tparam Keys Optional key types associated with the object.
462  
        @param args Arguments forwarded to the constructor of `T`.
462  
        @param args Arguments forwarded to the constructor of `T`.
463  
        @return A reference to the existing or newly created object.
463  
        @return A reference to the existing or newly created object.
464  
    */
464  
    */
465  
    template<class T, class... Keys, class... Args>
465  
    template<class T, class... Keys, class... Args>
466  
    auto try_emplace(Args&&... args) ->
466  
    auto try_emplace(Args&&... args) ->
467  
        typename std::enable_if<get_key<T>::value, T&>::type
467  
        typename std::enable_if<get_key<T>::value, T&>::type
468  
    {
468  
    {
469  
        // Can't have Keys with nested key_type
469  
        // Can't have Keys with nested key_type
470  
        BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0);
470  
        BOOST_CORE_STATIC_ASSERT(sizeof...(Keys) == 0);
471  
        // T& must be convertible to key_type&
471  
        // T& must be convertible to key_type&
472  
        BOOST_CORE_STATIC_ASSERT(std::is_convertible<
472  
        BOOST_CORE_STATIC_ASSERT(std::is_convertible<
473  
            T&, typename get_key<T>::type&>::value);
473  
            T&, typename get_key<T>::type&>::value);
474  
        if(auto t = find<T>())
474  
        if(auto t = find<T>())
475  
            return *t;
475  
            return *t;
476  
        auto p = make_any<T>(std::forward<Args>(args)...);
476  
        auto p = make_any<T>(std::forward<Args>(args)...);
477  
        keyset<T, typename get_key<T>::type> ks(
477  
        keyset<T, typename get_key<T>::type> ks(
478  
            *static_cast<T*>(p->get()));
478  
            *static_cast<T*>(p->get()));
479  
        return *static_cast<T*>(insert_impl(
479  
        return *static_cast<T*>(insert_impl(
480  
            std::move(p), ks.kn, ks.N));
480  
            std::move(p), ks.kn, ks.N));
481  
    }
481  
    }
482  

482  

483  
    /** Return an existing object, creating it if necessary
483  
    /** Return an existing object, creating it if necessary
484  

484  

485  
        If an object of the exact type `T` already exists in the container,
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
486  
        a reference to that object is returned. Otherwise, a new object is
487  
        constructed in place using the provided arguments, and a reference
487  
        constructed in place using the provided arguments, and a reference
488  
        to the newly created object is returned. The type `T` must not
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
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
490  
        types refer to an existing object. The type `T` must be convertible
491  
        to a reference to each additional key type.
491  
        to a reference to each additional key type.
492  

492  

493  
        @par Exception Safety
493  
        @par Exception Safety
494  
        Strong guarantee.
494  
        Strong guarantee.
495  

495  

496  
        @par Thread Safety
496  
        @par Thread Safety
497  
        `const` member function calls are thread-safe.
497  
        `const` member function calls are thread-safe.
498  
        Calls to non-`const` member functions must not run concurrently
498  
        Calls to non-`const` member functions must not run concurrently
499  
        with other member functions on the same object.
499  
        with other member functions on the same object.
500  

500  

501  
        @throws std::invalid_argument On duplicate insertion.
501  
        @throws std::invalid_argument On duplicate insertion.
502  
        @tparam T The type of object to return or create.
502  
        @tparam T The type of object to return or create.
503  
        @tparam Keys Optional key types associated with the object.
503  
        @tparam Keys Optional key types associated with the object.
504  
        @param args Arguments forwarded to the constructor of `T`.
504  
        @param args Arguments forwarded to the constructor of `T`.
505  
        @return A reference to the existing or newly created object.
505  
        @return A reference to the existing or newly created object.
506  
    */
506  
    */
507  
    template<class T, class... Keys, class... Args>
507  
    template<class T, class... Keys, class... Args>
508  
    auto try_emplace(Args&&... args) ->
508  
    auto try_emplace(Args&&... args) ->
509  
        typename std::enable_if<! get_key<T>::value, T&>::type
509  
        typename std::enable_if<! get_key<T>::value, T&>::type
510  
    {
510  
    {
511  
        // T& must be convertible to each of Keys&
511  
        // T& must be convertible to each of Keys&
512  
        BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...));
512  
        BOOST_CORE_STATIC_ASSERT((std::is_convertible_v<T&, Keys&> && ...));
513  
        if(auto t = find<T>())
513  
        if(auto t = find<T>())
514  
            return *t;
514  
            return *t;
515  
        auto p = make_any<T>(std::forward<Args>(args)...);
515  
        auto p = make_any<T>(std::forward<Args>(args)...);
516  
        keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
516  
        keyset<T, Keys...> ks(*static_cast<T*>(p->get()));
517  
        return *static_cast<T*>(insert_impl(
517  
        return *static_cast<T*>(insert_impl(
518  
            std::move(p), ks.kn, ks.N));
518  
            std::move(p), ks.kn, ks.N));
519  
    }
519  
    }
520  

520  

521  
    /** Insert an object by moving or copying it into the container
521  
    /** Insert an object by moving or copying it into the container
522  

522  

523  
        If an object of the same type `T` already exists in the container,
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
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
525  
        object, an exception is thrown. Otherwise, the object is inserted
526  
        by move or copy construction, and a reference to the stored object
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
527  
        is returned. The type `T` must be convertible to a reference to each
528  
        additional key type.
528  
        additional key type.
529  

529  

530  
        @par Exception Safety
530  
        @par Exception Safety
531  
        Strong guarantee.
531  
        Strong guarantee.
532  

532  

533  
        @par Thread Safety
533  
        @par Thread Safety
534  
        Not thread-safe.
534  
        Not thread-safe.
535  

535  

536  
        @throws std::invalid_argument On duplicate insertion.
536  
        @throws std::invalid_argument On duplicate insertion.
537  
        @tparam T The type of object to insert.
537  
        @tparam T The type of object to insert.
538  
        @tparam Keys Optional key types associated with the object.
538  
        @tparam Keys Optional key types associated with the object.
539  
        @param t The object to insert.
539  
        @param t The object to insert.
540  
        @return A reference to the inserted object.
540  
        @return A reference to the inserted object.
541  
    */
541  
    */
542  
    template<class T, class... Keys>
542  
    template<class T, class... Keys>
543  
    T& insert(T&& t)
543  
    T& insert(T&& t)
544  
    {
544  
    {
545  
        return emplace<typename
545  
        return emplace<typename
546  
            std::remove_cv<T>::type, Keys...>(
546  
            std::remove_cv<T>::type, Keys...>(
547  
                std::forward<T>(t));
547  
                std::forward<T>(t));
548  
    }
548  
    }
549  

549  

550  
    /** Return an existing object or create a new one
550  
    /** Return an existing object or create a new one
551  

551  

552  
        If an object of the exact type `T` already exists in the container,
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
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
554  
        type `T` is default-constructed in the container, and a reference
555  
        to the newly created object is returned. This function ignores
555  
        to the newly created object is returned. This function ignores
556  
        nested key types and cannot be used to specify additional keys.
556  
        nested key types and cannot be used to specify additional keys.
557  

557  

558  
        @par Constraints
558  
        @par Constraints
559  
        `T` must be default-constructible.
559  
        `T` must be default-constructible.
560  

560  

561  
        @par Exception Safety
561  
        @par Exception Safety
562  
        Strong guarantee.
562  
        Strong guarantee.
563  

563  

564  
        @par Thread Safety
564  
        @par Thread Safety
565  
        Not thread-safe.
565  
        Not thread-safe.
566  

566  

567  
        @tparam T The type of object to retrieve or create.
567  
        @tparam T The type of object to retrieve or create.
568  
        @return A reference to the stored object.
568  
        @return A reference to the stored object.
569  
    */
569  
    */
570  
    template<class T>
570  
    template<class T>
571  
    T& use()
571  
    T& use()
572  
    {
572  
    {
573  
        // T must be default constructible
573  
        // T must be default constructible
574  
        BOOST_CORE_STATIC_ASSERT(
574  
        BOOST_CORE_STATIC_ASSERT(
575  
            std::is_default_constructible<T>::value);
575  
            std::is_default_constructible<T>::value);
576  
        if(auto t = find<T>())
576  
        if(auto t = find<T>())
577  
            return *t;
577  
            return *t;
578  
        return emplace<T>();
578  
        return emplace<T>();
579  
    }
579  
    }
580  

580  

581  
protected:
581  
protected:
582  
    struct any;
582  
    struct any;
583  
    class elements;
583  
    class elements;
584  

584  

585  
    /** Remove and destroy all objects in the container.
585  
    /** Remove and destroy all objects in the container.
586  

586  

587  
        All stored objects are destroyed in the reverse order
587  
        All stored objects are destroyed in the reverse order
588  
        of construction. The container is left empty.
588  
        of construction. The container is left empty.
589  
    */
589  
    */
590  
    BOOST_HTTP_DECL
590  
    BOOST_HTTP_DECL
591  
    void
591  
    void
592  
    clear() noexcept;
592  
    clear() noexcept;
593  

593  

594  
    /** Return a range of all stored elements
594  
    /** Return a range of all stored elements
595  
        @par Thread Safety
595  
        @par Thread Safety
596  
        `const` member function calls are thread-safe.
596  
        `const` member function calls are thread-safe.
597  
        Calls to non-`const` member functions must not run concurrently
597  
        Calls to non-`const` member functions must not run concurrently
598  
        with other member functions on the same object.
598  
        with other member functions on the same object.
599  
        @return An object representing the range of stored elements.
599  
        @return An object representing the range of stored elements.
600  
    */
600  
    */
601  
    BOOST_HTTP_DECL
601  
    BOOST_HTTP_DECL
602  
    elements
602  
    elements
603  
    get_elements() noexcept;
603  
    get_elements() noexcept;
604  

604  

605  
private:
605  
private:
606  
    template<class T, class = void>
606  
    template<class T, class = void>
607  
    struct has_start : std::false_type {};
607  
    struct has_start : std::false_type {};
608  

608  

609  
    template<class T>
609  
    template<class T>
610  
    struct has_start<T, typename std::enable_if<
610  
    struct has_start<T, typename std::enable_if<
611  
        std::is_same<decltype(std::declval<T>().start()),
611  
        std::is_same<decltype(std::declval<T>().start()),
612  
            void>::value>::type> : std::true_type {};
612  
            void>::value>::type> : std::true_type {};
613  

613  

614  
    template<class T, class = void>
614  
    template<class T, class = void>
615  
    struct has_stop : std::false_type {};
615  
    struct has_stop : std::false_type {};
616  

616  

617  
    template<class T>
617  
    template<class T>
618  
    struct has_stop<T, typename std::enable_if<
618  
    struct has_stop<T, typename std::enable_if<
619  
        std::is_same<decltype(std::declval<T>().stop()),
619  
        std::is_same<decltype(std::declval<T>().stop()),
620  
            void>::value>::type> : std::true_type {};
620  
            void>::value>::type> : std::true_type {};
621  

621  

622  
    struct key
622  
    struct key
623  
    {
623  
    {
624  
        detail::typeindex ti =
624  
        detail::typeindex ti =
625  
            detail::typeindex(BOOST_CORE_TYPEID(void));
625  
            detail::typeindex(BOOST_CORE_TYPEID(void));
626  
        void* p = nullptr;
626  
        void* p = nullptr;
627  

627  

628  
        key() = default;
628  
        key() = default;
629  
        key(detail::typeindex const& ti_,
629  
        key(detail::typeindex const& ti_,
630  
            void* p_) noexcept : ti(ti_) , p(p_) {}
630  
            void* p_) noexcept : ti(ti_) , p(p_) {}
631  
    };
631  
    };
632  

632  

633  
    template<class T, class... Key>
633  
    template<class T, class... Key>
634  
    struct keyset;
634  
    struct keyset;
635  

635  

636  
    template<class T>
636  
    template<class T>
637  
    struct keyset<T>
637  
    struct keyset<T>
638  
    {
638  
    {
639  
        static constexpr std::size_t N = 1;
639  
        static constexpr std::size_t N = 1;
640  
        key kn[1];
640  
        key kn[1];
641  

641  

642  
        explicit keyset(T& t) noexcept
642  
        explicit keyset(T& t) noexcept
643  
            : kn{ key(detail::typeindex(BOOST_CORE_TYPEID(T)), &t) }
643  
            : kn{ key(detail::typeindex(BOOST_CORE_TYPEID(T)), &t) }
644  
        {
644  
        {
645  
        }
645  
        }
646  
    };
646  
    };
647  

647  

648  
    template<class T, class... Keys>
648  
    template<class T, class... Keys>
649  
    struct keyset
649  
    struct keyset
650  
    {
650  
    {
651  
        static constexpr std::size_t N = 1 + sizeof...(Keys);
651  
        static constexpr std::size_t N = 1 + sizeof...(Keys);
652  
        key kn[N + 1];
652  
        key kn[N + 1];
653  

653  

654  
        explicit keyset(T& t) noexcept
654  
        explicit keyset(T& t) noexcept
655  
            : kn{
655  
            : kn{
656  
                key(detail::typeindex(BOOST_CORE_TYPEID(T)),
656  
                key(detail::typeindex(BOOST_CORE_TYPEID(T)),
657  
                    std::addressof(t)),
657  
                    std::addressof(t)),
658  
                key(detail::typeindex(BOOST_CORE_TYPEID(Keys)),
658  
                key(detail::typeindex(BOOST_CORE_TYPEID(Keys)),
659  
                    &static_cast<Keys&>(t))..., }
659  
                    &static_cast<Keys&>(t))..., }
660  
        {
660  
        {
661  
        }
661  
        }
662  
    };
662  
    };
663  

663  

664  
    template<class T> struct any_impl;
664  
    template<class T> struct any_impl;
665  

665  

666  
    using any_ptr = std::unique_ptr<any>;
666  
    using any_ptr = std::unique_ptr<any>;
667  

667  

668  
    template<class T, class... Args>
668  
    template<class T, class... Args>
669  
    auto
669  
    auto
670  
    make_any(Args&&... args) ->
670  
    make_any(Args&&... args) ->
671  
        std::unique_ptr<any_impl<T>>
671  
        std::unique_ptr<any_impl<T>>
672  
    {
672  
    {
673  
        return std::unique_ptr<any_impl<T>>(new
673  
        return std::unique_ptr<any_impl<T>>(new
674  
            any_impl<T>(std::forward<Args>(args)...));
674  
            any_impl<T>(std::forward<Args>(args)...));
675  
    }
675  
    }
676  

676  

677  
    void destroy() noexcept;
677  
    void destroy() noexcept;
678  
    BOOST_HTTP_DECL any& get(std::size_t i);
678  
    BOOST_HTTP_DECL any& get(std::size_t i);
679  
    BOOST_HTTP_DECL void* find(
679  
    BOOST_HTTP_DECL void* find(
680  
        core::typeinfo const& ti) const noexcept;
680  
        core::typeinfo const& ti) const noexcept;
681  
    BOOST_HTTP_DECL void* insert_impl(any_ptr,
681  
    BOOST_HTTP_DECL void* insert_impl(any_ptr,
682  
        key const* = nullptr, std::size_t = 0);
682  
        key const* = nullptr, std::size_t = 0);
683  

683  

684  
    std::vector<any_ptr> v_;
684  
    std::vector<any_ptr> v_;
685  
    std::unordered_map<
685  
    std::unordered_map<
686  
        detail::typeindex, void*> m_;
686  
        detail::typeindex, void*> m_;
687  
};
687  
};
688  

688  

689  
//------------------------------------------------
689  
//------------------------------------------------
690  

690  

691  
struct BOOST_HTTP_DECL
691  
struct BOOST_HTTP_DECL
692  
    polystore::any
692  
    polystore::any
693  
{
693  
{
694  
    virtual ~any() = default;
694  
    virtual ~any() = default;
695  
    virtual void start() = 0;
695  
    virtual void start() = 0;
696  
    virtual void stop() = 0;
696  
    virtual void stop() = 0;
697  
private:
697  
private:
698  
    friend class polystore;
698  
    friend class polystore;
699  
    virtual void* get() noexcept = 0;
699  
    virtual void* get() noexcept = 0;
700  
};
700  
};
701  

701  

702  
//------------------------------------------------
702  
//------------------------------------------------
703  

703  

704  
class polystore::elements
704  
class polystore::elements
705  
{
705  
{
706  
public:
706  
public:
707  
    std::size_t size() const noexcept
707  
    std::size_t size() const noexcept
708  
    {
708  
    {
709  
        return n_;
709  
        return n_;
710  
    }
710  
    }
711  

711  

712  
    any& operator[](
712  
    any& operator[](
713  
        std::size_t i) noexcept
713  
        std::size_t i) noexcept
714  
    {
714  
    {
715  
        return ps_.get(i);
715  
        return ps_.get(i);
716  
    }
716  
    }
717  

717  

718  
private:
718  
private:
719  
    friend class polystore;
719  
    friend class polystore;
720  

720  

721  
    elements(
721  
    elements(
722  
        std::size_t n,
722  
        std::size_t n,
723  
        polystore& ps)
723  
        polystore& ps)
724  
        : n_(n)
724  
        : n_(n)
725  
        , ps_(ps)
725  
        , ps_(ps)
726  
    {
726  
    {
727  
    }
727  
    }
728  

728  

729  
    std::size_t n_;
729  
    std::size_t n_;
730  
    polystore& ps_;
730  
    polystore& ps_;
731  
};
731  
};
732  

732  

733  
//------------------------------------------------
733  
//------------------------------------------------
734  

734  

735  
template<class T>
735  
template<class T>
736  
struct polystore::any_impl : polystore::any
736  
struct polystore::any_impl : polystore::any
737  
{
737  
{
738  
    T t;
738  
    T t;
739  

739  

740  
    template<class... Args>
740  
    template<class... Args>
741  
    explicit any_impl(Args&&... args)
741  
    explicit any_impl(Args&&... args)
742  
        : t(std::forward<Args>(args)...)
742  
        : t(std::forward<Args>(args)...)
743  
    {
743  
    {
744  
    }
744  
    }
745  
    void* get() noexcept override { return std::addressof(t); }
745  
    void* get() noexcept override { return std::addressof(t); }
746  
    void start() override { do_start(has_start<T>{}); }
746  
    void start() override { do_start(has_start<T>{}); }
747  
    void stop() override { do_stop(has_stop<T>{}); }
747  
    void stop() override { do_stop(has_stop<T>{}); }
748  
    void do_start(std::true_type) { t.start(); }
748  
    void do_start(std::true_type) { t.start(); }
749  
    void do_start(std::false_type) {}
749  
    void do_start(std::false_type) {}
750  
    void do_stop(std::true_type) { t.stop(); }
750  
    void do_stop(std::true_type) { t.stop(); }
751  
    void do_stop(std::false_type) {}
751  
    void do_stop(std::false_type) {}
752  
};
752  
};
753  

753  

754  
//------------------------------------------------
754  
//------------------------------------------------
755  

755  

756  
namespace detail {
756  
namespace detail {
757  

757  

758  
template<class T> struct arg;
758  
template<class T> struct arg;
759  
template<class T> struct arg<T const&> : arg<T&> {};
759  
template<class T> struct arg<T const&> : arg<T&> {};
760  
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&>
761  
template<class T> struct arg<T&>
762  
{
762  
{
763  
    T& operator()(polystore& ps) const
763  
    T& operator()(polystore& ps) const
764  
    {
764  
    {
765  
        return ps.get<T>();
765  
        return ps.get<T>();
766  
    }
766  
    }
767  
};
767  
};
768  
template<class T> struct arg<T*>
768  
template<class T> struct arg<T*>
769  
{
769  
{
770  
    T* operator()(polystore& ps) const
770  
    T* operator()(polystore& ps) const
771  
    {
771  
    {
772  
        return ps.find<T>();
772  
        return ps.find<T>();
773  
    }
773  
    }
774  
};
774  
};
775  

775  

776  
template<class F, class... Args>
776  
template<class F, class... Args>
777  
auto
777  
auto
778  
invoke(polystore& ps, F&& f,
778  
invoke(polystore& ps, F&& f,
779  
    type_list<Args...> const&) ->
779  
    type_list<Args...> const&) ->
780  
        typename call_traits<std::decay_t<F>>::return_type
780  
        typename call_traits<std::decay_t<F>>::return_type
781  
{
781  
{
782  
    return std::forward<F>(f)(arg<Args>()(ps)...);
782  
    return std::forward<F>(f)(arg<Args>()(ps)...);
783  
}
783  
}
784  

784  

785  
} // detail
785  
} // detail
786  

786  

787  
/** Invoke a callable, injecting stored objects as arguments
787  
/** Invoke a callable, injecting stored objects as arguments
788  
    The callable is invoked with zero or more arguments.
788  
    The callable is invoked with zero or more arguments.
789  
    For each argument type, if an object of that type
789  
    For each argument type, if an object of that type
790  
    (or key type) is stored in the container, a reference
790  
    (or key type) is stored in the container, a reference
791  
    to that object is passed to the callable.
791  
    to that object is passed to the callable.
792  
    @par Example
792  
    @par Example
793  
    @code
793  
    @code
794  
    struct A { int i = 1; };
794  
    struct A { int i = 1; };
795  
    polystore ps;
795  
    polystore ps;
796  
    ps.emplace<A>();
796  
    ps.emplace<A>();
797  
    ps.invoke([](A& a){ assert(a.i == 1; });
797  
    ps.invoke([](A& a){ assert(a.i == 1; });
798  
    @endcode
798  
    @endcode
799  
    @param f The callable to invoke.
799  
    @param f The callable to invoke.
800  
    @return The result of the invocation.
800  
    @return The result of the invocation.
801  
    @throws std::bad_typeid if any reference argument
801  
    @throws std::bad_typeid if any reference argument
802  
        types are not found in the container.
802  
        types are not found in the container.
803  
*/
803  
*/
804  
template<class F>
804  
template<class F>
805  
auto
805  
auto
806  
invoke(polystore& ps, F&& f) ->
806  
invoke(polystore& ps, F&& f) ->
807  
    typename detail::call_traits<std::decay_t<F>>::return_type
807  
    typename detail::call_traits<std::decay_t<F>>::return_type
808  
{
808  
{
809  
    return detail::invoke(ps, std::forward<F>(f),
809  
    return detail::invoke(ps, std::forward<F>(f),
810  
        typename detail::call_traits<std::decay_t<F>>::arg_types{});
810  
        typename detail::call_traits<std::decay_t<F>>::arg_types{});
811  
}
811  
}
812  

812  

813  
} // http
813  
} // http
814  
} // boost
814  
} // boost
815  

815  

816  
#endif
816  
#endif