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