Skip to content

Commit ced9d47

Browse files
committed
fix some portability issues
1 parent 3ef2c0a commit ced9d47

File tree

5 files changed

+97
-33
lines changed

5 files changed

+97
-33
lines changed

include/stdexec/__detail/__as_awaitable.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ namespace STDEXEC {
3636
extern const __q<__decayed_std_tuple> __as_single;
3737

3838
template <>
39-
inline const __q<__midentity> __as_single<1>;
39+
inline constexpr __q<__midentity> __as_single<1>;
4040

4141
template <>
42-
inline const __mconst<void> __as_single<0>;
42+
inline constexpr __mconst<void> __as_single<0>;
4343

4444
template <class... _Values>
4545
using __single_value = __minvoke<decltype(__as_single<sizeof...(_Values)>), _Values...>;
4646

4747
template <class _Sender, class _Promise>
4848
using __value_t = __decay_t<
4949
__value_types_of_t<_Sender, env_of_t<_Promise&>, __q<__single_value>, __msingle_or<void>>
50-
>;
50+
>;
5151
} // namespace __detail
5252

5353
/////////////////////////////////////////////////////////////////////////////

include/stdexec/__detail/__task.hpp

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <utility>
3333

3434
namespace STDEXEC {
35+
#if !STDEXEC_NO_STD_COROUTINES()
3536
namespace __task {
3637
////////////////////////////////////////////////////////////////////////////////
3738
// A base class for task::promise_type so it can be specialized when _Ty is void:
@@ -66,7 +67,7 @@ namespace STDEXEC {
6667
return (__total_size / __chunk_size) + (__total_size % __chunk_size != 0);
6768
}
6869

69-
struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) __block {
70+
struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) __memblock {
7071
std::byte __storage_[__STDCPP_DEFAULT_NEW_ALIGNMENT__];
7172
};
7273

@@ -77,10 +78,10 @@ namespace STDEXEC {
7778
template <class _PAlloc>
7879
struct __any_alloc final : __any_alloc_base {
7980
using value_type = std::allocator_traits<_PAlloc>::value_type;
80-
static_assert(__same_as<value_type, __block>);
81-
// Number of __block-sized chunks we needed store the allocator:
81+
static_assert(__same_as<value_type, __memblock>);
82+
// Number of __memblock-sized chunks we needed store the allocator:
8283
static constexpr size_t __alloc_blocks =
83-
__task::__divmod(sizeof(__any_alloc), sizeof(__block));
84+
__task::__divmod(sizeof(__any_alloc), sizeof(__memblock));
8485

8586
explicit __any_alloc(_PAlloc __alloc)
8687
: __alloc_(std::move(__alloc)) {
@@ -91,8 +92,8 @@ namespace STDEXEC {
9192
// overallocated to store the allocator in the blocks immediately following the
9293
// promise object. We now use that allocator to deallocate the entire block of
9394
// memory:
94-
size_t const __promise_blocks = __task::__divmod(__bytes, sizeof(__block));
95-
void* const __alloc_loc = static_cast<__block*>(__ptr) + __promise_blocks;
95+
size_t const __promise_blocks = __task::__divmod(__bytes, sizeof(__memblock));
96+
void* const __alloc_loc = static_cast<__memblock*>(__ptr) + __promise_blocks;
9697

9798
// Quick sanity check to make sure the allocator is where we expect it to be.
9899
STDEXEC_ASSERT(__alloc_loc == static_cast<void*>(this));
@@ -104,7 +105,7 @@ namespace STDEXEC {
104105
std::destroy_at(this);
105106
// Deallocate the entire block of memory:
106107
std::allocator_traits<_PAlloc>::deallocate(
107-
__alloc, static_cast<__block*>(__ptr), __promise_blocks + __alloc_blocks);
108+
__alloc, static_cast<__memblock*>(__ptr), __promise_blocks + __alloc_blocks);
108109
}
109110

110111
_PAlloc __alloc_;
@@ -263,7 +264,7 @@ namespace STDEXEC {
263264
// If the receiver's stop token is different from the task's stop token, then we need
264265
// to set up a callback to request a stop on the task's stop source when the receiver's
265266
// stop token is triggered:
266-
__callback().__construct(
267+
__stop_callback().__construct(
267268
get_stop_token(get_env(__rcvr_)),
268269
__on_stopped_t{__coro_.promise().__stop_.template get<0>()});
269270
}
@@ -299,7 +300,7 @@ namespace STDEXEC {
299300
}
300301
}
301302

302-
auto __callback() noexcept -> __manual_lifetime<__stop_callback_t<_Rcvr>>&
303+
auto __stop_callback() noexcept -> __manual_lifetime<__stop_callback_t<_Rcvr>>&
303304
requires __needs_stop_callback<_Rcvr>
304305
{
305306
return *this;
@@ -309,7 +310,7 @@ namespace STDEXEC {
309310
if constexpr (__needs_stop_callback<_Rcvr>) {
310311
// If we set up a stop callback on the receiver's stop token, then we need to
311312
// disable it when the operation completes:
312-
__callback().__destroy();
313+
__stop_callback().__destroy();
313314
}
314315

315316
std::printf("opstate completed, &__errors_ = %p\n", static_cast<void*>(&this->__errors_));
@@ -338,7 +339,7 @@ namespace STDEXEC {
338339

339340
void __canceled() noexcept final {
340341
if constexpr (__needs_stop_callback<_Rcvr>) {
341-
__callback().__destroy();
342+
__stop_callback().__destroy();
342343
}
343344

344345
std::exchange(__coro_, {}).destroy();
@@ -422,14 +423,14 @@ namespace STDEXEC {
422423

423424
template <class _Alloc, class... _Args>
424425
void* operator new(size_t __bytes, std::allocator_arg_t, _Alloc __alloc, _Args&&...) {
425-
using __palloc_t = std::allocator_traits<_Alloc>::template rebind_alloc<__task::__block>;
426+
using __palloc_t = std::allocator_traits<_Alloc>::template rebind_alloc<__task::__memblock>;
426427
using __pointer_t = std::allocator_traits<__palloc_t>::pointer;
427428
static_assert(std::is_pointer_v<__pointer_t>, "Allocator pointer type must be a raw pointer");
428429

429430
// the number of blocks needed to store an object of type __palloc_t:
430431
static constexpr size_t __alloc_blocks =
431-
__task::__divmod(sizeof(__task::__any_alloc<__palloc_t>), sizeof(__task::__block));
432-
size_t const __promise_blocks = __task::__divmod(__bytes, sizeof(__task::__block));
432+
__task::__divmod(sizeof(__task::__any_alloc<__palloc_t>), sizeof(__task::__memblock));
433+
size_t const __promise_blocks = __task::__divmod(__bytes, sizeof(__task::__memblock));
433434

434435
__palloc_t __palloc(__alloc);
435436
__pointer_t const __ptr =
@@ -447,8 +448,8 @@ namespace STDEXEC {
447448
}
448449

449450
void operator delete(void* __ptr, size_t __bytes) noexcept {
450-
size_t const __promise_blocks = __task::__divmod(__bytes, sizeof(__task::__block));
451-
void* const __alloc_loc = static_cast<__task::__block*>(__ptr) + __promise_blocks;
451+
size_t const __promise_blocks = __task::__divmod(__bytes, sizeof(__task::__memblock));
452+
void* const __alloc_loc = static_cast<__task::__memblock*>(__ptr) + __promise_blocks;
452453
auto* __alloc = static_cast<__task::__any_alloc_base*>(__alloc_loc);
453454
__alloc->__deallocate(__ptr, __bytes);
454455
}
@@ -497,4 +498,5 @@ namespace STDEXEC {
497498
__variant_for<stop_source_type, stop_token_type> __stop_{};
498499
__opstate_base* __state_ = nullptr;
499500
};
501+
#endif // !STDEXEC_NO_STD_COROUTINES()
500502
} // namespace STDEXEC

include/stdexec/__detail/__variant.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,10 @@ namespace STDEXEC {
187187

188188
__destroy();
189189
auto __sg = __mk_index_guard(__index_, __new_index);
190-
auto *__p =
190+
auto *__ptr =
191191
std::construct_at(static_cast<_Ty *>(__get_ptr()), static_cast<_As &&>(__as)...);
192192
__sg.__dismiss();
193-
return *std::launder(__p);
193+
return *std::launder(__ptr);
194194
}
195195

196196
template <std::size_t _Ny, class... _As>
@@ -201,10 +201,10 @@ namespace STDEXEC {
201201

202202
__destroy();
203203
auto __sg = __mk_index_guard(__index_, _Ny);
204-
auto *__p =
204+
auto *__ptr =
205205
std::construct_at(static_cast<__at<_Ny> *>(__get_ptr()), static_cast<_As &&>(__as)...);
206206
__sg.__dismiss();
207-
return *std::launder(__p);
207+
return *std::launder(__ptr);
208208
}
209209

210210
template <std::size_t _Ny, class _Fn, class... _As>
@@ -219,18 +219,18 @@ namespace STDEXEC {
219219
__destroy();
220220
auto __sg = __mk_index_guard(__index_, _Ny);
221221
if (std::is_constant_evaluated()) {
222-
auto *__p = std::construct_at<__at<_Ny>>(
222+
auto *__ptr = std::construct_at<__at<_Ny>>(
223223
static_cast<__at<_Ny> *>(__get_ptr()),
224224
STDEXEC::__emplace_from([&]() noexcept(__is_nothrow) -> decltype(auto) {
225225
return static_cast<_Fn &&>(__fn)(static_cast<_As &&>(__as)...);
226226
}));
227227
__sg.__dismiss();
228-
return *std::launder(__p);
228+
return *std::launder(__ptr);
229229
} else {
230-
auto *__p = ::new (__get_ptr())
230+
auto *__ptr = ::new (__get_ptr())
231231
__at<_Ny>(static_cast<_Fn &&>(__fn)(static_cast<_As &&>(__as)...));
232232
__sg.__dismiss();
233-
return *std::launder(__p);
233+
return *std::launder(__ptr);
234234
}
235235
}
236236

test/stdexec/types/test_task.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,21 @@
1515
* limitations under the License.
1616
*/
1717

18-
#include <stdexec/execution.hpp>
18+
#include <stdexec/coroutine.hpp>
1919

20-
#include <exec/single_thread_context.hpp>
21-
#include <stdexec/__detail/__task.hpp>
20+
#if !STDEXEC_NO_STD_COROUTINES()
2221

23-
#include <atomic>
22+
# include <stdexec/execution.hpp>
2423

25-
#include <catch2/catch.hpp>
24+
# include <exec/single_thread_context.hpp>
25+
# include <stdexec/__detail/__task.hpp>
2626

27-
#include <test_common/allocators.hpp>
27+
# include <atomic>
28+
29+
# include <catch2/catch.hpp>
30+
31+
# include <test_common/allocators.hpp>
32+
# include <test_common/senders.hpp>
2833

2934
namespace ex = STDEXEC;
3035

@@ -135,6 +140,24 @@ namespace {
135140
CHECK(!res.has_value());
136141
}
137142

143+
auto test_task_awaits_just_ref_sender() -> ex::task<void> {
144+
int value = 42;
145+
[[maybe_unused]]
146+
decltype(auto) value_ref = co_await just_ref(value);
147+
// BUGBUG TODO: references are not supported yet so just check that we get the right value back for now
148+
CHECK(value_ref == 42);
149+
// STATIC_REQUIRE(std::same_as<decltype(value_ref), int&>);
150+
// CHECK(&value_ref == &value);
151+
co_return;
152+
}
153+
154+
TEST_CASE("test task can await a just_ref sender", "[types][task]") {
155+
auto t = test_task_awaits_just_ref_sender();
156+
ex::sync_wait(std::move(t));
157+
}
158+
138159
// TODO: add tests for stop token support in task
139160

140161
} // anonymous namespace
162+
163+
#endif // !STDEXEC_NO_STD_COROUTINES()

test/test_common/senders.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,5 +252,44 @@ namespace {
252252
std::shared_ptr<std::atomic<int>> counter_;
253253
};
254254

255+
// A sender that sends by reference
256+
template <class Type>
257+
struct just_ref {
258+
using sender_concept = ex::sender_t;
259+
260+
explicit just_ref(Type& value)
261+
: value_(value) {
262+
}
263+
264+
template <class>
265+
static consteval auto get_completion_signatures() noexcept {
266+
return ex::completion_signatures<ex::set_value_t(Type&)>{};
267+
}
268+
269+
template <class Receiver>
270+
auto connect(Receiver rcvr) const noexcept {
271+
return opstate{value_, static_cast<Receiver&&>(rcvr)};
272+
}
273+
274+
private:
275+
template <class Receiver>
276+
struct opstate {
277+
using operation_state_concept = ex::operation_state_t;
278+
279+
explicit opstate(Type& value, Receiver rcvr)
280+
: value_(value)
281+
, rcvr_(std::move(rcvr)) {
282+
}
283+
284+
void start() noexcept {
285+
ex::set_value(static_cast<Receiver&&>(rcvr_), value_);
286+
}
287+
288+
Type& value_;
289+
Receiver rcvr_;
290+
};
291+
292+
Type& value_;
293+
};
255294

256295
} // namespace

0 commit comments

Comments
 (0)