From 665e3a08792828b110ba9df92b96686144bfc6c6 Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Wed, 5 Jul 2023 11:26:38 -0400 Subject: [PATCH 1/9] Replace C-style cast with move() in let* algos --- include/unifex/let_done.hpp | 2 +- include/unifex/let_error.hpp | 2 +- include/unifex/let_value.hpp | 7 ++++--- include/unifex/let_value_with.hpp | 6 ++++-- include/unifex/let_value_with_stop_source.hpp | 4 +++- include/unifex/let_value_with_stop_token.hpp | 2 ++ 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/unifex/let_done.hpp b/include/unifex/let_done.hpp index 17855843f..69016df00 100644 --- a/include/unifex/let_done.hpp +++ b/include/unifex/let_done.hpp @@ -227,7 +227,7 @@ class _op::type { , receiver_((Receiver2&&)dest) { unifex::activate_union_member_with(sourceOp_, [&] { - return unifex::connect((Source&&)source, source_receiver{this}); + return unifex::connect(std::move(source), source_receiver{this}); }); startedOp_ = 0 + 1; } diff --git a/include/unifex/let_error.hpp b/include/unifex/let_error.hpp index f2ae16f80..6f9901016 100644 --- a/include/unifex/let_error.hpp +++ b/include/unifex/let_error.hpp @@ -264,7 +264,7 @@ class _op::type final { : func_((Func2 &&) func) , receiver_((Receiver2 &&) dest) { unifex::activate_union_member_with(sourceOp_, [&] { - return unifex::connect((Source &&) source, source_receiver{this}); + return unifex::connect(std::move(source), source_receiver{this}); }); } diff --git a/include/unifex/let_value.hpp b/include/unifex/let_value.hpp index 842afb7c1..1aa1ea927 100644 --- a/include/unifex/let_value.hpp +++ b/include/unifex/let_value.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -85,7 +86,7 @@ struct _successor_receiver::type { void set_error(Error error) && noexcept { auto& op = op_; cleanup(); - unifex::set_error(std::move(op.receiver_), (Error &&) error); + unifex::set_error(std::move(op.receiver_), std::move(error)); } private: @@ -178,7 +179,7 @@ struct _predecessor_receiver::type { void set_error(Error error) && noexcept { auto& op = op_; unifex::deactivate_union_member(op.predOp_); - unifex::set_error(std::move(op.receiver_), (Error &&) error); + unifex::set_error(std::move(op.receiver_), std::move(error)); } template(typename CPO) @@ -236,7 +237,7 @@ struct _op::type { receiver_((Receiver2 &&) receiver) { unifex::activate_union_member_with(predOp_, [&] { return unifex::connect( - (Predecessor &&) pred, predecessor_receiver{*this}); + std::move(pred), predecessor_receiver{*this}); }); } diff --git a/include/unifex/let_value_with.hpp b/include/unifex/let_value_with.hpp index 2a13b9634..861002cff 100644 --- a/include/unifex/let_value_with.hpp +++ b/include/unifex/let_value_with.hpp @@ -23,6 +23,8 @@ #include #include +#include + #include namespace unifex { @@ -102,10 +104,10 @@ struct _operation::type { type(StateFactory2&& stateFactory, SuccessorFactory2&& func, Receiver2&& r) : stateFactory_(static_cast(stateFactory)), func_(static_cast(func)), - state_(static_cast(stateFactory_)()), + state_(std::move(stateFactory_)()), innerOp_( unifex::connect( - static_cast(func_)(state_), + std::move(func_)(state_), static_cast(r))) { } diff --git a/include/unifex/let_value_with_stop_source.hpp b/include/unifex/let_value_with_stop_source.hpp index 66d4f9bfc..46c6f806d 100644 --- a/include/unifex/let_value_with_stop_source.hpp +++ b/include/unifex/let_value_with_stop_source.hpp @@ -25,6 +25,8 @@ #include #include +#include + #include namespace unifex { @@ -165,7 +167,7 @@ struct _stop_source_operation::type { nothrow_connectable) { return unifex::connect( static_cast(func)(stopSource_), - receiver_t{*this, static_cast(r)}); + receiver_t{*this, std::move(r)}); } public: diff --git a/include/unifex/let_value_with_stop_token.hpp b/include/unifex/let_value_with_stop_token.hpp index bf9a5069e..843c268b2 100644 --- a/include/unifex/let_value_with_stop_token.hpp +++ b/include/unifex/let_value_with_stop_token.hpp @@ -25,6 +25,8 @@ #include #include +#include + #include namespace unifex { From 69a7ff9150b1078abf3575b81da575582647bc6b Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Wed, 5 Jul 2023 11:33:53 -0400 Subject: [PATCH 2/9] Remove unused state factory from operation --- include/unifex/let_value_with.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/unifex/let_value_with.hpp b/include/unifex/let_value_with.hpp index 861002cff..b87700345 100644 --- a/include/unifex/let_value_with.hpp +++ b/include/unifex/let_value_with.hpp @@ -102,9 +102,8 @@ template struct _operation::type { template type(StateFactory2&& stateFactory, SuccessorFactory2&& func, Receiver2&& r) : - stateFactory_(static_cast(stateFactory)), func_(static_cast(func)), - state_(std::move(stateFactory_)()), + state_(std::forward(stateFactory)()), innerOp_( unifex::connect( std::move(func_)(state_), @@ -115,7 +114,6 @@ struct _operation::type { unifex::start(innerOp_); } - StateFactory stateFactory_; SuccessorFactory func_; callable_result_t state_; connect_result_t< From 9e2815974ded1542e637760363783ac307b742ca Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Wed, 5 Jul 2023 22:15:02 -0400 Subject: [PATCH 3/9] Revert change to let_value_with and add test --- include/unifex/let_value_with.hpp | 4 +++- test/let_value_with_test.cpp | 38 +++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/let_value_with_test.cpp diff --git a/include/unifex/let_value_with.hpp b/include/unifex/let_value_with.hpp index b87700345..956abb127 100644 --- a/include/unifex/let_value_with.hpp +++ b/include/unifex/let_value_with.hpp @@ -102,8 +102,9 @@ template struct _operation::type { template type(StateFactory2&& stateFactory, SuccessorFactory2&& func, Receiver2&& r) : + stateFactory_(std::forward(stateFactory)), func_(static_cast(func)), - state_(std::forward(stateFactory)()), + state_(std::move(stateFactory_)()), innerOp_( unifex::connect( std::move(func_)(state_), @@ -114,6 +115,7 @@ struct _operation::type { unifex::start(innerOp_); } + StateFactory stateFactory_; SuccessorFactory func_; callable_result_t state_; connect_result_t< diff --git a/test/let_value_with_test.cpp b/test/let_value_with_test.cpp new file mode 100644 index 000000000..df046de2b --- /dev/null +++ b/test/let_value_with_test.cpp @@ -0,0 +1,38 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace unifex; + +namespace { +constexpr auto async = [](auto& context, auto&& func) { + return then( + schedule_after(context.get_scheduler(), std::chrono::milliseconds(10)), + (decltype(func))func); +}; +} + +TEST(LetValueWith, StatefulFactory) { + // Verifies the let_value_with operation state holds onto the + // Factory object until the operation is complete. + timed_single_thread_context context; + std::optional result = sync_wait( + let_value(just(), [&] { + return let_value_with([x = std::make_unique(10)]() -> int* { return x.get(); }, [&](int*& v) { + return async(context, [&v]() { return *v; }); + }); + }) + ); + ASSERT_TRUE(!!result); + EXPECT_EQ(*result, 10); +} From f79acfd7f0858a405a5656579b40af6487e4307b Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Wed, 5 Jul 2023 22:31:09 -0400 Subject: [PATCH 4/9] One more test --- test/let_value_with_test.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/let_value_with_test.cpp b/test/let_value_with_test.cpp index df046de2b..2bbf8992d 100644 --- a/test/let_value_with_test.cpp +++ b/test/let_value_with_test.cpp @@ -36,3 +36,16 @@ TEST(LetValueWith, StatefulFactory) { ASSERT_TRUE(!!result); EXPECT_EQ(*result, 10); } + +TEST(LetValueWith, CallOperatorRvalueRefOverload) { + struct Factory { + int operator()() && { + return 10; + } + }; + std::optional result = sync_wait(let_value_with(Factory{}, [&](int& v) { + return just(v); + })); + ASSERT_TRUE(!!result); + EXPECT_EQ(*result, 10); +} From 53ebccaa0c1d9e6275e35ca78eaf7ab9892ed8ff Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Thu, 6 Jul 2023 11:26:55 -0400 Subject: [PATCH 5/9] More fixes - Use forwarding reference in operation constructor - Fix let_error to allow it to be "lvalue connectable" or "multi shot." - Copy two tests from the window thread pool tests into the static_thread_pool_test to provide equivalent on non-Windows tests. --- include/unifex/let_done.hpp | 6 +++--- include/unifex/let_error.hpp | 10 ++++----- test/let_done_test.cpp | 7 ++++++ test/let_error_test.cpp | 7 ++++++ test/static_thread_pool_test.cpp | 37 ++++++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/include/unifex/let_done.hpp b/include/unifex/let_done.hpp index 69016df00..2380ede9d 100644 --- a/include/unifex/let_done.hpp +++ b/include/unifex/let_done.hpp @@ -218,8 +218,8 @@ class _op::type { using final_receiver = final_receiver_type; public: - template - explicit type(Source&& source, Done2&& done, Receiver2&& dest) + template + explicit type(Source2&& source, Done2&& done, Receiver2&& dest) noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v && is_nothrow_connectable_v) @@ -227,7 +227,7 @@ class _op::type { , receiver_((Receiver2&&)dest) { unifex::activate_union_member_with(sourceOp_, [&] { - return unifex::connect(std::move(source), source_receiver{this}); + return unifex::connect(std::forward(source), source_receiver{this}); }); startedOp_ = 0 + 1; } diff --git a/include/unifex/let_error.hpp b/include/unifex/let_error.hpp index 6f9901016..ccea83ce7 100644 --- a/include/unifex/let_error.hpp +++ b/include/unifex/let_error.hpp @@ -256,15 +256,15 @@ class _op::type final { using final_receiver = final_receiver_type; public: - template - explicit type(Source&& source, Func2&& func, Receiver2&& dest) noexcept( + template + explicit type(Source2&& source, Func2&& func, Receiver2&& dest) noexcept( std::is_nothrow_constructible_v&& std::is_nothrow_constructible_v&& is_nothrow_connectable_v) : func_((Func2 &&) func) , receiver_((Receiver2 &&) dest) { unifex::activate_union_member_with(sourceOp_, [&] { - return unifex::connect(std::move(source), source_receiver{this}); + return unifex::connect(std::forward(source), source_receiver{this}); }); } @@ -418,8 +418,8 @@ class _sndr::type final { is_nothrow_connectable_v, SourceReceiver> && std::is_nothrow_constructible_v> && std::is_nothrow_constructible_v, Receiver>) - -> operation_type { - return operation_type{ + -> operation_type, Func, Receiver> { + return operation_type , Func, Receiver>{ static_cast(s).source_, static_cast(s).func_, static_cast(r) diff --git a/test/let_done_test.cpp b/test/let_done_test.cpp index 74f4fe605..10fb15a7e 100644 --- a/test/let_done_test.cpp +++ b/test/let_done_test.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -104,3 +105,9 @@ TEST(TransformDone, WithValue) { EXPECT_TRUE(multiple.has_value()); EXPECT_EQ(*multiple, std::tuple(42, 1, 2)); } + +TEST(TransformDone, LvalueConnectable) { + sync_wait(repeat_effect_until( + let_done(just(), [] { return just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); +} diff --git a/test/let_error_test.cpp b/test/let_error_test.cpp index 158717388..52911f5d2 100644 --- a/test/let_error_test.cpp +++ b/test/let_error_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -173,6 +174,12 @@ TEST(TransformError, SequenceFwd) { EXPECT_EQ(*one, 42); } +TEST(TransformError, LvalueConnectable) { + sync_wait(repeat_effect_until( + let_error(just(), [](auto&&) { return just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); +} + #if !UNIFEX_NO_COROUTINES TEST(TransformError, WithTask) { auto value = let_error( diff --git a/test/static_thread_pool_test.cpp b/test/static_thread_pool_test.cpp index c35b3bf9f..ec408cb32 100644 --- a/test/static_thread_pool_test.cpp +++ b/test/static_thread_pool_test.cpp @@ -16,8 +16,12 @@ #include #include +#include +#include #include +#include #include +#include #include #include #include @@ -62,3 +66,36 @@ TEST(StaticThreadPool, Smoke) { EXPECT_EQ(x, 3); } + +TEST(StaticThreadPool, ScheduleCancelationThreadSafety) { + static_thread_pool tpContext; + auto sch = tpContext.get_scheduler(); + + unifex::sync_wait(unifex::repeat_effect_until( + unifex::let_done( + unifex::stop_when( + unifex::repeat_effect(unifex::schedule(sch)), + unifex::schedule(sch)), + [] { return unifex::just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); + + unifex::sync_wait(unifex::repeat_effect_until( + unifex::let_done( + unifex::let_error( + unifex::stop_when( + unifex::repeat_effect(unifex::schedule(sch)), + unifex::schedule(sch)), + [](auto&&) { return unifex::just(); }), + [] { return unifex::just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); + + unifex::sync_wait(unifex::repeat_effect_until( + unifex::let_error( + unifex::let_done( + unifex::stop_when( + unifex::repeat_effect(unifex::schedule(sch)), + unifex::schedule(sch)), + [] { return unifex::just(); }), + [](auto&&) { return unifex::just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); +} From 908df96ae5000de551924cd4e54f74fe17f93232 Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Thu, 6 Jul 2023 12:21:39 -0400 Subject: [PATCH 6/9] Fix another incorrect move --- include/unifex/let_value.hpp | 6 +++--- test/let_done_test.cpp | 6 +++--- test/let_error_test.cpp | 6 +++--- test/let_value_test.cpp | 11 ++++++++++- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/unifex/let_value.hpp b/include/unifex/let_value.hpp index 1aa1ea927..ea328521b 100644 --- a/include/unifex/let_value.hpp +++ b/include/unifex/let_value.hpp @@ -228,16 +228,16 @@ struct _op::type { template friend struct _successor_receiver; - template + template explicit type( - Predecessor&& pred, + Predecessor2&& pred, SuccessorFactory2&& func, Receiver2&& receiver) : func_((SuccessorFactory2 &&) func), receiver_((Receiver2 &&) receiver) { unifex::activate_union_member_with(predOp_, [&] { return unifex::connect( - std::move(pred), predecessor_receiver{*this}); + std::forward(pred), predecessor_receiver{*this}); }); } diff --git a/test/let_done_test.cpp b/test/let_done_test.cpp index 10fb15a7e..f049350ce 100644 --- a/test/let_done_test.cpp +++ b/test/let_done_test.cpp @@ -107,7 +107,7 @@ TEST(TransformDone, WithValue) { } TEST(TransformDone, LvalueConnectable) { - sync_wait(repeat_effect_until( - let_done(just(), [] { return just(); }), - [n=0]() mutable noexcept { return n++ == 1000; })); + sync_wait(repeat_effect_until( + let_done(just(), [] { return just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); } diff --git a/test/let_error_test.cpp b/test/let_error_test.cpp index 52911f5d2..ff11391bb 100644 --- a/test/let_error_test.cpp +++ b/test/let_error_test.cpp @@ -175,9 +175,9 @@ TEST(TransformError, SequenceFwd) { } TEST(TransformError, LvalueConnectable) { - sync_wait(repeat_effect_until( - let_error(just(), [](auto&&) { return just(); }), - [n=0]() mutable noexcept { return n++ == 1000; })); + sync_wait(repeat_effect_until( + let_error(just(), [](auto&&) { return just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); } #if !UNIFEX_NO_COROUTINES diff --git a/test/let_value_test.cpp b/test/let_value_test.cpp index cbb7edddc..bd55906c4 100644 --- a/test/let_value_test.cpp +++ b/test/let_value_test.cpp @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include + +#include +#include #include #include +#include #include #include #include @@ -281,3 +284,9 @@ TEST(Let, LetValueWithTraitlessPredecessor) { ASSERT_TRUE(ret); EXPECT_EQ(*ret, 42); } + +TEST(Let, LvalueConnectable) { + sync_wait(repeat_effect_until( + let_value(let_done(just(), [] { return just(); }), [] { return just(); }), + [n=0]() mutable noexcept { return n++ == 1000; })); +} From 195503efe598372473ece313b76c6dfa9db31035 Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Thu, 6 Jul 2023 15:23:36 -0400 Subject: [PATCH 7/9] Update test/let_value_test.cpp Co-authored-by: Ian Petersen --- test/let_value_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/let_value_test.cpp b/test/let_value_test.cpp index bd55906c4..e94740a44 100644 --- a/test/let_value_test.cpp +++ b/test/let_value_test.cpp @@ -288,5 +288,5 @@ TEST(Let, LetValueWithTraitlessPredecessor) { TEST(Let, LvalueConnectable) { sync_wait(repeat_effect_until( let_value(let_done(just(), [] { return just(); }), [] { return just(); }), - [n=0]() mutable noexcept { return n++ == 1000; })); + [n=0]() mutable noexcept { return n++ == 5; })); } From cc99df839b045d893e4c7e1a57829696495df7c3 Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Fri, 7 Jul 2023 15:17:49 -0400 Subject: [PATCH 8/9] Use forward with NOLINT and comment, add verification points to tests --- include/unifex/let_done.hpp | 13 ++++++++++--- include/unifex/let_error.hpp | 13 ++++++++++--- test/let_done_test.cpp | 4 +++- test/let_error_test.cpp | 4 +++- test/let_value_test.cpp | 4 +++- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/include/unifex/let_done.hpp b/include/unifex/let_done.hpp index 2380ede9d..4d5aba7be 100644 --- a/include/unifex/let_done.hpp +++ b/include/unifex/let_done.hpp @@ -218,16 +218,23 @@ class _op::type { using final_receiver = final_receiver_type; public: - template - explicit type(Source2&& source, Done2&& done, Receiver2&& dest) + template + explicit type( + Source&& source, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) + Done2&& done, Receiver2&& dest) noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v && is_nothrow_connectable_v) : done_((Done2&&)done) , receiver_((Receiver2&&)dest) { + // Note: 'Source' is not a forawrding reference since it's not deduced + // in this constructor. It can either be a Sender&& or Sender& for + // some concrete type Sender. Here, we want the forwarding behavior when + // the operation is constructed based on the type of Source, even though + // it's not a idiomatic use for std::forward. unifex::activate_union_member_with(sourceOp_, [&] { - return unifex::connect(std::forward(source), source_receiver{this}); + return unifex::connect(std::forward(source), source_receiver{this}); }); startedOp_ = 0 + 1; } diff --git a/include/unifex/let_error.hpp b/include/unifex/let_error.hpp index ccea83ce7..4a4455fe7 100644 --- a/include/unifex/let_error.hpp +++ b/include/unifex/let_error.hpp @@ -256,15 +256,22 @@ class _op::type final { using final_receiver = final_receiver_type; public: - template - explicit type(Source2&& source, Func2&& func, Receiver2&& dest) noexcept( + template + explicit type( + Source&& source, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) + Func2&& func, Receiver2&& dest) noexcept( std::is_nothrow_constructible_v&& std::is_nothrow_constructible_v&& is_nothrow_connectable_v) : func_((Func2 &&) func) , receiver_((Receiver2 &&) dest) { + // Note: 'Source' is not a forawrding reference since it's not deduced + // in this constructor. It can either be a Sender&& or Sender& for + // some concrete type Sender. Here, we want the forwarding behavior when + // the operation is constructed based on the type of Source, even though + // it's not a idiomatic use for std::forward. unifex::activate_union_member_with(sourceOp_, [&] { - return unifex::connect(std::forward(source), source_receiver{this}); + return unifex::connect(std::forward(source), source_receiver{this}); }); } diff --git a/test/let_done_test.cpp b/test/let_done_test.cpp index f049350ce..c9b643fb0 100644 --- a/test/let_done_test.cpp +++ b/test/let_done_test.cpp @@ -107,7 +107,9 @@ TEST(TransformDone, WithValue) { } TEST(TransformDone, LvalueConnectable) { + int n = 0; sync_wait(repeat_effect_until( let_done(just(), [] { return just(); }), - [n=0]() mutable noexcept { return n++ == 1000; })); + [&n]() mutable noexcept { return n++ == 5; })); + EXPECT_EQ(n, 6); } diff --git a/test/let_error_test.cpp b/test/let_error_test.cpp index ff11391bb..59f67cd1e 100644 --- a/test/let_error_test.cpp +++ b/test/let_error_test.cpp @@ -175,9 +175,11 @@ TEST(TransformError, SequenceFwd) { } TEST(TransformError, LvalueConnectable) { + int n = 0; sync_wait(repeat_effect_until( let_error(just(), [](auto&&) { return just(); }), - [n=0]() mutable noexcept { return n++ == 1000; })); + [&n]() mutable noexcept { return n++ == 5; })); + EXPECT_EQ(n, 6); } #if !UNIFEX_NO_COROUTINES diff --git a/test/let_value_test.cpp b/test/let_value_test.cpp index bd55906c4..a428b0330 100644 --- a/test/let_value_test.cpp +++ b/test/let_value_test.cpp @@ -286,7 +286,9 @@ TEST(Let, LetValueWithTraitlessPredecessor) { } TEST(Let, LvalueConnectable) { + int n = 0; sync_wait(repeat_effect_until( let_value(let_done(just(), [] { return just(); }), [] { return just(); }), - [n=0]() mutable noexcept { return n++ == 1000; })); + [&n]() mutable noexcept { return n++ == 5; })); + EXPECT_EQ(n, 6); } From e73aaf9edbfda5bcd6a31db3f7f0961007bcfadf Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Sat, 8 Jul 2023 00:28:15 -0400 Subject: [PATCH 9/9] typo --- include/unifex/let_done.hpp | 2 +- include/unifex/let_error.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/unifex/let_done.hpp b/include/unifex/let_done.hpp index 4d5aba7be..96b2b2663 100644 --- a/include/unifex/let_done.hpp +++ b/include/unifex/let_done.hpp @@ -228,7 +228,7 @@ class _op::type { : done_((Done2&&)done) , receiver_((Receiver2&&)dest) { - // Note: 'Source' is not a forawrding reference since it's not deduced + // Note: 'Source' is not a forwarding reference since it's not deduced // in this constructor. It can either be a Sender&& or Sender& for // some concrete type Sender. Here, we want the forwarding behavior when // the operation is constructed based on the type of Source, even though diff --git a/include/unifex/let_error.hpp b/include/unifex/let_error.hpp index 4a4455fe7..727083ccf 100644 --- a/include/unifex/let_error.hpp +++ b/include/unifex/let_error.hpp @@ -265,7 +265,7 @@ class _op::type final { is_nothrow_connectable_v) : func_((Func2 &&) func) , receiver_((Receiver2 &&) dest) { - // Note: 'Source' is not a forawrding reference since it's not deduced + // Note: 'Source' is not a forwarding reference since it's not deduced // in this constructor. It can either be a Sender&& or Sender& for // some concrete type Sender. Here, we want the forwarding behavior when // the operation is constructed based on the type of Source, even though