Skip to content

Commit 6fa341a

Browse files
authored
future-proof and constexpr-ify task and parallel scheduler (#1852)
1 parent 044d43b commit 6fa341a

File tree

4 files changed

+98
-118
lines changed

4 files changed

+98
-118
lines changed

include/stdexec/__detail/__parallel_scheduler.hpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,28 +57,29 @@ namespace STDEXEC {
5757
: __rcvr_{static_cast<_Rcvr&&>(__rcvr)} {
5858
}
5959

60-
void set_value() noexcept override {
60+
constexpr void set_value() noexcept override {
6161
STDEXEC::set_value(std::forward<_Rcvr>(__rcvr_));
6262
}
6363

64-
void set_error(std::exception_ptr&& __ex) noexcept override {
64+
STDEXEC_CONSTEXPR_CXX23 void set_error(std::exception_ptr __ex) noexcept override {
6565
STDEXEC::set_error(std::forward<_Rcvr>(__rcvr_), std::move(__ex));
6666
}
6767

68-
void set_stopped() noexcept override {
68+
constexpr void set_stopped() noexcept override {
6969
STDEXEC::set_stopped(std::forward<_Rcvr>(__rcvr_));
7070
}
7171

7272
protected:
73-
void __query_env(__type_index __query_type, __type_index __value_type, void* __dest)
73+
constexpr void __query_env(__type_index __query_type, __type_index __value_type, void* __dest)
7474
const noexcept override {
7575
if (__query_type == __mtypeid<get_stop_token_t>) {
7676
__query(get_stop_token, __value_type, __dest);
7777
}
7878
}
7979

8080
private:
81-
void __query(get_stop_token_t, __type_index __value_type, void* __dest) const noexcept {
81+
constexpr void
82+
__query(get_stop_token_t, __type_index __value_type, void* __dest) const noexcept {
8283
using __stop_token_t = stop_token_of_t<env_of_t<_Rcvr>>;
8384
if constexpr (std::is_same_v<inplace_stop_token, __stop_token_t>) {
8485
if (__value_type == __mtypeid<inplace_stop_token>) {
@@ -89,7 +90,7 @@ namespace STDEXEC {
8990
}
9091

9192
public:
92-
STDEXEC_ATTRIBUTE(no_unique_address)
93+
STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
9394
_Rcvr __rcvr_;
9495
};
9596

@@ -119,7 +120,8 @@ namespace STDEXEC {
119120
/// sender algorithms such as `bulk_chunked` and `bulk_unchunked`.
120121
struct __parallel_scheduler_domain : default_domain {
121122
template <__bulk_chunked_or_unchunked _Sender, class _Env>
122-
auto transform_sender(set_value_t, _Sender&& __sndr, const _Env& __env) const noexcept;
123+
constexpr auto
124+
transform_sender(set_value_t, _Sender&& __sndr, const _Env& __env) const noexcept;
123125
};
124126

125127
namespace __detail {
@@ -318,7 +320,7 @@ namespace STDEXEC {
318320

319321
/// Implementation __detail. Constructs the scheduler to wrap `__impl`.
320322
explicit parallel_scheduler(__detail::__backend_ptr_t&& __impl)
321-
: __impl_(__impl) {
323+
: __impl_(std::move(__impl)) {
322324
}
323325

324326
/// The underlying implementation of the scheduler.
@@ -728,7 +730,7 @@ namespace STDEXEC {
728730
};
729731

730732
template <__bulk_chunked_or_unchunked _Sender, class _Env>
731-
auto
733+
constexpr auto
732734
__parallel_scheduler_domain::transform_sender(set_value_t, _Sender&& __sndr, const _Env& __env)
733735
const noexcept {
734736
if constexpr (__completes_on<_Sender, parallel_scheduler, _Env>) {

include/stdexec/__detail/__parallel_scheduler_backend.hpp

Lines changed: 39 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -36,76 +36,69 @@ STDEXEC_PRAGMA_IGNORE_MSVC(4702) // warning C4702: unreachable code
3636
namespace STDEXEC {
3737
class task_scheduler;
3838

39-
// namespace __detail {
40-
// struct __env_proxy : __immovable {
41-
// [[nodiscard]]
42-
// virtual auto query(const get_stop_token_t&) const noexcept -> inplace_stop_token = 0;
43-
// [[nodiscard]]
44-
// virtual auto query(const get_allocator_t&) const noexcept -> __any_allocator<std::byte> = 0;
45-
// [[nodiscard]]
46-
// virtual auto query(const get_scheduler_t&) const noexcept -> task_scheduler = 0;
47-
// };
48-
// } // namespace __detail
49-
5039
namespace system_context_replaceability {
5140
/// Interface for completing a sender operation. Backend will call frontend though
5241
/// this interface for completing the `schedule` and `schedule_bulk` operations.
5342
class receiver_proxy { //: __detail::__env_proxy {
5443
public:
55-
virtual ~receiver_proxy() = 0;
56-
57-
virtual void set_value() noexcept = 0;
58-
virtual void set_error(std::exception_ptr&&) noexcept = 0;
59-
virtual void set_stopped() noexcept = 0;
44+
virtual constexpr ~receiver_proxy() = 0;
6045

61-
// // NOT TO SPEC:
62-
// [[nodiscard]]
63-
// auto get_env() const noexcept -> const __detail::__env_proxy& {
64-
// return *this;
65-
// }
46+
virtual constexpr void set_value() noexcept = 0;
47+
virtual STDEXEC_CONSTEXPR_CXX23 void set_error(std::exception_ptr) noexcept = 0;
48+
virtual constexpr void set_stopped() noexcept = 0;
6649

6750
/// Query the receiver for a property of type `_P`.
68-
template <class _P, __class _Query>
69-
auto try_query(_Query) const noexcept -> std::optional<_P> {
70-
std::optional<_P> __p;
71-
__query_env(__mtypeid<_Query>, __mtypeid<_P>, &__p);
51+
template <class _Value, __class _Query>
52+
constexpr auto try_query(_Query) const noexcept -> std::optional<_Value> {
53+
std::optional<_Value> __p;
54+
__query_env(__mtypeid<_Query>, __mtypeid<_Value>, &__p);
7255
return __p;
7356
}
7457

7558
protected:
76-
virtual void __query_env(__type_index, __type_index, void*) const noexcept = 0;
59+
virtual constexpr void __query_env(__type_index, __type_index, void*) const noexcept = 0;
7760
};
7861

79-
inline receiver_proxy::~receiver_proxy() = default;
62+
inline constexpr receiver_proxy::~receiver_proxy() = default;
8063

8164
struct bulk_item_receiver_proxy : receiver_proxy {
82-
virtual void execute(size_t, size_t) noexcept = 0;
65+
virtual constexpr void execute(size_t, size_t) noexcept = 0;
8366
};
8467

8568
/// Interface for the parallel scheduler backend.
8669
struct parallel_scheduler_backend {
87-
virtual ~parallel_scheduler_backend() = 0;
70+
virtual constexpr ~parallel_scheduler_backend() = 0;
71+
72+
/// Future-proofing: in case we need to add more virtual functions, we can use this
73+
/// to query for additional interfaces without breaking ABI.
74+
[[nodiscard]]
75+
virtual constexpr auto __query_interface(__type_index __id) const noexcept -> void* {
76+
if (__id == __mtypeid<parallel_scheduler_backend>) {
77+
return const_cast<parallel_scheduler_backend*>(this);
78+
}
79+
return nullptr;
80+
}
8881

8982
/// Schedule work on parallel scheduler, calling `__r` when done and using `__s` for preallocated
9083
/// memory.
91-
virtual void schedule(receiver_proxy&, std::span<std::byte>) noexcept = 0;
84+
virtual constexpr void schedule(receiver_proxy&, std::span<std::byte>) noexcept = 0;
9285

9386
/// Schedule bulk work of size `__n` on parallel scheduler, calling `__r` for different
9487
/// subranges of [0, __n), and using `__s` for preallocated memory.
95-
virtual void schedule_bulk_chunked(
88+
virtual constexpr void schedule_bulk_chunked(
9689
std::size_t,
9790
bulk_item_receiver_proxy&,
9891
std::span<std::byte>) noexcept = 0;
9992

10093
/// Schedule bulk work of size `__n` on parallel scheduler, calling `__r` for each item, and
10194
/// using `__s` for preallocated memory.
102-
virtual void schedule_bulk_unchunked(
95+
virtual constexpr void schedule_bulk_unchunked(
10396
std::size_t,
10497
bulk_item_receiver_proxy&,
10598
std::span<std::byte>) noexcept = 0;
10699
};
107100

108-
inline parallel_scheduler_backend::~parallel_scheduler_backend() = default;
101+
inline constexpr parallel_scheduler_backend::~parallel_scheduler_backend() = default;
109102
} // namespace system_context_replaceability
110103

111104
namespace __detail {
@@ -116,20 +109,20 @@ namespace STDEXEC {
116109
public:
117110
using receiver_concept = receiver_t;
118111

119-
explicit __receiver_proxy_base(_Rcvr rcvr) noexcept
112+
constexpr explicit __receiver_proxy_base(_Rcvr rcvr) noexcept
120113
: __rcvr_(static_cast<_Rcvr&&>(rcvr)) {
121114
}
122115

123-
void set_error(std::exception_ptr&& eptr) noexcept final {
116+
STDEXEC_CONSTEXPR_CXX23 void set_error(std::exception_ptr eptr) noexcept final {
124117
STDEXEC::set_error(std::move(__rcvr_), std::move(eptr));
125118
}
126119

127-
void set_stopped() noexcept final {
120+
constexpr void set_stopped() noexcept final {
128121
STDEXEC::set_stopped(std::move(__rcvr_));
129122
}
130123

131124
protected:
132-
void __query_env(__type_index __query_id, __type_index __value, void* __dest)
125+
constexpr void __query_env(__type_index __query_id, __type_index __value, void* __dest)
133126
const noexcept final {
134127
if (__query_id == __mtypeid<get_stop_token_t>) {
135128
__query(get_stop_token, __value, __dest);
@@ -139,7 +132,7 @@ namespace STDEXEC {
139132
}
140133

141134
private:
142-
void __query(get_stop_token_t, __type_index __value_type, void* __dest) const noexcept {
135+
constexpr void __query(get_stop_token_t, __type_index __value_type, void* __dest) const noexcept {
143136
using __stop_token_t = stop_token_of_t<env_of_t<_Rcvr>>;
144137
if constexpr (std::is_same_v<inplace_stop_token, __stop_token_t>) {
145138
if (__value_type == __mtypeid<inplace_stop_token>) {
@@ -149,7 +142,7 @@ namespace STDEXEC {
149142
}
150143
}
151144

152-
void __query(get_allocator_t, __type_index __value_type, void* __dest) const noexcept {
145+
constexpr void __query(get_allocator_t, __type_index __value_type, void* __dest) const noexcept {
153146
if (__value_type == __mtypeid<__any_allocator<std::byte>>) {
154147
using __dest_t = std::optional<__any_allocator<std::byte>>;
155148
constexpr auto __get_alloc = __with_default(get_allocator, std::allocator<std::byte>());
@@ -159,39 +152,16 @@ namespace STDEXEC {
159152
}
160153
}
161154

162-
// [[nodiscard]]
163-
// auto query(const get_stop_token_t&) const noexcept -> inplace_stop_token final {
164-
// if constexpr (__callable<const get_stop_token_t&, env_of_t<_Rcvr>>) {
165-
// if constexpr (__same_as<stop_token_of_t<env_of_t<_Rcvr>>, inplace_stop_token>) {
166-
// return get_stop_token(get_env(__rcvr_));
167-
// }
168-
// }
169-
// return inplace_stop_token{}; // MSVC thinks this is unreachable. :-?
170-
// }
171-
172-
// [[nodiscard]]
173-
// auto query(const get_allocator_t&) const noexcept -> any_allocator<std::byte> final {
174-
// return any_allocator{
175-
// __with_default(get_allocator, std::allocator<std::byte>())(get_env(__rcvr_))};
176-
// }
177-
178-
// // defined in task_scheduler.cuh:
179-
// [[nodiscard]]
180-
// auto query(const get_scheduler_t& __query) const noexcept -> task_scheduler final;
181-
182155
public:
183156
_Rcvr __rcvr_;
184157
};
185158

186159
template <class _Rcvr>
187160
struct __receiver_proxy
188161
: __receiver_proxy_base<_Rcvr, system_context_replaceability::receiver_proxy> {
189-
using __receiver_proxy_base<
190-
_Rcvr,
191-
system_context_replaceability::receiver_proxy
192-
>::__receiver_proxy_base;
162+
using __receiver_proxy::__receiver_proxy_base::__receiver_proxy_base;
193163

194-
void set_value() noexcept final {
164+
constexpr void set_value() noexcept final {
195165
STDEXEC::set_value(std::move(this->__rcvr_));
196166
}
197167
};
@@ -205,26 +175,26 @@ namespace STDEXEC {
205175
using receiver_concept = receiver_t;
206176
using __delete_fn_t = void(void*) noexcept;
207177

208-
void set_value() noexcept {
178+
constexpr void set_value() noexcept {
209179
auto& __proxy = __rcvr_proxy_;
210180
__delete_fn_(__opstate_storage_); // NB: destroys *this
211181
__proxy.set_value();
212182
}
213183

214-
void set_error(std::exception_ptr eptr) noexcept {
184+
STDEXEC_CONSTEXPR_CXX23 void set_error(std::exception_ptr __eptr) noexcept {
215185
auto& __proxy = __rcvr_proxy_;
216186
__delete_fn_(__opstate_storage_); // NB: destroys *this
217-
__proxy.set_error(std::move(eptr));
187+
__proxy.set_error(std::move(__eptr));
218188
}
219189

220-
void set_stopped() noexcept {
190+
constexpr void set_stopped() noexcept {
221191
auto& __proxy = __rcvr_proxy_;
222192
__delete_fn_(__opstate_storage_); // NB: destroys *this
223193
__proxy.set_stopped();
224194
}
225195

226196
[[nodiscard]]
227-
auto get_env() const noexcept -> env_of_t<_RcvrProxy> {
197+
constexpr auto get_env() const noexcept -> env_of_t<_RcvrProxy> {
228198
return STDEXEC::get_env(__rcvr_proxy_);
229199
}
230200

0 commit comments

Comments
 (0)