Skip to content

Commit 3eb5736

Browse files
authored
add the ability to co_await sender adaptor closure objects (#1601)
1 parent 50efa1a commit 3eb5736

21 files changed

Lines changed: 211 additions & 86 deletions

include/exec/__detail/__bit_cast.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace exec {
3939
requires(sizeof(_To) == sizeof(_From))
4040
[[nodiscard]]
4141
constexpr _To bit_cast(const _From& __from) noexcept {
42-
# if STDEXEC_HAS_BUILTIN(__builtin_bit_cast) || (_MSC_VER >= 1926)
42+
# if STDEXEC_HAS_BUILTIN(__builtin_bit_cast) || (STDEXEC_MSVC() && STDEXEC_MSVC_VERSION >= 19'26)
4343
return __builtin_bit_cast(_To, __from);
4444
# else
4545
_To __to;

include/exec/__detail/__numa.hpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#pragma once
1818

1919
#include "../../stdexec/__detail/__config.hpp"
20-
#include "../../stdexec/__detail/__meta.hpp"
2120
#include "../scope.hpp" // IWYU pragma: keep
2221

2322
#include <algorithm> // IWYU pragma: keep
@@ -27,14 +26,10 @@
2726
#include <thread>
2827
#include <utility>
2928

30-
// Work around a bug in the NVHPC compilers prior to version 24.03
31-
#if STDEXEC_NVHPC()
32-
# if STDEXEC_NVHPC_VERSION() <= 2403
33-
# define STDEXEC_NUMA_VTABLE_INLINE
34-
# endif
35-
#endif
36-
37-
#ifndef STDEXEC_NUMA_VTABLE_INLINE
29+
// Work around a bug in the NVHPC compilers prior to version 24.3
30+
#if STDEXEC_NVHPC() && STDEXEC_NVHPC_VERSION < 24'03
31+
# define STDEXEC_NUMA_VTABLE_INLINE
32+
#else
3833
# define STDEXEC_NUMA_VTABLE_INLINE inline
3934
#endif
4035

include/exec/task.hpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ namespace exec {
8888
__sticky
8989
};
9090

91-
struct __parent_promise_t { };
92-
9391
template <__scheduler_affinity _SchedulerAffinity = __scheduler_affinity::__sticky>
9492
class __default_task_context_impl {
9593
template <class _ParentPromise>
@@ -103,7 +101,7 @@ namespace exec {
103101

104102
public:
105103
template <class _ParentPromise>
106-
explicit __default_task_context_impl(__parent_promise_t, _ParentPromise& __parent) noexcept {
104+
explicit __default_task_context_impl(_ParentPromise& __parent) noexcept {
107105
if constexpr (_SchedulerAffinity == __scheduler_affinity::__sticky) {
108106
if constexpr (__check_parent_promise_has_scheduler<_ParentPromise>()) {
109107
__scheduler_ = get_scheduler(get_env(__parent));
@@ -281,6 +279,25 @@ namespace exec {
281279
__variant_for<__void, std::exception_ptr> __data_{};
282280
};
283281

282+
template <class _Sch>
283+
struct __just_void {
284+
using sender_concept = sender_t;
285+
using completion_signatures = stdexec::completion_signatures<set_value_t()>;
286+
287+
template <class _Rcvr>
288+
[[nodiscard]]
289+
static constexpr auto connect(_Rcvr __rcvr) noexcept {
290+
return stdexec::connect(just(), static_cast<_Rcvr&&>(__rcvr));
291+
}
292+
293+
[[nodiscard]]
294+
constexpr auto get_env() const noexcept {
295+
return prop{get_completion_scheduler<set_value_t>, __sch_};
296+
}
297+
298+
_Sch __sch_;
299+
};
300+
284301
enum class disposition : unsigned {
285302
stopped,
286303
succeeded,
@@ -319,6 +336,8 @@ namespace exec {
319336
}
320337

321338
private:
339+
using __scheduler_t = __query_result_or_t<get_scheduler_t, _Context, inline_scheduler>;
340+
322341
struct __final_awaitable {
323342
static constexpr auto await_ready() noexcept -> bool {
324343
return false;
@@ -399,6 +418,11 @@ namespace exec {
399418
}
400419
#endif
401420

421+
template <__sender_adaptor_closure_for<__just_void<__scheduler_t>> _Closure>
422+
auto await_transform(_Closure&& __closure) noexcept -> decltype(auto) {
423+
return await_transform(static_cast<_Closure&&>(__closure)(__just_void<__scheduler_t>()));
424+
}
425+
402426
template <class _Awaitable>
403427
auto await_transform(_Awaitable&& __awaitable) noexcept -> decltype(auto) {
404428
return with_awaitable_senders<__promise>::await_transform(
@@ -431,7 +455,7 @@ namespace exec {
431455
auto await_suspend(__coro::coroutine_handle<_ParentPromise2> __parent) noexcept
432456
-> __coro::coroutine_handle<> {
433457
static_assert(__one_of<_ParentPromise, _ParentPromise2, void>);
434-
__coro_.promise().__context_.emplace(__parent_promise_t(), __parent.promise());
458+
__coro_.promise().__context_.emplace(__parent.promise());
435459
__context_.emplace(*__coro_.promise().__context_, __parent.promise());
436460
__coro_.promise().set_continuation(__parent);
437461
if constexpr (requires { __coro_.promise().stop_requested() ? 0 : 1; }) {

include/exec/timed_scheduler.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ namespace exec {
126126
};
127127

128128
struct schedule_after_t : __schedule_after_base_t {
129-
#if !STDEXEC_CLANG() || (__clang_major__ >= 16)
129+
#if !STDEXEC_CLANG() || STDEXEC_CLANG_VERSION >= 16'00
130130
using __schedule_after_base_t::operator();
131131
#else
132132
// clang prior to 16 is not able to find the correct overload in the
@@ -198,7 +198,7 @@ namespace exec {
198198
};
199199

200200
struct schedule_at_t : __schedule_at_base_t {
201-
#if !STDEXEC_CLANG() || (__clang_major__ >= 16)
201+
#if !STDEXEC_CLANG() || STDEXEC_CLANG_VERSION >= 16'00
202202
using __schedule_at_base_t::operator();
203203
#else
204204
// clang prior to 16 is not able to find the correct overload in the

include/stdexec/__detail/__config.hpp

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,37 @@
4848
// macro name; nothing, otherwise.
4949
#if defined(__NVCC__)
5050
# define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
51+
# define STDEXEC_NVCC_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)
5152
#elif defined(__EDG__)
5253
# define STDEXEC_EDG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
54+
# define STDEXEC_EDG_VERSION __EDG_VERSION__
5355
# if defined(__NVCOMPILER)
5456
# define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
57+
# define STDEXEC_NVHPC_VERSION (__NVCOMPILER_MAJOR__ * 100 + __NVCOMPILER_MINOR__)
5558
# endif
5659
# if defined(__INTELLISENSE__)
5760
# define STDEXEC_INTELLISENSE(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
5861
# define STDEXEC_MSVC_HEADERS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
5962
# endif
6063
#elif defined(__clang__)
6164
# define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
65+
# define STDEXEC_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
6266
# if defined(_MSC_VER)
6367
# define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
6468
# endif
6569
# if defined(__apple_build_version__)
6670
# define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
71+
// Apple clang version is encoded as major * 1000000 + minor * 1000 + patch. We ignore the patch
72+
// version here, as it is not relevant for the purposes of this library.
73+
# define STDEXEC_APPLE_CLANG_VERSION (__apple_build_version__ / 1000)
6774
# endif
6875
#elif defined(__GNUC__)
6976
# define STDEXEC_GCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
77+
# define STDEXEC_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
7078
#elif defined(_MSC_VER)
7179
# define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
7280
# define STDEXEC_MSVC_HEADERS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
81+
# define STDEXEC_MSVC_VERSION _MSC_VER
7382
#endif
7483

7584
#ifndef STDEXEC_NVCC
@@ -103,10 +112,6 @@
103112
# define STDEXEC_INTELLISENSE(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
104113
#endif
105114

106-
#if STDEXEC_NVHPC()
107-
# define STDEXEC_NVHPC_VERSION() (__NVCOMPILER_MAJOR__ * 100 + __NVCOMPILER_MINOR__)
108-
#endif
109-
110115
////////////////////////////////////////////////////////////////////////////////////////////////////
111116
#if defined(__CUDACC__) || STDEXEC_NVHPC()
112117
# define STDEXEC_CUDA_COMPILATION(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
@@ -173,13 +178,25 @@ namespace __coro = std::experimental;
173178

174179
#if STDEXEC_NVHPC()
175180
// NVBUG #4067067: NVHPC does not fully support [[no_unique_address]]
176-
# define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/
181+
# if STDEXEC_NVHPC_VERSION < 23'05
182+
# define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/
183+
# else
184+
# define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]]
185+
# endif
186+
#elif STDEXEC_CLANG_CL()
187+
// clang-cl does not support [[no_unique_address]]: https://reviews.llvm.org/D110485
188+
# if STDEXEC_CLANG_VERSION < 18'01 // TODO: Find the version that started supporting [[msvc::no_unique_address]]
189+
# define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/
190+
# else
191+
# define STDEXEC_ATTR_WHICH_3(_ATTR) [[msvc::no_unique_address]]
192+
# endif
177193
#elif STDEXEC_MSVC()
178194
// MSVCBUG https://developercommunity.visualstudio.com/t/Incorrect-codegen-when-using-msvc::no_/10452874
179-
# define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]]
180-
#elif STDEXEC_CLANG_CL()
181-
// clang-cl does not support: https://reviews.llvm.org/D110485
182-
# define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]]
195+
# if STDEXEC_MSVC_VERSION < 19'43
196+
# define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/
197+
# else
198+
# define STDEXEC_ATTR_WHICH_3(_ATTR) [[msvc::no_unique_address]]
199+
# endif
183200
#else
184201
# define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]]
185202
#endif
@@ -190,7 +207,7 @@ namespace __coro = std::experimental;
190207
#elif STDEXEC_CLANG()
191208
# define STDEXEC_ATTR_WHICH_4(_ATTR) \
192209
__attribute__((__always_inline__, __artificial__, __nodebug__)) inline
193-
#elif defined(__GNUC__)
210+
#elif STDEXEC_GCC()
194211
# define STDEXEC_ATTR_WHICH_4(_ATTR) __attribute__((__always_inline__, __artificial__)) inline
195212
#else
196213
# define STDEXEC_ATTR_WHICH_4(_ATTR) /*nothing*/
@@ -272,7 +289,7 @@ namespace __coro = std::experimental;
272289
# define STDEXEC_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable_v<__VA_ARGS__>
273290
#endif
274291

275-
#if STDEXEC_HAS_BUILTIN(__is_base_of) || (_MSC_VER >= 1914)
292+
#if STDEXEC_HAS_BUILTIN(__is_base_of) || (STDEXEC_MSVC_VERSION >= 19'14)
276293
# define STDEXEC_IS_BASE_OF(...) __is_base_of(__VA_ARGS__)
277294
#else
278295
# define STDEXEC_IS_BASE_OF(...) std::is_base_of_v<__VA_ARGS__>
@@ -371,17 +388,19 @@ namespace stdexec {
371388
#endif
372389

373390
// Before gcc-12, gcc really didn't like tuples or variants of immovable types
374-
#if STDEXEC_GCC() && (__GNUC__ < 12)
391+
#if STDEXEC_GCC() && (STDEXEC_GCC_VERSION < 12'00)
375392
# define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&)
376393
#else
377394
# define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) = delete
378395
#endif
379396

397+
#if STDEXEC_GCC()
380398
// BUG (gcc#98995): copy elision fails when initializing a [[no_unique_address]] field
381399
// from a function returning an object of class type by value.
382-
//
383400
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995
384-
#if STDEXEC_GCC()
401+
# define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
402+
#elif STDEXEC_CLANG() && (__clang_major__ >= 15 && __clang_major__ < 19)
403+
// See https://github.com/llvm/llvm-project/issues/93563
385404
# define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
386405
#else
387406
# define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS STDEXEC_ATTRIBUTE(no_unique_address)
@@ -401,7 +420,7 @@ namespace stdexec {
401420
// Some compilers turn on pack indexing in pre-C++26 code. We want to use it if it is
402421
// available. Pack indexing is disabled for clang < 20 because of:
403422
// https://github.com/llvm/llvm-project/issues/116105
404-
#if defined(__cpp_pack_indexing) && !STDEXEC_NVCC() && !(STDEXEC_CLANG() && __clang_major__ < 20)
423+
#if defined(__cpp_pack_indexing) && !STDEXEC_NVCC() && !(STDEXEC_CLANG() && STDEXEC_CLANG_VERSION < 20'00)
405424
# define STDEXEC_HAS_PACK_INDEXING() 1
406425
#else // ^^^ has pack indexing ^^^ / vvv no pack indexing vvv
407426
# define STDEXEC_HAS_PACK_INDEXING() 0
@@ -416,7 +435,7 @@ namespace stdexec {
416435
// Before clang-16, clang did not like libstdc++'s ranges implementation
417436
#if __has_include(<ranges>) && \
418437
(defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L) && \
419-
(!STDEXEC_CLANG() || __clang_major__ >= 16 || defined(_LIBCPP_VERSION))
438+
(!STDEXEC_CLANG() || STDEXEC_CLANG_VERSION >= 16'00 || defined(_LIBCPP_VERSION))
420439
# define STDEXEC_HAS_STD_RANGES() 1
421440
#else
422441
# define STDEXEC_HAS_STD_RANGES() 0
@@ -461,7 +480,7 @@ namespace stdexec {
461480
}
462481

463482
// GCC 13 implements lexical friendship, but it is incomplete. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111018
464-
#if STDEXEC_CLANG() // || (STDEXEC_GCC() && __GNUC__ >= 13)
483+
#if STDEXEC_CLANG() // || (STDEXEC_GCC() && STDEXEC_GCC_VERSION >= 13'00)
465484
# define STDEXEC_FRIENDSHIP_IS_LEXICAL() 1
466485
#else
467486
# define STDEXEC_FRIENDSHIP_IS_LEXICAL() 0
@@ -473,25 +492,7 @@ namespace stdexec {
473492
# define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
474493
#endif
475494

476-
// Configure extra type checking
477-
#define STDEXEC_TYPE_CHECKING_ZERO() 0
478-
#define STDEXEC_TYPE_CHECKING_ONE() 1
479-
#define STDEXEC_TYPE_CHECKING_TWO() 2
480-
481-
#define STDEXEC_PROBE_TYPE_CHECKING_ STDEXEC_TYPE_CHECKING_ONE
482-
#define STDEXEC_PROBE_TYPE_CHECKING_0 STDEXEC_TYPE_CHECKING_ZERO
483-
#define STDEXEC_PROBE_TYPE_CHECKING_1 STDEXEC_TYPE_CHECKING_ONE
484-
#define STDEXEC_PROBE_TYPE_CHECKING_STDEXEC_ENABLE_EXTRA_TYPE_CHECKING STDEXEC_TYPE_CHECKING_TWO
485-
486-
#define STDEXEC_TYPE_CHECKING_WHICH3(...) STDEXEC_PROBE_TYPE_CHECKING_##__VA_ARGS__
487-
#define STDEXEC_TYPE_CHECKING_WHICH2(...) STDEXEC_TYPE_CHECKING_WHICH3(__VA_ARGS__)
488-
#define STDEXEC_TYPE_CHECKING_WHICH STDEXEC_TYPE_CHECKING_WHICH2(STDEXEC_ENABLE_EXTRA_TYPE_CHECKING)
489-
490-
#ifndef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
491-
# define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0
492-
#elif STDEXEC_TYPE_CHECKING_WHICH() == 2
493-
// do nothing
494-
#elif STDEXEC_TYPE_CHECKING_WHICH() == 0
495+
#if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING == 0
495496
# undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
496497
# define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0
497498
#else

include/stdexec/__detail/__connect_awaitable.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ namespace stdexec {
173173
}
174174

175175
template <class _Awaitable, class _Receiver>
176-
# if STDEXEC_GCC() && (__GNUC__ > 11)
176+
# if STDEXEC_GCC() && (STDEXEC_GCC_VERSION >= 12'00)
177177
__attribute__((__used__))
178178
# endif
179179
static auto __co_impl(_Awaitable __awaitable, _Receiver __rcvr) -> __operation_t<_Receiver> {

include/stdexec/__detail/__cpo.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@
8282
# pragma deprecated(STDEXEC_CUSTOM)
8383
#endif
8484

85-
#if STDEXEC_GCC() || (STDEXEC_CLANG() && __clang_major__ < 14)
85+
#if STDEXEC_GCC() || (STDEXEC_CLANG() && STDEXEC_CLANG_VERSION < 14'00)
8686
# define STDEXEC_CUSTOM \
8787
_Pragma("GCC warning \"STDEXEC_CUSTOM is deprecated; use STDEXEC_MEMFN_DECL instead.\"") \
8888
STDEXEC_MEMFN_DECL
8989
#else
9090
# define STDEXEC_CUSTOM STDEXEC_MEMFN_DECL
9191
#endif
9292

93-
#if STDEXEC_CLANG() && __clang_major__ >= 14
93+
#if STDEXEC_CLANG() && STDEXEC_CLANG_VERSION >= 14'00
9494
# pragma clang deprecated(STDEXEC_CUSTOM, "use STDEXEC_MEMFN_DECL instead.")
9595
#endif
9696

0 commit comments

Comments
 (0)