Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions examples/nvexec/launch.cu
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

#include <thrust/device_vector.h>

constexpr std::size_t N = 2 * 1024;
constexpr std::size_t THREAD_BLOCK_SIZE = 128u;
constexpr std::size_t N = 2ul * 1024ul;
constexpr std::size_t THREAD_BLOCK_SIZE = 128ul;
constexpr std::size_t NUM_BLOCKS = (N + THREAD_BLOCK_SIZE - 1) / THREAD_BLOCK_SIZE;

enum {
Expand All @@ -46,12 +46,13 @@ auto main() -> int {

nvexec::stream_context stream{};

auto snd = stdexec::transfer_just(stream.get_scheduler(), first, last)
auto snd = stdexec::just(first, last) //
| stdexec::continues_on(stream.get_scheduler())
| nvexec::launch(
{.grid_size = NUM_BLOCKS, .block_size = THREAD_BLOCK_SIZE},
[](cudaStream_t, int* first, int* last) {
assert(nvexec::is_on_gpu());
int32_t idx = blockIdx.x * blockDim.x + threadIdx.x;
ptrdiff_t idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < (last - first)) {
first[idx] *= scaling;
}
Expand Down
5 changes: 3 additions & 2 deletions examples/nvexec/reduce.cu
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#include <thrust/device_vector.h>

#include <cstdio>
#include <iostream>
#include <span>

namespace ex = stdexec;
Expand All @@ -32,7 +32,8 @@ auto main() -> int {

nvexec::stream_context stream_ctx{};

auto snd = ex::transfer_just(stream_ctx.get_scheduler(), std::span{first, last})
auto snd = ex::just(std::span{first, last}) //
| ex::continues_on(stream_ctx.get_scheduler()) //
| nvexec::reduce(42.0f);

auto [result] = stdexec::sync_wait(std::move(snd)).value();
Expand Down
25 changes: 12 additions & 13 deletions examples/server_theme/let_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,20 @@
* - optional GPU context that may be used on some types of servers
*
* Specific problem description:
* - we are looking at the flow of processing an HTTP request and sending back
* the response
* - show how one can break the (slightly complex) flow into steps with let_*
* functions
* - different phases of processing HTTP requests are broken down into separate
* concerns
* - each part of the processing might use different execution contexts (details
* not shown in this example)
* - error handling is generic, regardless which component fails; we always send
* the right response to the clients
*
* - we are looking at the flow of processing an HTTP request and sending back the
* response
* - show how one can break the (slightly complex) flow into steps with let_* functions
* - different phases of processing HTTP requests are broken down into separate concerns
* - each part of the processing might use different execution contexts (details not shown
* in this example)
* - error handling is generic, regardless which component fails; we always send the right
* response to the clients
*
* Example goals:
* - show how one can break more complex flows into steps with let_* functions
* - exemplify the use of let_value, let_error, let_stopped, transfer_just and just
* algorithms
* - exemplify the use of let_value, let_error, let_stopped, continues_on and just
* algorithms
*/

#include <iostream>
Expand Down Expand Up @@ -77,7 +76,7 @@ auto schedule_request_start(S sched, int idx) -> ex::sender auto {
std::cout << "HTTP request " << idx << " arrived\n";

// Return a sender for the incoming http_request
return ex::transfer_just(std::forward<S>(sched), std::move(req));
return ex::just(std::move(req)) | ex::continues_on(std::forward<S>(sched));
}

// Sends a response back to the client; yields a void signal on success
Expand Down
2 changes: 1 addition & 1 deletion include/exec/any_sender_of.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ namespace exec {
STDEXEC::inplace_stop_source __stop_source_{};
using __stop_callback = typename STDEXEC::stop_token_of_t<
STDEXEC::env_of_t<_Receiver>
>::template callback_type<__forward_stop_request>;
>::template callback_type<STDEXEC::__forward_stop_request>;
std::optional<__stop_callback> __on_stop_{};
};

Expand Down
10 changes: 5 additions & 5 deletions include/exec/env.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ namespace exec {
};

template <class _Env, class _Query>
struct __without : STDEXEC::__env::__env_base_t<_Env> {
struct __without : STDEXEC::__env_base_t<_Env> {
static_assert(STDEXEC::__nothrow_move_constructible<_Env>);

using STDEXEC::__env::__env_base_t<_Env>::query;
using STDEXEC::__env_base_t<_Env>::query;

STDEXEC_ATTRIBUTE(nodiscard, host, device)
auto query(_Query) const noexcept = delete;
Expand Down Expand Up @@ -168,9 +168,9 @@ namespace exec {
inline constexpr __read_with_default::__read_with_default_t read_with_default{};

[[deprecated("exec::write has been renamed to STDEXEC::write_env")]]
inline constexpr STDEXEC::__write::write_env_t write{};
[[deprecated("write_env has been moved to the STDEXEC:: namespace")]]
inline constexpr STDEXEC::__write::write_env_t write_env{};
inline constexpr STDEXEC::__write_env_t write{};
[[deprecated("exec::write_env has been moved to the STDEXEC:: namespace")]]
inline constexpr STDEXEC::__write_env_t write_env{};

namespace __write_attrs {
using namespace STDEXEC;
Expand Down
2 changes: 1 addition & 1 deletion include/exec/start_now.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ namespace exec {

struct start_now_t {
template <
STDEXEC::queryable _Env,
STDEXEC::__queryable _Env,
exec::__scope::__async_scope _AsyncScope,
STDEXEC::sender... _Sender
>
Expand Down
2 changes: 1 addition & 1 deletion include/exec/task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ namespace exec {

private:
using __scheduler_t =
__query_result_or_t<get_scheduler_t, _Context, STDEXEC::inline_scheduler>;
__call_result_or_t<get_scheduler_t, STDEXEC::inline_scheduler, _Context>;

struct __final_awaitable {
static constexpr auto await_ready() noexcept -> bool {
Expand Down
101 changes: 51 additions & 50 deletions include/stdexec/__detail/__as_awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace STDEXEC {
template <class _Sender, class _Promise>
using __value_t = __decay_t<
__value_types_of_t<_Sender, env_of_t<_Promise&>, __q<__single_value>, __msingle_or<void>>
>;
>;
} // namespace __detail

/////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -185,61 +185,62 @@ namespace STDEXEC {
constexpr void return_void() noexcept;
constexpr auto unhandled_stopped() noexcept -> __std::coroutine_handle<>;
};
} // namespace __as_awaitable

struct as_awaitable_t {
template <class _Tp, class _Promise>
static consteval auto __get_declfn() noexcept {
if constexpr (__connect_await::__has_as_awaitable_member<_Tp, _Promise>) {
using __result_t = decltype(__declval<_Tp>().as_awaitable(__declval<_Promise&>()));
constexpr bool __is_nothrow = noexcept(__declval<_Tp>()
.as_awaitable(__declval<_Promise&>()));
return __declfn<__result_t, __is_nothrow>();
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if constexpr (__awaitable<_Tp, __unspecified>) { // NOT __awaitable<_Tp, _Promise> !!
return __declfn<_Tp&&>();
} else if constexpr (__awaitable_sender<_Tp, _Promise>) {
using __result_t = __sender_awaitable<_Promise, _Tp>;
constexpr bool __is_nothrow =
__nothrow_constructible_from<__result_t, _Tp, __std::coroutine_handle<_Promise>>;
return __declfn<__result_t, __is_nothrow>();
} else {
return __declfn<_Tp&&>();
}
}

template <class _Tp, class _Promise, auto _DeclFn = __get_declfn<_Tp, _Promise>()>
requires __callable<__mtypeof<_DeclFn>>
auto operator()(_Tp&& __t, _Promise& __promise) const noexcept(noexcept(_DeclFn()))
-> decltype(_DeclFn()) {
if constexpr (__connect_await::__has_as_awaitable_member<_Tp, _Promise>) {
using __result_t = decltype(static_cast<_Tp&&>(__t).as_awaitable(__promise));
static_assert(__awaitable<__result_t, _Promise>);
return static_cast<_Tp&&>(__t).as_awaitable(__promise);
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if constexpr (__awaitable<_Tp, __unspecified>) { // NOT __awaitable<_Tp, _Promise> !!
return static_cast<_Tp&&>(__t);
} else if constexpr (__awaitable_sender<_Tp, _Promise>) {
auto __hcoro = __std::coroutine_handle<_Promise>::from_promise(__promise);
return __sender_awaitable<_Promise, _Tp>{static_cast<_Tp&&>(__t), __hcoro};
} else {
return static_cast<_Tp&&>(__t);
}
struct as_awaitable_t {
template <class _Tp, class _Promise>
static consteval auto __get_declfn() noexcept {
using __as_awaitable::__unspecified;
if constexpr (__connect_await::__has_as_awaitable_member<_Tp, _Promise>) {
using __result_t = decltype(__declval<_Tp>().as_awaitable(__declval<_Promise&>()));
constexpr bool __is_nothrow = noexcept(__declval<_Tp>()
.as_awaitable(__declval<_Promise&>()));
return __declfn<__result_t, __is_nothrow>();
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if constexpr (__awaitable<_Tp, __unspecified>) { // NOT __awaitable<_Tp, _Promise> !!
return __declfn<_Tp&&>();
} else if constexpr (__as_awaitable::__awaitable_sender<_Tp, _Promise>) {
using __result_t = __as_awaitable::__sender_awaitable<_Promise, _Tp>;
constexpr bool __is_nothrow =
__nothrow_constructible_from<__result_t, _Tp, __std::coroutine_handle<_Promise>>;
return __declfn<__result_t, __is_nothrow>();
} else {
return __declfn<_Tp&&>();
}
}

template <class _Tp, class _Promise, auto _DeclFn = __get_declfn<_Tp, _Promise>()>
requires __callable<__mtypeof<_DeclFn>> || __tag_invocable<as_awaitable_t, _Tp, _Promise&>
[[deprecated("the use of tag_invoke for as_awaitable is deprecated")]]
auto operator()(_Tp&& __t, _Promise& __promise) const
noexcept(__nothrow_tag_invocable<as_awaitable_t, _Tp, _Promise&>)
-> __tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&> {
using __result_t = __tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&>;
template <class _Tp, class _Promise, auto _DeclFn = __get_declfn<_Tp, _Promise>()>
requires __callable<__mtypeof<_DeclFn>>
auto operator()(_Tp&& __t, _Promise& __promise) const noexcept(noexcept(_DeclFn()))
-> decltype(_DeclFn()) {
using __as_awaitable::__unspecified;
if constexpr (__connect_await::__has_as_awaitable_member<_Tp, _Promise>) {
using __result_t = decltype(static_cast<_Tp&&>(__t).as_awaitable(__promise));
static_assert(__awaitable<__result_t, _Promise>);
return __tag_invoke(*this, static_cast<_Tp&&>(__t), __promise);
return static_cast<_Tp&&>(__t).as_awaitable(__promise);
// NOLINTNEXTLINE(bugprone-branch-clone)
} else if constexpr (__awaitable<_Tp, __unspecified>) { // NOT __awaitable<_Tp, _Promise> !!
return static_cast<_Tp&&>(__t);
} else if constexpr (__as_awaitable::__awaitable_sender<_Tp, _Promise>) {
auto __hcoro = __std::coroutine_handle<_Promise>::from_promise(__promise);
return __as_awaitable::__sender_awaitable<_Promise, _Tp>{static_cast<_Tp&&>(__t), __hcoro};
} else {
return static_cast<_Tp&&>(__t);
}
};
} // namespace __as_awaitable
}

template <class _Tp, class _Promise, auto _DeclFn = __get_declfn<_Tp, _Promise>()>
requires __callable<__mtypeof<_DeclFn>> || __tag_invocable<as_awaitable_t, _Tp, _Promise&>
[[deprecated("the use of tag_invoke for as_awaitable is deprecated")]]
auto operator()(_Tp&& __t, _Promise& __promise) const
noexcept(__nothrow_tag_invocable<as_awaitable_t, _Tp, _Promise&>)
-> __tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&> {
using __result_t = __tag_invoke_result_t<as_awaitable_t, _Tp, _Promise&>;
static_assert(__awaitable<__result_t, _Promise>);
return __tag_invoke(*this, static_cast<_Tp&&>(__t), __promise);
}
};

using __as_awaitable::as_awaitable_t;
inline constexpr as_awaitable_t as_awaitable{};
#endif
} // namespace STDEXEC
4 changes: 2 additions & 2 deletions include/stdexec/__detail/__basic_sender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ namespace STDEXEC {
#else // ^^^ EDG ^^^ / vvv !EDG vvv
# define STDEXEC_SEXPR_DESCRIPTOR_FN(_Descriptor) ([] { return _Descriptor(); })
# define STDEXEC_SEXPR_DESCRIPTOR(_Tag, _Data, _Child) \
STDEXEC::__descriptor_fn_v<STDEXEC::__detail::__desc<_Tag, _Data, _Child>>
STDEXEC::__descriptor_fn_v<STDEXEC::__desc<_Tag, _Data, _Child>>
#endif

#if defined(STDEXEC_DEMANGLE_SENDER_NAMES)
Expand All @@ -59,7 +59,7 @@ namespace STDEXEC {

template <class _Tag, class _Data, class... _Child>
consteval auto __descriptor_fn() noexcept {
return __descriptor_fn_v<__detail::__desc<_Tag, _Data, _Child...>>;
return __descriptor_fn_v<__desc<_Tag, _Data, _Child...>>;
}

template <class _Tag>
Expand Down
47 changes: 17 additions & 30 deletions include/stdexec/__detail/__bulk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ namespace STDEXEC {
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.adaptors.bulk]
namespace __bulk {
struct bulk_t;
struct bulk_chunked_t;
struct bulk_unchunked_t;

//! Wrapper for a policy object.
//!
//! If we wrap a standard execution policy, we don't store anything, as we know the type.
Expand Down Expand Up @@ -240,29 +236,6 @@ namespace STDEXEC {
template <class _Fun>
STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __as_bulk_chunked_fn(_Fun) -> __as_bulk_chunked_fn<_Fun>;

struct bulk_t : __generic_bulk_t<bulk_t> {
struct __transform_sender_fn {
template <class _Data, class _Child>
constexpr auto operator()(__ignore, _Data&& __data, _Child&& __child) const {
// Lower `bulk` to `bulk_chunked`. If `bulk_chunked` is customized, we will see the customization.
return bulk_chunked(
static_cast<_Child&&>(__child),
__data.__pol_.__get(),
__data.__shape_,
__as_bulk_chunked_fn(std::move(__data.__fun_)));
}
};

template <class _Sender>
static constexpr auto transform_sender(set_value_t, _Sender&& __sndr, __ignore) {
return __apply(__transform_sender_fn(), static_cast<_Sender&&>(__sndr));
}
};

struct bulk_chunked_t : __generic_bulk_t<bulk_chunked_t> { };

struct bulk_unchunked_t : __generic_bulk_t<bulk_unchunked_t> { };

template <class _AlgoTag>
struct __impl_base : __sexpr_defaults {
template <class _Sender>
Expand Down Expand Up @@ -356,9 +329,23 @@ namespace STDEXEC {
};
} // namespace __bulk

using __bulk::bulk_t;
using __bulk::bulk_chunked_t;
using __bulk::bulk_unchunked_t;
struct bulk_t : __bulk::__generic_bulk_t<bulk_t> {
template <class _Sender>
static constexpr auto transform_sender(set_value_t, _Sender&& __sndr, __ignore) {
auto& [__tag, __data, __child] = __sndr;
// Lower `bulk` to `bulk_chunked`. If `bulk_chunked` is customized, we will see the customization.
return bulk_chunked(
STDEXEC::__forward_like<_Sender>(__child),
__data.__pol_.__get(),
__data.__shape_,
__bulk::__as_bulk_chunked_fn(STDEXEC::__forward_like<_Sender>(__data).__fun_));
}
};

struct bulk_chunked_t : __bulk::__generic_bulk_t<bulk_chunked_t> { };

struct bulk_unchunked_t : __bulk::__generic_bulk_t<bulk_unchunked_t> { };

inline constexpr bulk_t bulk{};
inline constexpr bulk_chunked_t bulk_chunked{};
inline constexpr bulk_unchunked_t bulk_unchunked{};
Expand Down
Loading
Loading