Skip to content

Commit a352ca5

Browse files
committed
try to fix GNU and MSVC compilers
1 parent 92021e1 commit a352ca5

File tree

4 files changed

+153
-140
lines changed

4 files changed

+153
-140
lines changed

include/stdexec/__detail/__parallel_scheduler.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,7 @@ namespace STDEXEC {
671671
};
672672

673673
inline auto get_parallel_scheduler() -> parallel_scheduler {
674+
STDEXEC_ASSERT(&system_context_replaceability::query_parallel_scheduler_backend != nullptr);
674675
auto __impl = system_context_replaceability::query_parallel_scheduler_backend();
675676
if (!__impl) {
676677
STDEXEC_THROW(std::runtime_error{"No system context implementation found"});

include/stdexec/__detail/__parallel_scheduler_backend.hpp

Lines changed: 143 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,27 @@
3333
STDEXEC_PRAGMA_PUSH()
3434
STDEXEC_PRAGMA_IGNORE_MSVC(4702) // warning C4702: unreachable code
3535

36+
// For weak linking to work on Windows, we must leave query_parallel_scheduler_backend
37+
// undefined, and in a separate translation unit, provide a default implementation with a
38+
// different name, and then use a linker directive to alias the weak symbol to the default
39+
// implementation. For this, it is necessary to utter the mangled names of both
40+
// query_parallel_scheduler_backend and __default_query_parallel_scheduler_backend. We
41+
// don't want the mangled name to depend on the value of the STDEXEC macro, so we put both
42+
// functions in a separate namespace.
43+
#if STDEXEC_MSVC()
44+
namespace STDEXEC::system_context_replaceability {
45+
}
46+
namespace __system_context_replaceability {
47+
using namespace STDEXEC::system_context_replaceability;
48+
} // namespace __system_context_replaceability
49+
namespace STDEXEC::system_context_replaceability {
50+
using namespace ::__system_context_replaceability;
51+
} // namespace STDEXEC::system_context_replaceability
52+
# define STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE __system_context_replaceability
53+
#else
54+
# define STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE STDEXEC::system_context_replaceability
55+
#endif
56+
3657
namespace STDEXEC {
3758
class task_scheduler;
3859

@@ -95,9 +116,7 @@ namespace STDEXEC {
95116
// Give parallel_scheduler_backend a mangled name that does not depend on the value of the
96117
// STDEXEC macro. This is so that we can use weak linking to make
97118
// query_parallel_scheduler_backend replaceable.
98-
namespace __system_context_replaceability {
99-
using namespace STDEXEC::system_context_replaceability;
100-
119+
namespace STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE {
101120
/// Interface for the parallel scheduler backend.
102121
struct parallel_scheduler_backend : __parallel_scheduler_backend_base {
103122
/// Schedule work on parallel scheduler, calling `__r` when done and using `__s` for preallocated
@@ -118,138 +137,132 @@ namespace __system_context_replaceability {
118137
bulk_item_receiver_proxy&,
119138
std::span<std::byte>) noexcept = 0;
120139
};
121-
} // namespace __system_context_replaceability
122-
123-
namespace STDEXEC {
124-
namespace system_context_replaceability {
125-
using namespace ::__system_context_replaceability;
126-
} // namespace system_context_replaceability
127-
128-
namespace __detail {
129-
// Partially implements the _RcvrProxy interface (either receiver_proxy or
130-
// bulk_item_receiver_proxy) in terms of a concrete receiver type _Rcvr.
131-
template <class _Rcvr, class _RcvrProxy>
132-
struct __receiver_proxy_base : _RcvrProxy {
133-
public:
134-
using receiver_concept = receiver_t;
135-
136-
explicit __receiver_proxy_base(_Rcvr rcvr) noexcept
137-
: __rcvr_(static_cast<_Rcvr&&>(rcvr)) {
138-
}
139-
140-
void set_error(std::exception_ptr&& eptr) noexcept final {
141-
STDEXEC::set_error(std::move(__rcvr_), std::move(eptr));
142-
}
143-
144-
void set_stopped() noexcept final {
145-
STDEXEC::set_stopped(std::move(__rcvr_));
146-
}
147-
148-
protected:
149-
void __query_env(__type_index __query_id, __type_index __value, void* __dest)
150-
const noexcept final {
151-
if (__query_id == __mtypeid<get_stop_token_t>) {
152-
__query(get_stop_token, __value, __dest);
153-
} else if (__query_id == __mtypeid<get_allocator_t>) {
154-
__query(get_allocator, __value, __dest);
155-
}
140+
} // namespace STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE
141+
142+
namespace STDEXEC::__detail {
143+
// Partially implements the _RcvrProxy interface (either receiver_proxy or
144+
// bulk_item_receiver_proxy) in terms of a concrete receiver type _Rcvr.
145+
template <class _Rcvr, class _RcvrProxy>
146+
struct __receiver_proxy_base : _RcvrProxy {
147+
public:
148+
using receiver_concept = receiver_t;
149+
150+
explicit __receiver_proxy_base(_Rcvr rcvr) noexcept
151+
: __rcvr_(static_cast<_Rcvr&&>(rcvr)) {
152+
}
153+
154+
void set_error(std::exception_ptr&& eptr) noexcept final {
155+
STDEXEC::set_error(std::move(__rcvr_), std::move(eptr));
156+
}
157+
158+
void set_stopped() noexcept final {
159+
STDEXEC::set_stopped(std::move(__rcvr_));
160+
}
161+
162+
protected:
163+
void __query_env(__type_index __query_id, __type_index __value, void* __dest)
164+
const noexcept final {
165+
if (__query_id == __mtypeid<get_stop_token_t>) {
166+
__query(get_stop_token, __value, __dest);
167+
} else if (__query_id == __mtypeid<get_allocator_t>) {
168+
__query(get_allocator, __value, __dest);
156169
}
157-
158-
private:
159-
void __query(get_stop_token_t, __type_index __value_type, void* __dest) const noexcept {
160-
using __stop_token_t = stop_token_of_t<env_of_t<_Rcvr>>;
161-
if constexpr (std::is_same_v<inplace_stop_token, __stop_token_t>) {
162-
if (__value_type == __mtypeid<inplace_stop_token>) {
163-
using __dest_t = std::optional<inplace_stop_token>;
164-
*static_cast<__dest_t*>(__dest) = STDEXEC::get_stop_token(STDEXEC::get_env(__rcvr_));
165-
}
166-
}
167-
}
168-
169-
void __query(get_allocator_t, __type_index __value_type, void* __dest) const noexcept {
170-
if (__value_type == __mtypeid<__any_allocator<std::byte>>) {
171-
using __dest_t = std::optional<__any_allocator<std::byte>>;
172-
constexpr auto __get_alloc = __with_default(get_allocator, std::allocator<std::byte>());
173-
auto __alloc = STDEXEC::__rebind_allocator<std::byte>(
174-
__get_alloc(STDEXEC::get_env(__rcvr_)));
175-
*static_cast<__dest_t*>(__dest) = __any_allocator{std::move(__alloc)};
170+
}
171+
172+
private:
173+
void __query(get_stop_token_t, __type_index __value_type, void* __dest) const noexcept {
174+
using __stop_token_t = stop_token_of_t<env_of_t<_Rcvr>>;
175+
if constexpr (std::is_same_v<inplace_stop_token, __stop_token_t>) {
176+
if (__value_type == __mtypeid<inplace_stop_token>) {
177+
using __dest_t = std::optional<inplace_stop_token>;
178+
*static_cast<__dest_t*>(__dest) = STDEXEC::get_stop_token(STDEXEC::get_env(__rcvr_));
176179
}
177180
}
178-
179-
// [[nodiscard]]
180-
// auto query(const get_stop_token_t&) const noexcept -> inplace_stop_token final {
181-
// if constexpr (__callable<const get_stop_token_t&, env_of_t<_Rcvr>>) {
182-
// if constexpr (__same_as<stop_token_of_t<env_of_t<_Rcvr>>, inplace_stop_token>) {
183-
// return get_stop_token(get_env(__rcvr_));
184-
// }
185-
// }
186-
// return inplace_stop_token{}; // MSVC thinks this is unreachable. :-?
187-
// }
188-
189-
// [[nodiscard]]
190-
// auto query(const get_allocator_t&) const noexcept -> any_allocator<std::byte> final {
191-
// return any_allocator{
192-
// __with_default(get_allocator, std::allocator<std::byte>())(get_env(__rcvr_))};
193-
// }
194-
195-
// // defined in task_scheduler.cuh:
196-
// [[nodiscard]]
197-
// auto query(const get_scheduler_t& __query) const noexcept -> task_scheduler final;
198-
199-
public:
200-
_Rcvr __rcvr_;
201-
};
202-
203-
template <class _Rcvr>
204-
struct __receiver_proxy
205-
: __receiver_proxy_base<_Rcvr, system_context_replaceability::receiver_proxy> {
206-
using __receiver_proxy_base<
207-
_Rcvr,
208-
system_context_replaceability::receiver_proxy
209-
>::__receiver_proxy_base;
210-
211-
void set_value() noexcept final {
212-
STDEXEC::set_value(std::move(this->__rcvr_));
213-
}
214-
};
215-
216-
// A receiver type that forwards its completion operations to a _RcvrProxy member held
217-
// by reference (where _RcvrProxy is one of receiver_proxy or
218-
// bulk_item_receiver_proxy). It is also responsible for destroying and, if necessary,
219-
// deallocating the operation state.
220-
template <class _RcvrProxy>
221-
struct __proxy_receiver {
222-
using receiver_concept = receiver_t;
223-
using __delete_fn_t = void(void*) noexcept;
224-
225-
void set_value() noexcept {
226-
auto& __proxy = __rcvr_proxy_;
227-
__delete_fn_(__opstate_storage_); // NB: destroys *this
228-
__proxy.set_value();
229-
}
230-
231-
void set_error(std::exception_ptr eptr) noexcept {
232-
auto& __proxy = __rcvr_proxy_;
233-
__delete_fn_(__opstate_storage_); // NB: destroys *this
234-
__proxy.set_error(std::move(eptr));
235-
}
236-
237-
void set_stopped() noexcept {
238-
auto& __proxy = __rcvr_proxy_;
239-
__delete_fn_(__opstate_storage_); // NB: destroys *this
240-
__proxy.set_stopped();
181+
}
182+
183+
void __query(get_allocator_t, __type_index __value_type, void* __dest) const noexcept {
184+
if (__value_type == __mtypeid<__any_allocator<std::byte>>) {
185+
using __dest_t = std::optional<__any_allocator<std::byte>>;
186+
constexpr auto __get_alloc = __with_default(get_allocator, std::allocator<std::byte>());
187+
auto __alloc = STDEXEC::__rebind_allocator<std::byte>(
188+
__get_alloc(STDEXEC::get_env(__rcvr_)));
189+
*static_cast<__dest_t*>(__dest) = __any_allocator{std::move(__alloc)};
241190
}
191+
}
192+
193+
// [[nodiscard]]
194+
// auto query(const get_stop_token_t&) const noexcept -> inplace_stop_token final {
195+
// if constexpr (__callable<const get_stop_token_t&, env_of_t<_Rcvr>>) {
196+
// if constexpr (__same_as<stop_token_of_t<env_of_t<_Rcvr>>, inplace_stop_token>) {
197+
// return get_stop_token(get_env(__rcvr_));
198+
// }
199+
// }
200+
// return inplace_stop_token{}; // MSVC thinks this is unreachable. :-?
201+
// }
202+
203+
// [[nodiscard]]
204+
// auto query(const get_allocator_t&) const noexcept -> any_allocator<std::byte> final {
205+
// return any_allocator{
206+
// __with_default(get_allocator, std::allocator<std::byte>())(get_env(__rcvr_))};
207+
// }
208+
209+
// // defined in task_scheduler.cuh:
210+
// [[nodiscard]]
211+
// auto query(const get_scheduler_t& __query) const noexcept -> task_scheduler final;
212+
213+
public:
214+
_Rcvr __rcvr_;
215+
};
242216

243-
[[nodiscard]]
244-
auto get_env() const noexcept -> env_of_t<_RcvrProxy> {
245-
return STDEXEC::get_env(__rcvr_proxy_);
246-
}
217+
template <class _Rcvr>
218+
struct __receiver_proxy
219+
: __receiver_proxy_base<_Rcvr, system_context_replaceability::receiver_proxy> {
220+
using __receiver_proxy_base<
221+
_Rcvr,
222+
system_context_replaceability::receiver_proxy
223+
>::__receiver_proxy_base;
224+
225+
void set_value() noexcept final {
226+
STDEXEC::set_value(std::move(this->__rcvr_));
227+
}
228+
};
247229

248-
_RcvrProxy& __rcvr_proxy_;
249-
void* __opstate_storage_;
250-
__delete_fn_t* __delete_fn_;
251-
};
252-
} // namespace __detail
253-
} // namespace STDEXEC
230+
// A receiver type that forwards its completion operations to a _RcvrProxy member held
231+
// by reference (where _RcvrProxy is one of receiver_proxy or
232+
// bulk_item_receiver_proxy). It is also responsible for destroying and, if necessary,
233+
// deallocating the operation state.
234+
template <class _RcvrProxy>
235+
struct __proxy_receiver {
236+
using receiver_concept = receiver_t;
237+
using __delete_fn_t = void(void*) noexcept;
238+
239+
void set_value() noexcept {
240+
auto& __proxy = __rcvr_proxy_;
241+
__delete_fn_(__opstate_storage_); // NB: destroys *this
242+
__proxy.set_value();
243+
}
244+
245+
void set_error(std::exception_ptr eptr) noexcept {
246+
auto& __proxy = __rcvr_proxy_;
247+
__delete_fn_(__opstate_storage_); // NB: destroys *this
248+
__proxy.set_error(std::move(eptr));
249+
}
250+
251+
void set_stopped() noexcept {
252+
auto& __proxy = __rcvr_proxy_;
253+
__delete_fn_(__opstate_storage_); // NB: destroys *this
254+
__proxy.set_stopped();
255+
}
256+
257+
[[nodiscard]]
258+
auto get_env() const noexcept -> env_of_t<_RcvrProxy> {
259+
return STDEXEC::get_env(__rcvr_proxy_);
260+
}
261+
262+
_RcvrProxy& __rcvr_proxy_;
263+
void* __opstate_storage_;
264+
__delete_fn_t* __delete_fn_;
265+
};
266+
} // namespace STDEXEC::__detail
254267

255268
STDEXEC_PRAGMA_POP()

include/stdexec/__detail/__system_context_default_impl_entry.hpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,20 @@
2929

3030
#include "__system_context_default_impl.hpp" // IWYU pragma: keep
3131

32-
namespace __system_context_replaceability {
32+
namespace STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE {
3333

3434
#if STDEXEC_MSVC()
3535
/// Get the backend for the parallel scheduler.
3636
/// Users might replace this function.
3737
STDEXEC_SYSTEM_CONTEXT_INLINE auto __default_query_parallel_scheduler_backend() //
3838
-> std::shared_ptr<parallel_scheduler_backend> {
39-
return __system_context_default_impl::__parallel_scheduler_backend_singleton
39+
return STDEXEC::__system_context_default_impl::__parallel_scheduler_backend_singleton
4040
.__get_current_instance();
4141
}
4242

4343
// If query_parallel_scheduler_backend is defined by the user, it will override the
4444
// default implementation. If not, the linker will resolve to the default implementation.
45-
#pragma comment(linker, "/alternatename:"
45+
# pragma comment(linker, "/alternatename:"
4646
"?query_parallel_scheduler_backend@__system_context_replaceability@@YA?AV?$shared_ptr@Uparallel_scheduler_backend@__system_context_replaceability@@@std@@XZ"
4747
"="
4848
"?__default_query_parallel_scheduler_backend@__system_context_replaceability@@YA?AV?$shared_ptr@Uparallel_scheduler_backend@__system_context_replaceability@@@std@@XZ")
@@ -51,8 +51,7 @@ namespace __system_context_replaceability {
5151

5252
/// Get the backend for the parallel scheduler.
5353
/// Users might replace this function.
54-
extern STDEXEC_SYSTEM_CONTEXT_INLINE STDEXEC_ATTRIBUTE(weak) //
55-
auto query_parallel_scheduler_backend() -> std::shared_ptr<parallel_scheduler_backend> {
54+
auto query_parallel_scheduler_backend() -> std::shared_ptr<parallel_scheduler_backend> {
5655
return STDEXEC::__system_context_default_impl::__parallel_scheduler_backend_singleton
5756
.__get_current_instance();
5857
}
@@ -67,4 +66,4 @@ namespace __system_context_replaceability {
6766
return STDEXEC::__system_context_default_impl::__parallel_scheduler_backend_singleton
6867
.__set_backend_factory(__new_factory);
6968
}
70-
} // namespace __system_context_replaceability
69+
} // namespace STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE

include/stdexec/__detail/__system_context_replaceability_api.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121

2222
#include <memory>
2323

24-
namespace __system_context_replaceability {
24+
namespace STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE {
2525
/// Get the backend for the parallel scheduler.
2626
/// Users might replace this function.
27-
STDEXEC_ATTRIBUTE(weak) auto query_parallel_scheduler_backend()
28-
-> std::shared_ptr<parallel_scheduler_backend>;
27+
STDEXEC_ATTRIBUTE(weak)
28+
auto query_parallel_scheduler_backend() -> std::shared_ptr<parallel_scheduler_backend>;
2929

3030
/// The type of a factory that can create `parallel_scheduler_backend` instances.
3131
/// NOT TO SPEC
@@ -40,4 +40,4 @@ namespace __system_context_replaceability {
4040
"instead.")]]
4141
auto set_parallel_scheduler_backend(__parallel_scheduler_backend_factory_t __new_factory)
4242
-> __parallel_scheduler_backend_factory_t;
43-
} // namespace __system_context_replaceability
43+
} // namespace STDEXEC_SYSTEM_CONTEXT_REPLACEABILITY_NAMESPACE

0 commit comments

Comments
 (0)