]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/experimental/executor
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / experimental / executor
CommitLineData
e5989e71
JW
1// <experimental/executor> -*- C++ -*-
2
a5544970 3// Copyright (C) 2015-2019 Free Software Foundation, Inc.
e5989e71
JW
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file experimental/executor
26 * This is a TS C++ Library header.
27 */
28
29#ifndef _GLIBCXX_EXPERIMENTAL_EXECUTOR
30#define _GLIBCXX_EXPERIMENTAL_EXECUTOR 1
31
32#pragma GCC system_header
33
34#if __cplusplus >= 201402L
35
36#include <algorithm>
82a0f2fd 37#include <condition_variable>
e5989e71
JW
38#include <functional>
39#include <future>
40#include <list>
e5989e71
JW
41#include <queue>
42#include <thread>
43#include <tuple>
44#include <unordered_map>
45#include <utility>
46#include <experimental/netfwd>
47#include <bits/unique_ptr.h>
48#include <experimental/bits/net.h>
49
50namespace std _GLIBCXX_VISIBILITY(default)
51{
a70a4be9 52_GLIBCXX_BEGIN_NAMESPACE_VERSION
e5989e71
JW
53namespace experimental
54{
55namespace net
56{
57inline namespace v1
58{
e5989e71
JW
59
60 /**
61 * @ingroup networking
62 * @{
63 */
64
65 /// Customization point for asynchronous operations.
66 template<typename _CompletionToken, typename _Signature, typename = void>
67 class async_result;
68
69 /// Convenience utility to help implement asynchronous operations.
70 template<typename _CompletionToken, typename _Signature>
71 class async_completion;
72
73 template<typename _Tp, typename _ProtoAlloc, typename = __void_t<>>
74 struct __associated_allocator_impl
75 {
76 using type = _ProtoAlloc;
77
78 static type
79 _S_get(const _Tp&, const _ProtoAlloc& __a) noexcept { return __a; }
80 };
81
82 template<typename _Tp, typename _ProtoAlloc>
83 struct __associated_allocator_impl<_Tp, _ProtoAlloc,
84 __void_t<typename _Tp::allocator_type>>
85 {
86 using type = typename _Tp::allocator_type;
87
88 static type
89 _S_get(const _Tp& __t, const _ProtoAlloc&) noexcept
90 { return __t.get_allocator(); }
91 };
92
93 /// Helper to associate an allocator with a type.
94 template<typename _Tp, typename _ProtoAllocator = allocator<void>>
95 struct associated_allocator
96 : __associated_allocator_impl<_Tp, _ProtoAllocator>
97 {
98 static auto
99 get(const _Tp& __t,
100 const _ProtoAllocator& __a = _ProtoAllocator()) noexcept
101 {
102 using _Impl = __associated_allocator_impl<_Tp, _ProtoAllocator>;
103 return _Impl::_S_get(__t, __a);
104 }
105 };
106
107 /// Alias template for associated_allocator.
108 template<typename _Tp, typename _ProtoAllocator = allocator<void>>
109 using associated_allocator_t
110 = typename associated_allocator<_Tp, _ProtoAllocator>::type;
111
112 // get_associated_allocator:
113
114 template<typename _Tp>
115 inline associated_allocator_t<_Tp>
116 get_associated_allocator(const _Tp& __t) noexcept
117 { return associated_allocator<_Tp>::get(__t); }
118
119 template<typename _Tp, typename _ProtoAllocator>
120 inline associated_allocator_t<_Tp, _ProtoAllocator>
121 get_associated_allocator(const _Tp& __t,
122 const _ProtoAllocator& __a) noexcept
123 { return associated_allocator<_Tp, _ProtoAllocator>::get(__t, __a); }
124
125 enum class fork_event { prepare, parent, child };
126
127 /// An extensible, type-safe, polymorphic set of services.
128 class execution_context;
129
130 class service_already_exists : public logic_error { };
131
132 template<typename _Tp> struct is_executor;
133
134 struct executor_arg_t { };
135
136 constexpr executor_arg_t executor_arg = executor_arg_t();
137
138 /// Trait for determining whether to construct an object with an executor.
139 template<typename _Tp, typename _Executor> struct uses_executor;
140
141 template<typename _Tp, typename _Executor, typename = __void_t<>>
142 struct __associated_executor_impl
143 {
144 using type = _Executor;
145
146 static type
147 _S_get(const _Tp&, const _Executor& __e) noexcept { return __e; }
148 };
149
150 template<typename _Tp, typename _Executor>
151 struct __associated_executor_impl<_Tp, _Executor,
152 __void_t<typename _Tp::executor_type>>
153 {
154 using type = typename _Tp::executor_type;
155
156 static type
157 _S_get(const _Tp& __t, const _Executor&) noexcept
158 { return __t.get_executor(); }
159 };
160
161 /// Helper to associate an executor with a type.
162 template<typename _Tp, typename _Executor = system_executor>
163 struct associated_executor
164 : __associated_executor_impl<_Tp, _Executor>
165 {
166 static auto
167 get(const _Tp& __t, const _Executor& __e = _Executor()) noexcept
168 { return __associated_executor_impl<_Tp, _Executor>::_S_get(__t, __e); }
169 };
170
171
172 template<typename _Tp, typename _Executor = system_executor>
173 using associated_executor_t
174 = typename associated_executor<_Tp, _Executor>::type;
175
176 template<typename _ExecutionContext>
177 using __is_exec_context
178 = is_convertible<_ExecutionContext&, execution_context&>;
179
180 template<typename _Tp>
181 using __executor_t = typename _Tp::executor_type;
182
183 // get_associated_executor:
184
185 template<typename _Tp>
186 inline associated_executor_t<_Tp>
187 get_associated_executor(const _Tp& __t) noexcept
188 { return associated_executor<_Tp>::get(__t); }
189
190 template<typename _Tp, typename _Executor>
191 inline
192 enable_if_t<is_executor<_Executor>::value,
193 associated_executor_t<_Tp, _Executor>>
194 get_associated_executor(const _Tp& __t, const _Executor& __ex)
195 { return associated_executor<_Tp, _Executor>::get(__t, __ex); }
196
197 template<typename _Tp, typename _ExecutionContext>
198 inline
199 enable_if_t<__is_exec_context<_ExecutionContext>::value,
200 associated_executor_t<_Tp, __executor_t<_ExecutionContext>>>
201 get_associated_executor(const _Tp& __t, _ExecutionContext& __ctx) noexcept
202 { return net::get_associated_executor(__t, __ctx.get_executor()); }
203
204
205 /// Helper to bind an executor to an object or function.
206 template<typename _Tp, typename _Executor>
207 class executor_binder;
208
209 template<typename _Tp, typename _Executor, typename _Signature>
210 class async_result<executor_binder<_Tp, _Executor>, _Signature>;
211
212 template<typename _Tp, typename _Executor, typename _ProtoAllocator>
213 struct associated_allocator<executor_binder<_Tp, _Executor>,
214 _ProtoAllocator>;
215
216 template<typename _Tp, typename _Executor, typename _Executor1>
217 struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>;
218
219 // bind_executor:
220
221 template<typename _Executor, typename _Tp>
222 inline
223 enable_if_t<is_executor<_Executor>::value,
224 executor_binder<decay_t<_Tp>, _Executor>>
225 bind_executor(const _Executor& __ex, _Tp&& __t)
226 { return { std::forward<_Tp>(__t), __ex }; }
227
228 template<typename _ExecutionContext, typename _Tp>
229 inline
230 enable_if_t<__is_exec_context<_ExecutionContext>::value,
231 executor_binder<decay_t<_Tp>, __executor_t<_ExecutionContext>>>
232 bind_executor(_ExecutionContext& __ctx, _Tp&& __t)
233 { return { __ctx.get_executor(), forward<_Tp>(__t) }; }
234
235
236 /// A scope-guard type to record when work is started and finished.
237 template<typename _Executor>
238 class executor_work_guard;
239
240 // make_work_guard:
241
242 template<typename _Executor>
243 inline
244 enable_if_t<is_executor<_Executor>::value, executor_work_guard<_Executor>>
245 make_work_guard(const _Executor& __ex)
246 { return executor_work_guard<_Executor>(__ex); }
247
248 template<typename _ExecutionContext>
249 inline
250 enable_if_t<__is_exec_context<_ExecutionContext>::value,
251 executor_work_guard<__executor_t<_ExecutionContext>>>
252 make_work_guard(_ExecutionContext& __ctx)
253 { return net::make_work_guard(__ctx.get_executor()); }
254
255 template<typename _Tp>
256 inline
257 enable_if_t<__not_<__or_<is_executor<_Tp>, __is_exec_context<_Tp>>>::value,
258 executor_work_guard<associated_executor_t<_Tp>>>
259 make_work_guard(const _Tp& __t)
260 { return net::get_associated_executor(__t); }
261
262 template<typename _Tp, typename _Up>
263 auto
264 make_work_guard(const _Tp& __t, _Up&& __u)
265 -> decltype(net::make_work_guard(
266 net::get_associated_executor(__t, forward<_Up>(__u))))
267 {
268 return net::make_work_guard(
269 net::get_associated_executor(__t, forward<_Up>(__u)));
270 }
271
272 /// Allows function objects to execute on any thread.
273 class system_executor;
274
275 /// The execution context associated with system_executor objects.
276 class system_context;
277
278 inline bool
279 operator==(const system_executor&, const system_executor&) { return true; }
280
281 inline bool
282 operator!=(const system_executor&, const system_executor&) { return false; }
283
284 /// Exception thrown by empty executors.
285 class bad_executor;
286
287 /// Polymorphic wrapper for types satisfying the Executor requirements.
288 class executor;
289
290 bool
291 operator==(const executor& __a, const executor& __b) noexcept;
292
293 bool
294 operator==(const executor& __e, nullptr_t) noexcept;
295
296 inline bool
297 operator==(nullptr_t, const executor& __e) noexcept
298 { return __e == nullptr; }
299
300 inline bool
301 operator!=(const executor& __a, const executor& __b) noexcept
302 { return !(__a == __b); }
303
304 inline bool
305 operator!=(const executor& __e, nullptr_t) noexcept
306 { return !(__e == nullptr); }
307
308 inline bool
309 operator!=(nullptr_t, const executor& __e) noexcept
310 { return !(__e == nullptr); }
311
312 void swap(executor&, executor&) noexcept;
313
314 // dispatch:
315
316 template<typename _CompletionToken>
317 __deduced_t<_CompletionToken, void()>
318 dispatch(_CompletionToken&& __token);
319
320 template<typename _Executor, typename _CompletionToken>
321 __deduced_t<_CompletionToken, void()>
322 dispatch(const _Executor& __ex, _CompletionToken&& __token);
323
324 template<typename _ExecutionContext, typename _CompletionToken>
325 __deduced_t<_CompletionToken, void()>
326 dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token);
327
328 // post:
329
330 template<typename _CompletionToken>
331 __deduced_t<_CompletionToken, void()>
332 post(_CompletionToken&& __token);
333 template<typename _Executor, typename _CompletionToken>
334 enable_if_t<is_executor<_Executor>::value,
335 __deduced_t<_CompletionToken, void()>>
336 post(const _Executor& __ex, _CompletionToken&& __token);
337 template<typename _ExecutionContext, typename _CompletionToken>
338 enable_if_t<__is_exec_context<_ExecutionContext>::value,
339 __deduced_t<_CompletionToken, void()>>
340 post(_ExecutionContext& __ctx, _CompletionToken&& __token);
341
342 // defer:
343
344 template<typename _CompletionToken>
345 __deduced_t<_CompletionToken, void()>
346 defer(_CompletionToken&& __token);
347 template<typename _Executor, typename _CompletionToken>
348 __deduced_t<_CompletionToken, void()>
349 defer(const _Executor& __ex, _CompletionToken&& __token);
350 template<typename _ExecutionContext, typename _CompletionToken>
351 __deduced_t<_CompletionToken, void()>
352 defer(_ExecutionContext& __ctx, _CompletionToken&& __token);
353
354 template<typename _Executor>
355 class strand;
356
357 template<typename _Executor>
358 bool
359 operator==(const strand<_Executor>& __a, const strand<_Executor>& __b);
360
361 template<typename _Executor>
362 bool
363 operator!=(const strand<_Executor>& __a, const strand<_Executor>& __b)
364 { return !(__a == __b); }
365
366 template<typename _CompletionToken, typename _Signature, typename>
367 class async_result
368 {
369 public:
370 typedef _CompletionToken completion_handler_type;
371 typedef void return_type;
372
373 explicit async_result(completion_handler_type&) {}
374 async_result(const async_result&) = delete;
375 async_result& operator=(const async_result&) = delete;
376
377 return_type get() {}
378 };
379
380 template<typename _CompletionToken, typename _Signature>
381 class async_completion
382 {
383 using __result_type
384 = async_result<decay_t<_CompletionToken>, _Signature>;
385
386 public:
387 using completion_handler_type
388 = typename __result_type::completion_handler_type;
389
390 private:
391 using __handler_type = conditional_t<
392 is_same<_CompletionToken, completion_handler_type>::value,
393 completion_handler_type&,
394 completion_handler_type>;
395
396 public:
397 explicit
398 async_completion(_CompletionToken& __t)
399 : completion_handler(std::forward<__handler_type>(__t)),
400 result(completion_handler)
401 { }
402
403 async_completion(const async_completion&) = delete;
404 async_completion& operator=(const async_completion&) = delete;
405
406 __handler_type completion_handler;
407 __result_type result;
408 };
409
410
411 class execution_context
412 {
413 public:
414 class service
415 {
416 protected:
417 // construct / copy / destroy:
418
419 explicit
420 service(execution_context& __owner) : _M_context(__owner) { }
421
422 service(const service&) = delete;
423 service& operator=(const service&) = delete;
424
425 virtual ~service() { } // TODO should not be inline
426
427 // service observers:
428
429 execution_context& context() const noexcept { return _M_context; }
430
431 private:
432 // service operations:
433
434 virtual void shutdown() noexcept = 0;
435 virtual void notify_fork(fork_event) { }
436
437 friend class execution_context;
438 execution_context& _M_context;
439 };
440
441 // construct / copy / destroy:
442
443 execution_context() { }
444
445 execution_context(const execution_context&) = delete;
446 execution_context& operator=(const execution_context&) = delete;
447
448 virtual ~execution_context()
449 {
450 shutdown();
451 destroy();
452 }
453
454 // execution context operations:
455
456 void
457 notify_fork(fork_event __e)
458 {
459 auto __l = [=](auto& __svc) { __svc._M_ptr->notify_fork(__e); };
460 if (__e == fork_event::prepare)
461 std::for_each(_M_services.rbegin(), _M_services.rend(), __l);
462 else
463 std::for_each(_M_services.begin(), _M_services.end(), __l);
464 }
465
466 protected:
467 // execution context protected operations:
468
469 void
470 shutdown()
471 {
472 std::for_each(_M_services.rbegin(), _M_services.rend(),
473 [=](auto& __svc) {
474 if (__svc._M_active)
475 {
476 __svc._M_ptr->shutdown();
477 __svc._M_active = false;
478 }
479 });
480 }
481
482 void
483 destroy()
484 {
485 while (_M_services.size())
486 _M_services.pop_back();
487 _M_keys.clear();
488 }
489
490 protected:
491
492 template<typename _Service>
493 static void
494 _S_deleter(service* __svc) { delete static_cast<_Service*>(__svc); }
495
496 struct _ServicePtr
497 {
498 template<typename _Service>
499 explicit
500 _ServicePtr(_Service* __svc)
501 : _M_ptr(__svc, &_S_deleter<_Service>), _M_active(true) { }
502
503 std::unique_ptr<service, void(*)(service*)> _M_ptr;
504 bool _M_active;
505 };
506
507 mutable std::mutex _M_mutex;
508
509 // Sorted in order of beginning of service object lifetime.
510 std::list<_ServicePtr> _M_services;
511
512 template<typename _Service, typename... _Args>
513 service*
514 _M_add_svc(_Args&&... __args)
515 {
516 _M_services.push_back(
517 _ServicePtr{new _Service{*this, std::forward<_Args>(__args)...}} );
518 return _M_services.back()._M_ptr.get();
519 }
520
521 using __key_type = void(*)();
522
523 template<typename _Key>
524 static __key_type
525 _S_key() { return reinterpret_cast<__key_type>(&_S_key<_Key>); }
526
527 std::unordered_map<__key_type, service*> _M_keys;
528
529 template<typename _Service>
530 friend typename _Service::key_type&
531 use_service(execution_context&);
532
533 template<typename _Service, typename... _Args>
534 friend _Service&
535 make_service(execution_context&, _Args&&...);
536
537 template<typename _Service>
538 friend bool
539 has_service(const execution_context&) noexcept;
540 };
541
542 // service access:
543
544 template<typename _Service>
545 typename _Service::key_type&
546 use_service(execution_context& __ctx)
547 {
548 using _Key = typename _Service::key_type;
549 static_assert(is_base_of<execution_context::service, _Key>::value,
550 "a service type must derive from execution_context::service");
551 static_assert(is_base_of<_Key, _Service>::value,
552 "a service type must match or derive from its key_type");
553 auto __key = execution_context::_S_key<_Key>();
554 std::lock_guard<std::mutex> __lock(__ctx._M_mutex);
555 auto& __svc = __ctx._M_keys[__key];
556 if (__svc == nullptr)
557 {
558 __try {
559 __svc = __ctx._M_add_svc<_Service>();
560 } __catch(...) {
561 __ctx._M_keys.erase(__key);
562 __throw_exception_again;
563 }
564 }
565 return static_cast<_Key&>(*__svc);
566 }
567
568 template<typename _Service, typename... _Args>
569 _Service&
570 make_service(execution_context& __ctx, _Args&&... __args)
571 {
572 using _Key = typename _Service::key_type;
573 static_assert(is_base_of<execution_context::service, _Key>::value,
574 "a service type must derive from execution_context::service");
575 static_assert(is_base_of<_Key, _Service>::value,
576 "a service type must match or derive from its key_type");
577 auto __key = execution_context::_S_key<_Key>();
578 std::lock_guard<std::mutex> __lock(__ctx._M_mutex);
579 auto& __svc = __ctx._M_keys[__key];
580 if (__svc != nullptr)
581 throw service_already_exists();
582 __try {
583 __svc = __ctx._M_add_svc<_Service>(std::forward<_Args>(__args)...);
584 } __catch(...) {
585 __ctx._M_keys.erase(__key);
586 __throw_exception_again;
587 }
588 return static_cast<_Service&>(*__svc);
589 }
590
591 template<typename _Service>
592 inline bool
593 has_service(const execution_context& __ctx) noexcept
594 {
595 using _Key = typename _Service::key_type;
596 static_assert(is_base_of<execution_context::service, _Key>::value,
597 "a service type must derive from execution_context::service");
598 static_assert(is_base_of<_Key, _Service>::value,
599 "a service type must match or derive from its key_type");
600 std::lock_guard<std::mutex> __lock(__ctx._M_mutex);
601 return __ctx._M_keys.count(execution_context::_S_key<_Key>());
602 }
603
604 template<typename _Tp, typename = __void_t<>>
605 struct __is_executor_impl : false_type
606 { };
607
608 // Check Executor requirements.
609 template<typename _Tp, typename _Up = remove_const_t<_Tp>>
610 auto
611 __executor_reqs(_Up* __x = 0, const _Up* __cx = 0, void(*__f)() = 0,
612 const allocator<int>& __a = {})
613 -> enable_if_t<__is_value_constructible<_Tp>::value, __void_t<
614 decltype(*__cx == *__cx),
615 decltype(*__cx != *__cx),
616 decltype(__x->context()),
617 decltype(__x->on_work_started()),
618 decltype(__x->on_work_finished()),
619 decltype(__x->dispatch(std::move(__f), __a)),
620 decltype(__x->post(std::move(__f), __a)),
621 decltype(__x->defer(std::move(__f), __a))
622 >>;
623
624 template<typename _Tp>
625 struct __is_executor_impl<_Tp, decltype(__executor_reqs<_Tp>())>
626 : true_type
627 { };
628
629 template<typename _Tp>
630 struct is_executor : __is_executor_impl<_Tp>
631 { };
632
633 template<typename _Tp>
634 constexpr bool is_executor_v = is_executor<_Tp>::value;
635
636 template<typename _Tp, typename _Executor, typename = __void_t<>>
637 struct __uses_executor_impl : false_type
638 { };
639
640 template<typename _Tp, typename _Executor>
641 struct __uses_executor_impl<_Tp, _Executor,
642 __void_t<typename _Tp::executor_type>>
643 : is_convertible<_Executor, typename _Tp::executor_type>
644 { };
645
646 template<typename _Tp, typename _Executor>
647 struct uses_executor : __uses_executor_impl<_Tp, _Executor>::type
648 { };
649
650 template<typename _Tp, typename _Executor>
651 constexpr bool uses_executor_v = uses_executor<_Tp, _Executor>::value;
652
653 template<typename _Tp, typename _Executor>
654 class executor_binder
655 {
656 struct __use_exec { };
657
658 public:
659 // types:
660
661 typedef _Tp target_type;
662 typedef _Executor executor_type;
663
664 // construct / copy / destroy:
665
666 executor_binder(_Tp __t, const _Executor& __ex)
667 : executor_binder(__use_exec{}, std::move(__t), __ex)
668 { }
669
670 executor_binder(const executor_binder&) = default;
671 executor_binder(executor_binder&&) = default;
672
673 template<typename _Up, typename _OtherExecutor>
674 executor_binder(const executor_binder<_Up, _OtherExecutor>& __other)
675 : executor_binder(__use_exec{}, __other.get(), __other.get_executor())
676 { }
677
678 template<typename _Up, typename _OtherExecutor>
679 executor_binder(executor_binder<_Up, _OtherExecutor>&& __other)
680 : executor_binder(__use_exec{}, std::move(__other.get()),
681 __other.get_executor())
682 { }
683
684 template<typename _Up, typename _OtherExecutor>
685 executor_binder(executor_arg_t, const _Executor& __ex,
686 const executor_binder<_Up, _OtherExecutor>& __other)
687 : executor_binder(__use_exec{}, __other.get(), __ex)
688 { }
689
690 template<typename _Up, typename _OtherExecutor>
691 executor_binder(executor_arg_t, const _Executor& __ex,
692 executor_binder<_Up, _OtherExecutor>&& __other)
693 : executor_binder(__use_exec{}, std::move(__other.get()), __ex)
694 { }
695
696 ~executor_binder();
697
698 // executor binder access:
699
700 _Tp& get() noexcept { return _M_target; }
701 const _Tp& get() const noexcept { return _M_target; }
702 executor_type get_executor() const noexcept { return _M_ex; }
703
704 // executor binder invocation:
705
706 template<class... _Args>
707 result_of_t<_Tp&(_Args&&...)>
708 operator()(_Args&&... __args)
709 { return std::__invoke(get(), std::forward<_Args>(__args)...); }
710
711 template<class... _Args>
712 result_of_t<const _Tp&(_Args&&...)>
713 operator()(_Args&&... __args) const
714 { return std::__invoke(get(), std::forward<_Args>(__args)...); }
715
716 private:
717 template<typename _Up>
718 using __use_exec_cond
719 = __and_<uses_executor<_Tp, _Executor>,
720 is_constructible<_Tp, executor_arg_t, _Executor, _Up>>;
721
722 template<typename _Up, typename _Exec, typename =
723 enable_if_t<__use_exec_cond<_Up>::value>>
724 executor_binder(__use_exec, _Up&& __u, _Exec&& __ex)
725 : _M_ex(std::forward<_Exec>(__ex)),
726 _M_target(executor_arg, _M_ex, std::forward<_Up>(__u))
727 { }
728
729 template<typename _Up, typename _Exec, typename =
730 enable_if_t<!__use_exec_cond<_Up>::value>>
731 executor_binder(__use_exec, _Up&& __u, const _Exec& __ex)
732 : _M_ex(std::forward<_Exec>(__ex)),
733 _M_target(std::forward<_Up>(__u))
734 { }
735
736 _Executor _M_ex;
737 _Tp _M_target;
738 };
739
740 template<typename _Tp, typename _Executor, typename _Signature>
741 class async_result<executor_binder<_Tp, _Executor>, _Signature>
742 {
743 using __inner = async_result<_Tp, _Signature>;
744
745 public:
746 using completion_handler_type =
747 executor_binder<typename __inner::completion_handler_type, _Executor>;
748
749 using return_type = typename __inner::return_type;
750
751 explicit
752 async_result(completion_handler_type& __h)
753 : _M_target(__h.get()) { }
754
755 async_result(const async_result&) = delete;
756 async_result& operator=(const async_result&) = delete;
757
758 return_type get() { return _M_target.get(); }
759
760 private:
761 __inner _M_target;
762 };
763
764 template<typename _Tp, typename _Executor, typename _ProtoAlloc>
765 struct associated_allocator<executor_binder<_Tp, _Executor>, _ProtoAlloc>
766 {
767 typedef associated_allocator_t<_Tp, _ProtoAlloc> type;
768
769 static type
770 get(const executor_binder<_Tp, _Executor>& __b,
771 const _ProtoAlloc& __a = _ProtoAlloc()) noexcept
772 { return associated_allocator<_Tp, _ProtoAlloc>::get(__b.get(), __a); }
773 };
774
775 template<typename _Tp, typename _Executor, typename _Executor1>
776 struct associated_executor<executor_binder<_Tp, _Executor>, _Executor1>
777 {
778 typedef _Executor type;
779
780 static type
781 get(const executor_binder<_Tp, _Executor>& __b,
782 const _Executor1& = _Executor1()) noexcept
783 { return __b.get_executor(); }
784 };
785
786 template<typename _Executor>
787 class executor_work_guard
788 {
789 public:
790 // types:
791
792 typedef _Executor executor_type;
793
794 // construct / copy / destroy:
795
796 explicit
797 executor_work_guard(const executor_type& __ex) noexcept
798 : _M_ex(__ex), _M_owns(true)
799 { _M_ex.on_work_started(); }
800
801 executor_work_guard(const executor_work_guard& __other) noexcept
802 : _M_ex(__other._M_ex), _M_owns(__other._M_owns)
803 {
804 if (_M_owns)
805 _M_ex.on_work_started();
806 }
807
808 executor_work_guard(executor_work_guard&& __other) noexcept
809 : _M_ex(__other._M_ex), _M_owns(__other._M_owns)
810 { __other._M_owns = false; }
811
812 executor_work_guard& operator=(const executor_work_guard&) = delete;
813
814 ~executor_work_guard()
815 {
816 if (_M_owns)
817 _M_ex.on_work_finished();
818 }
819
820 // executor work guard observers:
821
822 executor_type get_executor() const noexcept { return _M_ex; }
823
824 bool owns_work() const noexcept { return _M_owns; }
825
826 // executor work guard modifiers:
827
828 void reset() noexcept
829 {
830 if (_M_owns)
831 _M_ex.on_work_finished();
832 _M_owns = false;
833 }
834
835 private:
836 _Executor _M_ex;
837 bool _M_owns;
838 };
839
840
841 class system_context : public execution_context
842 {
843 public:
844 // types:
845
846 typedef system_executor executor_type;
847
848 // construct / copy / destroy:
849
850 system_context() = default;
851 system_context(const system_context&) = delete;
852 system_context& operator=(const system_context&) = delete;
853
854 ~system_context()
855 {
856 stop();
857 join();
858 }
859
860 // system_context operations:
861
862 executor_type get_executor() noexcept;
863
864 void stop()
865 {
866 lock_guard<mutex> __lock(_M_mtx);
867 _M_stopped = true;
868 _M_cv.notify_all();
869 }
870
871 bool stopped() const noexcept
872 {
873 lock_guard<mutex> __lock(_M_mtx);
874 return _M_stopped;
875 }
876
877 void join()
878 {
879 _M_thread.join();
880 }
881
882 private:
883 friend system_executor;
884
885 struct __tag { };
886 system_context(__tag) { }
887
888 thread _M_thread;
889 mutable mutex _M_mtx;
890 condition_variable _M_cv;
891 queue<function<void()>> _M_tasks;
892 bool _M_stopped = false;
893
894 void
895 _M_run()
896 {
897 while (true)
898 {
899 function<void()> __f;
900 {
901 unique_lock<mutex> __lock(_M_mtx);
902 _M_cv.wait(__lock,
903 [this]{ return !_M_stopped && !_M_tasks.empty(); });
904 if (_M_stopped)
905 return;
906 __f = std::move(_M_tasks.front());
907 _M_tasks.pop();
908 }
909 __f();
910 }
911 }
912
913 void
914 _M_post(std::function<void()> __f)
915 {
916 lock_guard<mutex> __lock(_M_mtx);
917 if (_M_stopped)
918 return;
919 if (!_M_thread.joinable())
920 _M_thread = std::thread(&system_context::_M_run, this);
921 _M_tasks.push(std::move(__f)); // XXX allocator not used
922 _M_cv.notify_one();
923 }
924
925 static system_context&
926 _S_get() noexcept
927 {
928 static system_context __sc(__tag{});
929 return __sc;
930 }
931 };
932
933 class system_executor
934 {
935 public:
936 // executor operations:
937
938 system_executor() { }
939
940 system_context&
941 context() const noexcept { return system_context::_S_get(); }
942
943 void on_work_started() const noexcept { }
944 void on_work_finished() const noexcept { }
945
946 template<typename _Func, typename _ProtoAlloc>
947 void
948 dispatch(_Func&& __f, const _ProtoAlloc& __a) const
949 { decay_t<_Func>{std::forward<_Func>(__f)}(); }
950
951 template<typename _Func, typename _ProtoAlloc>
952 void
953 post(_Func&& __f, const _ProtoAlloc&) const // XXX allocator not used
954 {
955 system_context::_S_get()._M_post(std::forward<_Func>(__f));
956 }
957
958 template<typename _Func, typename _ProtoAlloc>
959 void
960 defer(_Func&& __f, const _ProtoAlloc& __a) const
961 { post(std::forward<_Func>(__f), __a); }
962 };
963
964 inline system_executor
965 system_context::get_executor() noexcept
966 { return {}; }
967
968 class bad_executor : public std::exception
969 {
970 virtual const char* what() const noexcept { return "bad executor"; }
971 };
972
973 inline void __throw_bad_executor() // TODO make non-inline
974 {
975#if __cpp_exceptions
976 throw bad_executor();
977#else
978 __builtin_abort();
979#endif
980 }
981
982 class executor
983 {
984 public:
985 // construct / copy / destroy:
986
987 executor() noexcept = default;
988
989 executor(nullptr_t) noexcept { }
990 executor(const executor&) noexcept = default;
991 executor(executor&&) noexcept = default;
992
993 template<typename _Executor>
994 executor(_Executor __e)
995 : _M_target(_M_create(std::move(__e)))
996 { }
997
998 template<typename _Executor, typename _ProtoAlloc>
999 executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e)
1000 : _M_target(_M_create(std::move(__e), __a))
1001 { }
1002
1003 executor& operator=(const executor&) noexcept = default;
1004 executor& operator=(executor&&) noexcept = default;
1005
1006 executor&
1007 operator=(nullptr_t) noexcept
1008 {
1009 _M_target = nullptr;
1010 return *this;
1011 }
1012
1013 template<typename _Executor>
1014 executor&
1015 operator=(_Executor __e)
1016 {
1017 executor(std::move(__e)).swap(*this);
1018 return *this;
1019 }
1020
1021 ~executor() = default;
1022
1023 // executor modifiers:
1024
1025 void
1026 swap(executor& __other) noexcept
1027 { _M_target.swap(__other._M_target); }
1028
1029 template<typename _Executor, typename _Alloc>
1030 void
1031 assign(_Executor __e, const _Alloc& __a)
1032 { executor(allocator_arg, __a, std::move(__e)).swap(*this); }
1033
1034 // executor operations:
1035
1036 execution_context&
1037 context() const noexcept
1038 {
1039 __glibcxx_assert( _M_target );
1040 return _M_target->context();
1041 }
1042
1043 void
1044 on_work_started() const noexcept
1045 {
1046 __glibcxx_assert( _M_target );
1047 return _M_target->on_work_started();
1048 }
1049
1050 void
1051 on_work_finished() const noexcept
1052 {
1053 __glibcxx_assert( _M_target );
1054 return _M_target->on_work_finished();
1055 }
1056
1057 template<typename _Func, typename _Alloc>
1058 void
1059 dispatch(_Func&& __f, const _Alloc& __a) const
1060 {
1061 if (!_M_target)
1062 __throw_bad_executor();
1063 // _M_target->dispatch({allocator_arg, __a, std::forward<_Func>(__f)});
1064 _M_target->dispatch(std::forward<_Func>(__f));
1065 }
1066
1067 template<typename _Func, typename _Alloc>
1068 void
1069 post(_Func&& __f, const _Alloc& __a) const
1070 {
1071 if (!_M_target)
1072 __throw_bad_executor();
1073 // _M_target->post({allocator_arg, __a, std::forward<_Func>(__f)});
1074 _M_target->post(std::forward<_Func>(__f));
1075 }
1076
1077 template<typename _Func, typename _Alloc>
1078 void
1079 defer(_Func&& __f, const _Alloc& __a) const
1080 {
1081 if (!_M_target)
1082 __throw_bad_executor();
1083 // _M_target->defer({allocator_arg, __a, std::forward<_Func>(__f)});
1084 _M_target->defer(std::forward<_Func>(__f));
1085 }
1086
1087 // executor capacity:
1088
1089 explicit operator bool() const noexcept
1090 { return static_cast<bool>(_M_target); }
1091
1092 // executor target access:
1093
1094#if __cpp_rtti
1095 const type_info&
1096 target_type() const noexcept
1097 { return _M_target ? _M_target->target_type() : typeid(void); }
1098
1099 template<typename _Executor>
1100 _Executor*
1101 target() noexcept
1102 {
1103 if (_M_target)
1104 if (const auto* __p = _M_target->target(typeid(_Executor)))
1105 return const_cast<_Executor*>(static_cast<const _Executor>(__p));
1106 return nullptr;
1107 }
1108
1109 template<typename _Executor>
1110 const _Executor*
1111 target() const noexcept
1112 {
1113 if (_M_target)
1114 if (const auto* __p = _M_target->target(typeid(_Executor)))
1115 return static_cast<const _Executor*>(__p);
1116 return nullptr;
1117 }
1118#endif
1119
1120 private:
1121 struct _Tgt
1122 {
1123 virtual void on_work_started() const noexcept = 0;
1124 virtual void on_work_finished() const noexcept = 0;
1125 virtual execution_context& context() const noexcept = 0;
1126 virtual void dispatch(std::function<void()>) const = 0;
1127 virtual void post(std::function<void()>) const = 0;
1128 virtual void defer(std::function<void()>) const = 0;
1129#if __cpp_rtti
1130 virtual const type_info& target_type() const = 0;
1131 virtual void* target(const std::type_info&) const = 0;
1132 virtual bool _M_equals(_Tgt*) const noexcept = 0;
1133 virtual const void* _M_get_executor() const noexcept = 0;
1134#endif
1135 };
1136
1137 template<typename _Ex, typename _Alloc>
1138 struct _TgtImpl : _Tgt
1139 {
1140 explicit
1141 _TgtImpl(_Ex&& __ex, const _Alloc& __a)
1142 : _M_impl(std::move(__ex), __a) { }
1143
1144 void on_work_started() const noexcept { _M_ex().on_work_started(); }
1145 void on_work_finished() const noexcept { _M_ex().on_work_finished(); }
1146 execution_context& context() const noexcept { return _M_ex().context(); }
1147 void
1148 dispatch(std::function<void()> __f) const
1149 { _M_ex().dispatch(std::move(__f), _M_alloc()); }
1150 void
1151 post(std::function<void()> __f) const
1152 { _M_ex().post(std::move(__f), _M_alloc()); }
1153 void
1154 defer(std::function<void()> __f) const
1155 { _M_ex().defer(std::move(__f), _M_alloc()); }
1156
1157#if __cpp_rtti
1158 virtual const type_info&
1159 target_type() const
1160 { return typeid(_Ex); }
1161
1162 virtual const void*
1163 target(const std::type_info& __ti) const
1164 {
1165 if (__ti == typeid(_Ex))
1166 return std::addressof(_M_ex());
1167 return nullptr;
1168 }
1169
1170 virtual bool
1171 _M_equals(const _Tgt* __tgt) const noexcept
1172 {
1173 if (__tgt->target_type() == typeid(_Ex))
1174 *static_cast<const _Ex*>(__tgt->_M_get_executor()) == _M_ex();
1175 return false;
1176 }
1177
1178 virtual const void*
1179 _M_get_executor() const noexcept
1180 { return std::addressof(_M_ex()); }
1181#endif
1182
1183 _Ex& _M_ex() { return std::get<0>(_M_impl); }
1184 _Alloc& _M_alloc() { return std::get<1>(_M_impl); }
1185 std::tuple<_Ex, _Alloc> _M_impl;
1186 };
1187
1188 template<typename _Ex, typename _Alloc = std::allocator<void>>
1189 shared_ptr<_Tgt>
1190 _M_create(_Ex&& __ex, const _Alloc& __a = _Alloc())
1191 {
1192 return allocate_shared<_TgtImpl<_Ex, _Alloc>>(__a, std::move(__ex),
1193 __a);
1194 }
1195
1196 friend bool
1197 operator==(const executor& __a, const executor& __b) noexcept
1198 {
1199 if (__a._M_target == __b._M_target)
1200 return true;
1201 if (!__a._M_target || !__b._M_target)
1202 return false;
1203#if __cpp_rtti
1204 return __a._M_target->_M_equals(__b._M_target.get());
1205#else
1206 return false; // XXX can we do better?
1207#endif
1208 }
1209
1210 shared_ptr<_Tgt> _M_target;
1211 };
1212
1213 template<> struct is_executor<executor> : true_type { };
1214
1215 /// executor comparisons
1216 inline bool
1217 operator==(const executor& __e, nullptr_t) noexcept
1218 { return !__e; }
1219
1220 /// Swap two executor objects.
1221 inline void swap(executor& __a, executor& __b) noexcept { __a.swap(__b); }
1222
1223
1224 template<typename _CompletionHandler>
1225 struct __dispatcher
1226 {
1227 explicit
1228 __dispatcher(_CompletionHandler& __h)
1229 : _M_h(std::move(__h)), _M_w(net::make_work_guard(_M_h))
1230 { }
1231
1232 void operator()()
1233 {
1234 auto __alloc = net::get_associated_allocator(_M_h);
1235 _M_w.get_executor().dispatch(std::move(_M_h), __alloc);
1236 _M_w.reset();
1237 }
1238
1239 _CompletionHandler _M_h;
1240 decltype(net::make_work_guard(_M_h)) _M_w;
1241 };
1242
1243 template<typename _CompletionHandler>
1244 inline __dispatcher<_CompletionHandler>
1245 __make_dispatcher(_CompletionHandler& __h)
1246 { return __dispatcher<_CompletionHandler>{__h}; }
1247
1248
1249
1250 // dispatch:
1251
1252 template<typename _CompletionToken>
1253 inline __deduced_t<_CompletionToken, void()>
1254 dispatch(_CompletionToken&& __token)
1255 {
1256 async_completion<_CompletionToken, void()> __cmpl{__token};
1257 auto __ex = net::get_associated_executor(__cmpl.completion_handler);
1258 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
1259 __ex.dispatch(std::move(__cmpl.completion_handler), __alloc);
1260 return __cmpl.result.get();
1261 }
1262
1263 template<typename _Executor, typename _CompletionToken>
1264 inline
1265 enable_if_t<is_executor<_Executor>::value,
1266 __deduced_t<_CompletionToken, void()>>
1267 dispatch(const _Executor& __ex, _CompletionToken&& __token)
1268 {
1269 async_completion<_CompletionToken, void()> __cmpl{__token};
1270 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
1271 __ex.dispatch(net::__make_dispatcher(__cmpl.completion_handler),
1272 __alloc);
1273 return __cmpl.result.get();
1274 }
1275
1276 template<typename _ExecutionContext, typename _CompletionToken>
1277 inline
1278 enable_if_t<__is_exec_context<_ExecutionContext>::value,
1279 __deduced_t<_CompletionToken, void()>>
1280 dispatch(_ExecutionContext& __ctx, _CompletionToken&& __token)
1281 {
1282 return net::dispatch(__ctx.get_executor(),
1283 forward<_CompletionToken>(__token));
1284 }
1285
1286 // post:
1287
1288 template<typename _CompletionToken>
1289 inline __deduced_t<_CompletionToken, void()>
1290 post(_CompletionToken&& __token)
1291 {
1292 async_completion<_CompletionToken, void()> __cmpl{__token};
1293 auto __ex = net::get_associated_executor(__cmpl.completion_handler);
1294 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
1295 __ex.post(std::move(__cmpl.completion_handler), __alloc);
1296 return __cmpl.result.get();
1297 }
1298
1299 template<typename _Executor, typename _CompletionToken>
1300 inline
1301 enable_if_t<is_executor<_Executor>::value,
1302 __deduced_t<_CompletionToken, void()>>
1303 post(const _Executor& __ex, _CompletionToken&& __token)
1304 {
1305 async_completion<_CompletionToken, void()> __cmpl{__token};
1306 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
1307 __ex.post(net::__make_dispatcher(__cmpl.completion_handler), __alloc);
1308 return __cmpl.result.get();
1309 }
1310
1311 template<typename _ExecutionContext, typename _CompletionToken>
1312 inline
1313 enable_if_t<__is_exec_context<_ExecutionContext>::value,
1314 __deduced_t<_CompletionToken, void()>>
1315 post(_ExecutionContext& __ctx, _CompletionToken&& __token)
1316 {
1317 return net::post(__ctx.get_executor(),
1318 forward<_CompletionToken>(__token));
1319 }
1320
1321 // defer:
1322
1323 template<typename _CompletionToken>
1324 inline __deduced_t<_CompletionToken, void()>
1325 defer(_CompletionToken&& __token)
1326 {
1327 async_completion<_CompletionToken, void()> __cmpl{__token};
1328 auto __ex = net::get_associated_executor(__cmpl.completion_handler);
1329 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
1330 __ex.defer(std::move(__cmpl.completion_handler), __alloc);
1331 return __cmpl.result.get();
1332 }
1333
1334 template<typename _Executor, typename _CompletionToken>
1335 inline
1336 enable_if_t<is_executor<_Executor>::value,
1337 __deduced_t<_CompletionToken, void()>>
1338 defer(const _Executor& __ex, _CompletionToken&& __token)
1339 {
1340 async_completion<_CompletionToken, void()> __cmpl{__token};
1341 auto __alloc = net::get_associated_allocator(__cmpl.completion_handler);
1342 __ex.defer(net::__make_dispatcher(__cmpl.completion_handler), __alloc);
1343 return __cmpl.result.get();
1344 }
1345
1346 template<typename _ExecutionContext, typename _CompletionToken>
1347 inline
1348 enable_if_t<__is_exec_context<_ExecutionContext>::value,
1349 __deduced_t<_CompletionToken, void()>>
1350 defer(_ExecutionContext& __ctx, _CompletionToken&& __token)
1351 {
1352 return net::defer(__ctx.get_executor(),
1353 forward<_CompletionToken>(__token));
1354 }
1355
1356
1357 template<typename _Executor>
1358 class strand
1359 {
1360 public:
1361 // types:
1362
1363 typedef _Executor inner_executor_type;
1364
1365 // construct / copy / destroy:
1366
1367 strand(); // TODO make state
1368
1369 explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state
1370
1371 template<typename _Alloc>
1372 strand(allocator_arg_t, const _Alloc& __a, _Executor __ex)
1373 : _M_inner_ex(__ex) { } // TODO make state
1374
1375 strand(const strand& __other) noexcept
1376 : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }
1377
1378 strand(strand&& __other) noexcept
1379 : _M_state(std::move(__other._M_state)),
1380 _M_inner_ex(std::move(__other._M_inner_ex)) { }
1381
1382 template<typename _OtherExecutor>
1383 strand(const strand<_OtherExecutor>& __other) noexcept
1384 : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }
1385
1386 template<typename _OtherExecutor>
1387 strand(strand<_OtherExecutor>&& __other) noexcept
1388 : _M_state(std::move(__other._M_state)),
1389 _M_inner_ex(std::move(__other._M_inner_ex)) { }
1390
1391 strand&
1392 operator=(const strand& __other) noexcept
1393 {
1394 static_assert(is_copy_assignable<_Executor>::value,
1395 "inner executor type must be CopyAssignable");
1396
1397 // TODO lock __other
1398 // TODO copy state
1399 _M_inner_ex = __other._M_inner_ex;
1400 return *this;
1401 }
1402
1403 strand&
1404 operator=(strand&& __other) noexcept
1405 {
1406 static_assert(is_move_assignable<_Executor>::value,
1407 "inner executor type must be MoveAssignable");
1408
1409 // TODO move state
1410 _M_inner_ex = std::move(__other._M_inner_ex);
1411 return *this;
1412 }
1413
1414 template<typename _OtherExecutor>
1415 strand&
1416 operator=(const strand<_OtherExecutor>& __other) noexcept
1417 {
1418 static_assert(is_convertible<_OtherExecutor, _Executor>::value,
1419 "inner executor type must be compatible");
1420
1421 // TODO lock __other
1422 // TODO copy state
1423 _M_inner_ex = __other._M_inner_ex;
1424 return *this;
1425 }
1426
1427 template<typename _OtherExecutor>
1428 strand&
1429 operator=(strand<_OtherExecutor>&& __other) noexcept
1430 {
1431 static_assert(is_convertible<_OtherExecutor, _Executor>::value,
1432 "inner executor type must be compatible");
1433
1434 // TODO move state
1435 _M_inner_ex = std::move(__other._M_inner_ex);
1436 return *this;
1437 }
1438
1439 ~strand()
1440 {
1441 // the task queue outlives this object if non-empty
1442 // TODO create circular ref in queue?
1443 }
1444
1445 // strand operations:
1446
1447 inner_executor_type
1448 get_inner_executor() const noexcept
1449 { return _M_inner_ex; }
1450
1451 bool
1452 running_in_this_thread() const noexcept
1453 { return std::this_thread::get_id() == _M_state->_M_running_on; }
1454
1455 execution_context&
1456 context() const noexcept
1457 { return _M_inner_ex.context(); }
1458
1459 void on_work_started() const noexcept { _M_inner_ex.on_work_started(); }
1460 void on_work_finished() const noexcept { _M_inner_ex.on_work_finished(); }
1461
1462 template<typename _Func, typename _Alloc>
1463 void
1464 dispatch(_Func&& __f, const _Alloc& __a) const
1465 {
1466 if (running_in_this_thread())
1467 decay_t<_Func>{std::forward<_Func>(__f)}();
1468 else
1469 post(std::forward<_Func>(__f), __a);
1470 }
1471
1472 template<typename _Func, typename _Alloc>
1473 void
1474 post(_Func&& __f, const _Alloc& __a) const; // TODO
1475
1476 template<typename _Func, typename _Alloc>
1477 void
1478 defer(_Func&& __f, const _Alloc& __a) const
1479 { post(std::forward<_Func>(__f), __a); }
1480
1481 private:
1482 friend bool
1483 operator==(const strand& __a, const strand& __b)
1484 { return __a._M_state == __b._M_state; }
1485
1486 // TODO add synchronised queue
1487 struct _State
1488 {
1489 std::thread::id _M_running_on;
1490 };
1491 shared_ptr<_State> _M_state;
1492 _Executor _M_inner_ex;
1493 };
1494
1495#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
1496
1497 // Completion token for asynchronous operations initiated with use_future.
1498 template<typename _Func, typename _Alloc>
1499 struct __use_future_ct
1500 {
1501 std::tuple<_Func, _Alloc> _M_t;
1502 };
1503
1504 template<typename _ProtoAllocator = allocator<void>>
1505 class use_future_t
1506 {
1507 public:
1508 // use_future_t types:
1509 typedef _ProtoAllocator allocator_type;
1510
1511 // use_future_t members:
1512 constexpr use_future_t() noexcept : _M_alloc() { }
1513
1514 explicit
1515 use_future_t(const _ProtoAllocator& __a) noexcept : _M_alloc(__a) { }
1516
1517 template<class _OtherAllocator>
1518 use_future_t<_OtherAllocator>
1519 rebind(const _OtherAllocator& __a) const noexcept
1520 { return use_future_t<_OtherAllocator>(__a); }
1521
1522 allocator_type get_allocator() const noexcept { return _M_alloc; }
1523
1524 template<typename _Func>
1525 auto
1526 operator()(_Func&& __f) const
1527 {
1528 using _Token = __use_future_ct<decay_t<_Func>, _ProtoAllocator>;
1529 return _Token{ {std::forward<_Func>(__f), _M_alloc} };
1530 }
1531
1532 private:
1533 _ProtoAllocator _M_alloc;
1534 };
1535
1536 constexpr use_future_t<> use_future = use_future_t<>();
1537
1538 template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
1539 class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>;
1540
1541 template<typename _Result, typename _Executor>
1542 struct __use_future_ex;
1543
1544 // Completion handler for asynchronous operations initiated with use_future.
1545 template<typename _Func, typename... _Args>
1546 struct __use_future_ch
1547 {
1548 template<typename _Alloc>
1549 explicit
1550 __use_future_ch(__use_future_ct<_Func, _Alloc>&& __token)
1551 : _M_f{ std::move(std::get<0>(__token._M_t)) },
1552 _M_promise{ std::get<1>(__token._M_t) }
1553 { }
1554
1555 void
1556 operator()(_Args&&... __args)
1557 {
1558 __try
1559 {
1560 _M_promise.set_value(_M_f(std::forward<_Args>(__args)...));
1561 }
1562 __catch(__cxxabiv1::__forced_unwind&)
1563 {
1564 __throw_exception_again;
1565 }
1566 __catch(...)
1567 {
1568 _M_promise.set_exception(std::current_exception());
1569 }
1570 }
1571
1572 using __result = result_of_t<_Func(decay_t<_Args>...)>;
1573
1574 future<__result> get_future() { return _M_promise.get_future(); }
1575
1576 private:
1577 template<typename _Result, typename _Executor>
1578 friend struct __use_future_ex;
1579
1580 _Func _M_f;
1581 mutable promise<__result> _M_promise;
1582 };
1583
1584 // Specialization of async_result for operations initiated with use_future.
1585 template<typename _Func, typename _Alloc, typename _Res, typename... _Args>
1586 class async_result<__use_future_ct<_Func, _Alloc>, _Res(_Args...)>
1587 {
1588 public:
1589 using completion_handler_type = __use_future_ch<_Func, _Args...>;
1590 using return_type = future<typename completion_handler_type::__result>;
1591
1592 explicit
1593 async_result(completion_handler_type& __h)
1594 : _M_future(__h.get_future())
1595 { }
1596
1597 async_result(const async_result&) = delete;
1598 async_result& operator=(const async_result&) = delete;
1599
1600 return_type get() { return std::move(_M_future); }
1601
1602 private:
1603 return_type _M_future;
1604 };
1605
1606 template<typename _Result, typename _Executor>
1607 struct __use_future_ex
1608 {
1609 template<typename _Handler>
1610 __use_future_ex(const _Handler& __h, _Executor __ex)
1611 : _M_t(__h._M_promise, __ex)
1612 { }
1613
1614 template<typename _Fn, typename _Alloc>
1615 void
1616 dispatch(_Fn&& __fn)
1617 {
1618 __try
1619 {
1620 std::get<1>(_M_t).dispatch(std::forward<_Fn>(__fn));
1621 }
1622 __catch(__cxxabiv1::__forced_unwind&)
1623 {
1624 __throw_exception_again;
1625 }
1626 __catch(...)
1627 {
1628 std::get<0>(_M_t).set_exception(std::current_exception());
1629 }
1630 }
1631
1632 template<typename _Fn, typename _Alloc>
1633 void
1634 post(_Fn&& __fn)
1635 {
1636 __try
1637 {
1638 std::get<1>(_M_t).post(std::forward<_Fn>(__fn));
1639 }
1640 __catch(__cxxabiv1::__forced_unwind&)
1641 {
1642 __throw_exception_again;
1643 }
1644 __catch(...)
1645 {
1646 std::get<0>(_M_t).set_exception(std::current_exception());
1647 }
1648 }
1649
1650 template<typename _Fn, typename _Alloc>
1651 void
1652 defer(_Fn&& __fn)
1653 {
1654 __try
1655 {
1656 std::get<1>(_M_t).defer(std::forward<_Fn>(__fn));
1657 }
1658 __catch(__cxxabiv1::__forced_unwind&)
1659 {
1660 __throw_exception_again;
1661 }
1662 __catch(...)
1663 {
1664 std::get<0>(_M_t).set_exception(std::current_exception());
1665 }
1666 }
1667
1668 private:
1669 tuple<promise<_Result>&, _Executor> _M_t;
1670 };
1671
1672 template<typename _Func, typename... _Args, typename _Executor>
1673 struct associated_executor<__use_future_ch<_Func, _Args...>, _Executor>
1674 {
1675 private:
1676 using __handler = __use_future_ch<_Func, _Args...>;
1677
1678 using type = __use_future_ex<typename __handler::__result, _Executor>;
1679
1680 static type
1681 get(const __handler& __h, const _Executor& __ex)
1682 { return { __h, __ex }; }
1683 };
1684
1685#if 0
1686
1687 // [async.use.future.traits]
1688 template<typename _Allocator, typename _Ret, typename... _Args>
1689 class handler_type<use_future_t<_Allocator>, _Ret(_Args...)> // TODO uglify name
1690 {
1691 template<typename... _Args>
1692 struct __is_error_result : false_type { };
1693
1694 template<typename... _Args>
1695 struct __is_error_result<error_code, _Args...> : true_type { };
1696
1697 template<typename... _Args>
1698 struct __is_error_result<exception_ptr, _Args...> : true_type { };
1699
1700 static exception_ptr
1701 _S_exptr(exception_ptr& __ex)
1702 { return std::move(__ex); }
1703
1704 static exception_ptr
1705 _S_exptr(const error_code& __ec)
1706 { return make_exception_ptr(system_error(__ec)); }
1707
1708 template<bool _IsError, typename... _UArgs>
1709 struct _Type;
1710
1711 // N == 0
1712 template<bool _IsError>
1713 struct _Type<_IsError>
1714 {
1715 std::promise<void> _M_promise;
1716
1717 void
1718 operator()()
1719 {
1720 _M_promise.set_value();
1721 }
1722 };
1723
1724 // N == 1, U0 is error_code or exception_ptr
1725 template<typename _UArg0>
1726 struct _Type<true, _UArg0>
1727 {
1728 std::promise<void> _M_promise;
1729
1730 template<typename _Arg0>
1731 void
1732 operator()(_Arg0&& __a0)
1733 {
1734 if (__a0)
1735 _M_promise.set_exception(_S_exptr(__a0));
1736 else
1737 _M_promise.set_value();
1738 }
1739 };
1740
1741 // N == 1, U0 is not error_code or exception_ptr
1742 template<typename _UArg0>
1743 struct _Type<false, _UArg0>
1744 {
1745 std::promise<_UArg0> _M_promise;
1746
1747 template<typename _Arg0>
1748 void
1749 operator()(_Arg0&& __a0)
1750 {
1751 _M_promise.set_value(std::forward<_Arg0>(__a0));
1752 }
1753 };
1754
1755 // N == 2, U0 is error_code or exception_ptr
1756 template<typename _UArg0, typename _UArg1>
1757 struct _Type<true, _UArg0, _UArg1>
1758 {
1759 std::promise<_UArg1> _M_promise;
1760
1761 template<typename _Arg0, typename _Arg1>
1762 void
1763 operator()(_Arg0&& __a0, _Arg1&& __a1)
1764 {
1765 if (__a0)
1766 _M_promise.set_exception(_S_exptr(__a0));
1767 else
1768 _M_promise.set_value(std::forward<_Arg1>(__a1));
1769 }
1770 };
1771
1772 // N >= 2, U0 is not error_code or exception_ptr
1773 template<typename... _UArgs>
1774 struct _Type<false, _UArgs...>
1775 {
1776 static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");
1777
1778 std::promise<tuple<_UArgs...>> _M_promise;
1779
1780 template<typename... _Args>
1781 void
1782 operator()(_Args&&... __args)
1783 {
1784 _M_promise.set_value(
1785 std::forward_as_tuple(std::forward<_Args>(__args)...));
1786 }
1787 };
1788
1789 // N > 2, U0 is error_code or exception_ptr
1790 template<typename _UArg0, typename... _UArgs>
1791 struct _Type<true, _UArg0, _UArgs...>
1792 {
1793 static_assert(sizeof...(_UArgs) > 1, "wrong partial specialization");
1794
1795 std::promise<tuple<_UArgs...>> _M_promise;
1796
1797 template<typename _Arg0, typename... _Args>
1798 void
1799 operator()(_Arg0&& __a0, _Args&&... __args)
1800 {
1801 if (__a0)
1802 _M_promise.set_exception(_S_exptr(__a0));
1803 else
1804 _M_promise.set_value(
1805 std::forward_as_tuple(std::forward<_Args>(__args)...));
1806 }
1807 };
1808
1809 public:
1810 using type =
1811 _Type<__is_error_result<_Args...>::value, decay_t<_Args>...>;
1812 };
1813
1814
1815 template<typename _Alloc, typename _Ret, typename... _Args>
1816 struct async_result<use_future_t<_Alloc>, _Ret(_Args...)>
1817 {
1818 using completion_handler_type
1819 = typename handler_type<use_future_t<_Alloc>, _Ret(_Args...)>::type;
1820
1821 using return_type = void; // XXX TODO ???;
1822
1823 explicit
1824 async_result(completion_handler_type& __h) : _M_handler(__h) { }
1825
1826 auto get() { return _M_handler._M_provider.get_future(); }
1827
1828 async_result(const async_result&) = delete;
1829 async_result& operator=(const async_result&) = delete;
1830
1831 return_type get() { return _M_handler._M_promise.get_future(); }
1832
1833 private:
1834 completion_handler_type& _M_handler;
1835 };
1836
1837 // TODO specialize associated_executor for
1838 // async_result<use_future_t<A>, Sig>::completion_handler_type
1839 // to use a __use_future_ex
1840 // (probably need to move _Type outside of handler_type so we don't have
1841 // a non-deduced context)
1842
1843
1844#endif
1845
1846 // [async.packaged.task.specializations]
1847 template<typename _Ret, typename... _Args, typename _Signature>
1848 class async_result<packaged_task<_Ret(_Args...)>, _Signature>
1849 {
1850 public:
1851 using completion_handler_type = packaged_task<_Ret(_Args...)>;
1852 using return_type = future<_Ret>;
1853
1854 explicit
1855 async_result(completion_handler_type& __h)
1856 : _M_future(__h.get_future()) { }
1857
1858 async_result(const async_result&) = delete;
1859 async_result& operator=(const async_result&) = delete;
1860
1861 return_type get() { return std::move(_M_future); }
1862
1863 private:
1864 return_type _M_future;
1865 };
1866
1867#endif
1868
1869 /// @}
1870
e5989e71
JW
1871} // namespace v1
1872} // namespace net
1873} // namespace experimental
1874
e5989e71
JW
1875 template<typename _Alloc>
1876 struct uses_allocator<experimental::net::executor, _Alloc>
1877 : true_type {};
1878
1879_GLIBCXX_END_NAMESPACE_VERSION
1880} // namespace std
1881
1882#endif // C++14
1883
1884#endif // _GLIBCXX_EXPERIMENTAL_EXECUTOR