include/boost/capy/ex/execution_context.hpp

100.0% Lines (52/0/52) 89.1% List of functions (49/0/55)
execution_context.hpp
f(x) Functions (55)
Function Calls Lines Blocks
boost::capy::execution_context::service::~service() :124 54x 100.0% 100.0% boost::capy::execution_context::service::service() :128 54x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::base_service>() const :201 2x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::derived_service>() const :201 1x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::keyed_a>() const :201 1x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::keyed_b>() const :201 1x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::multi_arg_service>() const :201 1x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::nested_service>() const :201 1x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::simple_service>() const :201 6x 100.0% 100.0% bool boost::capy::execution_context::has_service<boost::capy::(anonymous namespace)::test_service>() const :201 3x 100.0% 100.0% (anonymous namespace)::ex_1::file_service* boost::capy::execution_context::find_service<(anonymous namespace)::ex_1::file_service>() const :216 0 0.0% 0.0% (anonymous namespace)::ex_1::posix_file_service* boost::capy::execution_context::find_service<(anonymous namespace)::ex_1::posix_file_service>() const :216 0 0.0% 0.0% boost::capy::(anonymous namespace)::base_service* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::base_service>() const :216 3x 100.0% 100.0% boost::capy::(anonymous namespace)::derived_service* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::derived_service>() const :216 2x 100.0% 100.0% boost::capy::(anonymous namespace)::keyed_a* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::keyed_a>() const :216 1x 100.0% 100.0% boost::capy::(anonymous namespace)::keyed_b* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::keyed_b>() const :216 1x 100.0% 100.0% boost::capy::(anonymous namespace)::multi_arg_service* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::multi_arg_service>() const :216 2x 100.0% 100.0% boost::capy::(anonymous namespace)::nested_service* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::nested_service>() const :216 1x 100.0% 100.0% boost::capy::(anonymous namespace)::simple_service* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::simple_service>() const :216 10x 100.0% 100.0% boost::capy::(anonymous namespace)::test_service* boost::capy::execution_context::find_service<boost::capy::(anonymous namespace)::test_service>() const :216 5x 100.0% 100.0% boost::capy::(anonymous namespace)::derived_service& boost::capy::execution_context::use_service<boost::capy::(anonymous namespace)::derived_service>() :244 1x 100.0% 100.0% boost::capy::(anonymous namespace)::nested_service& boost::capy::execution_context::use_service<boost::capy::(anonymous namespace)::nested_service>() :244 1x 100.0% 100.0% boost::capy::(anonymous namespace)::simple_service& boost::capy::execution_context::use_service<boost::capy::(anonymous namespace)::simple_service>() :244 13x 100.0% 100.0% boost::capy::(anonymous namespace)::test_service& boost::capy::execution_context::use_service<boost::capy::(anonymous namespace)::test_service>() :244 4x 100.0% 100.0% boost::capy::detail::strand_service_impl& boost::capy::execution_context::use_service<boost::capy::detail::strand_service_impl>() :244 11446x 100.0% 100.0% boost::capy::execution_context::use_service<boost::capy::(anonymous namespace)::test_service>()::impl::impl() :253 4x 100.0% 100.0% boost::capy::execution_context::use_service<boost::capy::detail::strand_service_impl>()::impl::impl() :253 11446x 100.0% 100.0% boost::capy::execution_context::use_service<boost::capy::(anonymous namespace)::test_service>()::impl::create(boost::capy::execution_context&) :262 2x 100.0% 100.0% boost::capy::execution_context::use_service<boost::capy::detail::strand_service_impl>()::impl::create(boost::capy::execution_context&) :262 34x 100.0% 71.0% (anonymous namespace)::ex_1::posix_file_service& boost::capy::execution_context::make_service<(anonymous namespace)::ex_1::posix_file_service>() :300 0 0.0% 0.0% boost::capy::(anonymous namespace)::derived_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::derived_service, int>(int&&) :300 1x 100.0% 100.0% boost::capy::(anonymous namespace)::keyed_a& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::keyed_a>() :300 1x 100.0% 50.0% boost::capy::(anonymous namespace)::keyed_b& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::keyed_b>() :300 1x 100.0% 100.0% boost::capy::(anonymous namespace)::multi_arg_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::multi_arg_service, int, char const (&) [5], double>(int&&, char const (&) [5], double&&) :300 1x 100.0% 100.0% boost::capy::(anonymous namespace)::multi_arg_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::multi_arg_service, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double>(int&&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&, double&&) :300 1x 100.0% 100.0% boost::capy::(anonymous namespace)::other_derived_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::other_derived_service>() :300 1x 100.0% 50.0% boost::capy::(anonymous namespace)::simple_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::simple_service, int>(int&&) :300 3x 100.0% 100.0% boost::capy::(anonymous namespace)::test_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::test_service, int>(int&&) :300 2x 100.0% 100.0% boost::capy::(anonymous namespace)::tracking_service& boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::tracking_service, bool&>(bool&) :300 1x 100.0% 100.0% boost::capy::execution_context::make_service<(anonymous namespace)::ex_1::posix_file_service>()::impl::impl() :315 0 0.0% 0.0% boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::test_service, int>(int&&)::impl::impl(int&&) :315 2x 100.0% 100.0% boost::capy::execution_context::make_service<(anonymous namespace)::ex_1::posix_file_service>()::impl::create(boost::capy::execution_context&) :325 0 0.0% 0.0% boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::test_service, int>(int&&)::impl::create(boost::capy::execution_context&) :325 1x 100.0% 100.0% auto boost::capy::execution_context::make_service<(anonymous namespace)::ex_1::posix_file_service>()::impl::create(boost::capy::execution_context&)::{lambda((auto:1&&)...)#1}::operator()<>() const :327 0 0.0% 0.0% auto boost::capy::execution_context::make_service<boost::capy::(anonymous namespace)::test_service, int>(int&&)::impl::create(boost::capy::execution_context&)::{lambda((auto:1&&)...)#1}::operator()<int>(int&&) const :327 1x 100.0% 100.0% boost::capy::execution_context::get_frame_allocator() const :350 1933x 100.0% 100.0% boost::capy::execution_context::set_frame_allocator(std::pmr::memory_resource*) :370 1x 100.0% 100.0% void boost::capy::execution_context::set_frame_allocator<std::allocator<int> >(std::allocator<int> const&) :397 1x 100.0% 100.0% void boost::capy::execution_context::set_frame_allocator<std::allocator<void> >(std::allocator<void> const&) :397 397x 100.0% 100.0% boost::capy::execution_context_test::testTarget()::other_context const* boost::capy::execution_context::target<boost::capy::execution_context_test::testTarget()::other_context>() const :426 1x 75.0% 80.0% boost::capy::test_io_context const* boost::capy::execution_context::target<boost::capy::test_io_context>() const :426 1x 75.0% 80.0% boost::capy::execution_context_test::testTarget()::other_context* boost::capy::execution_context::target<boost::capy::execution_context_test::testTarget()::other_context>() :435 1x 75.0% 80.0% boost::capy::test_io_context* boost::capy::execution_context::target<boost::capy::test_io_context>() :435 1x 75.0% 80.0% boost::capy::execution_context::factory::factory(std::type_info const&, std::type_info const&) :501 11477x 100.0% 100.0% boost::capy::execution_context::execution_context<boost::capy::test_io_context>(boost::capy::test_io_context*) :530 29x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/capy
9 //
10
11 #ifndef BOOST_CAPY_EXECUTION_CONTEXT_HPP
12 #define BOOST_CAPY_EXECUTION_CONTEXT_HPP
13
14 #include <boost/capy/detail/config.hpp>
15 #include <boost/capy/detail/frame_memory_resource.hpp>
16 #include <boost/capy/detail/type_id.hpp>
17 #include <boost/capy/concept/executor.hpp>
18 #include <concepts>
19 #include <memory>
20 #include <memory_resource>
21 #include <mutex>
22 #include <tuple>
23 #include <type_traits>
24 #include <utility>
25
26 namespace boost {
27 namespace capy {
28
29 /** Registers, looks up, and shuts down `service` objects owned by a derived context.
30
31 An execution context represents a place where function objects are
32 executed. It provides a service registry where polymorphic services
33 can be stored and retrieved by type. Each service type may be stored
34 at most once. Services may specify a nested `key_type` to enable
35 lookup by a base class type.
36
37 Derived classes such as `io_context` extend this to provide
38 execution facilities like event loops and thread pools. Derived
39 class destructors must call `shutdown()` and `destroy()` to ensure
40 proper service cleanup before member destruction.
41
42 @par Service Lifecycle
43 Services are created on first use via `use_service()` or explicitly
44 via `make_service()`. During destruction, `shutdown()` is called on
45 each service in reverse order of creation, then `destroy()` deletes
46 them. Both functions are idempotent.
47
48 @par Thread Safety
49 Service registration and lookup functions are thread-safe.
50 The `shutdown()` and `destroy()` functions are not thread-safe
51 and must only be called during destruction.
52
53 @par Example
54 @par !example example
55
56
57 @see service, ExecutionContext
58 */
59 class BOOST_CAPY_DECL
60 execution_context
61 {
62 detail::type_info const* ti_ = nullptr;
63
64 template<class T, class = void>
65 struct get_key : std::false_type
66 {};
67
68 template<class T>
69 struct get_key<T, std::void_t<typename T::key_type>> : std::true_type
70 {
71 using type = typename T::key_type;
72 };
73 protected:
74 /** Construct from the most-derived context type.
75
76 Records the dynamic type of the context so that
77 @ref target can later downcast `this` to the
78 requested derived type. Derived classes must pass
79 `this` typed as the most-derived type (i.e. invoke
80 this constructor from the most-derived class with
81 `this` of that type). Passing a pointer typed as a
82 base class records the wrong type and causes
83 `target<Derived>()` to return `nullptr`.
84
85 @tparam Derived The most-derived context type.
86
87 @param self `this`, typed as the most-derived context type.
88 Only its type is recorded; the pointer is not stored.
89 */
90 template< typename Derived >
91 explicit execution_context( Derived* self ) noexcept;
92
93 public:
94 //------------------------------------------------
95
96 /** Gives a derived service a `shutdown()` hook, run when its owning `execution_context` is destroyed.
97
98 Services provide extensible functionality to an execution context.
99 Each service type can be registered at most once. Services are
100 created via `use_service()` or `make_service()` and are owned by
101 the execution context for their lifetime.
102
103 Derived classes must implement the pure virtual `shutdown()` member
104 function, which is called when the owning execution context is
105 being destroyed. The `shutdown()` function should release resources
106 and cancel outstanding operations without blocking.
107
108 @par Deriving from service
109 @li Implement `shutdown()` to perform cleanup.
110 @li Accept `execution_context&` as the first constructor parameter.
111 @li Optionally define `key_type` to enable base-class lookup.
112
113 @par Example
114 @par !example example
115
116
117 @see execution_context
118 */
119 class BOOST_CAPY_DECL
120 service
121 {
122 public:
123 /// Destructor.
124 54x virtual ~service() = default;
125
126 protected:
127 /// Construct a service. Only derived classes may do so.
128 54x service() = default;
129
130 /** Called when the owning execution context shuts down.
131
132 Implementations should release resources and cancel any
133 outstanding asynchronous operations. This function must
134 not block and must not throw exceptions. Services are
135 shut down in reverse order of creation.
136
137 @par Exception Safety
138 No-throw guarantee.
139 */
140 virtual void shutdown() = 0;
141
142 private:
143 friend class execution_context;
144
145 service* next_ = nullptr;
146
147 // warning C4251: 'std::type_index' needs to have dll-interface
148 BOOST_CAPY_MSVC_WARNING_PUSH
149 BOOST_CAPY_MSVC_WARNING_DISABLE(4251)
150 detail::type_index t0_{detail::type_id<void>()};
151 detail::type_index t1_{detail::type_id<void>()};
152 BOOST_CAPY_MSVC_WARNING_POP
153 };
154
155 //------------------------------------------------
156
157 /** Copy construction is disabled; a context owns its services.
158
159 @param other The context that would be copied.
160 */
161 execution_context(execution_context const& other) = delete;
162
163 /** Copy assignment is disabled; a context owns its services.
164
165 @param other The context that would be assigned from.
166
167 @return A reference to `*this`.
168 */
169 execution_context& operator=(execution_context const& other) = delete;
170
171 /** Destructor.
172
173 Calls `shutdown()` then `destroy()` to clean up all services.
174
175 @par Effects
176 All services are shut down and deleted in reverse order
177 of creation.
178
179 @par Exception Safety
180 No-throw guarantee.
181 */
182 ~execution_context();
183
184 /** Construct a default instance.
185
186 @par Exception Safety
187 Strong guarantee.
188 */
189 execution_context();
190
191 /** Return true if a service of type T exists.
192
193 @par Thread Safety
194 Thread-safe.
195
196 @tparam T The type of service to check.
197
198 @return `true` if the service exists.
199 */
200 template<class T>
201 16x bool has_service() const noexcept
202 {
203 16x return find_service<T>() != nullptr;
204 }
205
206 /** Return a pointer to the service of type T, or nullptr.
207
208 @par Thread Safety
209 Thread-safe.
210
211 @tparam T The type of service to find.
212
213 @return A pointer to the service, or `nullptr` if not present.
214 */
215 template<class T>
216 25x T* find_service() const noexcept
217 {
218 25x std::lock_guard<std::mutex> lock(mutex_);
219 25x return static_cast<T*>(find_impl(detail::type_id<T>()));
220 25x }
221
222 /** Return a reference to the service of type T, creating it if needed.
223
224 If no service of type T exists, one is created by calling
225 `T(execution_context&)`. If T has a nested `key_type`, the
226 service is also indexed under that type.
227
228 @par Constraints
229 @li `T` must derive from `service`.
230 @li `T` must be constructible from `execution_context&`.
231
232 @par Exception Safety
233 Strong guarantee. If service creation throws, the container
234 is unchanged.
235
236 @par Thread Safety
237 Thread-safe.
238
239 @tparam T The type of service to retrieve or create.
240
241 @return A reference to the service.
242 */
243 template<class T>
244 11465x T& use_service()
245 {
246 static_assert(std::is_base_of<service, T>::value,
247 "T must derive from service");
248 static_assert(std::is_constructible<T, execution_context&>::value,
249 "T must be constructible from execution_context&");
250
251 struct impl : factory
252 {
253 11450x impl()
254 : factory(
255 detail::type_id<T>(),
256 get_key<T>::value
257 ? detail::type_id<typename get_key<T>::type>()
258 11450x : detail::type_id<T>())
259 {
260 11450x }
261
262 36x service* create(execution_context& ctx) override
263 {
264 36x return new T(ctx);
265 }
266 };
267
268 11465x impl f;
269 22930x return static_cast<T&>(use_service_impl(f));
270 }
271
272 /** Construct and add a service.
273
274 A new service of type T is constructed using the provided
275 arguments and added to the container. If T has a nested
276 `key_type`, the service is also indexed under that type.
277
278 @par Constraints
279 @li `T` must derive from `service`.
280 @li `T` must be constructible from `execution_context&, Args...`.
281 @li If `T::key_type` exists, `T&` must be convertible to `key_type&`.
282
283 @par Exception Safety
284 Strong guarantee. If service creation throws, the container
285 is unchanged.
286
287 @par Thread Safety
288 Thread-safe.
289
290 @throws std::invalid_argument if a service of the same type
291 or `key_type` already exists.
292
293 @tparam T The type of service to create.
294
295 @param args Arguments forwarded to the constructor of T.
296
297 @return A reference to the created service.
298 */
299 template<class T, class... Args>
300 12x T& make_service(Args&&... args)
301 {
302 static_assert(std::is_base_of<service, T>::value,
303 "T must derive from service");
304 if constexpr(get_key<T>::value)
305 {
306 static_assert(
307 std::is_convertible<T&, typename get_key<T>::type&>::value,
308 "T& must be convertible to key_type&");
309 }
310
311 struct impl : factory
312 {
313 std::tuple<Args&&...> args_;
314
315 2x explicit impl(Args&&... a)
316 : factory(
317 detail::type_id<T>(),
318 get_key<T>::value
319 ? detail::type_id<typename get_key<T>::type>()
320 : detail::type_id<T>())
321 2x , args_(std::forward<Args>(a)...)
322 {
323 2x }
324
325 1x service* create(execution_context& ctx) override
326 {
327 2x return std::apply([&ctx](auto&&... a) {
328 1x return new T(ctx, std::forward<decltype(a)>(a)...);
329 3x }, std::move(args_));
330 }
331 };
332
333 12x impl f(std::forward<Args>(args)...);
334 20x return static_cast<T&>(make_service_impl(f));
335 }
336
337 //------------------------------------------------
338
339 /** Return the memory resource used for coroutine frame allocation.
340
341 The returned pointer is valid for the lifetime of this context.
342 By default, this returns a pointer to the recycling memory
343 resource which pools frame allocations for reuse.
344
345 @return Pointer to the frame allocator.
346
347 @see set_frame_allocator
348 */
349 std::pmr::memory_resource*
350 1933x get_frame_allocator() const noexcept
351 {
352 1933x return frame_alloc_;
353 }
354
355 /** Set the memory resource used for coroutine frame allocation.
356
357 The caller is responsible for ensuring the memory resource
358 remains valid for the lifetime of all coroutines started
359 using this context's executor.
360
361 @par Thread Safety
362 Not thread-safe. Must not be called while any thread may
363 be referencing this execution context or its executor.
364
365 @param mr Pointer to the memory resource.
366
367 @see get_frame_allocator
368 */
369 void
370 1x set_frame_allocator(std::pmr::memory_resource* mr) noexcept
371 {
372 1x owned_.reset();
373 1x frame_alloc_ = mr;
374 1x }
375
376 /** Set the frame allocator from a standard Allocator.
377
378 The allocator is wrapped in an internal memory resource
379 adapter owned by this context. The wrapper remains valid
380 for the lifetime of this context or until a subsequent
381 call to set_frame_allocator.
382
383 @par Thread Safety
384 Not thread-safe. Must not be called while any thread may
385 be referencing this execution context or its executor.
386
387 @tparam Allocator The allocator type satisfying the
388 standard Allocator requirements.
389
390 @param a The allocator to use.
391
392 @see get_frame_allocator
393 */
394 template<class Allocator>
395 requires (!std::is_pointer_v<Allocator>)
396 void
397 398x set_frame_allocator(Allocator const& a)
398 {
399 static_assert(
400 requires { typename std::allocator_traits<Allocator>::value_type; },
401 "Allocator must satisfy allocator requirements");
402 static_assert(
403 std::is_copy_constructible_v<Allocator>,
404 "Allocator must be copy constructible");
405
406 398x auto p = std::make_shared<
407 detail::frame_memory_resource<Allocator>>(a);
408 398x frame_alloc_ = p.get();
409 398x owned_ = std::move(p);
410 398x }
411
412 /** Return a pointer to this context if it matches the
413 requested type.
414
415 Performs a type check and downcasts `this` when the
416 types match, or returns `nullptr` otherwise. Analogous
417 to `std::any_cast< ExecutionContext >( &a )`.
418
419 @tparam ExecutionContext The derived context type to
420 retrieve.
421
422 @return A pointer to this context as the requested
423 type, or `nullptr` if the type does not match.
424 */
425 template< typename ExecutionContext >
426 2x const ExecutionContext* target() const
427 {
428 2x if ( ti_ && *ti_ == detail::type_id< ExecutionContext >() )
429 1x return static_cast< ExecutionContext const* >( this );
430 1x return nullptr;
431 }
432
433 /// @copydoc target() const
434 template< typename ExecutionContext >
435 2x ExecutionContext* target()
436 {
437 2x if ( ti_ && *ti_ == detail::type_id< ExecutionContext >() )
438 1x return static_cast< ExecutionContext* >( this );
439 1x return nullptr;
440 }
441
442 protected:
443 /** Shut down all services.
444
445 Calls `shutdown()` on each service in reverse order of creation.
446 After this call, services remain allocated but are in a stopped
447 state. Derived classes should call this in their destructor
448 before any members are destroyed. This function is idempotent;
449 subsequent calls have no effect.
450
451 @par Effects
452 Each service's `shutdown()` member function is invoked once.
453
454 @par Postconditions
455 @li All services are in a stopped state.
456
457 @par Exception Safety
458 No-throw guarantee.
459
460 @par Thread Safety
461 Not thread-safe. Must not be called concurrently with other
462 operations on this execution_context.
463 */
464 void shutdown() noexcept;
465
466 /** Destroy all services.
467
468 Deletes all services in reverse order of creation. Derived
469 classes should call this as the final step of destruction.
470 This function is idempotent; subsequent calls have no effect.
471
472 @par Preconditions
473 @li `shutdown()` was called.
474
475 @par Effects
476 All services are deleted and removed from the container.
477
478 @par Postconditions
479 @li The service container is empty.
480
481 @par Exception Safety
482 No-throw guarantee.
483
484 @par Thread Safety
485 Not thread-safe. Must not be called concurrently with other
486 operations on this execution_context.
487 */
488 void destroy() noexcept;
489
490 private:
491 struct BOOST_CAPY_DECL
492 factory
493 {
494 // warning C4251: 'std::type_index' needs to have dll-interface
495 BOOST_CAPY_MSVC_WARNING_PUSH
496 BOOST_CAPY_MSVC_WARNING_DISABLE(4251)
497 detail::type_index t0;
498 detail::type_index t1;
499 BOOST_CAPY_MSVC_WARNING_POP
500
501 11477x factory(
502 detail::type_info const& t0_,
503 detail::type_info const& t1_)
504 11477x : t0(t0_), t1(t1_)
505 {
506 11477x }
507
508 virtual service* create(execution_context&) = 0;
509
510 protected:
511 ~factory() = default;
512 };
513
514 service* find_impl(detail::type_index ti) const noexcept;
515 service& use_service_impl(factory& f);
516 service& make_service_impl(factory& f);
517
518 // warning C4251: std::mutex, std::shared_ptr need dll-interface
519 BOOST_CAPY_MSVC_WARNING_PUSH
520 BOOST_CAPY_MSVC_WARNING_DISABLE(4251)
521 mutable std::mutex mutex_;
522 std::shared_ptr<void> owned_;
523 BOOST_CAPY_MSVC_WARNING_POP
524 std::pmr::memory_resource* frame_alloc_ = nullptr;
525 service* head_ = nullptr;
526 bool shutdown_ = false;
527 };
528
529 template< typename Derived >
530 29x execution_context::
531 execution_context( Derived* ) noexcept
532 29x : execution_context()
533 {
534 29x ti_ = &detail::type_id< Derived >();
535 29x }
536
537 } // namespace capy
538 } // namespace boost
539
540 #endif
541