Skip to content

Commit 770f795

Browse files
authored
add a get_completion_behavior query like in P3206 (#1658)
1 parent 15351cc commit 770f795

File tree

10 files changed

+413
-170
lines changed

10 files changed

+413
-170
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright (c) 2025 NVIDIA Corporation
3+
*
4+
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
5+
* (the "License"); you may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* https://llvm.org/LICENSE.txt
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#pragma once
17+
18+
#include <compare>
19+
#include <type_traits>
20+
#include <initializer_list>
21+
22+
#include "__config.hpp"
23+
#include "__concepts.hpp"
24+
#include "__query.hpp"
25+
#include "__meta.hpp"
26+
#include "__execution_fwd.hpp"
27+
#include "__type_traits.hpp"
28+
29+
namespace stdexec {
30+
//////////////////////////////////////////////////////////////////////////////////////////
31+
// get_completion_behavior
32+
namespace __completion_behavior {
33+
enum class completion_behavior : int {
34+
unknown, ///< The completion behavior is unknown.
35+
asynchronous, ///< The operation's completion will not happen on the calling thread before `start()`
36+
///< returns.
37+
synchronous, ///< The operation's completion happens-before the return of `start()`.
38+
inline_completion ///< The operation completes synchronously within `start()` on the same thread that called
39+
///< `start()`.
40+
};
41+
42+
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
43+
constexpr auto operator<=>(completion_behavior __a, completion_behavior __b) noexcept
44+
-> std::strong_ordering {
45+
return static_cast<int>(__a) <=> static_cast<int>(__b);
46+
}
47+
48+
template <completion_behavior _CB>
49+
using __constant_t = std::integral_constant<completion_behavior, _CB>;
50+
51+
using __unknown_t = __constant_t<completion_behavior::unknown>;
52+
using __asynchronous_t = __constant_t<completion_behavior::asynchronous>;
53+
using __synchronous_t = __constant_t<completion_behavior::synchronous>;
54+
using __inline_completion_t = __constant_t<completion_behavior::inline_completion>;
55+
} // namespace __completion_behavior
56+
57+
struct min_t;
58+
59+
struct completion_behavior {
60+
private:
61+
template <__completion_behavior::completion_behavior _CB>
62+
using __constant_t = std::integral_constant<__completion_behavior::completion_behavior, _CB>;
63+
64+
friend struct min_t;
65+
66+
public:
67+
struct unknown_t : __completion_behavior::__unknown_t { };
68+
struct asynchronous_t : __completion_behavior::__asynchronous_t { };
69+
struct synchronous_t : __completion_behavior::__synchronous_t { };
70+
struct inline_completion_t : __completion_behavior::__inline_completion_t { };
71+
72+
static constexpr unknown_t unknown{};
73+
static constexpr asynchronous_t asynchronous{};
74+
static constexpr synchronous_t synchronous{};
75+
static constexpr inline_completion_t inline_completion{};
76+
};
77+
78+
//////////////////////////////////////////////////////////////////////////////////////////
79+
// get_completion_behavior: A sender can define this attribute to describe the sender's
80+
// completion behavior
81+
struct get_completion_behavior_t
82+
: __query<get_completion_behavior_t, completion_behavior::unknown, __q1<__decay_t>> {
83+
template <class _Attrs, class... _Env>
84+
STDEXEC_ATTRIBUTE(always_inline, host, device)
85+
static constexpr void __validate() noexcept {
86+
static_assert(
87+
__nothrow_queryable_with<_Attrs, get_completion_behavior_t, _Env...>,
88+
"The get_completion_behavior query must be noexcept.");
89+
static_assert(
90+
convertible_to<
91+
__query_result_t<_Attrs, get_completion_behavior_t, _Env...>,
92+
__completion_behavior::completion_behavior
93+
>,
94+
"The get_completion_behavior query must return one of the static member variables in "
95+
"execution::completion_behavior.");
96+
}
97+
98+
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
99+
static constexpr auto query(forwarding_query_t) noexcept -> bool {
100+
return true;
101+
}
102+
};
103+
104+
struct min_t {
105+
using __completion_behavior_t = __completion_behavior::completion_behavior;
106+
107+
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
108+
static constexpr auto __minimum(std::initializer_list<__completion_behavior_t> __cbs) noexcept
109+
-> __completion_behavior_t {
110+
auto __result = __completion_behavior::completion_behavior::inline_completion;
111+
for (auto __cb: __cbs) {
112+
if (__cb < __result) {
113+
__result = __cb;
114+
}
115+
}
116+
return __result;
117+
}
118+
119+
template <__completion_behavior_t... _CBs>
120+
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
121+
constexpr auto operator()(completion_behavior::__constant_t<_CBs>...) const noexcept {
122+
constexpr auto __behavior = __minimum({_CBs...});
123+
124+
if constexpr (__behavior == completion_behavior::unknown) {
125+
return completion_behavior::unknown;
126+
} else if constexpr (__behavior == completion_behavior::asynchronous) {
127+
return completion_behavior::asynchronous;
128+
} else if constexpr (__behavior == completion_behavior::synchronous) {
129+
return completion_behavior::synchronous;
130+
} else if constexpr (__behavior == completion_behavior::inline_completion) {
131+
return completion_behavior::inline_completion;
132+
}
133+
STDEXEC_UNREACHABLE();
134+
}
135+
};
136+
137+
constexpr min_t min{};
138+
139+
template <class _Attrs, class... _Env>
140+
concept __completes_inline =
141+
(__call_result_t<get_completion_behavior_t, const _Attrs&, const _Env&...>{}
142+
== completion_behavior::inline_completion);
143+
144+
template <class _Sndr, class... _Env>
145+
STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device)
146+
consteval auto get_completion_behavior() noexcept {
147+
using __behavior_t =
148+
__call_result_t<get_completion_behavior_t, env_of_t<_Sndr>, const _Env&...>;
149+
return __behavior_t{};
150+
}
151+
152+
} // namespace stdexec

0 commit comments

Comments
 (0)