• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bemanproject / execution / 21500390227

30 Jan 2026 12:55AM UTC coverage: 86.458% (-6.2%) from 92.63%
21500390227

Pull #203

github

web-flow
Merge f59fbc6df into a098f9098
Pull Request #203: create a script to create a module file

10 of 118 new or added lines in 5 files covered. (8.47%)

2 existing lines in 1 file now uncovered.

1213 of 1403 relevant lines covered (86.46%)

159.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.14
/src/beman/execution/execution.cppm
1
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2

3
// *****************************************************;
4
// *** WARNING: this file is generated: do not edit! ***;
5
// *****************************************************;
6
// generated by ./bin/mk-module.py src/beman/execution/execution.cppm
7

8
module;
9

10
#include <beman/execution/modules_export.hpp>
11
#include <cassert>
12

13
#ifdef BEMAN_HAS_IMPORT_STD
14
import std;
15
#else
16
#include <algorithm>
17
#include <atomic>
18
#include <cassert>
19
#include <concepts>
20
#include <condition_variable>
21
#include <coroutine>
22
#include <cstddef>
23
#include <cstdlib>
24
#include <exception>
25
#include <functional>
26
#include <memory>
27
#include <mutex>
28
#include <optional>
29
#include <system_error>
30
#include <thread>
31
#include <tuple>
32
#include <type_traits>
33
#include <utility>
34
#include <variant>
35
#endif
36

37
export module beman.execution;
38

39
// ----------------------------------------------------------------------------
40

41
#ifndef BEMAN_EXECUTION_EXPORT
42
#define BEMAN_EXECUTION_EXPORT
43
#endif
44

45
#if defined(disabled__cpp_deleted_function)
46
#define BEMAN_EXECUTION_DELETE(msg) delete (msg)
47
#else
48
#define BEMAN_EXECUTION_DELETE(msg) delete
49
#endif
50

51
// ----------------------------------------------------------------------------
52
/*!
53
 * \mainpage Asynchronous Operation Support
54
 *
55
 * This project implements the C++ support for asynchronous operations,
56
 * knows as _sender/receiver_ or `std::execution`.
57
 *
58
 * There are a few ingredients to using `std::execution`:
59
 *
60
 * - Sender algorithms to composes work into an asynchronous workflow.
61
 * - Something holding and starting senders like `sync_wait()`
62
 *   or `counting_scope`.
63
 * - A coroutine binding like `task` to make sender composition
64
 *   easier for typical use cases.
65
 * - Some tools like a sender-aware `concurrent_queue`.
66
 * - Senders describing some asynchronous work. Sadly, there are
67
 *   currently no such senders are proposed.
68
 */
69

70
/*!
71
 * \namespace beman
72
 * \brief Namespace for Beman projects http://github.com/bemanproject/beman
73
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
74
 */
75
namespace beman {
76
/*!
77
 * \namespace beman::execution
78
 * \brief Namespace for asynchronous operations and their vocabulary.
79
 *
80
 * \details
81
 * The beman::execution namespace contains various components for
82
 * accessing asynchronous operations.
83
 *
84
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
85
 */
86
namespace execution {
87

88
/*!
89
 * \namespace beman::execution::detail
90
 * \brief Namespace for implementation details related to beman::execution
91
 * \internal
92
 */
93
namespace detail {}
94
} // namespace execution
95
} // namespace beman
96

97
// ----------------------------------------------------------------------------
98

99
// ----------------------------------------------------------------------------
100

101
#if defined(__GNUC__)
102
#define BEMAN_EXECUTION_DIAGNOSTIC_PUSHED
103
#pragma GCC diagnostic push
104
#pragma GCC diagnostic ignored "-Wmissing-braces"
105
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
106
#endif // #if defined(__GNUC__)
107

108
#if defined(__clang__)
109
#define BEMAN_EXECUTION_DIAGNOSTIC_PUSHED
110
#pragma clang diagnostic push
111
#pragma clang diagnostic ignored "-Wunknown-warning-option"
112
#pragma clang diagnostic ignored "-Wmissing-braces"
113
#pragma clang diagnostic ignored "-Wc++26-extensions"
114
#endif // #if defined(__clang__)
115

116
// ----------------------------------------------------------------------------
117

118
#ifdef BEMAN_EXECUTION_DIAGNOSTIC_PUSHED
119
#if defined(__GNUC__)
120
#pragma GCC diagnostic pop
121
#endif // #if defined(__GNUC__)
122
#if defined(__clang__)
123
#pragma clang diagnostic pop
124
#endif // #if defined(__clang__)
125
#undef BEMAN_EXECUTION_DIAGNOSTIC_PUSHED
126
#endif // #ifdef BEMAN_EXECUTION_DIAGNOSTIC_PUSHED
127

128
// ----------------------------------------------------------------------------
129

130
namespace beman::execution::detail {
131
template <typename T>
132
concept queryable = ::std::destructible<T>;
133
}
134

135
// ----------------------------------------------------------------------------
136

137
// ----------------------------------------------------------------------------
138

139
namespace beman::execution::detail {
140
/*!
141
 * \brief Actual implementation of the forwarding_query customization point object
142
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
143
 * \internal
144
 */
145
struct forwarding_query_t {
146
    template <typename Object>
147
        requires requires(Object&& object, const forwarding_query_t& query) {
148
            { ::std::forward<Object>(object).query(query) } noexcept -> ::std::same_as<bool>;
149
        }
150
    constexpr auto operator()(Object&& object) const noexcept -> bool {
151
        return ::std::forward<Object>(object).query(*this);
152
    }
153
    template <typename Object>
154
    constexpr auto operator()(Object&&) const noexcept -> bool {
155
        return ::std::derived_from<::std::remove_cvref_t<Object>, ::beman::execution::detail::forwarding_query_t>;
156
    }
157
};
158
} // namespace beman::execution::detail
159

160
namespace beman::execution {
161
/*!
162
 * \brief Type of the forwarding_query customization point object
163
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
164
 */
165
export using forwarding_query_t = beman::execution::detail::forwarding_query_t;
166
/*!
167
 * \brief The customization point object to determine whether queries should be forwarded
168
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
169
 *
170
 * \details
171
 * The `constexpr` call `forwarding_query(q)` determines whether the query `q` passed
172
 * as argument should be forwarded. The result is determined as follows:
173
 *
174
 * * If the `q.query(forwarding_query)` is a `noexcept` expression of type `bool` the result of this call.
175
 * * If the type of `q` is derived from `forwarding_query_t`.
176
 * * `false` otherwise.
177
 */
178
export inline constexpr forwarding_query_t forwarding_query{};
179
} // namespace beman::execution
180

181
// ----------------------------------------------------------------------------
182

183
// ----------------------------------------------------------------------------
184

185
namespace beman::execution::detail {
186
template <typename T>
187
concept movable_value =
188
    ::std::move_constructible<::std::decay_t<T>> && ::std::constructible_from<::std::decay_t<T>, T> &&
189
    (!::std::is_array_v<::std::remove_reference_t<T>>);
190
}
191

192
// ----------------------------------------------------------------------------
193

194
// ----------------------------------------------------------------------------
195

196
namespace beman::execution::detail {
197
template <typename Fun>
198
struct matching_sig_transform {
199
    using type = Fun;
200
};
201
template <typename Return, typename... Args>
202
struct matching_sig_transform<Return(Args...)> {
203
    using type = Return(Args&&...);
204
};
205

206
template <typename Fun1, typename Fun2>
207
inline constexpr bool matching_sig =
208
    ::std::same_as<typename ::beman::execution::detail::matching_sig_transform<Fun1>::type,
209
                   typename ::beman::execution::detail::matching_sig_transform<Fun2>::type>;
210
} // namespace beman::execution::detail
211

212
// ----------------------------------------------------------------------------
213

214
// ----------------------------------------------------------------------------
215

216
namespace beman::execution::detail {
217
/*!
218
 * \brief Turn an error into a suitable exception_ptr.
219
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
220
 * \internal
221
 */
222
template <typename Error>
223
decltype(auto) as_except_ptr(Error&& error) {
224
    if constexpr (::std::same_as<::std::exception_ptr, ::std::decay_t<Error>>) {
225
        return ::std::forward<Error>(error);
226
    } else if constexpr (::std::same_as<::std::error_code, ::std::decay_t<Error>>) {
227
        return ::std::make_exception_ptr(::std::system_error(error));
228
    } else {
229
        return ::std::make_exception_ptr(::std::forward<Error>(error));
230
    }
231
}
232
} // namespace beman::execution::detail
233

234
// ----------------------------------------------------------------------------
235

236
// ----------------------------------------------------------------------------
237

238
namespace beman::execution {
239
/*!
240
 * \brief Type of the customization point object for successful completions.
241
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
242
 */
243
export struct set_value_t {
244
    template <typename Receiver, typename... Args>
245
    auto operator()(Receiver&, Args&&...) const
246
        -> void = BEMAN_EXECUTION_DELETE("set_value requires the receiver to be passed as non-const rvalue");
247
    template <typename Receiver, typename... Args>
248
    auto operator()(const Receiver&&, Args&&...) const
249
        -> void = BEMAN_EXECUTION_DELETE("set_value requires the receiver to be passed as non-const rvalue");
250
    template <typename Receiver, typename... Args>
251
    auto operator()(Receiver&&, Args&&...) const -> void
252
        requires(not requires(Receiver&& receiver, Args&&... args) {
253
                    ::std::forward<Receiver>(receiver).set_value(::std::forward<Args>(args)...);
254
                })
255
    = BEMAN_EXECUTION_DELETE("set_value requires a suitable member overload on the receiver");
256
    template <typename Receiver, typename... Args>
257
        requires(not noexcept(::std::declval<Receiver>().set_value(::std::declval<Args>()...)))
258
    auto operator()(Receiver&&, Args&&...) const
259
        -> void = BEMAN_EXECUTION_DELETE("the call to receiver.set_value(args...) has to be noexcept");
260

261
    template <typename Receiver, typename... Args>
262
    auto operator()(Receiver&& receiver, Args&&... args) const noexcept -> void {
263
        ::std::forward<Receiver>(receiver).set_value(::std::forward<Args>(args)...);
264
    }
265
};
266
/*!
267
 * \var set_value
268
 * \brief Customization point object for successful completions.
269
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
270
 */
271
export inline constexpr set_value_t set_value{};
272
} // namespace beman::execution
273

274
// ----------------------------------------------------------------------------
275

276
// ----------------------------------------------------------------------------
277

278
namespace beman::execution {
279
/*!
280
 * \brief Type of the customization point object for error completions.
281
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
282
 */
283
export struct set_error_t {
284
    template <typename Receiver, typename Error>
285
    auto operator()(Receiver&, Error&&) const
286
        -> void = BEMAN_EXECUTION_DELETE("set_error requires the receiver to be passed as non-const rvalue");
287
    template <typename Receiver, typename Error>
288
    auto operator()(const Receiver&&, Error&&) const
289
        -> void = BEMAN_EXECUTION_DELETE("set_error requires the receiver to be passed as non-const rvalue");
290
    template <typename Receiver, typename Error>
291
    auto operator()(Receiver&&, Error&&) const -> void
292
        requires(not requires(Receiver&& receiver, Error&& error) {
293
                    ::std::forward<Receiver>(receiver).set_error(::std::forward<Error>(error));
294
                })
295
    = BEMAN_EXECUTION_DELETE("set_error requires a suitable member overload on the receiver");
296
    template <typename Receiver, typename Error>
297
        requires(not noexcept(::std::declval<Receiver>().set_error(::std::declval<Error>())))
298
    auto operator()(Receiver&&, Error&&) const
299
        -> void = BEMAN_EXECUTION_DELETE("the call to receiver.set_error(error) has to be noexcept");
300

301
    // NOLINTBEGIN(misc-no-recursion)
302
    template <typename Receiver, typename Error>
303
    auto operator()(Receiver&& receiver, Error&& error) const noexcept -> void {
304
        ::std::forward<Receiver>(receiver).set_error(::std::forward<Error>(error));
305
    }
306
    // NOLINTEND(misc-no-recursion)
307
};
308

309
/*!
310
 * \brief Customization point object for error completions.
311
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
312
 */
313
export inline constexpr set_error_t set_error{};
314
} // namespace beman::execution
315

316
// ----------------------------------------------------------------------------
317

318
// ----------------------------------------------------------------------------
319

320
namespace beman::execution {
321
/*!
322
 * \brief Type of the customization point object for cancellation completions.
323
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
324
 */
325
export struct set_stopped_t {
326
    template <typename Receiver>
327
    auto operator()(Receiver&) const
328
        -> void = BEMAN_EXECUTION_DELETE("set_stopped requires the receiver to be passed as non-const rvalue");
329
    template <typename Receiver>
330
    auto operator()(const Receiver&&) const
331
        -> void = BEMAN_EXECUTION_DELETE("set_stopped requires the receiver to be passed as non-const rvalue");
332
    template <typename Receiver>
333
    auto operator()(Receiver&&) const -> void
334
        requires(not requires(Receiver&& receiver) { ::std::forward<Receiver>(receiver).set_stopped(); })
335
    = BEMAN_EXECUTION_DELETE("set_stopped requires a suitable member overload on the receiver");
336
    template <typename Receiver>
337
        requires(not noexcept(::std::declval<Receiver>().set_stopped()))
338
    auto operator()(Receiver&&) const
339
        -> void = BEMAN_EXECUTION_DELETE("the call to receiver.set_stopped() has to be noexcept");
340

341
    template <typename Receiver>
342
    auto operator()(Receiver&& receiver) const noexcept -> void {
343
        ::std::forward<Receiver>(receiver).set_stopped();
344
    }
345
};
346

347
/*!
348
 * \brief Customization point object for cancellation completions.
349
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
350
 */
351
export inline constexpr set_stopped_t set_stopped{};
352
} // namespace beman::execution
353

354
// ----------------------------------------------------------------------------
355

356
// ----------------------------------------------------------------------------
357

358
namespace beman::execution {
359
export struct start_t {
360
    template <typename State>
361
    auto operator()(State&&) const -> void = BEMAN_EXECUTION_DELETE("start(obj) requires an lvalue argument");
362
    template <typename State>
363
        requires(not requires(State& state) { state.start(); })
364
    auto operator()(State&) const -> void = BEMAN_EXECUTION_DELETE("state needs to have a start() member");
365
    template <typename State>
366
        requires(not requires(const State& state) { state.start(); })
367
    auto operator()(const State&) const -> void = BEMAN_EXECUTION_DELETE("state needs to have a start() member");
368

369
    template <typename State>
370
        requires(not requires(State& state) {
371
                    { state.start() } noexcept;
372
                })
373
    auto operator()(State&) const -> void = BEMAN_EXECUTION_DELETE("state start() member has to be noexcept");
374
    template <typename State>
375
        requires(not requires(const State& state) {
376
                    { state.start() } noexcept;
377
                })
378
    auto operator()(const State&) const -> void = BEMAN_EXECUTION_DELETE("state start() member has to be noexcept");
379

380
    template <typename State>
381
    auto operator()(const State& state) const noexcept -> void {
382
        state.start();
383
    }
384
    // NOLINTBEGIN(misc-no-recursion)
385
    template <typename State>
386
    auto operator()(State& state) const noexcept -> void {
387
        state.start();
388
    }
389
    // NOLINTEND(misc-no-recursion)
390
};
391

392
export inline constexpr start_t start{};
393
} // namespace beman::execution
394

395
// ----------------------------------------------------------------------------
396

397
// ----------------------------------------------------------------------------
398

399
namespace beman::execution::detail {
400
struct non_assignable;
401
}
402

403
// ----------------------------------------------------------------------------
404

405
struct beman::execution::detail::non_assignable {
406
    non_assignable()                                         = default;
407
    non_assignable(non_assignable&&)                         = default;
408
    non_assignable(const non_assignable&)                    = default;
409
    auto operator=(non_assignable&&) -> non_assignable&      = delete;
410
    auto operator=(const non_assignable&) -> non_assignable& = delete;
411
};
412

413
// ----------------------------------------------------------------------------
414

415
// ----------------------------------------------------------------------------
416

417
namespace beman::execution::detail {
418
template <typename Alloc>
419
concept simple_allocator =
420
    requires(::std::remove_cvref_t<Alloc> alloc, ::std::size_t n) {
421
        { *alloc.allocate(n) } -> ::std::same_as<typename ::std::remove_cvref_t<Alloc>::value_type&>;
422
        alloc.deallocate(alloc.allocate(n), n);
423
    } && ::std::copy_constructible<::std::remove_cvref_t<Alloc>> &&
424
    ::std::equality_comparable<::std::remove_cvref_t<Alloc>>;
425
} // namespace beman::execution::detail
426

427
// ----------------------------------------------------------------------------
428

429
// ----------------------------------------------------------------------------
430

431
namespace beman::execution {
432
export class never_stop_token;
433
}
434

435
// ----------------------------------------------------------------------------
436

437
class beman::execution::never_stop_token {
438
    struct private_callback_type {
439
        explicit private_callback_type(never_stop_token, auto&&) noexcept {}
440
    };
441

442
  public:
443
    template <typename>
444
    using callback_type = private_callback_type;
445

446
    static constexpr auto stop_requested() noexcept -> bool { return {}; }
447
    static constexpr auto stop_possible() noexcept -> bool { return {}; }
448
    auto                  operator==(const never_stop_token&) const -> bool = default;
449
};
450

451
// ----------------------------------------------------------------------------
452

453
// ----------------------------------------------------------------------------
454

455
namespace beman::execution::detail {
456
//-dk:TODO thoroughly test the concept
457
/*!
458
 * \brief Helper concept to determine if the result of decaying two types results in the same type
459
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
460
 * \internal
461
 */
462
template <typename T0, typename T1>
463
concept decayed_same_as = ::std::same_as<::std::remove_cvref_t<T0>, ::std::remove_cvref_t<T1>>;
464
} // namespace beman::execution::detail
465

466
// ----------------------------------------------------------------------------
467

468
// ----------------------------------------------------------------------------
469

470
namespace beman::execution::detail {
471
/*!
472
 * \brief Concept used to detect callable objects.
473
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
474
 * \concept callable
475
 * \internal
476
 */
477
template <typename Fun, typename... Args>
478
concept callable = requires(Fun&& fun, Args&&... args) { ::std::forward<Fun>(fun)(::std::forward<Args>(args)...); };
479
} // namespace beman::execution::detail
480

481
// ----------------------------------------------------------------------------
482

483
// ----------------------------------------------------------------------------
484
// std::forward_like() doesn't work on some compilers, yet. This header
485
// provides a work-around.
486

487
namespace beman::execution::detail {
488
template <typename>
489
struct forward_like_helper;
490

491
template <typename T>
492
struct forward_like_helper {
493
    template <typename U>
494
    static auto forward(U&& u) -> ::std::remove_reference_t<U>&& {
495
        return ::std::move(u); // NOLINT(bugprone-move-forwarding-reference)
496
    }
497
};
498
template <typename T>
499
struct forward_like_helper<T&&> {
500
    template <typename U>
501
    static auto forward(U&& u) -> ::std::remove_cvref_t<U>&& {
502
        return ::std::move(u); // NOLINT(bugprone-move-forwarding-reference)
503
    }
504
};
505
template <typename T>
506
struct forward_like_helper<T&> {
507
    template <typename U>
508
    static auto forward(U&& u) -> ::std::remove_cvref_t<U>& {
509
        return ::std::forward<U&&>(u);
510
    }
511
};
512
template <typename T>
513
struct forward_like_helper<const T&&> {
514
    template <typename U>
515
    static auto forward(U&& u) -> const ::std::remove_cvref_t<U>&& {
516
        return ::std::move(u); // NOLINT(bugprone-move-forwarding-reference)
517
    }
518
};
519
template <typename T>
520
struct forward_like_helper<const T&> {
521
    template <typename U>
522
    static auto forward(U&& u) -> const ::std::remove_cvref_t<U>& {
523
        return ::std::forward<U&&>(u);
524
    }
525
};
526

527
// The overload own_forward_like is used for testing on systems
528
// which actually do provide an implementation.
529
template <typename T, typename U>
530
auto own_forward_like(U&& u) noexcept -> decltype(auto) {
531
    return ::beman::execution::detail::forward_like_helper<T>::forward(::std::forward<U>(u));
532
}
533

534
/*!
535
 * \brief Helper function to forward a subobject (in case the standard library version is unavailable)
536
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
537
 * \internal
538
 */
539
template <typename T, typename U>
540
auto forward_like(U&& u) noexcept -> decltype(auto) {
541
#if 202207 <= disabled__cpp_lib_forward_like
542
    return ::std::forward_like<T>(::std::forward<U>(u));
543
#else
544
    return ::beman::execution::detail::forward_like_helper<T>::forward(::std::forward<U>(u));
545
#endif
546
}
547

548
} // namespace beman::execution::detail
549

550
// ----------------------------------------------------------------------------
551

552
// ----------------------------------------------------------------------------
553

554
namespace beman::execution::detail {
555
template <typename Env1, typename Env2>
556
class join_env {
557
  private:
558
    Env1 env1;
559
    Env2 env2;
560

561
  public:
562
    template <typename E1, typename E2>
563
    join_env(E1&& e1, E2&& e2) : env1(::std::forward<E1>(e1)), env2(::std::forward<E2>(e2)) {}
564

565
    template <typename Query, typename... Args>
566
        requires(
567
            requires(Env1&, const Query& query, Args&&... args) {
568
                env1.query(query, ::std::forward<Args>(args)...);
569
            } ||
570
            requires(Env2& e2, const Query& query, Args&&... args) { e2.query(query, ::std::forward<Args>(args)...); })
571
    auto query(const Query& query, Args&&... args) noexcept -> decltype(auto) {
572
        if constexpr (requires { env1.query(query, ::std::forward<Args>(args)...); }) {
573
            return env1.query(query, ::std::forward<Args>(args)...);
574
        } else {
575
            return env2.query(query, ::std::forward<Args>(args)...);
576
        }
577
    }
578
    template <typename Query, typename... Args>
579
        requires(
580
            requires(const Env1&, const Query& query, Args&&... args) {
581
                env1.query(query, ::std::forward<Args>(args)...);
582
            } ||
583
            requires(const Env2& e2, const Query& query, Args&&... args) {
584
                e2.query(query, ::std::forward<Args>(args)...);
585
            })
586
    auto query(const Query& query, Args&&... args) const noexcept -> decltype(auto) {
587
        if constexpr (requires { env1.query(query, ::std::forward<Args>(args)...); }) {
588
            return env1.query(query, ::std::forward<Args>(args)...);
589
        } else {
590
            return env2.query(query, ::std::forward<Args>(args)...);
591
        }
592
    }
593
};
594

595
template <typename Env1, typename Env2>
596
join_env(Env1&&, Env2&&) -> join_env<::std::remove_cvref_t<Env1>, ::std::remove_cvref_t<Env2>>;
597
} // namespace beman::execution::detail
598

599
// ----------------------------------------------------------------------------
600

601
// ----------------------------------------------------------------------------
602

603
namespace beman::execution::detail {
604

605
template <::std::size_t I, typename T>
606
struct product_type_element {
607
    T    value;
608
    auto operator==(const product_type_element&) const -> bool = default;
609
};
610

611
template <typename, typename...>
612
struct product_type_base;
613

614
template <::std::size_t... I, typename... T>
615
struct product_type_base<::std::index_sequence<I...>, T...>
616
    : ::beman::execution::detail::product_type_element<I, T>... {
617
    static constexpr ::std::size_t size() { return sizeof...(T); }
618
    static constexpr bool          is_product_type{true};
619

620
    template <::std::size_t J, typename S>
621
    static auto element_get(::beman::execution::detail::product_type_element<J, S>& self) noexcept -> S& {
622
        return self.value;
623
    }
624
    template <::std::size_t J, typename S>
625
    static auto element_get(::beman::execution::detail::product_type_element<J, S>&& self) noexcept -> S&& {
626
        return ::std::move(self.value);
627
    }
628
    template <::std::size_t J, typename S>
629
    static auto element_get(const ::beman::execution::detail::product_type_element<J, S>& self) noexcept -> const S& {
630
        return self.value;
631
    }
632

633
    template <::std::size_t J>
634
    auto get() & -> decltype(auto) {
635
        return this->element_get<J>(*this);
636
    }
637
    template <::std::size_t J>
638
    auto get() && -> decltype(auto) {
639
        return this->element_get<J>(::std::move(*this));
640
    }
641
    template <::std::size_t J>
642
    auto get() const& -> decltype(auto) {
643
        return this->element_get<J>(*this);
644
    }
645

646
    template <::std::size_t J, typename Allocator, typename Self>
647
    static auto make_element(Allocator&& alloc, Self&& self) -> decltype(auto) {
648
        using type = ::std::remove_cvref_t<decltype(product_type_base::element_get<J>(std::forward<Self>(self)))>;
649
        if constexpr (::std::uses_allocator_v<type, Allocator>)
650
            return ::std::make_obj_using_allocator<type>(alloc,
651
                                                         product_type_base::element_get<J>(std::forward<Self>(self)));
652
        else
653
            return product_type_base::element_get<J>(std::forward<Self>(self));
654
    }
655

656
    auto operator==(const product_type_base&) const -> bool = default;
657
};
658

659
template <typename T>
660
concept is_product_type_c = requires(const T& t) { T::is_product_type; };
661

662
template <typename... T>
663
struct product_type : ::beman::execution::detail::product_type_base<::std::index_sequence_for<T...>, T...> {
664
    template <typename Allocator, typename Product, std::size_t... I>
665
    static auto make_from(Allocator&& allocator, Product&& product, std::index_sequence<I...>) -> product_type {
666
        return {product_type::template make_element<I>(allocator, ::std::forward<Product>(product))...};
667
    }
668

669
    template <typename Allocator, typename Product>
670
    static auto make_from(Allocator&& allocator, Product&& product) -> product_type {
671
        return product_type::make_from(
672
            ::std::forward<Allocator>(allocator), ::std::forward<Product>(product), ::std::index_sequence_for<T...>{});
673
    }
674

675
    template <typename Fun, ::std::size_t... I>
676
    constexpr auto apply_elements(::std::index_sequence<I...>, Fun&& fun) const -> decltype(auto) {
677
        return ::std::forward<Fun>(fun)(this->template get<I>()...);
678
    }
679
    template <typename Fun>
680
    constexpr auto apply(Fun&& fun) const -> decltype(auto) {
681
        return apply_elements(::std::index_sequence_for<T...>{}, ::std::forward<Fun>(fun));
682
    }
683
    template <typename Fun, ::std::size_t... I>
684
    constexpr auto apply_elements(::std::index_sequence<I...>, Fun&& fun) -> decltype(auto) {
685
        //-dk:TODO provide rvalue, lvalue, const lvalue overloads?
686
        return ::std::forward<Fun>(fun)(std::move(this->template get<I>())...);
687
    }
688
    template <typename Fun>
689
    constexpr auto apply(Fun&& fun) -> decltype(auto) {
690
        return apply_elements(::std::index_sequence_for<T...>{}, ::std::forward<Fun>(fun));
691
    }
692
};
693
template <typename... T>
694
product_type(T&&...) -> product_type<::std::decay_t<T>...>;
695

696
template <typename T>
697
constexpr auto is_product_type(const T&) -> ::std::false_type {
698
    return {};
699
}
700
template <typename... T>
701
constexpr auto is_product_type(const ::beman::execution::detail::product_type<T...>&) -> ::std::true_type {
702
    return {};
703
}
704

705
template <::std::size_t Start, typename Fun, typename Tuple, ::std::size_t... I>
706
constexpr auto sub_apply_helper(Fun&& fun, Tuple&& tuple, ::std::index_sequence<I...>) -> decltype(auto) {
707
    // NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
708
    return ::std::forward<Fun>(fun)(::std::forward<Tuple>(tuple).template get<I + Start>()...);
709
}
710

711
template <::std::size_t Start, typename Fun, typename Tuple>
712
constexpr auto sub_apply(Fun&& fun, Tuple&& tuple) -> decltype(auto) {
713
    constexpr ::std::size_t TSize{::std::tuple_size_v<::std::remove_cvref_t<Tuple>>};
714
    static_assert(Start <= TSize);
715
    return sub_apply_helper<Start>(
716
        ::std::forward<Fun>(fun), ::std::forward<Tuple>(tuple), ::std::make_index_sequence<TSize - Start>());
717
}
718

719
} // namespace beman::execution::detail
720

721
namespace std {
722
template <typename T>
723
    requires ::beman::execution::detail::is_product_type_c<T>
724
struct tuple_size<T> : ::std::integral_constant<std::size_t, T::size()> {};
725

726
template <::std::size_t I, typename T>
727
    requires ::beman::execution::detail::is_product_type_c<T>
728
struct tuple_element<I, T> {
729
    using type = ::std::decay_t<decltype(::std::declval<T>().template get<I>())>;
730
};
731
} // namespace std
732

733
// ----------------------------------------------------------------------------
734

735
// ----------------------------------------------------------------------------
736

737
namespace beman::execution::detail {
738
template <typename Tag, typename Env, typename Value>
739
    requires requires(const Tag& tag, const Env& env) { tag(env); }
740
constexpr auto query_with_default(Tag, const Env& env, Value&&) noexcept(noexcept(Tag()(env))) -> decltype(auto) {
741
    return Tag()(env);
742
}
743

744
template <typename Tag, typename Env, typename Value>
745
constexpr auto
746
query_with_default(Tag, const Env&, Value&& value) noexcept(noexcept(static_cast<Value>(std::forward<Value>(value))))
747
    -> decltype(auto) {
748
    return static_cast<Value>(std::forward<Value>(value));
749
}
750
} // namespace beman::execution::detail
751

752
// ----------------------------------------------------------------------------
753

754
// ----------------------------------------------------------------------------
755

756
namespace beman::execution::detail {
757
/*!
758
 * \brief Auxiliary type alias used to determine the type of a child sender.
759
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
760
 * \internal
761
 */
762
template <typename Sender, ::std::size_t I = 0u>
763
using child_type = decltype(::std::declval<Sender>().template get<I + 2>());
764
} // namespace beman::execution::detail
765

766
// ----------------------------------------------------------------------------
767

768
// ----------------------------------------------------------------------------
769

770
namespace beman::execution::detail {
771
/*!
772
 * \brief Helper type alias to get type type of a tuple after decaying the argument types
773
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
774
 * \internal
775
 */
776
template <typename... T>
777
using decayed_tuple = ::std::tuple<::std::decay_t<T>...>;
778
} // namespace beman::execution::detail
779

780
// ----------------------------------------------------------------------------
781

782
// ----------------------------------------------------------------------------
783

784
namespace beman::execution::detail {
785
template <typename Query, typename Value>
786
class make_env {
787
  private:
788
    Value value;
789

790
  public:
791
    template <typename V>
792
    make_env(const Query&, V&& v) : value(::std::forward<V>(v)) {}
793
    constexpr auto query(const Query&) const noexcept -> const Value& { return this->value; }
794
    constexpr auto query(const Query&) noexcept -> Value& { return this->value; }
795
};
796
template <typename Query, typename Value>
797
make_env(Query&&, Value&& value) -> make_env<::std::remove_cvref_t<Query>, ::std::remove_cvref_t<Value>>;
798
} // namespace beman::execution::detail
799

800
// ----------------------------------------------------------------------------
801

802
// ----------------------------------------------------------------------------
803

804
namespace beman::execution::detail::meta::detail {
805
template <typename, typename>
806
struct prepend;
807

808
template <template <typename...> class List, typename H, typename... T>
809
struct prepend<H, List<T...>> {
810
    using type = List<H, T...>;
811
};
812
} // namespace beman::execution::detail::meta::detail
813

814
namespace beman::execution::detail::meta {
815
template <typename H, typename Tail>
816
using prepend = typename ::beman::execution::detail::meta::detail::prepend<H, Tail>::type;
817
}
818

819
// ----------------------------------------------------------------------------
820

821
// ----------------------------------------------------------------------------
822

823
namespace beman::execution::detail::meta {
824
template <template <typename...> class To, typename>
825
struct to_type_list;
826
template <template <typename...> class To, template <typename...> class List, typename... T>
827
struct to_type_list<To, List<T...>> {
828
    using type = To<T...>;
829
};
830
template <template <typename...> class To, typename T>
831
using to = typename ::beman::execution::detail::meta::to_type_list<To, T>::type;
832
} // namespace beman::execution::detail::meta
833

834
// ----------------------------------------------------------------------------
835

836
// ----------------------------------------------------------------------------
837

838
namespace beman::execution::detail {
839
template <typename...>
840
struct type_list {};
841
} // namespace beman::execution::detail
842

843
// ----------------------------------------------------------------------------
844

845
// ----------------------------------------------------------------------------
846

847
namespace beman::execution {
848
export template <class Token, class CallbackFun>
849
using stop_callback_for_t = typename Token::template callback_type<CallbackFun>;
850
}
851

852
namespace beman::execution::detail {
853
template <typename CallbackFun, typename Token, typename Initializer = CallbackFun>
854
concept stoppable_callback_for =
855
    ::std::invocable<CallbackFun> && ::std::constructible_from<CallbackFun, Initializer> &&
856
    requires { typename ::beman::execution::stop_callback_for_t<Token, CallbackFun>; } &&
857
    ::std::constructible_from<::beman::execution::stop_callback_for_t<Token, CallbackFun>, Token, Initializer> &&
858
    ::std::constructible_from<::beman::execution::stop_callback_for_t<Token, CallbackFun>, Token&, Initializer> &&
859
    ::std::constructible_from<::beman::execution::stop_callback_for_t<Token, CallbackFun>, const Token&, Initializer>;
860
} // namespace beman::execution::detail
861

862
// ----------------------------------------------------------------------------
863

864
// ----------------------------------------------------------------------------
865

866
namespace beman::execution::detail {
867
template <typename Fun, typename... Args>
868
/*!
869
 * \brief Type alias used determine the result of function [object] call.
870
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
871
 * \internal
872
 */
873
using call_result_t = decltype(::std::declval<Fun>()(std::declval<Args>()...));
874
}
875

876
// ----------------------------------------------------------------------------
877

878
// ----------------------------------------------------------------------------
879

880
namespace beman::execution::detail::meta {
881
template <typename>
882
struct size;
883
template <template <typename...> class L, typename... T>
884
struct size<L<T...>> {
885
    static constexpr ::std::size_t value{sizeof...(T)};
886
};
887
template <typename T>
888
inline constexpr ::std::size_t size_v{::beman::execution::detail::meta::size<T>::value};
889
} // namespace beman::execution::detail::meta
890

891
// ----------------------------------------------------------------------------
892

893
// ----------------------------------------------------------------------------
894

895
namespace beman::execution::detail {
896
template <typename St>
897
struct on_stop_request {
898
    St&  st;
899
    auto operator()() const -> void { this->st.request_stop(); }
900
};
901
template <typename T>
902
on_stop_request(T&) -> on_stop_request<T>;
903
} // namespace beman::execution::detail
904

905
// ----------------------------------------------------------------------------
906

907
// ----------------------------------------------------------------------------
908

909
namespace beman::execution::detail {
910
/*!
911
 * \brief Auxiliary class template used to detect whether a type alias exist within a class.
912
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
913
 * \internal
914
 */
915
template <template <typename> class>
916
struct check_type_alias_exist;
917
} // namespace beman::execution::detail
918

919
// ----------------------------------------------------------------------------
920

921
// ----------------------------------------------------------------------------
922

923
namespace beman::execution {
924
/*!
925
 * \brief Tag type to indicate a class is a scheduler.
926
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
927
 */
928
export struct scheduler_t {};
929
} // namespace beman::execution
930

931
// ----------------------------------------------------------------------------
932

933
// ----------------------------------------------------------------------------
934

935
namespace beman::execution::detail {
936
template <typename Expr, typename Promise>
937
auto get_awaiter(Expr&& expr, Promise& promise) -> decltype(auto) {
938
    auto transform{[&]() -> decltype(auto) {
939
        if constexpr (requires { promise.await_transform(::std::forward<Expr>(expr)); })
940
            return promise.await_transform(::std::forward<Expr>(expr));
941
        else
942
            return ::std::forward<Expr>(expr);
943
    }};
944
    if constexpr (requires { operator co_await(transform()); }) {
945

946
        static_assert(not requires { transform().operator co_await(); }, "only one operator co_await is allowed");
947
        return operator co_await(transform());
948
    } else if constexpr (requires { transform().operator co_await(); })
949
        return transform().operator co_await();
950
    else
951
        return transform();
952
}
953
} // namespace beman::execution::detail
954

955
// ----------------------------------------------------------------------------
956

957
// ----------------------------------------------------------------------------
958

959
namespace beman::execution::detail {
960
struct sender_convert_to_any_t {
961
    template <typename T>
962
    constexpr operator T() const; // NOLINT(hicpp-explicit-conversions)
963
};
964

965
template <typename Tag, typename Data, typename Children>
966
struct sender_meta {
967
    using tag_type      = ::std::remove_cvref_t<Tag>;
968
    using data_type     = ::std::remove_cvref_t<Data>;
969
    using children_type = ::std::remove_cvref_t<Children>;
970
};
971

972
template <typename Tag, typename Data, typename Children>
973
struct sender_data {
974
    using tag_type      = ::std::remove_cvref_t<Tag>;
975
    using data_type     = ::std::remove_cvref_t<Data>;
976
    using children_type = ::std::remove_cvref_t<Children>;
977

978
    tag_type tag;
979
    Data&    data;
980
    Children children;
981
};
982
template <typename Tag, typename Data, typename Children>
983
sender_data(Tag&&, Data&, Children&&) -> sender_data<Tag, Data, Children>;
984

985
template <typename Sender>
986
auto get_sender_data(Sender&& sender) {
987
#if 0
988
        //-dk:TODO should use a dynamic/language approach:
989
        auto&& [tag, data, ... children] = sender;
990
        return sender_meta<decltype(tag), decltype(data), ::std::tuple<decltype(children)...>>;
991
#else
992
    using sender_type = ::std::remove_cvref_t<Sender>;
993
    static constexpr ::beman::execution::detail::sender_convert_to_any_t at{};
994

995
    if constexpr (requires {
996
                      sender.template get<0>();
997
                      sender.size();
998
                  })
999
        return [&sender]<::std::size_t... I>(::std::index_sequence<I...>) {
1000
            return ::beman::execution::detail::sender_data{
1001
                sender.template get<0>(), sender.template get<1>(), ::std::tie(sender.template get<2 + I>()...)};
1002
        }(::std::make_index_sequence<::std::decay_t<decltype(sender)>::size() - 2u>{});
1003
    else if constexpr (requires { sender_type{at, at, at, at, at, at}; }) {
1004
        auto&& [tag, data, c0, c1, c2, c3] = sender;
1005
        return ::beman::execution::detail::sender_data{tag, data, ::std::tie(c0, c1, c2, c3)};
1006
    } else if constexpr (requires { sender_type{at, at, at, at, at}; }) {
1007
        auto&& [tag, data, c0, c1, c2] = sender;
1008
        return ::beman::execution::detail::sender_data{tag, data, ::std::tie(c0, c1, c2)};
1009
    } else if constexpr (requires { sender_type{at, at, at, at}; }) {
1010
        auto&& [tag, data, c0, c1] = sender;
1011
        return ::beman::execution::detail::sender_data{tag, data, ::std::tie(c0, c1)};
1012
    } else if constexpr (requires { sender_type{at, at, at}; }) {
1013
        auto&& [tag, data, c0] = sender;
1014
        return ::beman::execution::detail::sender_data{tag, data, ::std::tie(c0)};
1015
    } else if constexpr (requires { sender_type{at, at}; }) {
1016
        auto&& [tag, data] = sender;
1017
        return ::beman::execution::detail::sender_data{tag, data, ::std::tuple<>{}};
1018
    } else {
1019
        return ::beman::execution::detail::sender_meta<void, void, void>{};
1020
    }
1021
#endif
1022
}
1023

1024
template <typename Sender>
1025
auto get_sender_meta(Sender&& sender) {
1026
    using type = decltype(get_sender_data(sender));
1027
    return sender_meta<typename type::tag_type, typename type::data_type, typename type::children_type>{};
1028
}
1029
} // namespace beman::execution::detail
1030

1031
// ----------------------------------------------------------------------------
1032

1033
// ----------------------------------------------------------------------------
1034

1035
namespace beman::execution::detail {
1036
template <typename Fun, typename... Args>
1037
auto suspend_complete(Fun fun, Args&&... args) noexcept {
1038
    auto f{[&, fun]() noexcept { fun(::std::forward<Args>(args)...); }};
1039
    struct awaiter {
1040
        decltype(f) fun;
1041

1042
        static constexpr auto await_ready() noexcept -> bool { return false; }
1043
        auto                  await_suspend(::std::coroutine_handle<>) noexcept { this->fun(); }
1044
#if __cpp_lib_unreachable < 202202L
1045
        [[noreturn]] auto await_resume() noexcept -> void { ::std::terminate(); }
1046
#else
1047
        [[noreturn]] auto await_resume() noexcept -> void { ::std::unreachable(); }
1048
#endif
1049
    };
1050
    return awaiter{f};
1051
}
1052
} // namespace beman::execution::detail
1053

1054
// ----------------------------------------------------------------------------
1055

1056
// ----------------------------------------------------------------------------
1057

1058
namespace beman::execution::detail::meta {
1059
template <typename T, typename... S>
1060
inline constexpr bool contains{(::std::same_as<T, S> || ...)};
1061
}
1062

1063
// ----------------------------------------------------------------------------
1064

1065
// ----------------------------------------------------------------------------
1066

1067
namespace beman::execution::detail {
1068
/*!
1069
 * \brief Helper concept to determine if the first argument decays to the second argument
1070
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1071
 * \internal
1072
 */
1073
template <typename From, typename To>
1074
concept decays_to = ::std::same_as<::std::decay_t<From>, To>;
1075
} // namespace beman::execution::detail
1076

1077
// ----------------------------------------------------------------------------
1078

1079
namespace beman::execution::detail {
1080

1081
template <auto Next>
1082
class atomic_intrusive_stack;
1083

1084
template <auto Next>
1085
class intrusive_stack;
1086

1087
//! @brief  This data structure is an intrusive queue that is not thread-safe.
1088
template <class Item, Item* Item::* Next>
1089
class intrusive_stack<Next> {
1090
  public:
1091
    //! @brief  Pushes an item to the queue.
1092
    auto push(Item* item) noexcept -> void { item->*Next = std::exchange(head_, item); }
1093

1094
    //! @brief  Pops one item from the queue.
1095
    //!
1096
    //! @return  The item that was popped from the queue, or nullptr if the queue is empty.
1097
    auto pop() noexcept -> Item* {
1098
        if (head_) {
1099
            auto item = head_;
1100
            head_     = std::exchange(item->*Next, nullptr);
1101
            return item;
1102
        }
1103
        return nullptr;
1104
    }
1105

1106
    //! @brief  Tests if the queue is empty.
1107
    auto empty() const noexcept -> bool { return !head_; }
1108

1109
  private:
1110
    friend class atomic_intrusive_stack<Next>;
1111
    Item* head_{nullptr};
1112
};
1113

1114
} // namespace beman::execution::detail
1115

1116
// ----------------------------------------------------------------------------
1117

1118
namespace beman::execution::detail {
1119
struct immovable;
1120
struct virtual_immovable;
1121
} // namespace beman::execution::detail
1122

1123
struct beman::execution::detail::immovable {
1124
    constexpr immovable()                          = default;
1125
    immovable(immovable&&)                         = delete;
1126
    immovable(const immovable&)                    = delete;
1127
    ~immovable()                                   = default;
1128
    auto operator=(immovable&&) -> immovable&      = delete;
1129
    auto operator=(const immovable&) -> immovable& = delete;
1130
};
1131

1132
struct beman::execution::detail::virtual_immovable {
1133
    constexpr virtual_immovable()                                  = default;
1134
    virtual_immovable(virtual_immovable&&)                         = delete;
1135
    virtual_immovable(const virtual_immovable&)                    = delete;
NEW
1136
    virtual ~virtual_immovable()                                   = default;
×
1137
    auto operator=(virtual_immovable&&) -> virtual_immovable&      = delete;
1138
    auto operator=(const virtual_immovable&) -> virtual_immovable& = delete;
1139
};
1140

1141
// ----------------------------------------------------------------------------
1142

1143
namespace beman::execution::detail {
1144
struct unspecified_promise {
1145
    auto get_return_object() noexcept -> unspecified_promise;
1146
    auto initial_suspend() noexcept -> ::std::suspend_never;
1147
    auto final_suspend() noexcept -> ::std::suspend_never;
1148
    void unhandled_exception() noexcept;
1149
    void return_void() noexcept;
1150
    auto unhandled_stopped() noexcept -> ::std::coroutine_handle<>;
1151
};
1152
} // namespace beman::execution::detail
1153

1154
// ----------------------------------------------------------------------------
1155

1156
namespace beman::execution::detail {
1157
/*!
1158
 * \brief Auxiliary type trait used to detect specializations of `std::coroutine_handle`.
1159
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1160
 * \internal
1161
 */
1162
template <typename>
1163
struct is_coroutine_handle : ::std::false_type {};
1164
/*!
1165
 * \brief The actual partial specialization detecting `std::coroutine_handle`.
1166
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1167
 * \internal
1168
 */
1169
template <typename T>
1170
struct is_coroutine_handle<::std::coroutine_handle<T>> : ::std::true_type {};
1171

1172
/*!
1173
 * \brief A concept used to identify valid results for `await_suspend`.
1174
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1175
 * \internal
1176
 */
1177
template <typename T>
1178
concept await_suspend_result =
1179
    ::std::same_as<T, void> || ::std::same_as<T, bool> || ::beman::execution::detail::is_coroutine_handle<T>::value;
1180
} // namespace beman::execution::detail
1181

1182
// ----------------------------------------------------------------------------
1183

1184
// ----------------------------------------------------------------------------
1185

1186
namespace beman::execution::detail {
1187
template <template <typename...> class T, typename... Args>
1188
concept valid_specialization = requires { typename T<Args...>; };
1189
} // namespace beman::execution::detail
1190

1191
// ----------------------------------------------------------------------------
1192

1193
// ----------------------------------------------------------------------------
1194

1195
namespace beman::execution::detail {
1196
template <bool>
1197
struct indirect_meta_apply {
1198
    template <template <typename...> class T, class... A>
1199
    using meta_apply = T<A...>;
1200
};
1201
} // namespace beman::execution::detail
1202

1203
// ----------------------------------------------------------------------------
1204

1205
// ----------------------------------------------------------------------------
1206

1207
namespace beman::execution::detail {
1208
template <typename Sender>
1209
using indices_for = typename ::std::remove_reference_t<Sender>::indices_for;
1210
}
1211

1212
// ----------------------------------------------------------------------------
1213

1214
// ----------------------------------------------------------------------------
1215

1216
namespace beman::execution::detail {
1217
/*!
1218
 * \brief Helper type alias to get the type after decaying the argument
1219
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1220
 * \internal
1221
 */
1222
template <auto&& Tag>
1223
using decayed_typeof = ::std::decay_t<decltype(Tag)>;
1224
} // namespace beman::execution::detail
1225

1226
// ----------------------------------------------------------------------------
1227

1228
// ----------------------------------------------------------------------------
1229

1230
namespace beman::execution {
1231
export struct nostopstate_t {
1232
    explicit nostopstate_t() = default;
1233
};
1234

1235
export inline constexpr nostopstate_t nostopstate{};
1236
} // namespace beman::execution
1237

1238
// ----------------------------------------------------------------------------
1239

1240
// ----------------------------------------------------------------------------
1241

1242
namespace beman::execution::detail {
1243
template <::beman::execution::detail::queryable>
1244
struct env_base;
1245

1246
template <typename E, typename Q>
1247
concept has_query = requires(const E& e) { e.query(::std::declval<Q>()); };
1248

1249
template <typename Q, typename... E>
1250
struct find_env;
1251
template <typename Q, typename E0, typename... E>
1252
    requires has_query<E0, Q>
1253
struct find_env<Q, E0, E...> {
1254
    using type = E0;
1255
};
1256
template <typename Q, typename E0, typename... E>
1257
    requires(not has_query<E0, Q>)
1258
struct find_env<Q, E0, E...> {
1259
    using type = typename find_env<Q, E...>::type;
1260
};
1261
} // namespace beman::execution::detail
1262

1263
namespace beman::execution {
1264
export template <::beman::execution::detail::queryable... Envs>
1265
struct env;
1266

1267
template <::beman::execution::detail::queryable... Envs>
1268
env(Envs...) -> env<::std::unwrap_reference_t<Envs>...>;
1269
} // namespace beman::execution
1270

1271
// ----------------------------------------------------------------------------
1272

1273
template <::beman::execution::detail::queryable Env>
1274
struct beman::execution::detail::env_base {
1275
    Env env_;
1276
};
1277

1278
template <::beman::execution::detail::queryable... Envs>
1279
struct beman::execution::env : ::beman::execution::detail::env_base<Envs>... {
1280
    [[no_unique_address]] ::beman::execution::detail::non_assignable na_{};
1281

1282
    template <typename Q>
1283
        requires(::beman::execution::detail::has_query<Envs, Q> || ...)
1284
    constexpr auto query(Q q) const noexcept -> decltype(auto) {
1285
        using E = typename ::beman::execution::detail::find_env<Q, Envs...>::type;
1286
        return q(static_cast<const ::beman::execution::detail::env_base<E>&>(*this).env_);
1287
    }
1288
};
1289

1290
// ----------------------------------------------------------------------------
1291

1292
// ----------------------------------------------------------------------------
1293

1294
namespace beman::execution {
1295
export struct get_allocator_t {
1296
    template <typename Object>
1297
        requires(not requires(Object&& object, const get_allocator_t& tag) { ::std::as_const(object).query(tag); })
1298
    auto
1299
    operator()(Object&&) const = BEMAN_EXECUTION_DELETE("the object requires a const query(get_allocator_t) overload");
1300
    template <typename Object>
1301
        requires(
1302
                    not requires(const Object& object, const get_allocator_t& tag) { object.query(tag); } &&
1303
                    not requires(Object&& object, const get_allocator_t& tag) { ::std::as_const(object).query(tag); })
1304
    auto operator()(Object&&) const = BEMAN_EXECUTION_DELETE("the object requires a query(get_allocator_t) overload");
1305
    template <typename Object>
1306
        requires(not requires(const Object& object, const get_allocator_t& tag) {
1307
                    { object.query(tag) } noexcept;
1308
                })
1309
    auto
1310
    operator()(Object&&) const = BEMAN_EXECUTION_DELETE("the query(get_allocator_t) overload needs to be noexcept");
1311

1312
    template <typename Object>
1313
        requires(not requires(const Object& object, const get_allocator_t& tag) {
1314
                    { object.query(tag) } noexcept -> ::beman::execution::detail::simple_allocator<>;
1315
                })
1316
    auto
1317
    operator()(Object&&) const = BEMAN_EXECUTION_DELETE("the query(get_allocator_t) overload needs to be noexcept");
1318

1319
    template <typename Object>
1320
        requires(requires(const Object& object, const get_allocator_t& tag) {
1321
            { object.query(tag) } noexcept -> ::beman::execution::detail::simple_allocator<>;
1322
        })
1323
    auto operator()(Object&& object) const noexcept {
1324
        return ::std::as_const(object).query(*this);
1325
    }
1326

1327
    constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; }
1328
};
1329

1330
export inline constexpr get_allocator_t get_allocator{};
1331
} // namespace beman::execution
1332

1333
// ----------------------------------------------------------------------------
1334

1335
// ----------------------------------------------------------------------------
1336

1337
namespace beman::execution {
1338
export struct get_domain_t {
1339
    template <typename Object>
1340
        requires(not requires(Object&& object, const get_domain_t& tag) {
1341
                    ::std::forward<Object>(object).query(tag);
1342
                }) && (not requires(Object&& object, const get_domain_t& tag) { ::std::as_const(object).query(tag); })
1343
    auto operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("object needs a query(get_domain_t) overload");
1344
    template <typename Object>
1345
        requires(not requires(Object&& object, const get_domain_t& tag) { ::std::as_const(object).query(tag); })
1346
    auto
1347
    operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("query(get_domain_t) overload needs to be const");
1348
    template <typename Object>
1349
        requires(not requires(Object&& object, const get_domain_t& tag) {
1350
                    { ::std::as_const(object).query(tag) } noexcept;
1351
                })
1352
    auto
1353
    operator()(Object&&) const noexcept = BEMAN_EXECUTION_DELETE("query(get_domain_t) overload needs to be noexcept");
1354

1355
    template <typename Object>
1356
    constexpr auto operator()(Object&& object) const noexcept {
1357
        return ::std::as_const(object).query(*this);
1358
    }
1359
    constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; }
1360
};
1361

1362
export inline constexpr get_domain_t get_domain{};
1363
} // namespace beman::execution
1364

1365
// ----------------------------------------------------------------------------
1366

1367
// ----------------------------------------------------------------------------
1368

1369
namespace beman::execution {
1370
export struct get_scheduler_t : ::beman::execution::forwarding_query_t {
1371
    template <typename Env>
1372
        requires requires(const get_scheduler_t& self, Env&& env) { ::std::as_const(env).query(self); }
1373
    auto operator()(Env&& env) const noexcept {
1374
        static_assert(noexcept(::std::as_const(env).query(*this)));
1375
        //-dk:TODO mandate that the result is a scheduler
1376
        // static_assert(::beman::execution::scheduler<
1377
        //     decltype(::std::as_const(env).query(*this))
1378
        // >)
1379
        return ::std::as_const(env).query(*this);
1380
    }
1381
};
1382

1383
export inline constexpr get_scheduler_t get_scheduler{};
1384
} // namespace beman::execution
1385

1386
// ----------------------------------------------------------------------------
1387

1388
// ----------------------------------------------------------------------------
1389

1390
namespace beman::execution {
1391
export struct operation_state_t {};
1392

1393
export template <typename State>
1394
concept operation_state =
1395
    ::std::derived_from<typename State::operation_state_concept, ::beman::execution::operation_state_t> &&
1396
    ::std::is_object_v<State> && requires(State& state) {
1397
        { ::beman::execution::start(state) } noexcept;
1398
    };
1399
} // namespace beman::execution
1400

1401
// ----------------------------------------------------------------------------
1402

1403
// ----------------------------------------------------------------------------
1404

1405
namespace beman::execution::detail {
1406
template <typename, typename>
1407
struct valid_completion_for_aux;
1408

1409
template <typename Rcvr, typename Tag, typename... Args>
1410
struct valid_completion_for_aux<Rcvr, Tag (*)(Args...)> {
1411
    static auto test(Tag (*)(Args...)) -> void
1412
        requires ::beman::execution::detail::callable<Tag, ::std::remove_cvref_t<Rcvr>, Args...>
1413
    {}
1414
};
1415

1416
template <typename Signature, typename Rcvr>
1417
concept valid_completion_for = requires(Signature* signature) {
1418
#if 1
1419
    valid_completion_for_aux<Rcvr, Signature*>::test(signature);
1420
#else
1421
    // This definition crashes some versions of clang.
1422
    []<typename Tag, typename... Args>(Tag (*)(Args...))
1423
        requires ::beman::execution::detail::callable<Tag, ::std::remove_cvref_t<Rcvr>, Args...>
1424
    {}(signature);
1425
#endif
1426
};
1427
} // namespace beman::execution::detail
1428

1429
// ----------------------------------------------------------------------------
1430

1431
// ----------------------------------------------------------------------------
1432

1433
namespace beman::execution::detail {
1434
template <typename>
1435
struct is_set_error : ::std::false_type {};
1436
template <typename Error>
1437
struct is_set_error<::beman::execution::set_error_t(Error)> : ::std::true_type {};
1438

1439
template <typename Fun>
1440
using is_set_stopped = ::std::is_same<Fun, ::beman::execution::set_stopped_t()>;
1441

1442
template <typename>
1443
struct is_set_value : ::std::false_type {};
1444
template <typename... Args>
1445
struct is_set_value<::beman::execution::set_value_t(Args...)> : ::std::true_type {};
1446

1447
/*!
1448
 * \brief Detect if a type is a completion signature.
1449
 *
1450
 * \details
1451
 * The three completion signatures are
1452
 * - set_error_t(E) for completion with an error.
1453
 * - set_stopped_t() to indicate that operation was cancelled.
1454
 * - set_value_t(A...) for successful completion with a set of argument.
1455
 *
1456
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1457
 * \concept copmletion_signature
1458
 * \internal
1459
 */
1460
template <typename Fun>
1461
concept completion_signature =
1462
    ::beman::execution::detail::is_set_error<Fun>::value || ::beman::execution::detail::is_set_stopped<Fun>::value ||
1463
    ::beman::execution::detail::is_set_value<Fun>::value;
1464
} // namespace beman::execution::detail
1465

1466
// ----------------------------------------------------------------------------
1467

1468
// ----------------------------------------------------------------------------
1469

1470
namespace beman::execution::detail {
1471
template <typename>
1472
struct prop_like;
1473
}
1474

1475
namespace beman::execution {
1476
export template <typename Query, typename Value>
1477
struct prop;
1478

1479
template <typename Query, typename Value>
1480
prop(Query, Value, ::beman::execution::detail::non_assignable = {}) -> prop<Query, ::std::unwrap_reference_t<Value>>;
1481
} // namespace beman::execution
1482

1483
template <typename V>
1484
struct beman::execution::detail::prop_like {
1485
    V    value;
1486
    auto query(auto) const noexcept -> const V& { return this->value; }
1487
};
1488

1489
template <typename Query, typename Value>
1490
struct beman::execution::prop {
1491
    static_assert(::beman::execution::detail::callable<Query, ::beman::execution::detail::prop_like<Value>>);
1492

1493
    [[no_unique_address]] Query                                      query_{};
1494
    [[no_unique_address]] Value                                      value_{};
1495
    [[no_unique_address]] ::beman::execution::detail::non_assignable non_assignable_{};
1496

1497
    // prop(prop&&)                = default;
1498
    // prop(const prop&)           = default;
1499
    // auto operator=(prop&&) -> prop&      = delete;
1500
    // auto operator=(const prop&) -> prop& = delete;
1501

1502
    constexpr auto query(Query) const noexcept -> const Value& { return this->value_; }
1503
};
1504

1505
// ----------------------------------------------------------------------------
1506

1507
// ----------------------------------------------------------------------------
1508

1509
namespace beman::execution {
1510
export template <typename Token>
1511
concept stoppable_token = requires(const Token& token) {
1512
    typename ::beman::execution::detail::check_type_alias_exist<Token::template callback_type>;
1513
    { token.stop_requested() } noexcept -> ::std::same_as<bool>;
1514
    { token.stop_possible() } noexcept -> ::std::same_as<bool>;
1515
    { Token(token) } noexcept;
1516
} && ::std::copyable<Token> && ::std::equality_comparable<Token> && ::std::swappable<Token>;
1517
} // namespace beman::execution
1518

1519
// ----------------------------------------------------------------------------
1520

1521
// ----------------------------------------------------------------------------
1522

1523
namespace beman::execution::detail {
1524
/*!
1525
 * \brief A helper concept used to determine if a type is one of the completion tags.
1526
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1527
 * \internal
1528
 */
1529
template <typename Tag>
1530
concept completion_tag =
1531
    ::std::same_as<Tag, ::beman::execution::set_error_t> || ::std::same_as<Tag, ::beman::execution::set_stopped_t> ||
1532
    ::std::same_as<Tag, ::beman::execution::set_value_t>;
1533
} // namespace beman::execution::detail
1534

1535
// ----------------------------------------------------------------------------
1536

1537
// ----------------------------------------------------------------------------
1538

1539
namespace beman::execution::detail {
1540
/*!
1541
 * \brief Auxiliary type alias to get the result type of an awaiter.
1542
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1543
 * \internal
1544
 */
1545
template <typename T, typename Promise>
1546
using await_result_type =
1547
    decltype(::beman::execution::detail::get_awaiter(::std::declval<T>(), ::std::declval<Promise&>()).await_resume());
1548
} // namespace beman::execution::detail
1549

1550
// ----------------------------------------------------------------------------
1551

1552
// ----------------------------------------------------------------------------
1553

1554
namespace beman::execution::detail {
1555
/*!
1556
 * \brief A helper class to create environments and taking forwarding_query into account
1557
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
1558
 * \internal
1559
 */
1560
template <typename Env>
1561
class fwd_env {
1562
  private:
1563
    Env env;
1564

1565
  public:
1566
    explicit fwd_env(Env&& e) : env(::std::forward<Env>(e)) {}
1567

1568
    template <typename Query, typename... Args>
1569
        requires(!::beman::execution::forwarding_query(::std::remove_cvref_t<Query>()))
1570
    constexpr auto query(Query&& q,
1571
                         Args&&... args) const = BEMAN_EXECUTION_DELETE("the used query is not forwardable");
1572

1573
    template <typename Query, typename... Args>
1574
        requires(::beman::execution::forwarding_query(::std::remove_cvref_t<Query>())) &&
1575
                requires(const Env& e, Query&& q, Args&&... args) { e.query(q, ::std::forward<Args>(args)...); }
1576
    constexpr auto query(Query&& q, Args&&... args) const
1577
        noexcept(noexcept(env.query(q, ::std::forward<Args>(args)...))) {
1578
        return env.query(q, ::std::forward<Args>(args)...);
1579
    }
1580
};
1581
template <typename Env>
1582
fwd_env(Env&&) -> fwd_env<Env>;
1583
} // namespace beman::execution::detail
1584

1585
// ----------------------------------------------------------------------------
1586

1587
// ----------------------------------------------------------------------------
1588

1589
namespace beman::execution {
1590
export template <typename Sender>
1591
using tag_of_t = typename decltype(::beman::execution::detail::get_sender_meta(::std::declval<Sender&&>()))::tag_type;
1592
}
1593

1594
// ----------------------------------------------------------------------------
1595

1596
// ----------------------------------------------------------------------------
1597

1598
namespace beman::execution::detail::meta::detail {
1599
template <typename...>
1600
struct combine;
1601

1602
template <template <typename...> class L0, typename... T0>
1603
struct combine<L0<T0...>> {
1604
    using type = L0<T0...>;
1605
};
1606
template <template <typename...> class L0,
1607
          typename... T0,
1608
          template <typename...> class L1,
1609
          typename... T1,
1610
          typename... L>
1611
struct combine<L0<T0...>, L1<T1...>, L...> {
1612
    using type = typename combine<L0<T0..., T1...>, L...>::type;
1613
};
1614
} // namespace beman::execution::detail::meta::detail
1615

1616
namespace beman::execution::detail::meta {
1617
template <typename... L>
1618
using combine = typename ::beman::execution::detail::meta::detail::combine<L...>::type;
1619
}
1620

1621
// ----------------------------------------------------------------------------
1622

1623
// ----------------------------------------------------------------------------
1624

1625
namespace beman::execution::detail::meta::detail {
1626
template <typename, typename>
1627
struct make_unique;
1628
template <typename>
1629
struct unique;
1630

1631
template <template <typename...> class List, typename... R>
1632
struct make_unique<List<R...>, List<>> {
1633
    using type = List<R...>;
1634
};
1635

1636
template <template <typename...> class List, typename... R, typename H, typename... T>
1637
struct make_unique<List<R...>, List<H, T...>> {
1638
    using type = typename ::beman::execution::detail::meta::detail::make_unique<
1639
        ::std::conditional_t<::beman::execution::detail::meta::contains<H, R...>, List<R...>, List<R..., H>>,
1640
        List<T...>>::type;
1641
};
1642

1643
template <template <typename...> class List, typename... T>
1644
struct unique<List<T...>> {
1645
    using type = typename ::beman::execution::detail::meta::detail::make_unique<List<>, List<T...>>::type;
1646
};
1647
} // namespace beman::execution::detail::meta::detail
1648

1649
namespace beman::execution::detail::meta {
1650
template <typename T>
1651
using unique = typename ::beman::execution::detail::meta::detail::unique<T>::type;
1652
}
1653

1654
// ----------------------------------------------------------------------------
1655

1656
// ----------------------------------------------------------------------------
1657

1658
namespace beman::execution::detail::meta::detail {
1659
template <template <typename> class, typename>
1660
struct filter;
1661

1662
template <template <typename, typename> class, typename, typename>
1663
struct filter_tag;
1664

1665
template <template <typename> class Predicate, template <typename...> class List>
1666
struct filter<Predicate, List<>> {
1667
    using type = List<>;
1668
};
1669

1670
template <template <typename, typename> class Predicate, typename Tag, template <typename...> class List>
1671
struct filter_tag<Predicate, Tag, List<>> {
1672
    using type = List<>;
1673
};
1674

1675
template <template <typename> class Predicate, template <typename...> class List, typename H, typename... T>
1676
struct filter<Predicate, List<H, T...>> {
1677
    using tail = typename beman::execution::detail::meta::detail::filter<Predicate, List<T...>>::type;
1678
    using type = ::std::conditional_t<Predicate<H>::value, ::beman::execution::detail::meta::prepend<H, tail>, tail>;
1679
};
1680

1681
template <template <typename, typename> class Predicate,
1682
          typename Tag,
1683
          template <typename...> class List,
1684
          typename H,
1685
          typename... T>
1686
struct filter_tag<Predicate, Tag, List<H, T...>> {
1687
    using tail = typename beman::execution::detail::meta::detail::filter_tag<Predicate, Tag, List<T...>>::type;
1688
    using type =
1689
        ::std::conditional_t<Predicate<Tag, H>::value, ::beman::execution::detail::meta::prepend<H, tail>, tail>;
1690
};
1691
} // namespace beman::execution::detail::meta::detail
1692

1693
namespace beman::execution::detail::meta {
1694
template <template <typename> class Predicate, typename List>
1695
using filter = typename ::beman::execution::detail::meta::detail::filter<Predicate, List>::type;
1696

1697
template <template <typename, typename> class Predicate, typename Tag, typename List>
1698
using filter_tag = typename ::beman::execution::detail::meta::detail::filter_tag<Predicate, Tag, List>::type;
1699
} // namespace beman::execution::detail::meta
1700

1701
// ----------------------------------------------------------------------------
1702

1703
// ----------------------------------------------------------------------------
1704

1705
namespace beman::execution::detail::meta::detail {
1706
template <template <typename> class Transform, typename List>
1707
struct transform;
1708

1709
template <template <typename> class Transform, template <typename... T> class List, typename... T>
1710
struct transform<Transform, List<T...>> {
1711
    using type = List<Transform<T>...>;
1712
};
1713
} // namespace beman::execution::detail::meta::detail
1714

1715
namespace beman::execution::detail::meta {
1716
template <template <typename> class Transform, typename List>
1717
using transform = typename ::beman::execution::detail::meta::detail::transform<Transform, List>::type;
1718
}
1719

1720
// ----------------------------------------------------------------------------
1721

1722
// ----------------------------------------------------------------------------
1723

1724
namespace beman::execution::detail {
1725
/*!
1726
 * \brief Turn a completion signatures into a std::tuple type.
1727
 * \internal
1728
 */
1729
template <typename T>
1730
struct as_tuple;
1731
/*!
1732
 * \brief The actual operational partial specialization of as_tuple.
1733
 * \internal
1734
 */
1735
template <typename Rc, typename... A>
1736
struct as_tuple<Rc(A...)> {
1737
    using type = ::beman::execution::detail::decayed_tuple<Rc, A...>;
1738
};
1739

1740
template <typename T>
1741
using as_tuple_t = typename ::beman::execution::detail::as_tuple<T>::type;
1742
} // namespace beman::execution::detail
1743

1744
// ----------------------------------------------------------------------------
1745

1746
namespace beman::execution::detail {
1747

1748
template <auto Next>
1749
class atomic_intrusive_stack;
1750

1751
//! @brief  This data structure is an intrusive stack that can be used in a lock-free manner.
1752
//!
1753
//! The stack is implemented as a singly linked list where the head is an atomic pointer to the first item in
1754
//! the stack.
1755
//! try_push() is a lock-free operation that tries to push an item to the stack. If the stack is empty, it
1756
//! returns nullptr and the item is pushed to the stack.
1757
//! This stack has a closed state, which is indicated by the head pointing to the stack itself. In this state,
1758
//! try_push() returns std::nullopt and the stack is not modified.
1759
//! pop_all_and_shutdown() is a lock-free operation that pops all items from the stack and returns them in a
1760
//! queue. If the stack is empty, it returns an empty queue.
1761
//!
1762
//! We use this stack in the split implementation to store the listeners that are waiting for the operation to
1763
//! complete.
1764
//!
1765
//! @tparam Item  The type of the item in the stack.
1766
//! @tparam Next  The pointer to the next item in the stack.
1767
template <class Item, Item* Item::* Next>
1768
class atomic_intrusive_stack<Next> {
1769
  public:
1770
    atomic_intrusive_stack() = default;
1771
    ~atomic_intrusive_stack() { assert(!head_ || head_ == this); }
1772
    atomic_intrusive_stack(const atomic_intrusive_stack&)                        = delete;
1773
    auto operator=(const atomic_intrusive_stack&) -> atomic_intrusive_stack&     = delete;
1774
    atomic_intrusive_stack(atomic_intrusive_stack&&) noexcept                    = delete;
1775
    auto operator=(atomic_intrusive_stack&&) noexcept -> atomic_intrusive_stack& = delete;
1776

1777
    //! @brief  Tries to push an item to the stack.
1778
    //!
1779
    //! @param item  The item to push to the stack.
1780
    //!
1781
    //! @return  If the stack is empty, returns nullptr and pushes the item to the stack.
1782
    //!          If the stack is in the closed state, returns std::nullopt.
1783
    auto try_push(Item* item) noexcept -> std::optional<Item*> {
1784
        void* ptr = head_.load();
1785
        if (ptr == this) {
1786
            return std::nullopt;
1787
        }
1788
        item->*Next = static_cast<Item*>(ptr);
1789
        while (!head_.compare_exchange_weak(ptr, item)) {
1790
            if (ptr == this) {
1791
                return std::nullopt;
1792
            }
1793
            item->*Next = static_cast<Item*>(ptr);
1794
        }
1795
        return static_cast<Item*>(ptr);
1796
    }
1797

1798
    //! @brief  Tests if the stack is empty and not in the closed state.
1799
    auto empty_and_not_shutdown() const noexcept -> bool { return head_.load() == nullptr; }
1800

1801
    //! @brief  Pops all items from the stack, returns them and puts this stack into the closed state.
1802
    //!
1803
    //! @return  If the stack is empty, returns an empty stack.
1804
    auto pop_all_and_shutdown() noexcept -> ::beman::execution::detail::intrusive_stack<Next> {
1805
        auto  stack = ::beman::execution::detail::intrusive_stack<Next>{};
1806
        void* ptr   = head_.exchange(this);
1807
        if (ptr == this) {
1808
            return stack;
1809
        }
1810
        auto item   = static_cast<Item*>(ptr);
1811
        stack.head_ = item;
1812
        return stack;
1813
    }
1814

1815
  private:
1816
    ::std::atomic<void*> head_{nullptr};
1817
};
1818

1819
} // namespace beman::execution::detail
1820

1821
// ----------------------------------------------------------------------------
1822

1823
namespace beman::execution {
1824
export class inplace_stop_token;
1825
export class inplace_stop_source;
1826
export template <typename CallbackFun>
1827
class inplace_stop_callback;
1828
export template <typename CallbackFun>
1829
inplace_stop_callback(::beman::execution::inplace_stop_token, CallbackFun) -> inplace_stop_callback<CallbackFun>;
1830
} // namespace beman::execution
1831

1832
// ----------------------------------------------------------------------------
1833

1834
class beman::execution::inplace_stop_token {
1835
  public:
1836
    template <typename CallbackFun>
1837
    using callback_type = ::beman::execution::inplace_stop_callback<CallbackFun>;
1838

1839
    inplace_stop_token() = default;
1840

1841
    constexpr auto stop_requested() const noexcept -> bool;
1842
    constexpr auto stop_possible() const noexcept -> bool;
1843
    auto           operator==(const inplace_stop_token&) const -> bool = default;
1844

1845
    auto swap(inplace_stop_token&) noexcept -> void;
1846

1847
  private:
1848
    friend class ::beman::execution::inplace_stop_source;
1849
    template <typename CallbackFun>
1850
    friend class ::beman::execution::inplace_stop_callback;
NEW
1851
    explicit inplace_stop_token(::beman::execution::inplace_stop_source* src) : source(src) {}
×
1852

1853
    ::beman::execution::inplace_stop_source* source{};
1854
};
1855

1856
// ----------------------------------------------------------------------------
1857

1858
class beman::execution::inplace_stop_source {
1859
    struct callback_base : public ::beman::execution::detail::virtual_immovable {
1860
        callback_base* next{};
1861
        virtual auto   call() -> void = 0;
1862
    };
1863

1864
  public:
1865
    auto                  stop_requested() const noexcept -> bool;
1866
    static constexpr auto stop_possible() noexcept -> bool;
1867
    auto                  get_token() const -> ::beman::execution::inplace_stop_token;
1868

1869
    auto request_stop() -> bool;
1870

1871
  private:
1872
    template <typename CallbackFun>
1873
    friend class ::beman::execution::inplace_stop_callback;
1874
    ::std::atomic<bool>           stopped{};
1875
    ::std::atomic<callback_base*> running{};
1876
    ::std::thread::id             id{};
1877
    ::std::mutex                  lock;
1878
    callback_base*                callbacks{};
1879

1880
    auto add(callback_base* cb) -> void;
1881
    auto deregister(callback_base* cb) -> void;
1882
};
1883

1884
// ----------------------------------------------------------------------------
1885

1886
template <typename CallbackFun>
1887
class beman::execution::inplace_stop_callback final : public ::beman::execution::inplace_stop_source::callback_base {
1888
  public:
1889
    using callback_type = CallbackFun;
1890

1891
    template <typename Init>
1892
    inplace_stop_callback(::beman::execution::inplace_stop_token, Init&&);
1893
    inplace_stop_callback(const inplace_stop_callback&) = delete;
1894
    inplace_stop_callback(inplace_stop_callback&&)      = delete;
1895
    ~inplace_stop_callback() override {
1896
        if (this->source) {
1897
            this->source->deregister(this);
1898
        }
1899
    }
1900
    auto operator=(const inplace_stop_callback&) -> inplace_stop_callback& = delete;
1901
    auto operator=(inplace_stop_callback&&) -> inplace_stop_callback&      = delete;
1902

1903
  private:
1904
    auto call() -> void override;
1905

1906
    CallbackFun                              fun;
1907
    ::beman::execution::inplace_stop_source* source;
1908
};
1909

1910
// ----------------------------------------------------------------------------
1911

1912
inline constexpr auto beman::execution::inplace_stop_token::stop_requested() const noexcept -> bool {
1913
    return this->source && this->source->stop_requested();
1914
}
1915

1916
inline constexpr auto beman::execution::inplace_stop_token::stop_possible() const noexcept -> bool {
1917
    return this->source;
1918
}
1919

1920
inline auto beman::execution::inplace_stop_token::swap(inplace_stop_token& other) noexcept -> void {
1921
    ::std::swap(this->source, other.source);
1922
}
1923

1924
inline auto beman::execution::inplace_stop_source::stop_requested() const noexcept -> bool { return this->stopped; }
1925

1926
inline constexpr auto beman::execution::inplace_stop_source::stop_possible() noexcept -> bool { return true; }
1927

NEW
1928
inline auto beman::execution::inplace_stop_source::get_token() const -> ::beman::execution::inplace_stop_token {
×
NEW
1929
    return ::beman::execution::inplace_stop_token(const_cast<::beman::execution::inplace_stop_source*>(this));
×
1930
}
1931

NEW
1932
inline auto beman::execution::inplace_stop_source::request_stop() -> bool {
×
NEW
1933
    using relock = ::std::unique_ptr<::std::unique_lock<::std::mutex>, decltype([](auto p) { p->lock(); })>;
×
NEW
1934
    if (false == this->stopped.exchange(true)) {
×
NEW
1935
        ::std::unique_lock guard(this->lock);
×
NEW
1936
        for (auto it = this->callbacks; it != nullptr; it = this->callbacks) {
×
NEW
1937
            this->running   = it;
×
NEW
1938
            this->id        = ::std::this_thread::get_id();
×
NEW
1939
            this->callbacks = it->next;
×
1940
            {
NEW
1941
                relock r(&guard);
×
NEW
1942
                guard.unlock();
×
NEW
1943
                it->call();
×
NEW
1944
            }
×
NEW
1945
            this->running = nullptr;
×
1946
        }
NEW
1947
        return true;
×
NEW
1948
    }
×
NEW
1949
    return false;
×
1950
}
1951

1952
inline auto beman::execution::inplace_stop_source::add(callback_base* cb) -> void {
1953
    if (this->stopped) {
1954
        cb->call();
1955
    } else {
1956
        ::std::lock_guard guard(this->lock);
1957
        cb->next = ::std::exchange(this->callbacks, cb);
1958
    }
1959
}
1960

1961
inline auto beman::execution::inplace_stop_source::deregister(callback_base* cb) -> void {
1962
    ::std::unique_lock guard(this->lock);
1963
    if (this->running == cb) {
1964
        if (this->id == ::std::this_thread::get_id()) {
1965
            return;
1966
        }
1967
        guard.unlock();
1968
        while (this->running == cb) {
1969
        }
1970
        return;
1971
    }
1972

1973
    for (callback_base** it{&this->callbacks}; *it; it = &(*it)->next) {
1974
        if (*it == cb) {
1975
            *it = cb->next;
1976
            break;
1977
        }
1978
    }
1979
}
1980

1981
template <typename CallbackFun>
1982
template <typename Init>
1983
inline beman::execution::inplace_stop_callback<CallbackFun>::inplace_stop_callback(
1984
    ::beman::execution::inplace_stop_token token, Init&& init)
1985
    : fun(::std::forward<Init>(init)), source(token.source) {
1986
    if (this->source) {
1987
        this->source->add(this);
1988
    }
1989
}
1990

1991
template <typename CallbackFun>
1992
inline auto beman::execution::inplace_stop_callback<CallbackFun>::call() -> void {
1993
    this->fun();
1994
}
1995

1996
// ----------------------------------------------------------------------------
1997

1998
// ----------------------------------------------------------------------------
1999

2000
namespace beman::execution::detail {
2001
template <class... Args>
2002
using decayed_type_list = ::beman::execution::detail::type_list<::std::decay_t<Args>...>;
2003
} // namespace beman::execution::detail
2004

2005
// ----------------------------------------------------------------------------
2006

2007
// ----------------------------------------------------------------------------
2008

2009
namespace beman::execution::detail {
2010
/*!
2011
 * \brief Auxiliary concept used to detect class types. [execution.syn#concept:class-type]
2012
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2013
 * \internal
2014
 */
2015
template <typename Tp>
2016
concept class_type = ::beman::execution::detail::decays_to<Tp, Tp> && ::std::is_class_v<Tp>;
2017
} // namespace beman::execution::detail
2018

2019
// ----------------------------------------------------------------------------
2020

2021
// ----------------------------------------------------------------------------
2022

2023
namespace beman::execution::detail {
2024
template <typename Fun, typename... Args>
2025
concept nothrow_callable = ::beman::execution::detail::callable<Fun, Args...> && requires(Fun&& fun, Args&&... args) {
2026
    { ::std::forward<Fun>(fun)(::std::forward<Args>(args)...) } noexcept;
2027
};
2028
} // namespace beman::execution::detail
2029

2030
// ----------------------------------------------------------------------------
2031

2032
// ----------------------------------------------------------------------------
2033

2034
namespace beman::execution::detail {
2035
class counting_scope_base;
2036
}
2037

2038
// ----------------------------------------------------------------------------
2039

2040
class beman::execution::detail::counting_scope_base : ::beman::execution::detail::immovable {
2041
  public:
2042
    counting_scope_base()                      = default;
2043
    counting_scope_base(counting_scope_base&&) = delete;
2044
    ~counting_scope_base();
2045

2046
    static constexpr ::std::size_t max_associations{8194u};
2047

2048
    auto close() noexcept -> void;
2049

2050
    struct node {
2051
        virtual auto complete() noexcept -> void        = 0;
2052
        virtual auto complete_inline() noexcept -> void = 0;
2053
        node*        next{};
2054
    };
2055
    auto start_node(node*) -> void;
2056

2057
  protected:
2058
    class token {
2059
      public:
NEW
2060
        auto try_associate() const noexcept -> bool { return this->scope->try_associate(); }
×
NEW
2061
        auto disassociate() const noexcept -> void { this->scope->disassociate(); }
×
2062

2063
      protected:
NEW
2064
        explicit token(::beman::execution::detail::counting_scope_base* s) : scope(s) {}
×
2065
        ::beman::execution::detail::counting_scope_base* scope;
2066
    };
2067

2068
  private:
2069
    enum class state_t : unsigned char {
2070
        unused,
2071
        open,
2072
        open_and_joining,
2073
        closed,
2074
        closed_and_joining,
2075
        unused_and_closed,
2076
        joined
2077
    };
2078

2079
    auto try_associate() noexcept -> bool;
2080
    auto disassociate() noexcept -> void;
2081
    auto complete() noexcept -> void;
2082
    auto add_node(node* n, ::std::lock_guard<::std::mutex>&) noexcept -> void;
2083

2084
    ::std::mutex mutex;
2085
    //-dk:TODO fuse state and count and use atomic accesses
2086
    ::std::size_t count{};
2087
    state_t       state{state_t::unused};
2088
    node*         head{};
2089
};
2090

2091
// ----------------------------------------------------------------------------
2092

2093
inline beman::execution::detail::counting_scope_base::~counting_scope_base() {
2094
    ::std::lock_guard kerberos(this->mutex);
2095
    switch (this->state) {
2096
    default:
2097
        ::std::terminate();
2098
    case state_t::unused:
2099
    case state_t::unused_and_closed:
2100
    case state_t::joined:
2101
        break;
2102
    }
2103
}
2104

2105
inline auto beman::execution::detail::counting_scope_base::close() noexcept -> void {
2106
    switch (this->state) {
2107
    default:
2108
        break;
2109
    case state_t::unused:
2110
        this->state = state_t::unused_and_closed;
2111
        break;
2112
    case state_t::open:
2113
        this->state = state_t::closed;
2114
        break;
2115
    case state_t::open_and_joining:
2116
        this->state = state_t::closed_and_joining;
2117
        break;
2118
    }
2119
}
2120

2121
inline auto beman::execution::detail::counting_scope_base::add_node(node* n, ::std::lock_guard<::std::mutex>&) noexcept
2122
    -> void {
2123
    n->next = std::exchange(this->head, n);
2124
}
2125

NEW
2126
inline auto beman::execution::detail::counting_scope_base::try_associate() noexcept -> bool {
×
NEW
2127
    ::std::lock_guard lock(this->mutex);
×
NEW
2128
    switch (this->state) {
×
NEW
2129
    default:
×
NEW
2130
        return false;
×
NEW
2131
    case state_t::unused:
×
NEW
2132
        this->state = state_t::open; // fall-through!
×
2133
        [[fallthrough]];
NEW
2134
    case state_t::open:
×
2135
    case state_t::open_and_joining:
NEW
2136
        ++this->count;
×
NEW
2137
        return true;
×
2138
    }
NEW
2139
}
×
2140

NEW
2141
inline auto beman::execution::detail::counting_scope_base::disassociate() noexcept -> void {
×
2142
    {
NEW
2143
        ::std::lock_guard lock(this->mutex);
×
NEW
2144
        if (0u < --this->count)
×
NEW
2145
            return;
×
NEW
2146
        this->state = state_t::joined;
×
NEW
2147
    }
×
NEW
2148
    this->complete();
×
2149
}
2150

NEW
2151
inline auto beman::execution::detail::counting_scope_base::complete() noexcept -> void {
×
NEW
2152
    node* current{[this] {
×
NEW
2153
        ::std::lock_guard lock(this->mutex);
×
NEW
2154
        return ::std::exchange(this->head, nullptr);
×
NEW
2155
    }()};
×
NEW
2156
    while (current) {
×
NEW
2157
        ::std::exchange(current, current->next)->complete();
×
2158
    }
NEW
2159
}
×
2160

2161
inline auto beman::execution::detail::counting_scope_base::start_node(node* n) -> void {
2162
    ::std::lock_guard kerberos(this->mutex);
2163
    switch (this->state) {
2164
    case ::beman::execution::detail::counting_scope_base::state_t::unused:
2165
    case ::beman::execution::detail::counting_scope_base::state_t::unused_and_closed:
2166
    case ::beman::execution::detail::counting_scope_base::state_t::joined:
2167
        this->state = ::beman::execution::detail::counting_scope_base::state_t::joined;
2168
        n->complete_inline();
2169
        return;
2170
    case ::beman::execution::detail::counting_scope_base::state_t::open:
2171
        this->state = ::beman::execution::detail::counting_scope_base::state_t::open_and_joining;
2172
        break;
2173
    case ::beman::execution::detail::counting_scope_base::state_t::open_and_joining:
2174
        break;
2175
    case ::beman::execution::detail::counting_scope_base::state_t::closed:
2176
        this->state = ::beman::execution::detail::counting_scope_base::state_t::closed_and_joining;
2177
        break;
2178
    case ::beman::execution::detail::counting_scope_base::state_t::closed_and_joining:
2179
        break;
2180
    }
2181
    this->add_node(n, kerberos);
2182
}
2183

2184
// ----------------------------------------------------------------------------
2185

2186
// ----------------------------------------------------------------------------
2187

2188
namespace beman::execution::detail {
2189
template <typename Awaiter, typename Promise>
2190
concept is_awaiter = requires(Awaiter& awaiter, ::std::coroutine_handle<Promise> handle) {
2191
    awaiter.await_ready() ? 1 : 0;
2192
    { awaiter.await_suspend(handle) } -> ::beman::execution::detail::await_suspend_result;
2193
    awaiter.await_resume();
2194
};
2195
} // namespace beman::execution::detail
2196

2197
// ----------------------------------------------------------------------------
2198

2199
// ----------------------------------------------------------------------------
2200

2201
namespace beman::execution {
2202
export class stop_token;
2203
export class stop_source;
2204
export template <typename CallbackFun>
2205
class stop_callback;
2206
export template <typename CallbackFun>
2207
stop_callback(::beman::execution::stop_token, CallbackFun) -> stop_callback<CallbackFun>;
2208
} // namespace beman::execution
2209

2210
namespace beman::execution::detail {
2211
struct stop_state;
2212
struct stop_callback_base;
2213
} // namespace beman::execution::detail
2214
// ----------------------------------------------------------------------------
2215

2216
struct beman::execution::detail::stop_state {
2217
    ::std::atomic<bool>                           stop_requested{};
2218
    ::std::atomic<::std::size_t>                  sources{};
2219
    ::std::mutex                                  lock{};
2220
    beman::execution::detail::stop_callback_base* callbacks{};
2221
    ::std::atomic<bool>                           executing{};
2222

NEW
2223
    auto stop_possible() const -> bool { return this->sources != 0 || this->stop_requested; }
×
2224
};
2225

2226
// ----------------------------------------------------------------------------
2227

2228
struct beman::execution::detail::stop_callback_base {
2229
  private:
2230
    using stop_state = ::beman::execution::detail::stop_state;
2231
    ::std::shared_ptr<stop_state> state;
2232

2233
    virtual auto do_call() -> void = 0;
2234

2235
  protected:
2236
    explicit stop_callback_base(const ::beman::execution::stop_token&);
2237
    ~stop_callback_base();
2238

2239
  public:
2240
    stop_callback_base(stop_callback_base&&)                         = delete;
2241
    stop_callback_base(const stop_callback_base&)                    = delete;
2242
    auto operator=(stop_callback_base&&) -> stop_callback_base&      = delete;
2243
    auto operator=(const stop_callback_base&) -> stop_callback_base& = delete;
2244
    auto call() -> void;
2245
    auto setup() -> void;
2246
    auto deregister() -> void;
2247

2248
    stop_callback_base* next{};
2249
    ::std::thread::id   id{};
2250
};
2251

2252
// ----------------------------------------------------------------------------
2253

2254
class beman::execution::stop_source {
2255
  private:
2256
    using stop_state = ::beman::execution::detail::stop_state;
2257

2258
    ::std::shared_ptr<stop_state> state{::std::make_shared<stop_state>()};
2259

2260
  public:
2261
    using stop_token = ::beman::execution::stop_token;
2262

2263
    stop_source();
2264
    explicit stop_source(::beman::execution::nostopstate_t) noexcept;
2265
    stop_source(const stop_source&);
2266
    stop_source(stop_source&&) = default;
2267
    auto operator=(const stop_source&) -> stop_source&;
2268
    auto operator=(stop_source&&) -> stop_source& = default;
2269
    ~stop_source();
2270

2271
    auto swap(stop_source&) noexcept -> void;
2272
    auto get_token() const -> stop_token;
2273
    auto stop_requested() const noexcept -> bool;
2274
    auto stop_possible() const noexcept -> bool;
2275
    auto request_stop() noexcept -> bool;
2276
};
2277

2278
// ----------------------------------------------------------------------------
2279

2280
class beman::execution::stop_token {
2281
  private:
2282
    friend ::beman::execution::stop_source;
2283
    friend ::beman::execution::detail::stop_callback_base;
2284
    ::std::shared_ptr<::beman::execution::detail::stop_state> state;
2285

2286
    explicit stop_token(::std::shared_ptr<::beman::execution::detail::stop_state>);
2287

2288
  public:
2289
    template <typename Fun>
2290
    using callback_type = ::beman::execution::stop_callback<Fun>;
2291

2292
    stop_token() = default;
2293

2294
    auto               swap(stop_token& other) noexcept -> void;
2295
    [[nodiscard]] auto stop_requested() const noexcept -> bool;
2296
    [[nodiscard]] auto stop_possible() const noexcept -> bool;
2297

2298
    [[nodiscard]] auto operator==(const stop_token&) const noexcept -> bool = default;
2299
};
2300

2301
// ----------------------------------------------------------------------------
2302

2303
template <typename CallbackFun>
2304
class beman::execution::stop_callback final : private CallbackFun, beman::execution::detail::stop_callback_base {
2305
  private:
2306
    static_assert(::std::invocable<CallbackFun>);
2307
    static_assert(::std::destructible<CallbackFun>);
2308

2309
    using stop_token = ::beman::execution::stop_token;
2310

2311
    auto do_call() -> void override { (*this)(); }
2312

2313
  public:
2314
    using callback_type = CallbackFun;
2315

2316
    template <typename Initializer>
2317
    stop_callback(const stop_token& token,
2318
                  Initializer&&     init) noexcept(::std::is_nothrow_constructible_v<CallbackFun, Initializer>)
2319
        requires(::std::constructible_from<CallbackFun, Initializer>)
2320
        : CallbackFun(::std::forward<Initializer>(init)), stop_callback_base(token) {
2321
        this->setup();
2322
    }
2323
    template <typename Initializer>
2324
    stop_callback(stop_token&&  token,
2325
                  Initializer&& init) noexcept(::std::is_nothrow_constructible_v<CallbackFun, Initializer>)
2326
        requires(::std::is_constructible_v<CallbackFun, Initializer>)
2327
        : CallbackFun(::std::forward<Initializer>(init)), stop_callback_base(::std::move(token)) {
2328
        this->setup();
2329
    }
2330
    stop_callback(const stop_callback&) = delete;
2331
    stop_callback(stop_callback&&)      = delete;
2332
    ~stop_callback() { this->deregister(); }
2333
    auto operator=(stop_callback&&) -> stop_callback&      = delete;
2334
    auto operator=(const stop_callback&) -> stop_callback& = delete;
2335
};
2336

2337
// ----------------------------------------------------------------------------
2338

2339
inline beman::execution::detail::stop_callback_base::stop_callback_base(const ::beman::execution::stop_token& token)
2340
    : state(token.state) {}
2341

2342
inline beman::execution::detail::stop_callback_base::~stop_callback_base() {}
2343

2344
inline auto beman::execution::detail::stop_callback_base::setup() -> void {
2345
    if (this->state) {
2346
        {
2347
            ::std::lock_guard guard(this->state->lock);
2348
            if (!this->state->stop_requested) {
2349
                this->next = ::std::exchange(this->state->callbacks, this);
2350
                return;
2351
            }
2352
        }
2353
        this->call();
2354
    }
2355
}
2356

2357
inline auto beman::execution::detail::stop_callback_base::deregister() -> void {
2358
    if (this->state) {
2359
        ::std::unique_lock guard(this->state->lock);
2360
        if (this->state->executing && this->id != ::std::this_thread::get_id()) {
2361
            using lock_again = decltype([](auto p) { p->lock(); });
2362
            ::std::unique_ptr<decltype(guard), lock_again> relock(&guard);
2363
            relock->unlock();
2364
            while (this->state->executing)
2365
                ;
2366
        }
2367
        for (auto n = &this->state->callbacks; *n; n = &this->next) {
2368
            if (*n == this) {
2369
                *n = this->next;
2370
                break;
2371
            }
2372
        }
2373
    }
2374
}
2375

2376
inline auto beman::execution::detail::stop_callback_base::call() -> void { this->do_call(); }
2377

2378
inline beman::execution::stop_token::stop_token(::std::shared_ptr<::beman::execution::detail::stop_state> st)
2379
    : state(::std::move(st)) {}
2380

2381
inline auto beman::execution::stop_token::swap(stop_token& other) noexcept -> void { this->state.swap(other.state); }
2382

2383
inline auto beman::execution::stop_token::stop_requested() const noexcept -> bool {
2384
    return this->state && this->state->stop_requested;
2385
}
2386

2387
inline auto beman::execution::stop_token::stop_possible() const noexcept -> bool {
2388
    return this->state && this->state->stop_possible();
2389
}
2390

2391
// ----------------------------------------------------------------------------
2392

2393
inline beman::execution::stop_source::stop_source() { ++this->state->sources; }
2394

2395
inline beman::execution::stop_source::stop_source(::beman::execution::nostopstate_t) noexcept : state() {}
2396

2397
inline beman::execution::stop_source::stop_source(const stop_source& other) : state(other.state) {
2398
    ++this->state->sources;
2399
}
2400

2401
inline auto beman::execution::stop_source::operator=(const stop_source& other) -> stop_source& {
2402
    stop_source(other).swap(*this);
2403
    return *this;
2404
}
2405

2406
inline beman::execution::stop_source::~stop_source() { this->state && --this->state->sources; }
2407

2408
inline auto beman::execution::stop_source::swap(::beman::execution::stop_source& other) noexcept -> void {
2409
    this->state.swap(other.state);
2410
}
2411

2412
inline auto beman::execution::stop_source::get_token() const -> stop_token { return stop_token{this->state}; }
2413

2414
inline auto beman::execution::stop_source::stop_requested() const noexcept -> bool {
2415
    return this->state && this->state->stop_requested;
2416
}
2417

2418
inline auto beman::execution::stop_source::stop_possible() const noexcept -> bool { return true && this->state; }
2419

2420
inline auto beman::execution::stop_source::request_stop() noexcept -> bool {
2421
    using release    = decltype([](auto p) { *p = false; });
2422
    using lock_again = decltype([](auto p) { p->lock(); });
2423

2424
    if (this->state && not this->state->stop_requested.exchange(true)) {
2425
        ::std::unique_lock guard(this->state->lock);
2426
        while (this->state->callbacks) {
2427
            auto front = ::std::exchange(this->state->callbacks, this->state->callbacks->next);
2428
            ::std::unique_ptr<::std::atomic<bool>, release> reset(&state->executing);
2429
            *reset    = true;
2430
            front->id = ::std::this_thread::get_id();
2431
            ::std::unique_ptr<decltype(guard), lock_again> relock(&guard);
2432
            relock->unlock();
2433
            front->call();
2434
        }
2435
        return true;
2436
    }
2437
    return false;
2438
}
2439

2440
// ----------------------------------------------------------------------------
2441

2442
// ----------------------------------------------------------------------------
2443

2444
namespace beman::execution::detail {
2445
template <typename Token>
2446
concept decayed_stoppable_token = ::beman::execution::stoppable_token<::std::decay_t<Token>>;
2447
}
2448
namespace beman::execution {
2449
export struct get_stop_token_t {
2450
    template <typename Object>
2451
        requires requires(Object&& object, const get_stop_token_t& tag) {
2452
            { ::std::as_const(object).query(tag) } noexcept -> ::beman::execution::detail::decayed_stoppable_token;
2453
        }
2454
    auto operator()(Object&& object) const noexcept {
2455
        return ::std::as_const(object).query(*this);
2456
    }
2457

2458
    template <typename Object>
2459
    auto operator()(Object&&) const noexcept -> ::beman::execution::never_stop_token {
2460
        return {};
2461
    }
2462

2463
    constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; }
2464
};
2465

2466
export inline constexpr get_stop_token_t get_stop_token{};
2467
} // namespace beman::execution
2468

2469
// ----------------------------------------------------------------------------
2470

2471
// ----------------------------------------------------------------------------
2472

2473
namespace beman::execution {
2474
export struct get_env_t {
2475
    template <typename Object>
2476
        requires(not requires(::std::add_const_t<::std::remove_cvref_t<Object>>& object) { object.get_env(); } ||
2477
                 ::beman::execution::detail::queryable<
2478
                     std::remove_cvref_t<decltype(::std::declval<const ::std::remove_cvref_t<Object>&>().get_env())>>)
2479
    auto operator()(Object&& object) const noexcept -> decltype(auto) {
2480
        ::std::add_const_t<::std::remove_cvref_t<Object>>& obj{object};
2481
        if constexpr (requires { obj.get_env(); }) {
2482
            static_assert(noexcept(obj.get_env()), "get_env requires the expression to be noexcept");
2483
            static_assert(::beman::execution::detail::queryable<std::remove_cvref_t<decltype(obj.get_env())>>,
2484
                          "get_env requires the result type to be destructible");
2485
            return obj.get_env();
2486
        } else {
2487
            return ::beman::execution::env<>{};
2488
        }
2489
    }
2490
};
2491

2492
export inline constexpr get_env_t get_env{};
2493
} // namespace beman::execution
2494

2495
// ----------------------------------------------------------------------------
2496

2497
// ----------------------------------------------------------------------------
2498

2499
namespace beman::execution {
2500
/*!
2501
 * \brief Class template used to a specify a list of completion signatures
2502
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2503
 *
2504
 * \details
2505
 * This class template is primarily used for type computations and objects of
2506
 * any specializaion are empty. Objects may be created to return them from
2507
 * functions used for type computations like get_completion_signatures(sender, env).
2508
 */
2509
export template <::beman::execution::detail::completion_signature...>
2510
struct completion_signatures {};
2511
} // namespace beman::execution
2512

2513
// ----------------------------------------------------------------------------
2514

2515
// ----------------------------------------------------------------------------
2516

2517
namespace beman::execution::detail {
2518
template <typename T, typename Promise>
2519
concept is_awaitable = requires(Promise& promise) {
2520
    {
2521
        ::beman::execution::detail::get_awaiter(::std::declval<T>(), promise)
2522
    } -> ::beman::execution::detail::is_awaiter<Promise>;
2523
};
2524
} // namespace beman::execution::detail
2525

2526
// ----------------------------------------------------------------------------
2527

2528
// ----------------------------------------------------------------------------
2529

2530
namespace beman::execution::detail {
2531
/*!
2532
 * \brief Helper class to get the result of a function which may be only called once.
2533
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2534
 * \internal
2535
 */
2536
template <typename Fun>
2537
struct emplace_from {
2538
    using type = ::beman::execution::detail::call_result_t<Fun>;
2539
    Fun fun;
2540

2541
    explicit constexpr operator type() && noexcept(::beman::execution::detail::nothrow_callable<Fun>) {
2542
        return ::std::move(fun)();
2543
    }
2544
};
2545
template <typename Fun>
2546
emplace_from(Fun&&) -> emplace_from<::std::remove_cvref_t<Fun>>;
2547
} // namespace beman::execution::detail
2548

2549
// ----------------------------------------------------------------------------
2550

2551
// ----------------------------------------------------------------------------
2552

2553
namespace beman::execution::detail {
2554
struct empty_variant {
2555
    empty_variant() = delete;
2556
};
2557

2558
template <typename... T>
2559
struct variant_or_empty_helper;
2560

2561
template <>
2562
struct variant_or_empty_helper<> {
2563
    using type = ::beman::execution::detail::empty_variant;
2564
};
2565

2566
template <typename... T>
2567
struct variant_or_empty_helper {
2568
    using type = ::beman::execution::detail::meta::unique<::std::variant<::std::decay_t<T>...>>;
2569
};
2570

2571
template <typename... T>
2572
using variant_or_empty = typename ::beman::execution::detail::variant_or_empty_helper<T...>::type;
2573
} // namespace beman::execution::detail
2574

2575
// ----------------------------------------------------------------------------
2576

2577
// ----------------------------------------------------------------------------
2578

2579
namespace beman::execution::detail {
2580
template <typename Source>
2581
concept stoppable_source = requires(Source& source, const Source& csource) {
2582
    { csource.get_token() } -> ::beman::execution::stoppable_token;
2583
    { csource.stop_possible() } noexcept -> ::std::same_as<bool>;
2584
    { csource.stop_requested() } noexcept -> ::std::same_as<bool>;
2585
    { source.request_stop() } -> ::std::same_as<bool>;
2586
};
2587
} // namespace beman::execution::detail
2588

2589
// ----------------------------------------------------------------------------
2590

2591
// ----------------------------------------------------------------------------
2592

2593
namespace beman::execution {
2594
export struct receiver_t {};
2595

2596
export template <typename Rcvr>
2597
concept receiver =
2598
    ::std::derived_from<typename ::std::remove_cvref_t<Rcvr>::receiver_concept, ::beman::execution::receiver_t> &&
2599
    requires(const ::std::remove_cvref_t<Rcvr>& rcvr) {
2600
        { ::beman::execution::get_env(rcvr) } -> ::beman::execution::detail::queryable;
2601
    } && ::std::move_constructible<::std::remove_cvref_t<Rcvr>> &&
2602
    ::std::constructible_from<::std::remove_cvref_t<Rcvr>, Rcvr> && (!::std::is_final_v<::std::remove_cvref_t<Rcvr>>);
2603
} // namespace beman::execution
2604

2605
// ----------------------------------------------------------------------------
2606

2607
// ----------------------------------------------------------------------------
2608

2609
namespace beman::execution::detail {
2610
template <typename>
2611
struct valid_completion_signatures_helper : ::std::false_type {};
2612
template <typename... Sigs>
2613
struct valid_completion_signatures_helper<::beman::execution::completion_signatures<Sigs...>> : ::std::true_type {};
2614

2615
template <typename Signatures>
2616
concept valid_completion_signatures = valid_completion_signatures_helper<Signatures>::value;
2617
} // namespace beman::execution::detail
2618

2619
// ----------------------------------------------------------------------------
2620

2621
// ----------------------------------------------------------------------------
2622

2623
namespace beman::execution {
2624
/*!
2625
 * \brief Determine the type of the environment associated with a type
2626
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2627
 */
2628
export template <typename T>
2629
using env_of_t = decltype(::beman::execution::get_env(::std::declval<T>()));
2630
} // namespace beman::execution
2631

2632
// ----------------------------------------------------------------------------
2633

2634
// ----------------------------------------------------------------------------
2635

2636
namespace beman::execution::detail {
2637
template <typename T, typename Context>
2638
/*!
2639
 * \brief Utility function use to move a possibly allocator aware object with an allocator from an environment.
2640
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2641
 * \internal
2642
 */
2643
auto allocator_aware_move(T&& obj, Context&& context) noexcept -> decltype(auto) {
2644
    try {
2645
        if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(context)); }) {
2646
            if constexpr (decltype(::beman::execution::detail::is_product_type(obj))()) {
2647
                return obj.make_from(::beman::execution::get_allocator(::beman::execution::get_env(context)),
2648
                                     ::std::forward<T>(obj));
2649
            } else {
2650
                return ::std::make_obj_using_allocator<T>(
2651
                    ::beman::execution::get_allocator(::beman::execution::get_env(context)), ::std::forward<T>(obj));
2652
            }
2653
        } else {
2654
            return ::std::forward<T>(obj);
2655
        }
2656
    } catch (...) {
2657
        ::std::terminate(); //-dk:TODO investigate if that can be avoided
2658
    }
2659
}
2660
} // namespace beman::execution::detail
2661

2662
// ----------------------------------------------------------------------------
2663

2664
// ----------------------------------------------------------------------------
2665

2666
namespace beman::execution {
2667
export template <typename T>
2668
using stop_token_of_t = ::std::remove_cvref_t<decltype(::beman::execution::get_stop_token(::std::declval<T>()))>;
2669
}
2670

2671
// ----------------------------------------------------------------------------
2672

2673
// ----------------------------------------------------------------------------
2674

2675
namespace beman::execution {
2676
export template <typename Token>
2677
concept unstoppable_token = ::beman::execution::stoppable_token<Token> &&
2678
                            requires() { requires ::std::bool_constant<not Token::stop_possible()>::value; };
2679
} // namespace beman::execution
2680

2681
// ----------------------------------------------------------------------------
2682

2683
// ----------------------------------------------------------------------------
2684

2685
namespace beman::execution::detail {
2686
template <typename T, typename Promise>
2687
concept has_as_awaitable = requires(T&& obj, Promise& promise) {
2688
    { ::std::forward<T>(obj).as_awaitable(promise) } -> ::beman::execution::detail::is_awaitable<Promise&>;
2689
};
2690
} // namespace beman::execution::detail
2691

2692
// ----------------------------------------------------------------------------
2693

2694
// ----------------------------------------------------------------------------
2695

2696
namespace beman::execution::detail {
2697
#if not defined(__clang__)
2698
// The version of clang current (2024-09-01) installed on my Mac crashes
2699
// with this code - thus, there is a work-around.
2700
template <typename Receiver, typename Completions>
2701
concept has_completions = requires(Completions* completions) {
2702
    []<::beman::execution::detail::valid_completion_for<Receiver>... Signatures>(
2703
        ::beman::execution::completion_signatures<Signatures...>*) {}(completions);
2704
};
2705
#else
2706
template <typename, typename>
2707
struct has_completions_aux;
2708
template <typename Receiver, typename... Signature>
2709
struct has_completions_aux<Receiver, ::beman::execution::completion_signatures<Signature...>> {
2710
    static constexpr bool value =
2711
        (::beman::execution::detail::valid_completion_for<Signature, Receiver> && ... && true);
2712
};
2713

2714
template <typename Receiver, typename Completions>
2715
concept has_completions = has_completions_aux<Receiver, Completions>::value;
2716
#endif
2717
} // namespace beman::execution::detail
2718

2719
// ----------------------------------------------------------------------------
2720

2721
// ----------------------------------------------------------------------------
2722

2723
namespace beman::execution::detail {
2724
/*!
2725
 * \brief Helper type providing default implementations for basic_sender
2726
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2727
 * \internal
2728
 */
2729
struct default_impls {
2730
    static constexpr auto get_attrs = [](const auto&, const auto&... child) noexcept -> decltype(auto) {
2731
        if constexpr (1 == sizeof...(child))
2732
            return (::beman::execution::detail::fwd_env(::beman::execution::get_env(child)), ...);
2733
        else
2734
            return ::beman::execution::env<>{};
2735
    };
2736
    static constexpr auto get_env = [](auto, auto&, const auto& receiver) noexcept -> decltype(auto) {
2737
        return ::beman::execution::detail::fwd_env(::beman::execution::get_env(receiver));
2738
    };
2739
    static constexpr auto get_state =
2740
        []<typename Sender, typename Receiver>(Sender&& sender, Receiver& receiver) noexcept -> decltype(auto) {
2741
        auto&& data{[&sender]() -> decltype(auto) {
2742
            if constexpr (requires {
2743
                              sender.size();
2744
                              sender.template get<1>();
2745
                          })
2746
                return sender.template get<1>();
2747
            else
2748
                return ::beman::execution::detail::get_sender_data(::std::forward<Sender>(sender)).data;
2749
        }()};
2750

2751
        return ::beman::execution::detail::allocator_aware_move(::beman::execution::detail::forward_like<Sender>(data),
2752
                                                                receiver);
2753
    };
2754
    static constexpr auto start = [](auto&, auto&, auto&... ops) noexcept -> void {
2755
        (::beman::execution::start(ops), ...);
2756
    };
2757
    static constexpr auto complete = []<typename Index, typename Receiver, typename Tag, typename... Args>(
2758
                                         Index, auto&, Receiver& receiver, Tag, Args&&... args) noexcept -> void
2759
        requires ::beman::execution::detail::callable<Tag, Receiver, Args...>
2760
    {
2761
        static_assert(Index::value == 0);
2762
        Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
2763
    };
2764
};
2765
} // namespace beman::execution::detail
2766

2767
// ----------------------------------------------------------------------------
2768

2769
// ----------------------------------------------------------------------------
2770

2771
namespace beman::execution::detail {
2772
// NOLINTBEGIN(bugprone-crtp-constructor-accessibility)
2773
template <typename Derived>
2774
struct with_await_transform {
2775
    template <typename T>
2776
    auto await_transform(T&& obj) noexcept -> T&& {
2777
        return ::std::forward<T>(obj);
2778
    }
2779

2780
    template <::beman::execution::detail::has_as_awaitable<Derived> T>
2781
    auto await_transform(T&& obj) noexcept(noexcept(::std::forward<T>(obj).as_awaitable(::std::declval<Derived&>())))
2782
        -> decltype(auto) {
2783
        return ::std::forward<T>(obj).as_awaitable(static_cast<Derived&>(*this));
2784
    }
2785
};
2786
// NOLINTEND(bugprone-crtp-constructor-accessibility)
2787
} // namespace beman::execution::detail
2788

2789
// ----------------------------------------------------------------------------
2790

2791
// ----------------------------------------------------------------------------
2792

2793
namespace beman::execution {
2794
export template <typename Receiver, typename Completions>
2795
concept receiver_of =
2796
    beman::execution::receiver<Receiver> && beman::execution::detail::has_completions<Receiver, Completions>;
2797
}
2798

2799
// ----------------------------------------------------------------------------
2800

2801
// ----------------------------------------------------------------------------
2802

2803
namespace beman::execution::detail {
2804
template <typename...>
2805
concept always_true = true;
2806

2807
template <typename, typename>
2808
struct same_tag;
2809
template <typename Tag, typename R, typename... A>
2810
struct same_tag<Tag, R(A...)> {
2811
    static constexpr bool value = ::std::same_as<Tag, R>;
2812
};
2813
template <typename Tag>
2814
struct bound_tag {
2815
    using type = Tag;
2816
    template <typename T>
2817
    using predicate = ::beman::execution::detail::same_tag<Tag, T>;
2818
};
2819

2820
template <typename, template <typename...> class>
2821
struct gather_signatures_apply;
2822
template <typename R, typename... A, template <typename...> class Transform>
2823
    requires requires {
2824
        typename ::beman::execution::detail::indirect_meta_apply<
2825
            ::beman::execution::detail::always_true<R>>::template meta_apply<Transform, A...>;
2826
    }
2827
struct gather_signatures_apply<R(A...), Transform> {
2828
    using type = typename ::beman::execution::detail::indirect_meta_apply<
2829
        ::beman::execution::detail::always_true<R>>::template meta_apply<Transform, A...>;
2830
};
2831

2832
template <::beman::execution::detail::valid_completion_signatures,
2833
          template <typename...> class,
2834
          template <typename...> class>
2835
struct gather_signatures_helper;
2836

2837
template <typename... Signatures, template <typename...> class Tuple, template <typename...> class Variant>
2838
    requires requires {
2839
        requires always_true<typename ::beman::execution::detail::gather_signatures_apply<Signatures, Tuple>::type...>;
2840
    } && requires {
2841
        typename ::beman::execution::detail::indirect_meta_apply<
2842
            always_true<typename ::beman::execution::detail::gather_signatures_apply<Signatures, Tuple>::type...>>::
2843
            template meta_apply<
2844
                Variant,
2845
                typename ::beman::execution::detail::gather_signatures_apply<Signatures, Tuple>::type...>;
2846
    }
2847
struct gather_signatures_helper<::beman::execution::completion_signatures<Signatures...>, Tuple, Variant> {
2848
    using type = typename ::beman::execution::detail::indirect_meta_apply<
2849
        always_true<typename ::beman::execution::detail::gather_signatures_apply<Signatures, Tuple>::type...>>::
2850
        template meta_apply<Variant,
2851
                            typename ::beman::execution::detail::gather_signatures_apply<Signatures, Tuple>::type...>;
2852
};
2853

2854
template <typename Tag,
2855
          ::beman::execution::detail::valid_completion_signatures signatures,
2856
          template <typename...> class Tuple,
2857
          template <typename...> class Variant>
2858
    requires requires {
2859
        typename ::beman::execution::detail::gather_signatures_helper<
2860
            ::beman::execution::detail::meta::filter_tag<::beman::execution::detail::same_tag, Tag, signatures>,
2861
            Tuple,
2862
            Variant>::type;
2863
    }
2864
using gather_signatures = typename ::beman::execution::detail::gather_signatures_helper<
2865
    ::beman::execution::detail::meta::filter_tag<::beman::execution::detail::same_tag, Tag, signatures>,
2866
    Tuple,
2867
    Variant>::type;
2868
} // namespace beman::execution::detail
2869

2870
// ----------------------------------------------------------------------------
2871

2872
// ----------------------------------------------------------------------------
2873

2874
namespace beman::execution::detail {
2875
/*!
2876
 * \brief A helper promise type with an associated environment
2877
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
2878
 * \internal
2879
 */
2880
template <typename Env>
2881
struct env_promise : ::beman::execution::detail::with_await_transform<Env> {
2882
    auto get_return_object() noexcept -> void;
2883
    auto initial_suspend() noexcept -> ::std::suspend_always;
2884
    auto final_suspend() noexcept -> ::std::suspend_always;
2885
    auto unhandled_exception() noexcept -> void;
2886
    auto return_void() noexcept -> void;
2887
    auto unhandled_stopped() noexcept -> ::std::coroutine_handle<>;
2888
    auto get_env() const noexcept -> const Env&;
2889
};
2890
} // namespace beman::execution::detail
2891

2892
// ----------------------------------------------------------------------------
2893

2894
// ----------------------------------------------------------------------------
2895

2896
namespace beman::execution::detail {
2897
template <typename Tag>
2898
struct impls_for : ::beman::execution::detail::default_impls {};
2899
} // namespace beman::execution::detail
2900

2901
// ----------------------------------------------------------------------------
2902

2903
// ----------------------------------------------------------------------------
2904

2905
namespace beman::execution::detail {
2906
template <typename Receiver>
2907
struct operation_state_task;
2908

2909
template <typename Receiver>
2910
struct connect_awaitable_promise;
2911
} // namespace beman::execution::detail
2912

2913
// ----------------------------------------------------------------------------
2914

2915
template <typename Receiver>
2916
struct beman::execution::detail::connect_awaitable_promise
2917
    : ::beman::execution::detail::with_await_transform<connect_awaitable_promise<Receiver>> {
2918
    connect_awaitable_promise(auto&&, Receiver& rcvr) noexcept : receiver(rcvr) {}
2919
    auto              initial_suspend() noexcept -> ::std::suspend_always { return {}; }
2920
    [[noreturn]] auto final_suspend() noexcept -> ::std::suspend_always { ::std::terminate(); }
2921
    [[noreturn]] auto unhandled_exception() noexcept -> void { ::std::terminate(); }
2922
    [[noreturn]] auto return_void() noexcept -> void { ::std::terminate(); }
2923

2924
    auto unhandled_stopped() noexcept -> ::std::coroutine_handle<> {
2925
        ::beman::execution::set_stopped(::std::move(this->receiver));
2926
        return ::std::noop_coroutine();
2927
    }
2928

2929
    auto get_env() const noexcept -> ::beman::execution::env_of_t<Receiver> {
2930
        return ::beman::execution::get_env(this->receiver);
2931
    }
2932

2933
    auto get_return_object() noexcept -> ::beman::execution::detail::operation_state_task<Receiver>;
2934

2935
  private:
2936
    Receiver& receiver;
2937
};
2938

2939
// ----------------------------------------------------------------------------
2940

2941
template <typename Receiver>
2942
struct beman::execution::detail::operation_state_task {
2943
    using operation_state_concept = ::beman::execution::operation_state_t;
2944
    using promise_type            = ::beman::execution::detail::connect_awaitable_promise<Receiver>;
2945

2946
    explicit operation_state_task(::std::coroutine_handle<> hndl) noexcept : handle(hndl) {}
2947
    operation_state_task(const operation_state_task&) = delete;
2948
    operation_state_task(operation_state_task&& other) noexcept : handle(::std::exchange(other.handle, {})) {}
2949
    ~operation_state_task() {
2950
        if (this->handle)
2951
            this->handle.destroy();
2952
    }
2953
    auto operator=(operation_state_task&&) -> operation_state_task&      = delete;
2954
    auto operator=(const operation_state_task&) -> operation_state_task& = delete;
2955

2956
    auto start() & noexcept -> void { this->handle.resume(); }
2957

2958
    ::std::coroutine_handle<> handle;
2959
};
2960

2961
// ----------------------------------------------------------------------------
2962

2963
template <typename Receiver>
2964
auto beman::execution::detail::connect_awaitable_promise<Receiver>::get_return_object() noexcept
2965
    -> ::beman::execution::detail::operation_state_task<Receiver> {
2966
    return ::beman::execution::detail::operation_state_task<Receiver>(
2967
        std::coroutine_handle<connect_awaitable_promise>::from_promise(*this));
2968
}
2969

2970
// ----------------------------------------------------------------------------
2971

2972
// ----------------------------------------------------------------------------
2973

2974
namespace beman::execution {
2975
export struct sender_t {};
2976
} // namespace beman::execution
2977
namespace beman::execution::detail {
2978
template <typename Sender>
2979
concept is_sender = ::std::derived_from<typename Sender::sender_concept, ::beman::execution::sender_t>;
2980

2981
template <typename Sender>
2982
concept enable_sender =
2983
    ::beman::execution::detail::is_sender<Sender> ||
2984
    ::beman::execution::detail::is_awaitable<Sender,
2985
                                             ::beman::execution::detail::env_promise<::beman::execution::env<>>>;
2986
} // namespace beman::execution::detail
2987
namespace beman::execution {
2988
export template <typename Sender>
2989
concept sender = ::beman::execution::detail::enable_sender<::std::remove_cvref_t<Sender>> &&
2990
                 requires(const ::std::remove_cvref_t<Sender>& sndr) {
2991
                     { ::beman::execution::get_env(sndr) } -> ::beman::execution::detail::queryable;
2992
                 } && ::std::move_constructible<::std::remove_cvref_t<Sender>> &&
2993
                 ::std::constructible_from<::std::remove_cvref_t<Sender>, Sender>;
2994
} // namespace beman::execution
2995

2996
// ----------------------------------------------------------------------------
2997

2998
// ----------------------------------------------------------------------------
2999

3000
namespace beman::execution::detail {
3001
/*!
3002
 * \brief A helper template used determine the completion signature for type T which may be void
3003
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3004
 * \internal
3005
 */
3006
template <typename T>
3007
struct awaiter_set_value {
3008
    using type = ::beman::execution::set_value_t(T);
3009
};
3010
/*!
3011
 * \brief Specialization for awaiter_set_value when the type is void
3012
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3013
 * \internal
3014
 */
3015
template <>
3016
struct awaiter_set_value<void> {
3017
    using type = ::beman::execution::set_value_t();
3018
};
3019

3020
/*!
3021
 * \brief A helper template used to determine the completion signature matching an awaiter
3022
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3023
 * \internal
3024
 */
3025
template <typename Awaiter, typename Receiver>
3026
using awaiter_completion_signatures = ::beman::execution::completion_signatures<
3027
    typename ::beman::execution::detail::awaiter_set_value<::beman::execution::detail::await_result_type<
3028
        Awaiter,
3029
        ::beman::execution::detail::connect_awaitable_promise<Receiver>>>::type,
3030
    ::beman::execution::set_error_t(::std::exception_ptr),
3031
    ::beman::execution::set_stopped_t()>;
3032

3033
/*!
3034
 * \brief A helper function used to connect an awaiter to a receiver
3035
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3036
 * \internal
3037
 */
3038
template <typename Awaiter, ::beman::execution::receiver Receiver>
3039
auto connect_awaitable(Awaiter awaiter, Receiver receiver)
3040
    -> ::beman::execution::detail::operation_state_task<Receiver>
3041
    requires ::beman::execution::
3042
        receiver_of<Receiver, ::beman::execution::detail::awaiter_completion_signatures<Awaiter, Receiver>>
3043
{
3044
    // NOTE: suspened_complete(...) is co_await to make sure that the
3045
    //    coroutine is suspended at the point when set_*(...) is called.
3046
    using result_type =
3047
        ::beman::execution::detail::await_result_type<Awaiter,
3048
                                                      ::beman::execution::detail::connect_awaitable_promise<Receiver>>;
3049

3050
    ::std::exception_ptr ep;
3051
    try {
3052
        if constexpr (std::same_as<void, result_type>) {
3053
            co_await ::std::move(awaiter);
3054
            co_await ::beman::execution::detail::suspend_complete(::beman::execution::set_value,
3055
                                                                  ::std::move(receiver));
3056
        } else {
3057
            co_await ::beman::execution::detail::suspend_complete(
3058
                ::beman::execution::set_value, ::std::move(receiver), co_await ::std::move(awaiter));
3059
        }
3060
    } catch (...) {
3061
        ep = ::std::current_exception();
3062
    }
3063
    co_await ::beman::execution::detail::suspend_complete(::beman::execution::set_error, ::std::move(receiver), ep);
3064
}
3065
} // namespace beman::execution::detail
3066

3067
// ----------------------------------------------------------------------------
3068

3069
// ----------------------------------------------------------------------------
3070

3071
namespace beman::execution::detail {
3072
template <typename Sender, typename Receiver>
3073
using state_type = ::std::decay_t<::beman::execution::detail::call_result_t<
3074
    decltype(::beman::execution::detail::impls_for<::beman::execution::tag_of_t<Sender>>::get_state),
3075
    Sender,
3076
    Receiver&>>;
3077
}
3078

3079
// ----------------------------------------------------------------------------
3080

3081
// ----------------------------------------------------------------------------
3082

3083
namespace beman::execution {
3084
export struct schedule_t {
3085
    template <typename Scheduler>
3086
        requires(not requires(Scheduler&& sched) {
3087
                    { ::std::forward<Scheduler>(sched).schedule() } -> ::beman::execution::sender;
3088
                })
3089
    auto operator()(Scheduler&& sched) const =
3090
        BEMAN_EXECUTION_DELETE("the scheduler needs a schedule() member returning a sender");
3091

3092
    template <typename Scheduler>
3093
        requires requires(Scheduler&& sched) {
3094
            { ::std::forward<Scheduler>(sched).schedule() } -> ::beman::execution::sender;
3095
        }
3096
    auto operator()(Scheduler&& sched) const noexcept(noexcept(std::forward<Scheduler>(sched).schedule())) {
3097
        return std::forward<Scheduler>(sched).schedule();
3098
    }
3099
};
3100

3101
export inline constexpr ::beman::execution::schedule_t schedule{};
3102
} // namespace beman::execution
3103

3104
// ----------------------------------------------------------------------------
3105

3106
// ----------------------------------------------------------------------------
3107

3108
namespace beman::execution::detail::pipeable {
3109
struct sender_adaptor_closure_base {};
3110
} // namespace beman::execution::detail::pipeable
3111

3112
namespace beman::execution {
3113
// NOLINTBEGIN(bugprone-crtp-constructor-accessibility)
3114
export template <typename>
3115
struct sender_adaptor_closure : ::beman::execution::detail::pipeable::sender_adaptor_closure_base {};
3116
// NOLINTEND(bugprone-crtp-constructor-accessibility)
3117

3118
} // namespace beman::execution
3119

3120
namespace beman::execution::detail {
3121
template <typename Closure>
3122
concept is_sender_adaptor_closure =
3123
    ::std::derived_from<::std::decay_t<Closure>, ::beman::execution::sender_adaptor_closure<::std::decay_t<Closure>>>;
3124
}
3125

3126
namespace beman::execution::detail::pipeable {
3127
export template <::beman::execution::sender Sender, typename Adaptor>
3128
    requires(!::beman::execution::sender<Adaptor>) &&
3129
            ::std::derived_from<::std::decay_t<Adaptor>,
3130
                                ::beman::execution::sender_adaptor_closure<::std::decay_t<Adaptor>>> &&
3131
            requires(Sender&& sender, Adaptor&& adaptor) {
3132
                { adaptor(::std::forward<Sender>(sender)) } -> ::beman::execution::sender;
3133
            }
3134
auto operator|(Sender&& sender, Adaptor&& adaptor) {
3135
    return adaptor(::std::forward<Sender>(sender));
3136
}
3137
} // namespace beman::execution::detail::pipeable
3138

3139
// ----------------------------------------------------------------------------
3140

3141
// ----------------------------------------------------------------------------
3142

3143
namespace beman::execution::detail {
3144
template <typename Sender, typename Tag>
3145
concept sender_for = ::beman::execution::sender<Sender> && ::std::same_as<::beman::execution::tag_of_t<Sender>, Tag>;
3146
}
3147

3148
// ----------------------------------------------------------------------------
3149

3150
// ----------------------------------------------------------------------------
3151

3152
namespace beman::execution::detail {
3153
template <typename Sender, typename Env>
3154
concept sender_has_affine_on =
3155
    beman::execution::sender<::std::remove_cvref_t<Sender>> && requires(Sender&& sndr, const Env& env) {
3156
        sndr.template get<0>();
3157
        { sndr.template get<0>().affine_on(std::forward<Sender>(sndr), env) } -> ::beman::execution::sender;
3158
    };
3159
} // namespace beman::execution::detail
3160

3161
// ----------------------------------------------------------------------------
3162

3163
// ----------------------------------------------------------------------------
3164

3165
namespace beman::execution {
3166
/*!
3167
 * \brief Domain type used when no domain is specified explicitly.
3168
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3169
 *
3170
 * \details
3171
 * The default_domain tries to delegate any of the transformations to a member
3172
 * function of the
3173
 * tag type of the passed sender. If there is no corresponding member function
3174
 * no transformation is applied.
3175
 */
3176
export struct default_domain {
3177
    template <::beman::execution::sender Sender, ::beman::execution::detail::queryable... Env>
3178
        requires(sizeof...(Env) <= 1) && requires(Sender&& sender, Env&&... env) {
3179
            ::beman::execution::tag_of_t<Sender>().transform_sender(::std::forward<Sender>(sender),
3180
                                                                    ::std::forward<Env>(env)...);
3181
        }
3182
    static constexpr auto transform_sender(Sender&& sender, Env&&... env) noexcept(
3183
        noexcept(::beman::execution::tag_of_t<Sender>().transform_sender(::std::forward<Sender>(sender),
3184
                                                                         ::std::forward<Env>(env)...)))
3185
        -> ::beman::execution::sender decltype(auto) {
3186
        return ::beman::execution::tag_of_t<Sender>().transform_sender(::std::forward<Sender>(sender),
3187
                                                                       ::std::forward<Env>(env)...);
3188
    }
3189

3190
    template <::beman::execution::sender Sender, ::beman::execution::detail::queryable... Env>
3191
        requires(sizeof...(Env) <= 1) && (not requires(Sender&& sender, Env&&... env) {
3192
                    ::beman::execution::tag_of_t<Sender>().transform_sender(::std::forward<Sender>(sender),
3193
                                                                            ::std::forward<Env>(env)...);
3194
                })
3195
    static constexpr auto transform_sender(Sender&& sender,
3196
                                           Env&&...) noexcept(noexcept(::std::forward<Sender>(sender)))
3197
        -> ::beman::execution::sender decltype(auto) {
3198
        return ::std::forward<Sender>(sender);
3199
    }
3200

3201
    template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env>
3202
        requires requires(Sender&& sender, Env&& env) {
3203
            ::beman::execution::tag_of_t<Sender>().transform_env(::std::forward<Sender>(sender),
3204
                                                                 ::std::forward<Env>(env));
3205
        }
3206
    static constexpr auto transform_env(Sender&& sender, Env&& env) noexcept -> ::beman::execution::detail::queryable
3207
        decltype(auto) {
3208
        return ::beman::execution::tag_of_t<Sender>().transform_env(::std::forward<Sender>(sender),
3209
                                                                    ::std::forward<Env>(env));
3210
    }
3211

3212
    template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env>
3213
        requires(not requires(Sender&& sender, Env&& env) {
3214
            ::beman::execution::tag_of_t<Sender>().transform_env(::std::forward<Sender>(sender),
3215
                                                                 ::std::forward<Env>(env));
3216
        })
3217
    static constexpr auto transform_env(Sender&&, Env&& env) noexcept -> ::beman::execution::detail::queryable
3218
        decltype(auto) {
3219
        return static_cast<Env>(::std::forward<Env>(env));
3220
    }
3221

3222
    template <typename Tag, ::beman::execution::sender Sender, typename... Args>
3223
        requires requires(Sender&& sender, Args&&... args) {
3224
            Tag().apply_sender(::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3225
        }
3226
    static constexpr auto apply_sender(Tag, Sender&& sender, Args&&... args) noexcept(noexcept(
3227
        Tag().apply_sender(::std::forward<Sender>(sender), ::std::forward<Args>(args)...))) -> decltype(auto) {
3228
        return Tag().apply_sender(::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3229
    }
3230
};
3231
} // namespace beman::execution
3232

3233
// ----------------------------------------------------------------------------
3234

3235
// ----------------------------------------------------------------------------
3236

3237
namespace beman::execution::detail {
3238
template <::beman::execution::sender Sndr, typename Ev>
3239
auto spawn_get_allocator(const Sndr& sndr, const Ev& ev) {
3240
    if constexpr (requires { ::beman::execution::get_allocator(ev); }) {
3241
        return ::std::pair(::beman::execution::get_allocator(ev), ev);
3242
    } else if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(sndr)); }) {
3243
        auto alloc{::beman::execution::get_allocator(::beman::execution::get_env(sndr))};
3244
        return ::std::pair(alloc,
3245
                           ::beman::execution::detail::join_env(
3246
                               ::beman::execution::prop(::beman::execution::get_allocator, alloc), ev));
3247
    } else {
3248
        return ::std::pair(::std::allocator<void>{}, ev);
3249
    }
3250
}
3251

3252
} // namespace beman::execution::detail
3253

3254
// ----------------------------------------------------------------------------
3255

3256
// ----------------------------------------------------------------------------
3257

3258
namespace beman::execution::detail {
3259
/*!
3260
 * \brief Class template used to present the receiver and operation state for library senders.
3261
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3262
 * \internal
3263
 */
3264
template <typename Sender, typename Receiver>
3265
struct basic_state {
3266
    basic_state(Sender&& sender, Receiver&& rcvr) noexcept(true)
3267
        : receiver(::std::move(rcvr)),
3268
          state(::beman::execution::detail::impls_for<::beman::execution::tag_of_t<Sender>>::get_state(
3269
              ::std::forward<Sender>(sender), this->receiver)) {}
3270

3271
    Receiver                                                 receiver;
3272
    ::beman::execution::detail::state_type<Sender, Receiver> state;
3273
};
3274
template <typename Sender, typename Receiver>
3275
basic_state(Sender&&, Receiver&&) -> basic_state<Sender&&, Receiver>;
3276
} // namespace beman::execution::detail
3277

3278
// ----------------------------------------------------------------------------
3279

3280
// ----------------------------------------------------------------------------
3281

3282
namespace beman::execution::detail {
3283
/*!
3284
 * \brief Helper alias to determine the environment type associated with sender in a basic_sender
3285
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3286
 * \internal
3287
 */
3288
template <typename Index, typename Sender, typename Receiver>
3289
using env_type = ::beman::execution::detail::call_result_t<
3290
    decltype(::beman::execution::detail::impls_for<::beman::execution::tag_of_t<Sender>>::get_env),
3291
    Index,
3292
    ::beman::execution::detail::state_type<Sender, Receiver>&,
3293
    const Receiver&>;
3294
} // namespace beman::execution::detail
3295

3296
// ----------------------------------------------------------------------------
3297

3298
// ----------------------------------------------------------------------------
3299

3300
namespace beman::execution::detail {
3301
/*!
3302
 * \brief Auxiliary concept used to break cycle for scheduler concept.
3303
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3304
 * \internal
3305
 * \concept almost_scheduler
3306
 */
3307
template <typename Scheduler>
3308
concept almost_scheduler = ::std::derived_from<typename ::std::remove_cvref_t<Scheduler>::scheduler_concept,
3309
                                               ::beman::execution::scheduler_t> &&
3310
                           ::beman::execution::detail::queryable<Scheduler> &&
3311
                           requires(Scheduler&& sched) {
3312
                               {
3313
                                   ::beman::execution::schedule(::std::forward<Scheduler>(sched))
3314
                               } -> ::beman::execution::sender;
3315
                           } && ::std::equality_comparable<::std::remove_cvref_t<Scheduler>> &&
3316
                           ::std::copy_constructible<::std::remove_cvref_t<Scheduler>>;
3317
} // namespace beman::execution::detail
3318

3319
// ----------------------------------------------------------------------------
3320

3321
// ----------------------------------------------------------------------------
3322

3323
namespace beman::execution::detail {
3324
template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3325
    requires(sizeof...(Env) < 2) &&
3326
            requires(Domain dom, Sender&& sender, const Env&... env) {
3327
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3328
            } &&
3329
            (::std::same_as<::std::remove_cvref_t<Sender>,
3330
                            std::remove_cvref_t<decltype(::std::declval<Domain>().transform_sender(
3331
                                ::std::declval<Sender>(), ::std::declval<const Env&>()...))>>)
3332
constexpr auto transform_sender(Domain, Sender&& sender, const Env&...) noexcept -> ::beman::execution::sender auto {
3333
    return ::std::forward<Sender>(sender);
3334
}
3335

3336
template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3337
    requires(sizeof...(Env) < 2) &&
3338
            requires(Domain dom, Sender&& sender, const Env&... env) {
3339
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3340
            } &&
3341
            (!::std::same_as<::std::remove_cvref_t<Sender>,
3342
                             std::remove_cvref_t<decltype(::std::declval<Domain>().transform_sender(
3343
                                 ::std::declval<Sender>(), ::std::declval<const Env&>()...))>>)
3344
constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept -> ::beman::execution::sender
3345
    decltype(auto) {
3346
    return ::beman::execution::detail::transform_sender(
3347
        dom, dom.transform_sender(::std::forward<Sender>(sender), env...), env...);
3348
}
3349

3350
template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3351
    requires(not requires(Domain dom, Sender&& sender, const Env&... env) {
3352
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3353
            }) && ::std::same_as<::std::remove_cvref_t<Sender>,
3354
                                 ::std::remove_cvref_t<decltype(::beman::execution::default_domain{}.transform_sender(
3355
                                     ::std::declval<Sender>(), ::std::declval<Env>()...))>>
3356
constexpr auto
3357
    transform_sender(Domain, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward<Sender>(sender)))
3358
        -> ::beman::execution::sender auto {
3359
    return sender;
3360
}
3361

3362
template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3363
    requires(not requires(Domain dom, Sender&& sender, const Env&... env) {
3364
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3365
            }) &&
3366
            (!::std::same_as<::std::remove_cvref_t<Sender>,
3367
                             ::std::remove_cvref_t<decltype(::beman::execution::default_domain{}.transform_sender(
3368
                                 ::std::declval<Sender>(), ::std::declval<Env>()...))>>)
3369
constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept(noexcept(
3370
    ::beman::execution::default_domain{}.transform_sender(::std::declval<Sender>(), ::std::declval<Env>()...)))
3371
    -> ::beman::execution::sender decltype(auto) {
3372
    return ::beman::execution::detail::transform_sender(
3373
        dom, ::beman::execution::default_domain{}.transform_sender(::std::forward<Sender>(sender), env...), env...);
3374
}
3375
} // namespace beman::execution::detail
3376

3377
namespace beman::execution {
3378
export template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3379
    requires(sizeof...(Env) < 2) &&
3380
            requires(Domain dom, Sender&& sender, const Env&... env) {
3381
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3382
            } &&
3383
            (::std::same_as<::std::remove_cvref_t<Sender>,
3384
                            std::remove_cvref_t<decltype(::std::declval<Domain>().transform_sender(
3385
                                ::std::declval<Sender>(), ::std::declval<const Env&>()...))>>)
3386
constexpr auto transform_sender(Domain, Sender&& sender, const Env&...) noexcept -> ::beman::execution::sender
3387
    decltype(auto) {
3388
    return ::std::forward<Sender>(sender);
3389
}
3390

3391
export template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3392
    requires(sizeof...(Env) < 2) &&
3393
            requires(Domain dom, Sender&& sender, const Env&... env) {
3394
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3395
            } &&
3396
            (!::std::same_as<::std::remove_cvref_t<Sender>,
3397
                             std::remove_cvref_t<decltype(::std::declval<Domain>().transform_sender(
3398
                                 ::std::declval<Sender>(), ::std::declval<const Env&>()...))>>)
3399
constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept -> ::beman::execution::sender
3400
    auto {
3401
    return ::beman::execution::detail::transform_sender(
3402
        dom, dom.transform_sender(::std::forward<Sender>(sender), env...), env...);
3403
}
3404

3405
export template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3406
    requires(sizeof...(Env) < 2) && (not requires(Domain dom, Sender&& sender, const Env&... env) {
3407
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3408
            }) &&
3409
            ::std::same_as<::std::remove_cvref_t<Sender>,
3410
                           ::std::remove_cvref_t<decltype(::beman::execution::default_domain{}.transform_sender(
3411
                               ::std::declval<Sender>(), ::std::declval<Env>()...))>>
3412
constexpr auto
3413
    transform_sender(Domain, Sender&& sender, const Env&...) noexcept(noexcept(::std::forward<Sender>(sender)))
3414
        -> ::beman::execution::sender decltype(auto) {
3415
    return ::std::forward<Sender>(sender);
3416
}
3417

3418
export template <typename Domain, ::beman::execution::sender Sender, typename... Env>
3419
    requires(sizeof...(Env) < 2) && (not requires(Domain dom, Sender&& sender, const Env&... env) {
3420
                dom.transform_sender(::std::forward<Sender>(sender), env...);
3421
            }) &&
3422
            (!::std::same_as<::std::remove_cvref_t<Sender>,
3423
                             ::std::remove_cvref_t<decltype(::beman::execution::default_domain{}.transform_sender(
3424
                                 ::std::declval<Sender>(), ::std::declval<Env>()...))>>)
3425
constexpr auto transform_sender(Domain dom, Sender&& sender, const Env&... env) noexcept(
3426
    noexcept(::beman::execution::detail::transform_sender(
3427
        dom,
3428
        ::beman::execution::default_domain{}.transform_sender(::std::declval<Sender>(), ::std::declval<Env>()...),
3429
        env...))) -> ::beman::execution::sender decltype(auto) {
3430
    return ::beman::execution::detail::transform_sender(
3431
        dom, ::beman::execution::default_domain{}.transform_sender(::std::forward<Sender>(sender), env...), env...);
3432
}
3433
} // namespace beman::execution
3434

3435
// ----------------------------------------------------------------------------
3436

3437
// ----------------------------------------------------------------------------
3438

3439
namespace beman::execution::detail {
3440
template <typename Adaptor, typename... T>
3441
struct sender_adaptor : ::beman::execution::detail::product_type<::std::decay_t<Adaptor>, ::std::decay_t<T>...>,
3442
                        ::beman::execution::sender_adaptor_closure<sender_adaptor<Adaptor, T...>> {
3443
    template <::beman::execution::sender Sender, typename Self>
3444
    static auto apply(Sender&& sender, Self&& self) {
3445
        return [&self, &sender]<::std::size_t... I>(::std::index_sequence<I...>) {
3446
            auto&& fun(self.template get<0>());
3447
            return fun(::std::forward<Sender>(sender),
3448
                       ::beman::execution::detail::forward_like<Self>(self.template get<I + 1>())...);
3449
        }(::std::make_index_sequence<sender_adaptor::size() - 1u>{});
3450
    }
3451
    template <::beman::execution::sender Sender>
3452
    auto operator()(Sender&& sender) {
3453
        return apply(::std::forward<Sender>(sender), ::std::move(*this));
3454
    }
3455
    template <::beman::execution::sender Sender>
3456
    auto operator()(Sender&& sender) const {
3457
        return apply(::std::forward<Sender>(sender), *this);
3458
    }
3459
};
3460
template <typename... T>
3461
sender_adaptor(T&&...) -> sender_adaptor<T...>;
3462
} // namespace beman::execution::detail
3463

3464
// ----------------------------------------------------------------------------
3465

3466
// ----------------------------------------------------------------------------
3467

3468
namespace beman::execution::detail {
3469
template <typename Scheduler>
3470
class sched_env {
3471
  private:
3472
    Scheduler sched;
3473

3474
  public:
3475
    template <typename S>
3476
    explicit sched_env(S sch) : sched(::std::move(sch)) {}
3477

3478
    auto query(const ::beman::execution::get_scheduler_t&) const noexcept { return this->sched; }
3479
    auto query(const ::beman::execution::get_domain_t& q) const noexcept {
3480
        if constexpr (requires { this->sched.query(q); })
3481
            return this->sched.query(q);
3482
        else
3483
            return ::beman::execution::default_domain{};
3484
    }
3485
};
3486

3487
template <typename Scheduler>
3488
sched_env(Scheduler&&) -> sched_env<::std::remove_cvref_t<Scheduler>>;
3489
} // namespace beman::execution::detail
3490

3491
// ----------------------------------------------------------------------------
3492

3493
// ----------------------------------------------------------------------------
3494

3495
namespace beman::execution {
3496
/*!
3497
 * \brief Function used to transform a sender and its arguments for a domain.
3498
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3499
 */
3500
export template <typename Domain, typename Tag, ::beman::execution::sender Sender, typename... Args>
3501
    requires requires(Domain domain, Tag tag, Sender&& sender, Args&&... args) {
3502
        domain.apply_sender(Tag(), ::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3503
    }
3504
constexpr auto apply_sender(Domain domain, Tag, Sender&& sender, Args&&... args) noexcept(noexcept(
3505
    domain.apply_sender(Tag(), ::std::forward<Sender>(sender), ::std::forward<Args>(args)...))) -> decltype(auto) {
3506
    return domain.apply_sender(Tag(), ::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3507
}
3508

3509
/*!
3510
 * \brief Default function used to transform a second and its arguments.
3511
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3512
 */
3513
template <typename Domain, typename Tag, ::beman::execution::sender Sender, typename... Args>
3514
    requires(not requires(Domain domain, Tag tag, Sender&& sender, Args&&... args) {
3515
                domain.apply_sender(Tag(), ::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3516
            }) && requires(Tag tag, Sender&& sender, Args&&... args) {
3517
        beman::execution::default_domain().apply_sender(
3518
            Tag(), ::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3519
    }
3520
constexpr auto apply_sender(Domain, Tag, Sender&& sender, Args&&... args) noexcept(
3521
    noexcept(beman::execution::default_domain().apply_sender(Tag(),
3522
                                                             ::std::forward<Sender>(sender),
3523
                                                             ::std::forward<Args>(args)...))) -> decltype(auto) {
3524
    return beman::execution::default_domain().apply_sender(
3525
        Tag(), ::std::forward<Sender>(sender), ::std::forward<Args>(args)...);
3526
}
3527

3528
} // namespace beman::execution
3529

3530
// ----------------------------------------------------------------------------
3531

3532
// ----------------------------------------------------------------------------
3533

3534
namespace beman::execution::detail {
3535
template <typename Sender, typename Env>
3536
concept nested_sender_has_affine_on = requires(Sender&& sndr, const Env& env) {
3537
    { sndr.template get<2>() } -> ::beman::execution::detail::sender_has_affine_on<Env>;
3538
};
3539
} // namespace beman::execution::detail
3540

3541
// ----------------------------------------------------------------------------
3542

3543
// ----------------------------------------------------------------------------
3544

3545
namespace beman::execution::detail {
3546
/*!
3547
 * \brief Class template used as receiver for child completions for library senders.
3548
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3549
 * \internal
3550
 */
3551
template <typename Sender, typename Receiver, typename Index>
3552
    requires ::beman::execution::detail::
3553
        valid_specialization<::beman::execution::detail::env_type, Index, Sender, Receiver>
3554
    struct basic_receiver {
3555
    friend struct ::beman::execution::get_env_t;
3556
    friend struct ::beman::execution::set_error_t;
3557
    friend struct ::beman::execution::set_stopped_t;
3558
    friend struct ::beman::execution::set_value_t;
3559

3560
    using receiver_concept                = ::beman::execution::receiver_t;
3561
    using tag_t                           = ::beman::execution::tag_of_t<Sender>;
3562
    using state_t                         = ::beman::execution::detail::state_type<Sender, Receiver>;
3563
    static constexpr const auto& complete = ::beman::execution::detail::impls_for<tag_t>::complete;
3564
    ::beman::execution::detail::basic_state<Sender, Receiver>* op{};
3565

3566
  private:
3567
    template <typename... Args>
3568
    auto set_value(Args&&... args) && noexcept -> void
3569
        requires ::beman::execution::detail::
3570
            callable<decltype(complete), Index, state_t&, Receiver&, ::beman::execution::set_value_t, Args...>
3571
    {
3572
        this->complete(Index(),
3573
                       this->op->state,
3574
                       this->op->receiver,
3575
                       ::beman::execution::set_value_t(),
3576
                       ::std::forward<Args>(args)...);
3577
    }
3578

3579
    template <typename Error>
3580
    auto set_error(Error&& error) && noexcept -> void
3581
        requires ::beman::execution::detail::
3582
            callable<decltype(complete), Index, state_t&, Receiver&, ::beman::execution::set_error_t, Error>
3583
    {
3584
        this->complete(Index(),
3585
                       this->op->state,
3586
                       this->op->receiver,
3587
                       ::beman::execution::set_error_t(),
3588
                       ::std::forward<Error>(error));
3589
    }
3590

3591
    auto set_stopped() && noexcept -> void
3592
        requires ::beman::execution::detail::
3593
            callable<decltype(complete), Index, state_t&, Receiver&, ::beman::execution::set_stopped_t>
3594
    {
3595
        this->complete(Index(), this->op->state, this->op->receiver, ::beman::execution::set_stopped_t());
3596
    }
3597

3598
    auto get_env() const noexcept -> ::beman::execution::detail::env_type<Index, Sender, Receiver> {
3599
        return ::beman::execution::detail::impls_for<tag_t>::get_env(Index(), this->op->state, this->op->receiver);
3600
    }
3601
};
3602
} // namespace beman::execution::detail
3603

3604
// ----------------------------------------------------------------------------
3605

3606
// ----------------------------------------------------------------------------
3607

3608
namespace beman::execution {
3609
export template <typename Tag>
3610
struct get_completion_scheduler_t;
3611

3612
template <typename Tag>
3613
struct get_completion_scheduler_t : ::beman::execution::forwarding_query_t {
3614
    template <typename Env>
3615
        requires(not requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t<Env>& env) {
3616
                    env.query(self);
3617
                })
3618
    auto operator()(Env&&) const noexcept =
3619
        BEMAN_EXECUTION_DELETE("The environment needs a query(get_completion_scheduler_t) member");
3620

3621
    template <typename Env>
3622
        requires(requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t<Env>& env) {
3623
                    env.query(self);
3624
                } && (not requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t<Env>& env) {
3625
                     { env.query(self) } noexcept;
3626
                 }))
3627
    auto operator()(Env&&) const noexcept =
3628
        BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to be noexcept");
3629

3630
    template <typename Env>
3631
        requires(
3632
                    requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t<Env>& env) {
3633
                        env.query(self);
3634
                    } &&
3635
                    requires(const get_completion_scheduler_t& self, const ::std::remove_cvref_t<Env>& env) {
3636
                        { env.query(self) } noexcept;
3637
                    } &&
3638
                    (not requires(const get_completion_scheduler_t&                                  self,
3639
                                  const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self,
3640
                                  const ::std::remove_cvref_t<Env>&                                  env) {
3641
                        { env.query(self) } noexcept -> ::beman::execution::detail::almost_scheduler;
3642
                        {
3643
                            ::beman::execution::get_env(::beman::execution::schedule(env.query(self)))
3644
                                .query(value_self)
3645
                        } -> ::beman::execution::detail::decayed_same_as<decltype(env.query(self))>;
3646
                    }))
3647
    auto operator()(Env&&) const noexcept =
3648
        BEMAN_EXECUTION_DELETE("The environment's query(get_completion_scheduler_t) has to return a scheduler");
3649

3650
    template <typename Env>
3651
        requires requires(const get_completion_scheduler_t&                                  self,
3652
                          const get_completion_scheduler_t<::beman::execution::set_value_t>& value_self,
3653
                          const ::std::remove_cvref_t<Env>&                                  env) {
3654
            { env.query(self) } noexcept -> ::beman::execution::detail::almost_scheduler;
3655
            {
3656
                ::beman::execution::get_env(::beman::execution::schedule(env.query(self))).query(value_self)
3657
            } -> ::beman::execution::detail::decayed_same_as<decltype(env.query(self))>;
3658
        }
3659
    auto operator()(Env&& env) const noexcept {
3660
        return ::std::as_const(env).query(*this);
3661
    }
3662
};
3663

3664
export template <::beman::execution::detail::completion_tag Tag>
3665
inline constexpr get_completion_scheduler_t<Tag> get_completion_scheduler{};
3666
} // namespace beman::execution
3667

3668
// ----------------------------------------------------------------------------
3669

3670
// ----------------------------------------------------------------------------
3671

3672
namespace beman::execution {
3673
export template <typename Scheduler>
3674
concept scheduler = ::beman::execution::detail::almost_scheduler<Scheduler> && requires(Scheduler&& sched) {
3675
    {
3676
        ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>(
3677
            ::beman::execution::get_env(::beman::execution::schedule(::std::forward<Scheduler>(sched))))
3678
    } -> ::beman::execution::detail::decayed_same_as<Scheduler>;
3679
};
3680
} // namespace beman::execution
3681

3682
// ----------------------------------------------------------------------------
3683

3684
// ----------------------------------------------------------------------------
3685

3686
namespace beman::execution::detail {
3687

3688
template <typename Scheduler>
3689
class sched_attrs {
3690
  private:
3691
    Scheduler sched;
3692

3693
  public:
3694
    template <typename S>
3695
        requires(!::std::same_as<sched_attrs, ::std::remove_cvref_t<S>>)
3696
    explicit sched_attrs(S&& s) : sched(::std::forward<S>(s)) {}
3697

3698
    template <typename Tag>
3699
    auto query(const ::beman::execution::get_completion_scheduler_t<Tag>&) const noexcept {
3700
        return this->sched;
3701
    }
3702

3703
    template <typename T = bool>
3704
        requires requires(Scheduler&& s) { s.query(::beman::execution::get_domain); }
3705
    auto query(const ::beman::execution::get_domain_t& q, T = true) const noexcept {
3706
        return this->sched.query(q);
3707
    }
3708
};
3709

3710
template <typename Scheduler>
3711
sched_attrs(Scheduler&&) -> sched_attrs<::std::remove_cvref_t<Scheduler>>;
3712
} // namespace beman::execution::detail
3713

3714
// ----------------------------------------------------------------------------
3715

3716
// ----------------------------------------------------------------------------
3717

3718
namespace beman::execution::detail {
3719
struct completion_domain_undefined {};
3720
template <typename, typename>
3721
struct completion_domain_merge {};
3722
template <typename T>
3723
struct completion_domain_merge<T, T> {
3724
    using type = T;
3725
};
3726
template <typename T>
3727
struct completion_domain_merge<completion_domain_undefined, T> {
3728
    using type = T;
3729
};
3730
template <typename T>
3731
struct completion_domain_merge<T, completion_domain_undefined> {
3732
    using type = T;
3733
};
3734
template <>
3735
struct completion_domain_merge<completion_domain_undefined, completion_domain_undefined> {
3736
    using type = completion_domain_undefined;
3737
};
3738

3739
/*!
3740
 * \brief Get a sender's completion domain or the specified default.
3741
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
3742
 * \internal
3743
 */
3744
template <typename Default = ::beman::execution::default_domain, typename Sender>
3745
constexpr auto completion_domain(const Sender& sender) noexcept {
3746

3747
    static_assert(::beman::execution::sender<Sender>);
3748
    constexpr auto get = []<typename Tag>(Tag, const Sender& sender) {
3749
        if constexpr (requires {
3750
                          ::beman::execution::get_domain(
3751
                              ::beman::execution::get_completion_scheduler<Tag>(::beman::execution::get_env(sender)));
3752
                      }) {
3753
            return ::beman::execution::get_domain(
3754
                ::beman::execution::get_completion_scheduler<Tag>(::beman::execution::get_env(sender)));
3755
        } else {
3756
            return completion_domain_undefined{};
3757
        }
3758
    };
3759

3760
    using type = typename completion_domain_merge<
3761
        typename completion_domain_merge<decltype(get(::beman::execution::set_error, sender)),
3762
                                         decltype(get(::beman::execution::set_stopped, sender))>::type,
3763
        decltype(get(::beman::execution::set_value, sender))>::type;
3764
    return ::std::conditional_t<::std::same_as<type, completion_domain_undefined>, Default, type>();
3765
}
3766
} // namespace beman::execution::detail
3767

3768
// ----------------------------------------------------------------------------
3769

3770
// ----------------------------------------------------------------------------
3771

3772
namespace beman::execution {
3773
export struct get_delegation_scheduler_t {
3774
    template <typename Env>
3775
        requires requires(Env&& env, const get_delegation_scheduler_t& g) {
3776
            { ::std::as_const(env).query(g) } noexcept -> ::beman::execution::scheduler;
3777
        }
3778
    auto operator()(Env&& env) const noexcept {
3779
        return ::std::as_const(env).query(*this);
3780
    }
3781
    constexpr auto query(const ::beman::execution::forwarding_query_t&) const noexcept -> bool { return true; }
3782
};
3783

3784
export inline constexpr get_delegation_scheduler_t get_delegation_scheduler{};
3785
} // namespace beman::execution
3786

3787
// ----------------------------------------------------------------------------
3788

3789
// ----------------------------------------------------------------------------
3790

3791
namespace beman::execution::detail {
3792
template <typename T>
3793
concept not_void = !::std::same_as<T, void>;
3794

3795
template <typename Tag>
3796
struct get_domain_late_helper {
3797
    template <typename Sender, typename Env>
3798
    static constexpr auto get(const Sender& sender, const Env& env) noexcept {
3799
        if constexpr (requires {
3800
                          {
3801
                              ::beman::execution::get_domain(::beman::execution::get_env(sender))
3802
                          } -> ::beman::execution::detail::not_void;
3803
                      })
3804
            return ::beman::execution::get_domain(::beman::execution::get_env(sender));
3805
        else if constexpr (requires {
3806
                               {
3807
                                   ::beman::execution::detail::completion_domain<void>(sender)
3808
                               } -> ::beman::execution::detail::not_void;
3809
                           })
3810
            return ::beman::execution::detail::completion_domain<void>(sender);
3811
        else if constexpr (requires {
3812
                               { ::beman::execution::get_domain(env) } -> ::beman::execution::detail::not_void;
3813
                           })
3814
            return ::beman::execution::get_domain(env);
3815
        else if constexpr (requires {
3816
                               {
3817
                                   ::beman::execution::get_domain(::beman::execution::get_scheduler(env))
3818
                               } -> ::beman::execution::detail::not_void;
3819
                           })
3820
            return ::beman::execution::get_domain(::beman::execution::get_scheduler(env));
3821
        else
3822
            return ::beman::execution::default_domain();
3823
    }
3824
};
3825
template <typename Sender, typename Env>
3826
constexpr auto get_domain_late(const Sender& sender, const Env& env) noexcept {
3827
    using tag_t = ::beman::execution::tag_of_t<Sender>;
3828
    return ::beman::execution::detail::get_domain_late_helper<tag_t>::get(sender, env);
3829
}
3830
} // namespace beman::execution::detail
3831

3832
// ----------------------------------------------------------------------------
3833

3834
// ----------------------------------------------------------------------------
3835

3836
namespace beman::execution::detail {
3837
template <typename Sender>
3838
constexpr auto get_domain_early(const Sender& sender) noexcept {
3839
    if constexpr (requires { ::beman::execution::get_domain(::beman::execution::get_env(sender)); })
3840
        return decltype(::beman::execution::get_domain(::beman::execution::get_env(sender))){};
3841
    else if constexpr (requires { ::beman::execution::detail::completion_domain(sender); })
3842
        return decltype(::beman::execution::detail::completion_domain(sender)){};
3843
    else
3844
        return ::beman::execution::default_domain{};
3845
}
3846
} // namespace beman::execution::detail
3847

3848
// ----------------------------------------------------------------------------
3849

3850
// ----------------------------------------------------------------------------
3851

3852
namespace beman::execution {
3853
export template <::beman::execution::scheduler Scheduler>
3854
using schedule_result_t = decltype(::beman::execution::schedule(::std::declval<Scheduler>()));
3855
}
3856

3857
// ----------------------------------------------------------------------------
3858

3859
// ----------------------------------------------------------------------------
3860

3861
namespace beman::execution {
3862
export class run_loop {
3863
  private:
3864
    struct scheduler;
3865

3866
    struct env {
3867
        run_loop* loop;
3868

3869
        template <typename Completion>
3870
        auto query(const ::beman::execution::get_completion_scheduler_t<Completion>&) const noexcept -> scheduler {
3871
            return {this->loop};
3872
        }
3873
    };
3874

3875
    struct opstate_base : ::beman::execution::detail::virtual_immovable {
3876
        opstate_base* next{};
3877
        virtual auto  execute() noexcept -> void = 0;
3878
    };
3879

3880
    template <typename Receiver>
3881
    struct opstate : opstate_base {
3882
        using operation_state_concept = ::beman::execution::operation_state_t;
3883

3884
        run_loop* loop;
3885
        Receiver  receiver;
3886

3887
        // NOLINTBEGIN(misc-no-recursion)
3888
        template <typename R>
3889
        opstate(run_loop* l, R&& rcvr) : loop(l), receiver(::std::forward<Receiver>(rcvr)) {}
3890
        auto start() & noexcept -> void { this->loop->push_back(this); }
3891
        // NOLINTEND(misc-no-recursion)
3892
        auto execute() noexcept -> void override {
3893
            using token = decltype(::beman::execution::get_stop_token(::beman::execution::get_env(this->receiver)));
3894
            if constexpr (not ::beman::execution::unstoppable_token<token>) {
3895
                if (::beman::execution::get_stop_token(::beman::execution::get_env(this->receiver)).stop_requested())
3896
                    ::beman::execution::set_stopped(::std::move(this->receiver));
3897
                else
3898
                    ::beman::execution::set_value(::std::move(this->receiver));
3899
            } else
3900
                ::beman::execution::set_value(::std::move(this->receiver));
3901
        }
3902
    };
3903
    struct sender {
3904
        using sender_concept = ::beman::execution::sender_t;
3905
        template <typename Env = ::beman::execution::env<>>
3906
        auto get_completion_signatures(Env&& env) const noexcept {
3907
            if constexpr (::beman::execution::unstoppable_token<decltype(::beman::execution::get_stop_token(env))>)
3908
                return ::beman::execution::completion_signatures<::beman::execution::set_value_t()>{};
3909
            else
3910
                return ::beman::execution::completion_signatures<::beman::execution::set_value_t(),
3911
                                                                 ::beman::execution::set_stopped_t()>{};
3912
        }
3913

3914
        run_loop* loop;
3915

NEW
3916
        auto get_env() const noexcept -> env { return {this->loop}; }
×
3917
        template <typename Receiver>
3918
        auto connect(Receiver&& receiver) noexcept -> opstate<::std::decay_t<Receiver>> {
3919
            return {this->loop, ::std::forward<Receiver>(receiver)};
3920
        }
3921
    };
3922
    struct scheduler {
3923
        using scheduler_concept = ::beman::execution::scheduler_t;
3924

3925
        run_loop* loop;
3926

NEW
3927
        auto schedule() noexcept -> sender { return {this->loop}; }
×
3928
        auto operator==(const scheduler&) const -> bool = default;
3929
    };
3930

3931
    enum class state : unsigned char { starting, running, finishing };
3932

3933
    state                     current_state{state::starting};
3934
    ::std::mutex              mutex{};
3935
    ::std::condition_variable condition{};
3936
    opstate_base*             front{};
3937
    opstate_base*             back{};
3938

NEW
3939
    auto push_back(opstate_base* item) noexcept -> void {
×
3940
        //-dk:TODO run_loop::push_back should really be lock-free
NEW
3941
        ::std::lock_guard guard(this->mutex);
×
NEW
3942
        if (auto previous_back{::std::exchange(this->back, item)}) {
×
NEW
3943
            previous_back->next = item;
×
3944
        } else {
NEW
3945
            this->front = item;
×
NEW
3946
            this->condition.notify_one();
×
3947
        }
NEW
3948
    }
×
NEW
3949
    auto pop_front() noexcept -> opstate_base* {
×
3950
        //-dk:TODO run_loop::pop_front should really be lock-free
NEW
3951
        ::std::unique_lock guard(this->mutex);
×
NEW
3952
        this->condition.wait(guard, [this] { return this->front || this->current_state == state::finishing; });
×
NEW
3953
        if (this->front == this->back)
×
NEW
3954
            this->back = nullptr;
×
NEW
3955
        return this->front ? ::std::exchange(this->front, this->front->next) : nullptr;
×
NEW
3956
    }
×
3957

3958
  public:
3959
    run_loop() noexcept       = default;
3960
    run_loop(const run_loop&) = delete;
3961
    run_loop(run_loop&&)      = delete;
NEW
3962
    ~run_loop() {
×
NEW
3963
        ::std::lock_guard guard(this->mutex);
×
NEW
3964
        if (this->front != nullptr || this->current_state == state::running)
×
NEW
3965
            ::std::terminate();
×
NEW
3966
    }
×
3967
    auto operator=(const run_loop&) -> run_loop& = delete;
3968
    auto operator=(run_loop&&) -> run_loop&      = delete;
3969

NEW
3970
    auto get_scheduler() -> scheduler { return {this}; }
×
3971

NEW
3972
    auto run() -> void {
×
NEW
3973
        if (::std::lock_guard guard(this->mutex);
×
NEW
3974
            this->current_state != state::finishing &&
×
NEW
3975
            state::running == ::std::exchange(this->current_state, state::running)) {
×
NEW
3976
            ::std::terminate();
×
NEW
3977
        }
×
3978

NEW
3979
        while (auto* op{this->pop_front()}) {
×
NEW
3980
            op->execute();
×
NEW
3981
        }
×
NEW
3982
    }
×
NEW
3983
    auto finish() -> void {
×
3984
        {
NEW
3985
            ::std::lock_guard guard(this->mutex);
×
NEW
3986
            this->current_state = state::finishing;
×
NEW
3987
        }
×
NEW
3988
        this->condition.notify_one();
×
NEW
3989
    }
×
3990
};
3991
} // namespace beman::execution
3992

3993
// ----------------------------------------------------------------------------
3994

3995
// ----------------------------------------------------------------------------
3996

3997
namespace beman::execution {
3998
export struct get_completion_signatures_t {
3999
  private:
4000
    template <typename Sender, typename Env>
4001
    static auto get(Sender&& sender, Env&& env) noexcept {
4002
        auto new_sender{[](auto&& sndr, auto&& e) -> decltype(auto) {
4003
            auto domain{::beman::execution::detail::get_domain_late(sndr, e)};
4004
            return ::beman::execution::transform_sender(domain, ::std::forward<Sender>(sndr), ::std::forward<Env>(e));
4005
        }};
4006

4007
        using sender_type = ::std::remove_cvref_t<decltype(new_sender(sender, env))>;
4008
        using decayed_env = ::std::remove_cvref_t<Env>;
4009
        if constexpr (requires { new_sender(sender, env).get_completion_signatures(env); })
4010
            return decltype(new_sender(sender, env).get_completion_signatures(env)){};
4011
        else if constexpr (requires { typename sender_type::completion_signatures; })
4012
            return typename sender_type::completion_signatures{};
4013
        else if constexpr (::beman::execution::detail::
4014
                               is_awaitable<sender_type, ::beman::execution::detail::env_promise<decayed_env>>) {
4015
            using result_type =
4016
                ::beman::execution::detail::await_result_type<sender_type,
4017
                                                              ::beman::execution::detail::env_promise<decayed_env>>;
4018
            if constexpr (::std::same_as<void, result_type>) {
4019
                return ::beman::execution::completion_signatures<::beman::execution::set_value_t(),
4020
                                                                 ::beman::execution::set_error_t(::std::exception_ptr),
4021
                                                                 ::beman::execution::set_stopped_t()>{};
4022
            } else {
4023
                return ::beman::execution::completion_signatures<::beman::execution::set_value_t(result_type),
4024
                                                                 ::beman::execution::set_error_t(::std::exception_ptr),
4025
                                                                 ::beman::execution::set_stopped_t()>{};
4026
            }
4027
        }
4028
    }
4029

4030
  public:
4031
    template <typename Sender, typename Env>
4032
        requires(!::std::same_as<void,
4033
                                 decltype(get_completion_signatures_t::get(::std::declval<Sender>(),
4034
                                                                           ::std::declval<Env>()))>)
4035
    auto operator()(Sender&& sender, Env&& env) const noexcept {
4036
        return this->get(::std::forward<Sender>(sender), ::std::forward<Env>(env));
4037
    }
4038
};
4039
export inline constexpr get_completion_signatures_t get_completion_signatures{};
4040
} // namespace beman::execution
4041

4042
// ----------------------------------------------------------------------------
4043

4044
// ----------------------------------------------------------------------------
4045

4046
namespace beman::execution::detail {
4047
/*!
4048
 * \brief The actual implementation of the connect customization point type
4049
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4050
 * \internal
4051
 */
4052
export //-dk:TODO this seems to needed for MSVC++ (2026-01-30)
4053
    struct connect_t {
4054
  private:
4055
    template <typename Sender, typename Receiver>
4056
    static auto make_new_sender(Sender&& sender, Receiver&& receiver)
4057
        //-dk:TODO this noexcept needs to get confirmed/fixed
4058
        noexcept(true) -> decltype(auto) {
4059
        return ::beman::execution::transform_sender(
4060
            decltype(::beman::execution::detail::get_domain_late(::std::forward<Sender>(sender),
4061
                                                                 ::beman::execution::get_env(receiver))){},
4062
            ::std::forward<Sender>(sender),
4063
            ::beman::execution::get_env(receiver));
4064
    }
4065
    template <typename Sender, typename Receiver>
4066
    static constexpr auto connect_noexcept() -> bool {
4067
        if constexpr (requires {
4068
                          make_new_sender(::std::declval<Sender>(), ::std::declval<Receiver>())
4069
                              .connect(::std::declval<Receiver>());
4070
                      }) {
4071
            return noexcept(make_new_sender(::std::declval<Sender>(), ::std::declval<Receiver>())
4072
                                .connect(::std::declval<Receiver>()));
4073
        } else if constexpr (requires {
4074
                                 ::beman::execution::detail::connect_awaitable(
4075
                                     make_new_sender(::std::declval<Sender>(), ::std::declval<Receiver>()),
4076
                                     ::std::declval<Receiver>());
4077
                             }) {
4078
            return noexcept(::beman::execution::detail::connect_awaitable(
4079
                make_new_sender(::std::declval<Sender>(), ::std::declval<Receiver>()), ::std::declval<Receiver>()));
4080
        }
4081
        return true;
4082
    }
4083

4084
  public:
4085
    template <typename Sender, typename Receiver>
4086
    auto operator()(Sender&& sender, Receiver&& receiver) const noexcept(connect_noexcept<Sender, Receiver>()) {
4087
        auto new_sender = [&sender, &receiver]() -> decltype(auto) {
4088
            return make_new_sender(::std::forward<Sender>(sender), ::std::forward<Receiver>(receiver));
4089
        };
4090

4091
        if constexpr (requires { new_sender().connect(::std::forward<Receiver>(receiver)); }) {
4092
            using state_type = decltype(new_sender().connect(::std::forward<Receiver>(receiver)));
4093
            static_assert(::beman::execution::operation_state<state_type>);
4094
            return new_sender().connect(::std::forward<Receiver>(receiver));
4095
        } else if constexpr (requires {
4096
                                 ::beman::execution::detail::connect_awaitable(new_sender(),
4097
                                                                               ::std::forward<Receiver>(receiver));
4098
                             }) {
4099
            return ::beman::execution::detail::connect_awaitable(new_sender(), ::std::forward<Receiver>(receiver));
4100
        } else {
4101
            enum bad_sender {};
4102
            static_assert(::std::same_as<bad_sender, decltype(new_sender())>,
4103
                          "result from transform_sender has no suitable connect()");
4104
        }
4105
    }
4106
};
4107
} // namespace beman::execution::detail
4108

4109
namespace beman::execution {
4110
/*!
4111
 * \brief Type of the connect customization point object.
4112
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4113
 */
4114
export using connect_t = beman::execution::detail::connect_t;
4115
/*!
4116
 * \brief Customization point object used to connect a sender and a receiver.
4117
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4118
 *
4119
 * \details
4120
 * `connect(sender, receiver)` returns the result of calling `sender.connect(receiver)`.
4121
 * The returned object `state` is an `operation_state` object.
4122
 */
4123
export inline constexpr connect_t connect{};
4124
} // namespace beman::execution
4125

4126
// ----------------------------------------------------------------------------
4127

4128
// ----------------------------------------------------------------------------
4129

4130
namespace beman::execution {
4131
export template <typename Sender, typename Env = ::beman::execution::env<>>
4132
concept sender_in =
4133
    ::beman::execution::sender<Sender> && ::beman::execution::detail::queryable<Env> &&
4134
    requires(Sender&& sender, Env&& env) {
4135
        {
4136
            ::beman::execution::get_completion_signatures(::std::forward<Sender>(sender), ::std::forward<Env>(env))
4137
        } -> ::beman::execution::detail::valid_completion_signatures;
4138
    };
4139
} // namespace beman::execution
4140

4141
// ----------------------------------------------------------------------------
4142

4143
// ----------------------------------------------------------------------------
4144

4145
namespace beman::execution {
4146
/*!
4147
 * \brief Type alias to determine the operation state type returned from `connect()`.
4148
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4149
 */
4150
export template <typename Sender, typename Receiver>
4151
using connect_result_t = decltype(::beman::execution::connect(::std::declval<Sender>(), ::std::declval<Receiver>()));
4152
} // namespace beman::execution
4153

4154
// ----------------------------------------------------------------------------
4155

4156
// ----------------------------------------------------------------------------
4157

4158
namespace beman::execution::detail {
4159
inline constexpr struct stop_when_t {
4160
    template <::beman::execution::sender Sndr, ::beman::execution::stoppable_token Tok>
4161
    struct sender;
4162

4163
    template <::beman::execution::sender Sndr, ::beman::execution::stoppable_token Tok>
4164
    auto operator()(Sndr&& sndr, Tok&& tok) const noexcept;
4165
} stop_when{};
4166
} // namespace beman::execution::detail
4167

4168
template <::beman::execution::sender Sndr, ::beman::execution::stoppable_token Tok>
4169
struct beman::execution::detail::stop_when_t::sender {
4170
    using sender_concept = ::beman::execution::sender_t;
4171

4172
    stop_when_t               stop_when{};
4173
    std::remove_cvref_t<Tok>  tok;
4174
    std::remove_cvref_t<Sndr> sndr;
4175

4176
    template <::beman::execution::receiver Rcvr>
4177
    struct state {
4178
        using operation_state_concept = ::beman::execution::operation_state_t;
4179
        using rcvr_t                  = ::std::remove_cvref_t<Rcvr>;
4180
        using token1_t                = ::std::remove_cvref_t<Tok>;
4181
        using token2_t =
4182
            decltype(::beman::execution::get_stop_token(::beman::execution::get_env(::std::declval<rcvr_t>())));
4183

4184
        struct cb_t {
4185
            ::beman::execution::inplace_stop_source& source;
4186
            auto                                     operator()() const noexcept { this->source.request_stop(); }
4187
        };
4188
        struct base_state {
4189
            rcvr_t                                  rcvr;
4190
            ::beman::execution::inplace_stop_source source{};
4191
        };
4192
        struct env {
4193
            base_state* st;
4194
            auto        query(const ::beman::execution::get_stop_token_t&) const noexcept {
4195
                return this->st->source.get_token();
4196
            }
4197
            template <typename Q, typename... A>
4198
                requires requires(const Q& q, A&&... a, const rcvr_t& r) {
4199
                    q(::beman::execution::get_env(r), ::std::forward<A>(a)...);
4200
                }
4201
            auto query(const Q& q, A&&... a) const noexcept {
4202
                return q(::beman::execution::get_env(this->st->rcvr), ::std::forward<A>(a)...);
4203
            }
4204
        };
4205

4206
        struct receiver {
4207
            using receiver_concept = ::beman::execution::receiver_t;
4208
            base_state* st;
4209

4210
            auto get_env() const noexcept -> env { return env{this->st}; }
4211
            template <typename... A>
4212
            auto set_value(A&&... a) const noexcept -> void {
4213
                ::beman::execution::set_value(::std::move(this->st->rcvr), ::std::forward<A>(a)...);
4214
            }
4215
            template <typename E>
4216
            auto set_error(E&& e) const noexcept -> void {
4217
                ::beman::execution::set_error(::std::move(this->st->rcvr), ::std::forward<E>(e));
4218
            }
4219
            auto set_stopped() const noexcept -> void { ::beman::execution::set_stopped(::std::move(this->st->rcvr)); }
4220
        };
4221
        using inner_state_t =
4222
            decltype(::beman::execution::connect(::std::declval<Sndr>(), ::std::declval<receiver>()));
4223

4224
        token1_t                                                               tok;
4225
        base_state                                                             base;
4226
        std::optional<::beman::execution::stop_callback_for_t<token1_t, cb_t>> cb1;
4227
        std::optional<::beman::execution::stop_callback_for_t<token2_t, cb_t>> cb2;
4228
        inner_state_t                                                          inner_state;
4229

4230
        template <::beman::execution::sender S, ::beman::execution::stoppable_token T, ::beman::execution::receiver R>
4231
        state(S&& s, T&& t, R&& r)
4232
            : tok(::std::forward<T>(t)),
4233
              base{::std::forward<R>(r)},
4234
              inner_state(::beman::execution::connect(::std::forward<S>(s), receiver{&this->base})) {}
4235

4236
        auto start() & noexcept {
4237
            this->cb1.emplace(this->tok, cb_t{this->base.source});
4238
            this->cb2.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(this->base.rcvr)),
4239
                              cb_t{this->base.source});
4240
            ::beman::execution::start(this->inner_state);
4241
        }
4242
    };
4243

4244
    template <typename E>
4245
    auto get_completion_signatures(const E& e) const noexcept {
4246
        return ::beman::execution::get_completion_signatures(this->sndr, e);
4247
    }
4248
    template <::beman::execution::receiver Rcvr>
4249
    auto connect(Rcvr&& rcvr) && -> state<Rcvr> {
4250
        return state<Rcvr>{std::move(this->sndr), ::std::move(this->tok), ::std::forward<Rcvr>(rcvr)};
4251
    }
4252
};
4253

4254
template <::beman::execution::sender Sndr, ::beman::execution::stoppable_token Tok>
4255
inline auto beman::execution::detail::stop_when_t::operator()(Sndr&& sndr, Tok&& tok) const noexcept {
4256
    if constexpr (::beman::execution::unstoppable_token<Tok>) {
4257
        return ::std::forward<Sndr>(sndr);
4258
    } else {
4259
        return sender<Sndr, Tok>{*this, ::std::forward<Tok>(tok), ::std::forward<Sndr>(sndr)};
4260
    }
4261
}
4262

4263
// ----------------------------------------------------------------------------
4264

4265
// ----------------------------------------------------------------------------
4266

4267
namespace beman::execution::detail {
4268
struct token_test_env {};
4269

4270
struct token_test_sender {
4271
    using sender_concept = ::beman::execution::sender_t;
4272
    template <typename... Env>
4273
    auto get_completion_signatures(const Env&...) const noexcept {
4274
        return ::beman::execution::completion_signatures<>{};
4275
    }
4276
};
4277
static_assert(::beman::execution::sender<::beman::execution::detail::token_test_sender>);
4278
static_assert(::beman::execution::sender_in<::beman::execution::detail::token_test_sender,
4279
                                            ::beman::execution::detail::token_test_env>);
4280
} // namespace beman::execution::detail
4281

4282
namespace beman::execution {
4283
export template <typename Token>
4284
concept scope_token = ::std::copyable<Token> && requires(Token token) {
4285
    { token.try_associate() } -> ::std::same_as<bool>;
4286
    { token.disassociate() } noexcept;
4287
    {
4288
        token.wrap(::std::declval<::beman::execution::detail::token_test_sender>())
4289
    } -> ::beman::execution::sender_in<::beman::execution::detail::token_test_env>;
4290
};
4291
} // namespace beman::execution
4292

4293
// ----------------------------------------------------------------------------
4294

4295
// ----------------------------------------------------------------------------
4296

4297
namespace beman::execution::detail {
4298
/*!
4299
 * \brief Tag type used to determine if completion signatures were defined.
4300
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4301
 * \internal
4302
 */
4303
struct no_completion_signatures_defined_in_sender {};
4304

4305
/*!
4306
 * \brief Primary template declaration for the customization of sender completion signatures.
4307
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4308
 * \internal
4309
 */
4310
template <typename Sender, typename Env>
4311
struct completion_signatures_for_impl {
4312
    using type = ::beman::execution::detail::no_completion_signatures_defined_in_sender;
4313
};
4314

4315
/*!
4316
 * \brief Type alias used to access a senders completion signatures.
4317
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4318
 * \internal
4319
 */
4320
template <typename Sender, typename Env>
4321
using completion_signatures_for = ::std::conditional_t<
4322
    ::std::same_as<beman::execution::detail::no_completion_signatures_defined_in_sender,
4323
                   typename ::beman::execution::detail::completion_signatures_for_impl<Sender, Env>::type>,
4324
    typename ::beman::execution::detail::completion_signatures_for_impl<::std::remove_cvref_t<Sender>, Env>::type,
4325
    typename ::beman::execution::detail::completion_signatures_for_impl<Sender, Env>::type>;
4326
} // namespace beman::execution::detail
4327

4328
// ----------------------------------------------------------------------------
4329

4330
// ----------------------------------------------------------------------------
4331

4332
namespace beman::execution {
4333
/*!
4334
 * \brief Alias to access the completion signatures of a sender
4335
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4336
 */
4337
export template <typename Sender, typename Env = ::beman::execution::env<>>
4338
    requires ::beman::execution::sender_in<Sender, Env>
4339
using completion_signatures_of_t =
4340
    ::beman::execution::detail::call_result_t<::beman::execution::get_completion_signatures_t, Sender, Env>;
4341
} // namespace beman::execution
4342

4343
// ----------------------------------------------------------------------------
4344

4345
// ----------------------------------------------------------------------------
4346

4347
namespace beman::execution::detail {
4348
/*!
4349
 * \brief A helper types whose call operator connects all children of a basic_sender
4350
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4351
 * \internal
4352
 */
4353
struct connect_all_t {
4354
  private:
4355
    template <typename Fun, typename Tuple, ::std::size_t... I>
4356
    static auto apply_with_index_helper(::std::index_sequence<I...> seq, Fun&& fun, Tuple&& tuple) noexcept(noexcept(
4357
        ::std::forward<Fun>(fun)(seq, ::beman::execution::detail::forward_like<Tuple>(::std::get<I>(tuple))...)))
4358
        -> decltype(auto) {
4359
        return ::std::forward<Fun>(fun)(seq, ::beman::execution::detail::forward_like<Tuple>(::std::get<I>(tuple))...);
4360
    }
4361
    template <typename Fun, typename Tuple>
4362
    static auto apply_with_index(Fun&& fun, Tuple&& tuple) noexcept(
4363
        noexcept(apply_with_index_helper(::std::make_index_sequence<::std::tuple_size_v<::std::decay_t<Tuple>>>{},
4364
                                         ::std::forward<Fun>(fun),
4365
                                         ::std::forward<Tuple>(tuple)))) -> decltype(auto) {
4366
        return apply_with_index_helper(::std::make_index_sequence<::std::tuple_size_v<::std::decay_t<Tuple>>>{},
4367
                                       ::std::forward<Fun>(fun),
4368
                                       ::std::forward<Tuple>(tuple));
4369
    }
4370

4371
    template <::std::size_t Start, typename Fun, typename Tuple, ::std::size_t... I>
4372
    static auto sub_apply_with_index_helper(::std::index_sequence<I...> seq, Fun&& fun, Tuple&& tuple) noexcept(
4373
        noexcept(::std::forward<Fun>(fun)(
4374
            seq, ::beman::execution::detail::forward_like<Tuple>(tuple.template get<I + Start>())...)))
4375
        -> decltype(auto) {
4376
        return ::std::forward<Fun>(fun)(
4377
            seq, ::beman::execution::detail::forward_like<Tuple>(tuple.template get<I + Start>())...);
4378
    }
4379
    template <::std::size_t Start, typename Fun, typename Tuple>
4380
        requires requires { ::std::declval<Tuple>().size(); }
4381
    static auto sub_apply_with_index(Fun&& fun, Tuple&& tuple) noexcept(noexcept(sub_apply_with_index_helper<Start>(
4382
        ::std::make_index_sequence<::std::tuple_size_v<::std::decay_t<Tuple>> - Start>{},
4383
        ::std::forward<Fun>(fun),
4384
        ::std::forward<Tuple>(tuple)))) -> decltype(auto) {
4385
        return sub_apply_with_index_helper<Start>(
4386
            ::std::make_index_sequence<::std::tuple_size_v<::std::decay_t<Tuple>> - Start>{},
4387
            ::std::forward<Fun>(fun),
4388
            ::std::forward<Tuple>(tuple));
4389
    }
4390
    template <::std::size_t Start, typename Fun, typename Tuple>
4391
        requires(not requires { ::std::declval<Tuple>().size(); })
4392
    static auto
4393
    sub_apply_with_index(Fun&& fun,
4394
                         Tuple&&) noexcept(noexcept(::std::forward<Fun>(fun)(::std::make_index_sequence<0u>{}))) {
4395
        return ::std::forward<Fun>(fun)(::std::make_index_sequence<0u>{});
4396
    }
4397

4398
    template <typename Sender, typename Receiver>
4399
    struct connect_helper {
4400
        ::beman::execution::detail::basic_state<Sender, Receiver>* op;
4401

4402
        template <::std::size_t... J, typename... C>
4403
        auto operator()(::std::index_sequence<J...>, C&&... c) noexcept(
4404
            (noexcept(::beman::execution::connect(
4405
                 ::beman::execution::detail::forward_like<Sender>(c),
4406
                 ::beman::execution::detail::
4407
                     basic_receiver<Sender, Receiver, ::std::integral_constant<::std::size_t, J>>{this->op})) &&
4408
             ... && true)) -> decltype(auto) {
4409
            return ::beman::execution::detail::product_type{::beman::execution::connect(
4410
                ::beman::execution::detail::forward_like<Sender>(c),
4411
                ::beman::execution::detail::
4412
                    basic_receiver<Sender, Receiver, ::std::integral_constant<::std::size_t, J>>{this->op})...};
4413
        }
4414
    };
4415

4416
    static auto use(auto&&...) {}
4417

4418
  public:
4419
    //-dk:TODO is the S parameter deviating from the spec?
4420
    template <typename Sender, typename S, typename Receiver, ::std::size_t... I>
4421
        requires requires(Sender&& s) {
4422
            s.size();
4423
            s.template get<0>();
4424
        }
4425
    auto operator()(::beman::execution::detail::basic_state<Sender, Receiver>* op,
4426
                    S&&                                                        sender,
4427
                    ::std::index_sequence<I...>) const
4428
        noexcept(noexcept(sub_apply_with_index<2>(connect_helper<Sender, Receiver>{op}, ::std::forward<S>(sender))))
4429
            -> decltype(auto) {
4430
        return sub_apply_with_index<2>(connect_helper<Sender, Receiver>{op}, ::std::forward<S>(sender));
4431
    }
4432
    template <typename Sender, typename S, typename Receiver, ::std::size_t... I>
4433
    auto operator()(::beman::execution::detail::basic_state<Sender, Receiver>* op,
4434
                    S&&                                                        sender,
4435
                    ::std::index_sequence<I...>) const
4436
        noexcept(noexcept(apply_with_index(
4437
            connect_helper<Sender, Receiver>{op},
4438
            ::beman::execution::detail::get_sender_data(::std::forward<S>(sender)).children))) -> decltype(auto) {
4439
        return apply_with_index(connect_helper<Sender, Receiver>{op},
4440
                                ::beman::execution::detail::get_sender_data(::std::forward<S>(sender)).children);
4441
    }
4442
};
4443

4444
/*!
4445
 * \brief A helper object of type connect_all_t
4446
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4447
 * \internal
4448
 */
4449
inline constexpr connect_all_t connect_all{};
4450
} // namespace beman::execution::detail
4451

4452
// ----------------------------------------------------------------------------
4453

4454
// ----------------------------------------------------------------------------
4455

4456
namespace beman::execution {
4457
/*!
4458
 * \brief Type alias to get error types for a sender
4459
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4460
 */
4461
export template <typename Sender,
4462
                 typename Env                         = ::beman::execution::env<>,
4463
                 template <typename...> class Variant = ::beman::execution::detail::variant_or_empty>
4464
    requires ::beman::execution::sender_in<Sender, Env>
4465
using error_types_of_t =
4466
    ::beman::execution::detail::gather_signatures<::beman::execution::set_error_t,
4467
                                                  ::beman::execution::completion_signatures_of_t<Sender, Env>,
4468
                                                  ::std::type_identity_t,
4469
                                                  Variant>;
4470
} // namespace beman::execution
4471

4472
// ----------------------------------------------------------------------------
4473

4474
// ----------------------------------------------------------------------------
4475

4476
namespace beman::execution {
4477
export template <typename Sender, typename Env = ::beman::execution::env<>>
4478
    requires ::beman::execution::sender_in<Sender, Env>
4479
inline constexpr bool sends_stopped{!::std::same_as<
4480
    ::beman::execution::detail::type_list<>,
4481
    ::beman::execution::detail::gather_signatures<::beman::execution::set_stopped_t,
4482
                                                  ::beman::execution::completion_signatures_of_t<Sender, Env>,
4483
                                                  ::beman::execution::detail::type_list,
4484
                                                  ::beman::execution::detail::type_list>>};
4485
}
4486

4487
// ----------------------------------------------------------------------------
4488

4489
// ----------------------------------------------------------------------------
4490

4491
namespace beman::execution {
4492
export template <typename Sender,
4493
                 typename Env                         = ::beman::execution::env<>,
4494
                 template <typename...> class Tuple   = ::beman::execution::detail::decayed_tuple,
4495
                 template <typename...> class Variant = ::beman::execution::detail::variant_or_empty>
4496
    requires ::beman::execution::sender_in<Sender, Env>
4497
using value_types_of_t =
4498
    ::beman::execution::detail::gather_signatures<::beman::execution::set_value_t,
4499
                                                  ::beman::execution::completion_signatures_of_t<Sender, Env>,
4500
                                                  Tuple,
4501
                                                  Variant>;
4502
}
4503
// ----------------------------------------------------------------------------
4504

4505
// ----------------------------------------------------------------------------
4506

4507
namespace beman::execution::detail {
4508
/*!
4509
 * \brief Helper type used to determine the state type when connecting all senders in a basic_sender
4510
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4511
 * \internal
4512
 */
4513
template <typename Sender, typename Receiver>
4514
using connect_all_result =
4515
    ::beman::execution::detail::call_result_t<decltype(::beman::execution::detail::connect_all),
4516
                                              ::beman::execution::detail::basic_state<Sender, Receiver>*,
4517
                                              Sender,
4518
                                              ::beman::execution::detail::indices_for<Sender>>;
4519
} // namespace beman::execution::detail
4520

4521
// ----------------------------------------------------------------------------
4522

4523
// ----------------------------------------------------------------------------
4524

4525
namespace beman::execution::detail {
4526
struct sync_wait_env {
4527
    ::beman::execution::run_loop* loop{};
4528

NEW
4529
    auto query(::beman::execution::get_scheduler_t) const noexcept { return this->loop->get_scheduler(); }
×
NEW
4530
    auto query(::beman::execution::get_delegation_scheduler_t) const noexcept { return this->loop->get_scheduler(); }
×
4531
};
4532

4533
template <::beman::execution::sender_in<::beman::execution::detail::sync_wait_env> Sender>
4534
using sync_wait_result_type =
4535
    ::std::optional<::beman::execution::value_types_of_t<Sender,
4536
                                                         ::beman::execution::detail::sync_wait_env,
4537
                                                         ::beman::execution::detail::decayed_tuple,
4538
                                                         ::std::type_identity_t>>;
4539

4540
template <typename Sender>
4541
struct sync_wait_state {
4542
    ::beman::execution::run_loop loop{};
4543
    ::std::exception_ptr         error{};
4544

4545
    ::beman::execution::detail::sync_wait_result_type<Sender> result{};
4546
};
4547

4548
template <typename Sender>
4549
struct sync_wait_receiver {
4550
    using receiver_concept = ::beman::execution::receiver_t;
4551

4552
    ::beman::execution::detail::sync_wait_state<Sender>* state{};
4553

4554
    template <typename Error>
4555
    auto set_error(Error&& error) && noexcept -> void {
4556
        this->state->error = ::beman::execution::detail::as_except_ptr(::std::forward<Error>(error));
4557
        this->state->loop.finish();
4558
    }
4559
    auto set_stopped() && noexcept -> void { this->state->loop.finish(); }
4560
    template <typename... Args>
4561
    auto set_value(Args&&... args) && noexcept -> void {
4562
        try {
4563
            this->state->result.emplace(::std::forward<Args>(args)...);
4564
        } catch (...) {
4565
            this->state->error = ::std::current_exception();
4566
        }
4567
        this->state->loop.finish();
4568
    }
4569

4570
    auto get_env() const noexcept -> ::beman::execution::detail::sync_wait_env {
4571
        return ::beman::execution::detail::sync_wait_env{&this->state->loop};
4572
    }
4573
};
4574

4575
struct sync_wait_t {
4576
    template <typename Sender>
4577
    auto apply_sender(Sender&& sender) const {
4578
        ::beman::execution::detail::sync_wait_state<Sender> state;
4579
        auto op{::beman::execution::connect(::std::forward<Sender>(sender),
4580
                                            ::beman::execution::detail::sync_wait_receiver<Sender>{&state})};
4581
        ::beman::execution::start(op);
4582

4583
        state.loop.run();
4584
        if (state.error) {
4585
            ::std::rethrow_exception(state.error);
4586
        }
4587
        return ::std::move(state.result);
4588
    }
4589

4590
    template <::beman::execution::sender_in<::beman::execution::detail::sync_wait_env> Sender>
4591
        requires requires(Sender&& sender, const sync_wait_t& self) {
4592
            typename ::beman::execution::detail::sync_wait_result_type<Sender>;
4593
            {
4594
                ::beman::execution::apply_sender(
4595
                    ::beman::execution::detail::get_domain_early(std::forward<Sender>(sender)),
4596
                    self,
4597
                    ::std::forward<Sender>(sender))
4598
            } -> ::std::same_as<::beman::execution::detail::sync_wait_result_type<Sender>>;
4599
        }
4600
    auto operator()(Sender&& sender) const {
4601
        auto domain{::beman::execution::detail::get_domain_early(sender)};
4602
        return ::beman::execution::apply_sender(domain, *this, ::std::forward<Sender>(sender));
4603
    }
4604
};
4605
} // namespace beman::execution::detail
4606

4607
namespace beman::execution {
4608
export using sync_wait_t = ::beman::execution::detail::sync_wait_t;
4609
/*!
4610
 * \brief <code>sync_wait(_sender_)</code> starts <code>_sender_</code> and waits for its completion.
4611
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4612
 *
4613
 * \details
4614
 * `sync_wait` is a callable object of type `sync_wait_t`. Invoking
4615
 * <code>sync_wait(_sender_)</code> starts <code>_sender_</code> and
4616
 * waits for its completion. This involves a few steps:
4617
 * 1. A <code>run_loop</code> is created to provide a scheduler.
4618
 * 2. The <code>_sender_</code> is `connect`ed to a receiver capturing
4619
 *     the results and providing an environment with access to the
4620
 *     `run_loop`'s scheduler.
4621
 * 3. The operation state returned from `connect` is `start`ed.
4622
 * 4. The `run_loop` is run to process any work scheduled.
4623
 *
4624
 * Once the <code>_sender_</code> completes, the result is provided by `sync_wait`:
4625
 * - If the <code>_sender_</code> completes with <code>set_value(_arg_...)</code>, `sync_wait` returns
4626
 *     an <code>std::optional<std::tuple<_Arg_...>></code> containing the results
4627
 *     <code>_arg_...</code>.
4628
 * - If the <code>_sender_</code> completes with `set_stopped()`, `sync_wait` returns a
4629
 *    disengaged <code>std::optional<std::tuple<_Arg_...>></code>.
4630
 * - If the <code>_sender_</code> completes with
4631
 *    <code>set_error(_error_)</code>, `sync_wait` throw <code>_error_</code> or rethrows the exception if
4632
 * <code>_error_</code> is an <code>std::exception_ptr</code>.
4633
 *
4634
 * <h4>Usage</h4>
4635
 * <pre>
4636
 * sync_wait(<i>sender</i>...)
4637
 * </pre>
4638
 *
4639
 * <h4>Example</h4>
4640
 *
4641
 * The use of <code>sync_wait(_sender_)</code> is in `main`
4642
 * to synchronously wait for the completion of the asynchronous work
4643
 * of the program represented by <code>_sender_</code>.
4644
 *
4645
 * <pre example="doc-sync_wait.cpp">
4646
 * #include <beman/execution/execution.hpp>
4647
 * #include <cassert>
4648
 *
4649
 * int main() {
4650
 *     auto result = ex::sync_wait(ex::just(17));
4651
 *     assert(result);
4652
 *     assert(*result == std::tuple(17));
4653
 * }
4654
 * </pre>
4655
 */
4656
export inline constexpr ::beman::execution::sync_wait_t sync_wait{};
4657
} // namespace beman::execution
4658

4659
// ----------------------------------------------------------------------------
4660

4661
// ----------------------------------------------------------------------------
4662

4663
namespace beman::execution::detail {
4664
/*!
4665
 * \brief Class template use to factor out common operation state needs.
4666
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4667
 * \internal
4668
 */
4669
template <typename Sender, typename Receiver>
4670
    requires ::beman::execution::detail::
4671
        //-dk:TODO why is the remove_cvref_t needed...?
4672
    valid_specialization<::beman::execution::detail::state_type, std::remove_cvref_t<Sender>, Receiver>
4673
struct basic_operation : ::beman::execution::detail::basic_state<Sender, Receiver> {
4674
    // static_assert(std::same_as<Sender, std::remove_cvref_t<Sender>>);
4675
    friend struct ::beman::execution::start_t;
4676
    using operation_state_concept = ::beman::execution::operation_state_t;
4677
    using tag_t                   = ::beman::execution::tag_of_t<Sender>;
4678

4679
    using inner_ops_t = ::beman::execution::detail::connect_all_result<Sender, Receiver>;
4680
    inner_ops_t inner_ops;
4681

4682
    basic_operation(Sender&& sender, Receiver&& rcvr) noexcept(
4683
        noexcept(::beman::execution::detail::basic_state<Sender, Receiver>(::std::forward<Sender>(sender),
4684
                                                                           ::std::move(rcvr))) &&
4685
        noexcept(::beman::execution::detail::connect_all(this,
4686
                                                         ::std::forward<Sender>(sender),
4687
                                                         ::beman::execution::detail::indices_for<Sender>())))
4688
        : ::beman::execution::detail::basic_state<Sender, Receiver>(::std::forward<Sender>(sender), ::std::move(rcvr)),
4689
          // NOLINTBEGIN(bugprone-use-after-move,hicpp-invalid-access-moved)
4690
          //-dk:TODO deal with moving the sender twice
4691
          inner_ops(::beman::execution::detail::connect_all(
4692
              this, ::std::forward<Sender>(sender), ::beman::execution::detail::indices_for<Sender>())) {}
4693
    // NOLINTEND(bugprone-use-after-move,hicpp-invalid-access-moved)
4694

4695
  private:
4696
    auto start() & noexcept -> void {
4697
        ::std::invoke(
4698
            [this]<::std::size_t... I>(::std::index_sequence<I...>) {
4699
                ::beman::execution::detail::impls_for<tag_t>::start(
4700
                    this->state, this->receiver, this->inner_ops.template get<I>()...);
4701
            },
4702
            ::std::make_index_sequence<inner_ops_t::size()>{});
4703
    }
4704
};
4705
template <typename Sender, typename Receiver>
4706
basic_operation(Sender&&, Receiver&&) -> basic_operation<Sender&&, Receiver>;
4707
} // namespace beman::execution::detail
4708

4709
// ----------------------------------------------------------------------------
4710

4711
// ----------------------------------------------------------------------------
4712

4713
namespace beman::execution::detail {
4714
template <typename Sender, typename Env>
4715
struct single_sender_value_type_helper;
4716

4717
template <typename Sender, typename Env>
4718
    requires requires {
4719
        typename ::beman::execution::value_types_of_t<Sender, Env, ::std::decay_t, ::std::type_identity_t>;
4720
    }
4721
struct single_sender_value_type_helper<Sender, Env> {
4722
    using type = ::beman::execution::value_types_of_t<Sender, Env, ::std::decay_t, ::std::type_identity_t>;
4723
};
4724

4725
template <typename Sender, typename Env>
4726
    requires ::std::same_as<::std::variant<::std::tuple<>>,
4727
                            ::beman::execution::value_types_of_t<Sender, Env, ::std::tuple, ::std::variant>> ||
4728
             ::std::same_as<::std::variant<>,
4729
                            ::beman::execution::value_types_of_t<Sender, Env, ::std::tuple, ::std::variant>>
4730
struct single_sender_value_type_helper<Sender, Env> {
4731
    using type = void;
4732
};
4733

4734
template <typename Sender, typename Env>
4735
    requires(not requires {
4736
                typename ::beman::execution::value_types_of_t<Sender, Env, ::std::decay_t, ::std::type_identity_t>;
4737
            }) &&
4738
            (!::std::same_as<::std::variant<::std::tuple<>>,
4739
                             ::beman::execution::value_types_of_t<Sender, Env, ::std::tuple, ::std::variant>>) &&
4740
            requires {
4741
                typename ::beman::execution::
4742
                    value_types_of_t<Sender, Env, ::beman::execution::detail::decayed_tuple, ::std::type_identity_t>;
4743
            }
4744
struct single_sender_value_type_helper<Sender, Env> {
4745
    using type = ::beman::execution::
4746
        value_types_of_t<Sender, Env, ::beman::execution::detail::decayed_tuple, ::std::type_identity_t>;
4747
};
4748

4749
template <typename Sender, typename Env>
4750
using single_sender_value_type = typename single_sender_value_type_helper<Sender, Env>::type;
4751
} // namespace beman::execution::detail
4752

4753
// ----------------------------------------------------------------------------
4754

4755
// ----------------------------------------------------------------------------
4756

4757
namespace beman::execution::detail {
4758
/*!
4759
 * \brief Class template used to factor out common sender implementation for library senders.
4760
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
4761
 * \internal
4762
 */
4763
template <typename Tag, typename Data, typename... Child>
4764
struct basic_sender : ::beman::execution::detail::product_type<Tag, Data, Child...> {
4765
    friend struct ::beman::execution::detail::connect_t;
4766
    friend struct ::beman::execution::get_completion_signatures_t;
4767
    using sender_concept = ::beman::execution::sender_t;
4768
    using indices_for    = ::std::index_sequence_for<Child...>;
4769

4770
    auto get_env() const noexcept -> decltype(auto) {
4771
        auto&& d{this->template get<1>()};
4772
        return sub_apply<2>(
4773
            [&d](auto&&... c) { return ::beman::execution::detail::impls_for<Tag>::get_attrs(d, c...); }, *this);
4774
    }
4775

4776
    template <typename Receiver>
4777
        requires(!::beman::execution::receiver<Receiver>)
4778
    auto connect(Receiver receiver) = BEMAN_EXECUTION_DELETE("the passed receiver doesn't model receiver");
4779

4780
  private:
4781
#if __cpp_explicit_this_parameter < 302110L //-dk:TODO need to figure out how to use explicit this with forwarding
4782
    template <::beman::execution::receiver Receiver>
4783
    auto connect(Receiver receiver) & noexcept(
4784
        noexcept(::beman::execution::detail::basic_operation<basic_sender&, Receiver>{*this, ::std::move(receiver)}))
4785
        -> ::beman::execution::detail::basic_operation<basic_sender&, Receiver> {
4786
        return {*this, ::std::move(receiver)};
4787
    }
4788
    template <::beman::execution::receiver Receiver>
4789
    auto connect(Receiver receiver) const& noexcept(noexcept(
4790
        ::beman::execution::detail::basic_operation<const basic_sender&, Receiver>{*this, ::std::move(receiver)}))
4791
        -> ::beman::execution::detail::basic_operation<const basic_sender&, Receiver> {
4792
        return {*this, ::std::move(receiver)};
4793
    }
4794
    template <::beman::execution::receiver Receiver>
4795
    auto connect(Receiver receiver) && noexcept(
4796
        noexcept(::beman::execution::detail::basic_operation<basic_sender, Receiver>{::std::move(*this),
4797
                                                                                     ::std::move(receiver)}))
4798
        -> ::beman::execution::detail::basic_operation<basic_sender, Receiver> {
4799
        return {::std::move(*this), ::std::move(receiver)};
4800
    }
4801
#else
4802
    template <::beman::execution::detail::decays_to<basic_sender> Self, ::beman::execution::receiver Receiver>
4803
    auto
4804
    connect(this Self&& self,
4805
            Receiver receiver) noexcept(noexcept(::beman::execution::detail::basic_operation<basic_sender, Receiver>{
4806
        ::std::forward<Self>(self), ::std::move(receiver)}))
4807
        -> ::beman::execution::detail::basic_operation<Self, Receiver> {
4808
        return {::std::forward<Self>(self), ::std::move(receiver)};
4809
    }
4810
#endif
4811
#if __cpp_explicit_this_parameter < 302110L
4812
    template <typename Env>
4813
    auto
4814
    get_completion_signatures(Env&&) && -> ::beman::execution::detail::completion_signatures_for<basic_sender, Env> {
4815
        return {};
4816
    }
4817
    template <typename Env>
4818
    auto get_completion_signatures(
4819
        Env&&) const&& -> ::beman::execution::detail::completion_signatures_for<const basic_sender, Env> {
4820
        return {};
4821
    }
4822
    template <typename Env>
4823
    auto
4824
    get_completion_signatures(Env&&) & -> ::beman::execution::detail::completion_signatures_for<basic_sender, Env> {
4825
        return {};
4826
    }
4827
    template <typename Env>
4828
    auto get_completion_signatures(
4829
        Env&&) const& -> ::beman::execution::detail::completion_signatures_for<const basic_sender, Env> {
4830
        return {};
4831
    }
4832
#else
4833
    template <::beman::execution::detail::decays_to<basic_sender> Self, typename Env>
4834
    auto get_completion_signatures(this Self&&, Env&&) noexcept
4835
        -> ::beman::execution::detail::completion_signatures_for<Self, Env> {
4836
        return {};
4837
    }
4838
#endif
4839
};
4840
} // namespace beman::execution::detail
4841

4842
// ----------------------------------------------------------------------------
4843

4844
// ----------------------------------------------------------------------------
4845

4846
namespace beman::execution::detail {
4847
template <typename Sender, typename Env>
4848
concept single_sender = ::beman::execution::sender_in<Sender, Env> &&
4849
                        requires { typename ::beman::execution::detail::single_sender_value_type<Sender, Env>; };
4850
} // namespace beman::execution::detail
4851

4852
// ----------------------------------------------------------------------------
4853

4854
// ----------------------------------------------------------------------------
4855

4856
namespace beman::execution::detail {
4857
struct make_sender_empty {};
4858

4859
template <typename Tag, typename Data = ::beman::execution::detail::make_sender_empty, typename... Child>
4860
    requires ::std::semiregular<Tag> && ::beman::execution::detail::movable_value<Data> &&
4861
             (::beman::execution::sender<Child> && ...)
4862
constexpr auto make_sender(Tag tag, Data&& data, Child&&... child) {
1✔
4863
    return ::beman::execution::detail::basic_sender<Tag, ::std::decay_t<Data>, ::std::decay_t<Child>...>{
4864
        tag, ::std::forward<Data>(data), ::std::forward<Child>(child)...};
1✔
4865
}
4866
} // namespace beman::execution::detail
4867

4868
// ----------------------------------------------------------------------------
4869

4870
namespace beman::execution::detail {
4871
template <class Sndr, class Promise>
4872
concept awaitable_sender =
4873
    ::beman::execution::detail::single_sender<Sndr, ::beman::execution::env_of_t<Promise>> && requires(Promise& prom) {
4874
        { prom.unhandled_stopped() } -> ::std::convertible_to<::std::coroutine_handle<>>;
4875
    };
4876
} // namespace beman::execution::detail
4877

4878
namespace beman::execution::detail {
4879
template <class Sndr, class Promise>
4880
class sender_awaitable {
4881
    struct unit {};
4882
    using value_type =
4883
        ::beman::execution::detail::single_sender_value_type<Sndr, ::beman::execution::env_of_t<Promise>>;
4884
    using result_type  = ::std::conditional_t<::std::is_void_v<value_type>, unit, value_type>;
4885
    using variant_type = ::std::variant<::std::monostate, result_type, ::std::exception_ptr>;
4886
    using data_type    = ::std::tuple<variant_type, ::std::atomic<bool>, ::std::coroutine_handle<Promise>>;
4887

4888
    struct awaitable_receiver {
4889
        using receiver_concept = ::beman::execution::receiver_t;
4890

4891
        void resume() {
4892
            if (::std::get<1>(*result_ptr_).exchange(true, std::memory_order_acq_rel)) {
4893
                ::std::get<2>(*result_ptr_).resume();
4894
            }
4895
        }
4896

4897
        template <class... Args>
4898
            requires ::std::constructible_from<result_type, Args...>
4899
        void set_value(Args&&... args) && noexcept {
4900
            try {
4901
                ::std::get<0>(*result_ptr_).template emplace<1>(::std::forward<Args>(args)...);
4902
            } catch (...) {
4903
                ::std::get<0>(*result_ptr_).template emplace<2>(::std::current_exception());
4904
            }
4905
            this->resume();
4906
        }
4907
        template <class Error>
4908
        void set_error(Error&& error) && noexcept {
4909
            ::std::get<0>(*result_ptr_)
4910
                .template emplace<2>(::beman::execution::detail::as_except_ptr(::std::forward<Error>(error)));
4911
            this->resume();
4912
        }
4913

4914
        void set_stopped() && noexcept {
4915
            if (::std::get<1>(*result_ptr_).exchange(true, ::std::memory_order_acq_rel)) {
4916
                static_cast<::std::coroutine_handle<>>(::std::get<2>(*result_ptr_).promise().unhandled_stopped())
4917
                    .resume();
4918
            }
4919
        }
4920

4921
        auto get_env() const noexcept {
4922
            return ::beman::execution::detail::fwd_env{
4923
                ::beman::execution::get_env(::std::get<2>(*result_ptr_).promise())};
4924
        }
4925

4926
        data_type* result_ptr_;
4927
    };
4928
    using op_state_type = ::beman::execution::connect_result_t<Sndr, awaitable_receiver>;
4929

4930
    data_type     result{};
4931
    op_state_type state;
4932

4933
  public:
4934
    sender_awaitable(Sndr&& sndr, Promise& p)
4935
        : result{::std::monostate{}, false, ::std::coroutine_handle<Promise>::from_promise(p)},
4936
          state{::beman::execution::connect(::std::forward<Sndr>(sndr),
4937
                                            sender_awaitable::awaitable_receiver{::std::addressof(result)})} {}
4938

4939
    static constexpr bool     await_ready() noexcept { return false; }
4940
    ::std::coroutine_handle<> await_suspend(::std::coroutine_handle<Promise> handle) noexcept {
4941
        ::beman::execution::start(state);
4942
        if (::std::get<1>(this->result).exchange(true, std::memory_order_acq_rel)) {
4943
            if (::std::holds_alternative<::std::monostate>(::std::get<0>(this->result))) {
4944
                return ::std::get<2>(this->result).promise().unhandled_stopped();
4945
            }
4946
            return ::std::move(handle);
4947
        }
4948
        return ::std::noop_coroutine();
4949
    }
4950
    value_type await_resume() {
4951
        if (::std::holds_alternative<::std::exception_ptr>(::std::get<0>(result))) {
4952
            ::std::rethrow_exception(::std::get<::std::exception_ptr>(::std::get<0>(result)));
4953
        }
4954
        if constexpr (::std::is_void_v<value_type>) {
4955
            return;
4956
        } else {
4957
            return ::std::get<value_type>(std::move(::std::get<0>(result)));
4958
        }
4959
    }
4960
};
4961
} // namespace beman::execution::detail
4962

4963
namespace beman::execution::detail {
4964

4965
struct bulk_t : ::beman::execution::sender_adaptor_closure<bulk_t> {
4966

4967
    template <class Shape, class f>
4968
        requires(std::is_integral_v<Shape> && ::beman::execution::detail::movable_value<f>)
4969
    auto operator()(Shape&& shape, f&& fun) const {
4970
        return beman::execution::detail::sender_adaptor{*this, std::forward<Shape>(shape), std::forward<f>(fun)};
4971
    }
4972

4973
    template <class Sender, class Shape, class f>
4974
        requires(::beman::execution::sender<Sender> && std::is_integral_v<Shape> &&
4975
                 ::beman::execution::detail::movable_value<f>)
4976
    auto operator()(Sender&& sndr, Shape&& shape, f&& fun) const {
4977

4978
        auto domain{::beman::execution::detail::get_domain_early(sndr)};
4979

4980
        return ::beman::execution::transform_sender(
4981
            domain,
4982
            ::beman::execution::detail::make_sender(
4983
                *this, ::beman::execution::detail::product_type<Shape, f>{shape, fun}, std::forward<Sender>(sndr)));
4984
    }
4985
};
4986

4987
template <>
4988
struct impls_for<bulk_t> : ::beman::execution::detail::default_impls {
4989

4990
    static constexpr auto complete = []<class Index, class Shape, class Fun, class Rcvr, class Tag, class... Args>(
4991
                                         Index,
4992
                                         ::beman::execution::detail::product_type<Shape, Fun>& state,
4993
                                         Rcvr&                                                 rcvr,
4994
                                         Tag,
4995
                                         Args&&... args) noexcept -> void
4996
        requires(!::std::same_as<Tag, set_value_t> || std::is_invocable_v<Fun, Shape, Args...>)
4997
    {
4998
        if constexpr (std::same_as<Tag, set_value_t>) {
4999
            auto& [shape, f] = state;
5000

5001
            using s_type = std::remove_cvref_t<decltype(shape)>;
5002

5003
            constexpr bool nothrow = noexcept(f(s_type(shape), args...));
5004

5005
            try {
5006
                [&]() noexcept(nothrow) {
5007
                    for (decltype(s_type(shape)) i = 0; i < shape; i++) {
5008
                        f(s_type(i), args...);
5009
                    }
5010
                    Tag()(std::move(rcvr), std::forward<Args>(args)...);
5011
                }();
5012

5013
            } catch (...) {
5014
                if constexpr (not nothrow) {
5015
                    ::beman::execution::set_error(std::move(rcvr), std::current_exception());
5016
                }
5017
            }
5018
        } else {
5019
            Tag()(std::move(rcvr), std::forward<Args>(args)...);
5020
        }
5021
    };
5022
};
5023

5024
template <typename, typename, typename>
5025
struct fixed_completions_helper;
5026

5027
template <typename F, typename Shape, typename... Args>
5028
struct fixed_completions_helper<F, Shape, completion_signatures<Args...>> {
5029

5030
    template <typename, typename>
5031
    struct may_throw;
5032
    template <typename XF, typename Tag, typename... XArgs>
5033
    struct may_throw<XF, Tag(XArgs...)> {
5034
        static constexpr bool value =
5035
            std::same_as<Tag, ::beman::execution::set_value_t> && !::std::is_nothrow_invocable<XF, Shape, XArgs...>();
5036
    };
5037
    template <typename XF, typename... Sigs>
5038
    struct may_throw<XF, completion_signatures<Sigs...>> {
5039
        static constexpr bool value = (false || ... || may_throw<XF, Sigs>::value);
5040
    };
5041

5042
    using type = std::conditional_t<!may_throw<F, Args...>::value,
5043
                                    completion_signatures<Args...>,
5044
                                    completion_signatures<Args..., set_error_t(std::exception_ptr)>>;
5045
};
5046

5047
template <typename F, typename Shape, typename Completions>
5048
using fixed_completions = typename fixed_completions_helper<F, Shape, Completions>::type;
5049

5050
template <class Shape, class F, class Sender, class Env>
5051
struct completion_signatures_for_impl<
5052
    ::beman::execution::detail::
5053
        basic_sender<::beman::execution::detail::bulk_t, ::beman::execution::detail::product_type<Shape, F>, Sender>,
5054
    Env> {
5055

5056
    using completions = decltype(get_completion_signatures(std::declval<Sender>(), std::declval<Env>()));
5057
    using type        = ::beman::execution::detail::meta::unique<
5058
               ::beman::execution::detail::meta::combine<fixed_completions<F, Shape, completions>>>;
5059
};
5060

5061
} // namespace beman::execution::detail
5062

5063
namespace beman::execution {
5064

5065
export using bulk_t = ::beman::execution::detail::bulk_t;
5066
export inline constexpr ::beman::execution::bulk_t bulk{};
5067

5068
} // namespace beman::execution
5069

5070
// ----------------------------------------------------------------------------
5071

5072
namespace beman::execution::detail {
5073
export struct into_variant_t {
5074
    template <::beman::execution::sender Sender>
5075
    auto operator()(Sender&& sender) const {
5076
        auto domain{::beman::execution::detail::get_domain_early(sender)};
5077
        (void)domain;
5078
        return ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender));
5079
        // return ::beman::execution::transform_sender(
5080
        //     ::std::move(domain),
5081
        //     ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender))
5082
        //);
5083
    }
5084
};
5085

5086
template <>
5087
struct impls_for<::beman::execution::detail::into_variant_t> : ::beman::execution::detail::default_impls {
5088
    static constexpr auto get_state = []<typename Sender, typename Receiver>(Sender&&, Receiver&&) noexcept
5089
        -> ::std::type_identity<::beman::execution::value_types_of_t<::beman::execution::detail::child_type<Sender>,
5090
                                                                     ::beman::execution::env_of_t<Receiver>>> {
5091
        return {};
5092
    };
5093
    static constexpr auto complete = []<typename State, typename Tag, typename... Args>(
5094
                                         auto, State, auto& receiver, Tag, Args&&... args) noexcept -> void {
5095
        if constexpr (::std::same_as<Tag, ::beman::execution::set_value_t>) {
5096
            using variant_type = typename State::type;
5097
            using tuple_type   = ::beman::execution::detail::decayed_tuple<Args...>;
5098
            try {
5099
                if constexpr (sizeof...(Args) == 0u)
5100
                    ::beman::execution::set_value(::std::move(receiver));
5101
                else
5102
                    ::beman::execution::set_value(::std::move(receiver),
5103
                                                  variant_type(tuple_type{::std::forward<Args>(args)...}));
5104
            } catch (...) {
5105
                ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5106
            }
5107

5108
        } else {
5109
            Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
5110
        }
5111
    };
5112
};
5113

5114
template <typename Sender, typename State, typename Env>
5115
struct completion_signatures_for_impl<
5116
    ::beman::execution::detail::basic_sender<::beman::execution::detail::into_variant_t, State, Sender>,
5117
    Env> {
5118
    using variant_type = ::beman::execution::value_types_of_t<Sender, Env>;
5119
    using value_types =
5120
        ::std::conditional_t<::std::same_as<variant_type, ::beman::execution::detail::empty_variant>,
5121
                             ::beman::execution::completion_signatures<>,
5122
                             ::beman::execution::completion_signatures<::beman::execution::set_value_t(variant_type)>>;
5123
    template <typename... E>
5124
    using make_error_types = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
5125

5126
    using error_types = ::beman::execution::error_types_of_t<Sender, Env, make_error_types>;
5127
    using stopped_types =
5128
        ::std::conditional_t<::beman::execution::sends_stopped<Sender, Env>,
5129
                             ::beman::execution::completion_signatures<::beman::execution::set_stopped_t()>,
5130
                             ::beman::execution::completion_signatures<>>;
5131
    using type = ::beman::execution::detail::meta::
5132
        combine<value_types, ::beman::execution::detail::meta::combine<error_types, stopped_types>>;
5133
};
5134
} // namespace beman::execution::detail
5135

5136
namespace beman::execution {
5137
export using into_variant_t = ::beman::execution::detail::into_variant_t;
5138
export inline constexpr into_variant_t into_variant{};
5139
} // namespace beman::execution
5140

5141
// ----------------------------------------------------------------------------
5142

5143
// ----------------------------------------------------------------------------
5144

5145
namespace beman::execution::detail {
5146
template <typename Completion, typename... T>
5147
concept just_size = (!::std::same_as<Completion, ::beman::execution::set_error_t> or 1u == sizeof...(T)) &&
5148
                    (!::std::same_as<Completion, ::beman::execution::set_stopped_t> or 0u == sizeof...(T));
5149
template <typename Completion>
5150
struct just_t {
5151
    template <typename... T>
5152
        requires ::beman::execution::detail::just_size<Completion, T...> &&
5153
                 (::beman::execution::detail::movable_value<T> && ...)
5154
    auto operator()(T&&... arg) const {
5155
        return ::beman::execution::detail::make_sender(
5156
            *this, ::beman::execution::detail::product_type{::std::forward<T>(arg)...});
5157
    }
5158
    template <::beman::execution::sender Sender>
5159
    static auto affine_on(Sender&& sndr, const auto&) noexcept {
5160
        return ::std::forward<Sender>(sndr);
5161
    }
5162
};
5163

5164
template <typename Completion, typename... T, typename Env>
5165
struct completion_signatures_for_impl<
5166
    ::beman::execution::detail::basic_sender<just_t<Completion>, ::beman::execution::detail::product_type<T...>>,
5167
    Env> {
5168
    using type = ::beman::execution::completion_signatures<Completion(T...)>;
5169
};
5170

5171
template <typename Completion>
5172
struct impls_for<just_t<Completion>> : ::beman::execution::detail::default_impls {
5173
    static constexpr auto start = []<typename State>(State& state, auto& receiver) noexcept -> void {
5174
        [&state, &receiver]<::std::size_t... I>(::std::index_sequence<I...>) {
5175
            Completion()(::std::move(receiver), ::std::move(state.template get<I>())...);
5176
        }(::std::make_index_sequence<State::size()>{});
5177
    };
5178
};
5179
} // namespace beman::execution::detail
5180

5181
namespace beman::execution {
5182
export using just_t         = ::beman::execution::detail::just_t<::beman::execution::set_value_t>;
5183
export using just_error_t   = ::beman::execution::detail::just_t<::beman::execution::set_error_t>;
5184
export using just_stopped_t = ::beman::execution::detail::just_t<::beman::execution::set_stopped_t>;
5185

5186
/*!
5187
 * \brief <code>just(_arg_...)</code> yields a sender completing with <code>set_value_t(_Arg_...)</code>
5188
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
5189
 *
5190
 * \details
5191
 * `just` is a callable object of type `just_t`. Invoking <code>just(_arg_...)</code> yields a sender which stores its
5192
 * arguments and produces a value completion with these arguments when started. This sender completes synchronously
5193
 * when started.
5194
 *
5195
 * <h4>Usage</h4>
5196
 * <pre>
5197
 * just(<i>arg</i>...)
5198
 * </pre>
5199
 *
5200
 * Above <code>_Arg_...</code> is a pack of the types of <code>_arg_...</code>
5201
 * after removing top-level `const` and reference qualifications
5202
 * (<code>std::remove_cvref_t&lt;decltype(_arg_)&gt;...</code>).
5203
 *
5204
 * <h4>Completions Signatures</h4>
5205
 * <pre>
5206
 * completion_signatures<
5207
 *     set_value_t(<i>Arg</i>...)
5208
 * >;
5209
 * </pre>
5210
 *
5211
 * <h4>Example</h4>
5212
 *
5213
 * The normal use of <code>just(_args_...)</code> is as the starting
5214
 * point of a work graph. Various other examples will use `just` as
5215
 * their starting. The example below create a sender yielding three
5216
 * values and awaits the completion using <code>sync_wait(_sender_)</code>:
5217
 * for a value completion of <code>_sender_</code> it will yield an
5218
 * <code>std::optional&lt;std::tuple&lt;_Args_...&gt;&gt;</code> with the
5219
 * `tuple` containing the value copied/moved from the original arguments
5220
 * (an `optional` is returned to indicate cancellation).
5221
 *
5222
 * <pre example="doc-just.cpp">
5223
 * #include <beman/execution/execution.hpp>
5224
 * #include <cassert>
5225
 * #include <string>
5226
 * using namespace std::string_literals;
5227
 *
5228
 * int main() {
5229
 *     auto result = ex::sync_wait(ex::just(17, "hello"s, true));
5230
 *     assert(result);
5231
 *     assert(*result == std::tuple(17, "hello"s, true));
5232
 * }
5233
 * </pre>
5234
 */
5235
export inline constexpr ::beman::execution::just_t just{};
5236

5237
/*!
5238
 * \brief <code>just_error(_error_)</code> yields a sender completing with <code>set_error_t(_Error_)</code>
5239
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
5240
 *
5241
 * \details
5242
 * `just_error` is a callable object of type `just_error_t`. Invoking <code>just_error(_error_)</code> yields a sender
5243
 * which stores its argument and produces an error completion with this error when started. This sender completes
5244
 * synchronously when started.
5245
 *
5246
 * <h4>Usage</h4>
5247
 * <pre>
5248
 * just_error(<i>error</i>)
5249
 * </pre>
5250
 *
5251
 * The type <code>_Error_</code> used above is the type of <code>_error_</code>
5252
 * after removing top-level `const` and reference qualifications
5253
 * (<code>std::remove_cvref_t&lt;decltype(error)&gt;</code>).
5254
 *
5255
 * <h4>Completions Signatures</h4>
5256
 * <pre>
5257
 * completion_signatures<
5258
 *     set_error_t(<i>Error</i>)
5259
 * >;
5260
 * </pre>
5261
 *
5262
 * <h4>Example</h4>
5263
 *
5264
 * The normal use of <code>just_error(_error_)</code> is to report an
5265
 * error as the result of some work in a work graph. It would, e.g., be
5266
 * used as the completion produced by `let_value`.
5267
 * The example below creates a sender yielding an `std::error_code` on the error
5268
 * channel and
5269
 * uses that as the input for `upon_error` consuming the error and producing
5270
 * a value completion: using <code>sync_wait(just_error(_error_))</code>
5271
 * directly doesn't work because `sync_wait` requires exactly one value completion
5272
 * from its argument and `set_error` only has an error completion. The function used with `upon_error` verifies that
5273
 * the expected code was produced and also sets the flag `had_error` indicating it was called at all. This flag is
5274
 * checked after waiting for the result in `sync_wait`.
5275
 *
5276
 * <pre example="doc-just_error.cpp">
5277
 * #include <beman/execution/execution.hpp>
5278
 * #include <system_error>
5279
 * #include <cassert>
5280
 * namespace ex = beman::execution;
5281
 *
5282
 * int main() {
5283
 *     bool had_error{false};
5284
 *     auto result = ex::sync_wait(ex::just_error(std::error_code(17, std::system_category())) |
5285
 *                                 ex::upon_error([&](std::error_code ec) {
5286
 *                                     assert(ec.value() == 17);
5287
 *                                     had_error = true;
5288
 *                                 }));
5289
 *     assert(had_error);
5290
 * }
5291
 * </pre>
5292
 */
5293
export inline constexpr ::beman::execution::just_error_t just_error{};
5294

5295
/*!
5296
 * \brief <code>just_stopped()</code> yields a sender completing with <code>set_stopped_t()</code>
5297
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
5298
 *
5299
 * \details
5300
 * `just_stopped` is a callable object of type `just_stopped_t`. Invoking <code>just_stopped()</code> yields a sender
5301
 * which produces a cancellation completion when started. This sender completes synchronously when started.
5302
 *
5303
 * <h4>Usage</h4>
5304
 * <pre>
5305
 * just_stopped()
5306
 * </pre>
5307
 *
5308
 * <h4>Completions Signatures</h4>
5309
 * <pre>
5310
 * completion_signatures<
5311
 *     set_stopped_t()
5312
 * >;
5313
 * </pre>
5314
 *
5315
 * <h4>Example</h4>
5316
 *
5317
 * The normal use of <code>just_stopped()</code> is to report a
5318
 * cancellation as the result of some work in a work graph. It would, e.g., be
5319
 * used as the completion produced by `let_value`.
5320
 * The example below creates a sender yielding a completion on the cancellation
5321
 * channel and
5322
 * uses that as the input for `upon_stopped` consuming the cancellation and producing
5323
 * a value completion: using <code>sync_wait(just_stopped())</code>
5324
 * directly doesn't work because `sync_wait` requires exactly one value completion
5325
 * from its argument and `set_stopped` only has a cancellation completion. The function used with `upon_stopped`
5326
 * sets the flag `had_stopped` indicating it
5327
 * was called at all. This flag is checked after waiting for the result
5328
 * in `sync_wait`.
5329
 *
5330
 * <pre example="doc-just_error.cpp">
5331
 * #include <beman/execution/execution.hpp>
5332
 * #include <system_error>
5333
 * #include <cassert>
5334
 * namespace ex = beman::execution;
5335
 *
5336
 * int main() {
5337
 *     bool had_stopped{false};
5338
 *     auto result = ex::sync_wait(ex::just_error(std::error_code(17, std::system_category())) |
5339
 *                                 ex::upon_error([&](std::error_code ec) {
5340
 *                                     assert(ec.value() == 17);
5341
 *                                     had_stopped = true;
5342
 *                                 }));
5343
 *     assert(had_stopped);
5344
 * }
5345
 * </pre>
5346
 */
5347
export inline constexpr ::beman::execution::just_stopped_t just_stopped{};
5348
} // namespace beman::execution
5349

5350
// ----------------------------------------------------------------------------
5351

5352
// ----------------------------------------------------------------------------
5353

5354
namespace beman::execution::detail {
5355
template <typename Completion>
5356
struct let_t {
5357
    template <::beman::execution::detail::movable_value Fun>
5358
    auto operator()(Fun&& fun) const {
5359
        return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Fun>(fun)};
5360
    }
5361
    template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
5362
    auto operator()(Sender&& sender, Fun&& fun) const {
5363
        auto domain(::beman::execution::detail::get_domain_early(sender));
5364
        return ::beman::execution::detail::transform_sender(
5365
            domain,
5366
            ::beman::execution::detail::make_sender(*this, ::std::forward<Fun>(fun), std::forward<Sender>(sender)));
5367
    }
5368

5369
    template <typename Sender>
5370
    static auto env(Sender&& sender) {
5371
        if constexpr (requires {
5372
                          ::beman::execution::detail::sched_env(
5373
                              ::beman::execution::get_completion_scheduler<Completion>(
5374
                                  ::beman::execution::get_env(sender)));
5375
                      })
5376
            return ::beman::execution::detail::sched_env(
5377
                ::beman::execution::get_completion_scheduler<Completion>(::beman::execution::get_env(sender)));
5378
        else if constexpr (requires {
5379
                               ::beman::execution::detail::make_env(
5380
                                   ::beman::execution::get_domain,
5381
                                   ::beman::execution::get_domain(::beman::execution::get_env(sender)));
5382
                           })
5383
            return ::beman::execution::detail::make_env(
5384
                ::beman::execution::get_domain, ::beman::execution::get_domain(::beman::execution::get_env(sender)));
5385
        else
5386
            return ::beman::execution::env<>{};
5387
    }
5388
    template <typename Sender, typename Env>
5389
    static auto join_env(Sender&& sender, Env&& e) -> decltype(auto) {
5390
        return ::beman::execution::detail::join_env(env(sender), ::beman::execution::detail::fwd_env(e));
5391
    }
5392
};
5393

5394
template <typename Completion>
5395
struct impls_for<::beman::execution::detail::let_t<Completion>> : ::beman::execution::detail::default_impls {
5396

5397
    template <typename Receiver, typename Env>
5398
    struct let_receiver {
5399
        using receiver_concept = ::beman::execution::receiver_t;
5400

5401
        Receiver& receiver;
5402
        Env       env;
5403

5404
        auto get_env() const noexcept -> decltype(auto) {
5405
            return ::beman::execution::detail::join_env(
5406
                this->env, ::beman::execution::detail::fwd_env(::beman::execution::get_env(this->receiver)));
5407
        }
5408
        template <typename Error>
5409
        auto set_error(Error&& error) && noexcept -> void {
5410
            ::beman::execution::set_error(::std::move(this->receiver), ::std::forward<Error>(error));
5411
        }
5412
        auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(::std::move(this->receiver)); }
5413
        template <typename... Args>
5414
        auto set_value(Args&&... args) && noexcept -> void {
5415
            ::beman::execution::set_value(::std::move(this->receiver), ::std::forward<Args>(args)...);
5416
        }
5417
    };
5418

5419
    template <typename>
5420
    struct filter_pred : ::std::false_type {};
5421
    template <typename... A>
5422
    struct filter_pred<Completion(A...)> : ::std::true_type {};
5423
    template <typename>
5424
    struct to_tuple;
5425
    template <typename C, typename... A>
5426
    struct to_tuple<C(A...)> {
5427
        using type = ::beman::execution::detail::decayed_tuple<A...>;
5428
    };
5429
    template <typename T>
5430
    using to_tuple_t = typename to_tuple<T>::type;
5431
    template <typename Fun, typename Receiver, typename Env>
5432
    struct to_state {
5433
        template <typename Tuple>
5434
        using trans =
5435
            decltype(::beman::execution::connect(::std::apply(::std::declval<Fun>(), ::std::declval<Tuple>()),
5436
                                                 ::std::declval<let_receiver<Receiver, Env>>()));
5437
    };
5438

5439
    static constexpr auto get_state{[]<typename Sender, typename Receiver>(Sender&& sender, Receiver&& receiver) {
5440
        auto& fun{sender.template get<1>()};
5441
        auto& child{sender.template get<2>()};
5442

5443
        using fun_t   = ::std::remove_cvref_t<decltype(fun)>;
5444
        using child_t = ::std::remove_cvref_t<decltype(child)>;
5445
        using env_t   = decltype(::beman::execution::detail::let_t<Completion>::env(child));
5446
        using sigs_t = ::beman::execution::completion_signatures_of_t<child_t, ::beman::execution::env_of_t<Receiver>>;
5447
        using comp_sigs_t = ::beman::execution::detail::meta::filter<filter_pred, sigs_t>;
5448
        using type_list_t = ::beman::execution::detail::meta::to<::std::variant, comp_sigs_t>;
5449
        using tuples_t    = ::beman::execution::detail::meta::transform<to_tuple_t, type_list_t>;
5450
        using unique_t    = ::beman::execution::detail::meta::unique<tuples_t>;
5451
        using args_t      = ::beman::execution::detail::meta::prepend<std::monostate, unique_t>;
5452
        using ops_t       = ::beman::execution::detail::meta::prepend<
5453
                  ::std::monostate,
5454
                  ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::transform<
5455
                      to_state<fun_t, ::std::remove_cvref_t<Receiver>, env_t>::template trans,
5456
                      tuples_t>>>;
5457

5458
        struct state_t {
5459
            fun_t  fun;
5460
            env_t  env;
5461
            args_t args;
5462
            ops_t  ops2;
5463
        };
5464
        return state_t{beman::execution::detail::allocator_aware_move(
5465
                           ::beman::execution::detail::forward_like<Sender>(fun), receiver),
5466
                       ::beman::execution::detail::let_t<Completion>::env(child),
5467
                       {},
5468
                       {}};
5469
    }};
5470
    template <typename Receiver, typename... Args>
5471
    static auto
5472
    let_bind(auto& state, Receiver& receiver, Args&&... args) noexcept(noexcept(::beman::execution::connect(
5473
        ::std::apply(::std::move(state.fun),
5474
                     ::std::move(state.args.template emplace<::beman::execution::detail::decayed_tuple<Args...>>(
5475
                         ::std::forward<Args>(args)...))),
5476
        let_receiver<Receiver, decltype(state.env)>{receiver, state.env}))) {
5477
        using args_t = ::beman::execution::detail::decayed_tuple<Args...>;
5478
        auto mkop{[&] {
5479
            return ::beman::execution::connect(
5480
                ::std::apply(::std::move(state.fun),
5481
                             ::std::move(state.args.template emplace<args_t>(::std::forward<Args>(args)...))),
5482
                let_receiver<Receiver, decltype(state.env)>{receiver, state.env});
5483
        }};
5484
        ::beman::execution::start(
5485
            state.ops2.template emplace<decltype(mkop())>(beman::execution::detail::emplace_from{mkop}));
5486
    }
5487
    static constexpr auto complete{
5488
        []<class Tag, class... Args>(auto, auto& state, auto& receiver, Tag, Args&&... args) {
5489
            if constexpr (::std::same_as<Tag, Completion>) {
5490
                try {
5491
                    let_bind(state, receiver, ::std::forward<Args>(args)...);
5492
                } catch (...) {
5493
                    if constexpr (not noexcept(let_bind(state, receiver, ::std::forward<Args>(args)...)))
5494
                        ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5495
                }
5496
            } else {
5497
                Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
5498
            }
5499
        }};
5500
};
5501

5502
template <typename Completion, typename Fun, typename Sender, typename Env>
5503
struct completion_signatures_for_impl<
5504
    ::beman::execution::detail::basic_sender<::beman::execution::detail::let_t<Completion>, Fun, Sender>,
5505
    Env> {
5506
    template <typename>
5507
    struct other_completion : ::std::true_type {};
5508
    template <typename... A>
5509
    struct other_completion<Completion(A...)> : ::std::false_type {};
5510
    template <typename>
5511
    struct matching_completion : ::std::false_type {};
5512
    template <typename... A>
5513
    struct matching_completion<Completion(A...)> : ::std::true_type {};
5514

5515
    template <typename>
5516
    struct apply_decayed;
5517
    template <typename C, typename... A>
5518
    struct apply_decayed<C(A...)> {
5519
        using sender_type = ::beman::execution::detail::call_result_t<Fun, ::std::decay_t<A>...>;
5520
    };
5521
    template <typename>
5522
    struct get_completions;
5523
    template <template <typename...> class L, typename... C>
5524
    struct get_completions<L<C...>> {
5525
        using type = ::beman::execution::detail::meta::unique<
5526
            ::beman::execution::detail::meta::combine<decltype(::beman::execution::get_completion_signatures(
5527
                std::declval<typename apply_decayed<C>::sender_type>(), std::declval<Env>()))...>>;
5528
    };
5529

5530
    using upstream_env = decltype(::beman::execution::detail::let_t<Completion>::join_env(::std::declval<Sender>(),
5531
                                                                                          ::std::declval<Env>()));
5532
    using upstream_completions = decltype(::beman::execution::get_completion_signatures(
5533
        ::std::declval<Sender>(), ::std::declval<upstream_env>()));
5534
    using other_completions    = ::beman::execution::detail::meta::filter<other_completion, upstream_completions>;
5535
    using matching_completions = ::beman::execution::detail::meta::filter<matching_completion, upstream_completions>;
5536
    using type = ::beman::execution::detail::meta::combine<typename get_completions<matching_completions>::type,
5537
                                                           other_completions>;
5538
};
5539
} // namespace beman::execution::detail
5540

5541
namespace beman::execution {
5542
export using let_error_t   = ::beman::execution::detail::let_t<::beman::execution::set_error_t>;
5543
export using let_stopped_t = ::beman::execution::detail::let_t<::beman::execution::set_stopped_t>;
5544
export using let_value_t   = ::beman::execution::detail::let_t<::beman::execution::set_value_t>;
5545

5546
export inline constexpr ::beman::execution::let_error_t   let_error{};
5547
export inline constexpr ::beman::execution::let_stopped_t let_stopped{};
5548
export inline constexpr ::beman::execution::let_value_t   let_value{};
5549
} // namespace beman::execution
5550

5551
// ----------------------------------------------------------------------------
5552

5553
// ----------------------------------------------------------------------------
5554

5555
namespace beman::execution::detail {
5556
struct read_env_t {
5557
    auto operator()(auto&& query) const { return ::beman::execution::detail::make_sender(*this, query); }
5558
    template <::beman::execution::sender Sender>
5559
    static auto affine_on(Sender&& sndr, const auto&) noexcept {
5560
        return ::std::forward<Sender>(sndr);
5561
    }
5562
};
5563

5564
template <>
5565
struct impls_for<::beman::execution::detail::read_env_t> : ::beman::execution::detail::default_impls {
5566
    static constexpr auto start = [](auto query, auto& receiver) noexcept -> void {
5567
        try {
5568
            auto env{::beman::execution::get_env(receiver)};
5569
            ::beman::execution::set_value(::std::move(receiver), query(env));
5570
        } catch (...) {
5571
            ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5572
        }
5573
    };
5574
};
5575

5576
template <typename Query, typename Env>
5577
struct completion_signatures_for_impl<
5578
    ::beman::execution::detail::basic_sender<::beman::execution::detail::read_env_t, Query>,
5579
    Env> {
5580
    using set_value_type =
5581
        ::beman::execution::set_value_t(decltype(::std::declval<Query>()(::std::as_const(::std::declval<Env>()))));
5582
    using set_error_type = ::beman::execution::set_error_t(::std::exception_ptr);
5583
    using type           = ::std::conditional_t<noexcept(::std::declval<Query>()(::std::declval<const Env&>())),
5584
                                                ::beman::execution::completion_signatures<set_value_type>,
5585
                                                ::beman::execution::completion_signatures<set_value_type, set_error_type>>;
5586
};
5587
} // namespace beman::execution::detail
5588

5589
namespace beman::execution {
5590
export using read_env_t = beman::execution::detail::read_env_t;
5591
export inline constexpr read_env_t read_env{};
5592
} // namespace beman::execution
5593

5594
// ----------------------------------------------------------------------------
5595

5596
// ----------------------------------------------------------------------------
5597

5598
namespace beman::execution::detail {
5599
struct schedule_from_t {
5600
    template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender>
5601
    auto operator()(Scheduler&& scheduler, Sender&& sender) const {
5602
        auto domain{::beman::execution::detail::query_with_default(
5603
            ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})};
5604
        return ::beman::execution::transform_sender(
5605
            domain,
5606
            ::beman::execution::detail::make_sender(
5607
                *this, ::std::forward<Scheduler>(scheduler), ::std::forward<Sender>(sender)));
5608
    }
5609
};
5610

5611
template <>
5612
struct impls_for<::beman::execution::detail::schedule_from_t> : ::beman::execution::detail::default_impls {
5613
    template <typename State>
5614
    struct upstream_receiver {
5615
        using receiver_concept = ::beman::execution::receiver_t;
5616
        State* state;
5617

5618
        auto set_value() && noexcept -> void {
5619
            try {
5620
                ::std::visit(
5621
                    [this]<typename Tuple>(Tuple& result) noexcept -> void {
5622
                        if constexpr (!::std::same_as<::std::monostate, Tuple>) {
5623
                            ::std::apply(
5624
                                [this](auto&& tag, auto&&... args) {
5625
                                    tag(::std::move(this->state->receiver), ::std::move(args)...);
5626
                                },
5627
                                result);
5628
                        }
5629
                    },
5630
                    state->async_result);
5631
            } catch (...) {
5632
                ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception());
5633
            }
5634
        }
5635

5636
        template <typename Error>
5637
        auto set_error(Error&& err) && noexcept -> void {
5638
            ::beman::execution::set_error(std::move(state->receiver), std::forward<Error>(err));
5639
        }
5640

5641
        auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(std::move(state->receiver)); }
5642

5643
        auto get_env() const noexcept -> decltype(auto) {
5644
            return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver));
5645
        }
5646
    };
5647
    template <typename Receiver, typename Variant>
5648
    struct state_base {
5649
        Receiver receiver;
5650
        Variant  async_result{};
5651
    };
5652
    template <typename Receiver, typename Scheduler, typename Variant>
5653
    struct state_type : state_base<Receiver, Variant> {
5654
        using receiver_t = upstream_receiver<state_base<Receiver, Variant>>;
5655
        using operation_t =
5656
            ::beman::execution::connect_result_t<::beman::execution::schedule_result_t<Scheduler>, receiver_t>;
5657
        operation_t op_state;
5658

5659
        static constexpr bool nothrow() {
5660
            return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval<Scheduler>()),
5661
                                                        receiver_t{nullptr}));
5662
        }
5663
        explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow())
5664
            : state_base<Receiver, Variant>{rcvr},
5665
              op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {}
5666
    };
5667

5668
    static constexpr auto get_attrs{[](const auto& data, const auto& child) noexcept -> decltype(auto) {
5669
        return ::beman::execution::detail::join_env(
5670
            ::beman::execution::detail::sched_attrs(data),
5671
            ::beman::execution::detail::fwd_env(::beman::execution::get_env(child)));
5672
    }};
5673
    static constexpr auto get_state{
5674
        []<typename Sender, typename Receiver>(Sender&& sender, Receiver& receiver) //-dk:TODO noexcept(see below)
5675
            requires ::beman::execution::sender_in<::beman::execution::detail::child_type<Sender>,
5676
                                                   ::beman::execution::env_of_t<Receiver>>
5677
        {
5678
            auto sch{sender.template get<1>()};
5679

5680
            using sched_t   = ::std::remove_cvref_t<decltype(sch)>;
5681
            using variant_t = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
5682
                ::std::monostate,
5683
                ::beman::execution::detail::meta::transform<
5684
                    ::beman::execution::detail::as_tuple_t,
5685
                    ::beman::execution::detail::meta::to<::std::variant,
5686
                                                         ::beman::execution::detail::meta::combine<
5687
                                                             ::beman::execution::completion_signatures_of_t<
5688
                                                                 ::beman::execution::detail::child_type<Sender>,
5689
                                                                 ::beman::execution::env_of_t<Receiver>>,
5690
                                                             //-dk:TODO get proper error completion signatures
5691
                                                             ::beman::execution::completion_signatures<
5692
                                                                 ::beman::execution::set_error_t(::std::exception_ptr),
5693
                                                                 ::beman::execution::set_stopped_t()>>>>>>;
5694

5695
            return state_type<Receiver, sched_t, variant_t>(sch, receiver);
5696
        }};
5697
    static constexpr auto complete{
5698
        []<typename Tag, typename... Args>(auto, auto& state, auto& receiver, Tag, Args&&... args) noexcept -> void {
5699
            using result_t         = ::beman::execution::detail::decayed_tuple<Tag, Args...>;
5700
            constexpr bool nothrow = ::std::is_nothrow_constructible_v<result_t, Tag, Args...>;
5701

5702
            try {
5703
                [&]() noexcept(nothrow) {
5704
                    state.async_result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
5705
                }();
5706
            } catch (...) {
5707
                if constexpr (not nothrow)
5708
                    ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5709
            }
5710

5711
            if (state.async_result.index() == 0)
5712
                return;
5713

5714
            ::beman::execution::start(state.op_state);
5715
        }};
5716
};
5717

5718
template <typename Scheduler, typename Sender, typename Env>
5719
struct completion_signatures_for_impl<
5720
    ::beman::execution::detail::basic_sender<::beman::execution::detail::schedule_from_t, Scheduler, Sender>,
5721
    Env> {
5722
    using scheduler_sender = decltype(::beman::execution::schedule(::std::declval<Scheduler>()));
5723
    template <typename... E>
5724
    using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
5725
    using type         = ::beman::execution::detail::meta::combine<
5726
                decltype(::beman::execution::get_completion_signatures(::std::declval<Sender>(), ::std::declval<Env>())),
5727
                ::beman::execution::error_types_of_t<scheduler_sender, Env, as_set_error>,
5728
                ::beman::execution::completion_signatures<::beman::execution::set_error_t(
5729
            ::std::exception_ptr)> //-dk:TODO this one should be deduced
5730
                >;
5731
};
5732
} // namespace beman::execution::detail
5733

5734
namespace beman::execution {
5735
export using schedule_from_t = beman::execution::detail::schedule_from_t;
5736
export inline constexpr ::beman::execution::schedule_from_t schedule_from{};
5737
} // namespace beman::execution
5738

5739
// ----------------------------------------------------------------------------
5740

5741
// ----------------------------------------------------------------------------
5742

5743
namespace beman::execution::detail {
5744

5745
struct split_impl_t {};
5746
template <>
5747
struct impls_for<split_impl_t> : ::beman::execution::detail::default_impls {
5748

5749
    template <class Sndr>
5750
    struct shared_state;
5751

5752
    struct split_env {
5753
        ::beman::execution::inplace_stop_source* stop_source;
5754

NEW
5755
        ::beman::execution::inplace_stop_token query(::beman::execution::get_stop_token_t) const noexcept {
×
NEW
5756
            return stop_source->get_token();
×
5757
        }
5758
    };
5759

5760
    struct local_state_base {
5761
        local_state_base* next{nullptr};
5762
        virtual auto      notify() noexcept -> void = 0;
5763

5764
        local_state_base() noexcept                                  = default;
5765
        local_state_base(const local_state_base&)                    = delete;
5766
        local_state_base(local_state_base&&)                         = delete;
5767
        auto operator=(const local_state_base&) -> local_state_base& = delete;
5768
        auto operator=(local_state_base&&) -> local_state_base&      = delete;
5769

5770
      protected:
5771
        ~local_state_base() = default;
5772
    };
5773

5774
    template <class Sndr>
5775
    struct split_receiver {
5776
        using receiver_concept = ::beman::execution::receiver_t;
5777

5778
        explicit split_receiver(shared_state<Sndr>* state) noexcept : sh_state(state) {
5779
            if (sh_state) {
5780
                sh_state->inc_ref();
5781
            }
5782
        }
5783

5784
        ~split_receiver() noexcept {
5785
            if (sh_state) {
5786
                sh_state->dec_ref();
5787
            }
5788
        }
5789

5790
        split_receiver(split_receiver&& other) noexcept : sh_state(::std::exchange(other.sh_state, nullptr)) {}
5791
        split_receiver& operator=(split_receiver&& other) noexcept {
5792
            sh_state = ::std::exchange(other.sh_state, nullptr);
5793
            return *this;
5794
        }
5795

5796
        split_receiver(const split_receiver&)            = delete;
5797
        split_receiver& operator=(const split_receiver&) = delete;
5798

5799
        template <class Tag, class... Args>
5800
        void complete(Tag, Args&&... args) noexcept {
5801
            using tuple_t = ::beman::execution::detail::decayed_tuple<Tag, Args...>;
5802
            try {
5803
                sh_state->result.template emplace<tuple_t>(Tag(), ::std::forward<Args>(args)...);
5804
            } catch (...) {
5805
                using tuple_err = ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>;
5806
                sh_state->result.template emplace<tuple_err>(::beman::execution::set_error,
5807
                                                             ::std::current_exception());
5808
            }
5809
            sh_state->notify();
5810
        }
5811

5812
        template <class... Args>
5813
        void set_value(Args&&... args) && noexcept {
5814
            complete(::beman::execution::set_value, ::std::forward<Args>(args)...);
5815
        }
5816

5817
        template <class Error>
5818
        void set_error(Error&& err) && noexcept {
5819
            complete(::beman::execution::set_error, ::std::forward<Error>(err));
5820
        }
5821

5822
        void set_stopped() && noexcept { complete(::beman::execution::set_stopped); }
5823

5824
        split_env get_env() const noexcept { return split_env{&sh_state->stop_src}; }
5825

5826
        shared_state<Sndr>* sh_state;
5827
    };
5828

5829
    // [exec.split-10]
5830
    template <class Sndr>
5831
    struct shared_state {
5832
        template <class... Args>
5833
        using value_tuple = ::std::tuple<::beman::execution::set_value_t, ::std::decay_t<Args>...>;
5834

5835
        template <class... Args>
5836
        using error_tuples = ::std::variant<::std::tuple<::beman::execution::set_error_t, ::std::decay_t<Args>>...>;
5837

5838
        using variant_type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
5839
            ::std::variant<::std::monostate>,
5840
            ::std::variant<::std::tuple<::beman::execution::set_stopped_t>>,
5841
            ::std::variant<::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>>,
5842
            ::beman::execution::error_types_of_t<Sndr, split_env, error_tuples>,
5843
            ::beman::execution::value_types_of_t<Sndr, split_env, value_tuple>>>;
5844

5845
        using state_list_type = ::beman::execution::detail::atomic_intrusive_stack<&local_state_base::next>;
5846

5847
        using child_operation_state = ::beman::execution::connect_result_t<Sndr, split_receiver<Sndr>>;
5848

5849
        explicit shared_state(Sndr&& sndr) {
5850
            try {
5851
                op_state.emplace(::beman::execution::detail::emplace_from{[&] {
5852
                    return ::beman::execution::connect(::std::forward<Sndr>(sndr), split_receiver<Sndr>{this});
5853
                }});
5854
            } catch (...) {
5855
                using error_tuple_t = ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>;
5856
                result.template emplace<error_tuple_t>(::beman::execution::set_error, ::std::current_exception());
5857
                [[maybe_unused]] auto queue = waiting_states.pop_all_and_shutdown();
5858
                assert(queue.empty());
5859
            }
5860
        }
5861

5862
        // We use an intrusive list to store the listeners that are waiting for the operation to complete.
5863
        // if the intrusive list is empty, we start the operation
5864
        // if the intrusive list is not empty, we push the listener to the intrusive list
5865
        // if the intrusive list is shutdown, we immediately notify the listener
5866
        void add_listener(local_state_base* listener) noexcept {
5867
            // try to push the listener to the intrusive list, if the intrusive list is empty and not shutdown, start
5868
            // the operation
5869
            if (auto maybe_ptr = waiting_states.try_push(listener); !maybe_ptr) {
5870
                // the queue is shutdown, immediately notify the listener
5871
                listener->notify();
5872
            } else if (!(*maybe_ptr)) {
5873
                // the operation was not started yet, we are first, and we start it
5874
                assert(op_state);
5875
                if (op_state)
5876
                    ::beman::execution::start(*op_state);
5877
                else
5878
                    std::terminate();
5879
            }
5880
        }
5881

5882
        void notify() noexcept {
5883
            // note: this is different from stdexec.
5884
            // we discussed lifetime durations of operation at LEWG and haven't decided yet
5885
            // whether we should keep the operation alive as long as possible
5886
            op_state.reset();
5887
            auto listeners = waiting_states.pop_all_and_shutdown();
5888
            while (auto listener = listeners.pop()) {
5889
                listener->notify();
5890
            }
5891
        }
5892

5893
        void inc_ref() noexcept { ref_count.fetch_add(1); }
5894

5895
        // This is the most complicated part of the split implementation.
5896
        // On construction, the operation state increments the ref count.
5897
        // Before the operation is started, at least one listener is added to the queue.
5898
        // If the ref count is decreased to one and the there are no listeners in the queue
5899
        // the operation state is the last object holding the shared state and we can safely
5900
        // destroy it
5901
        //
5902
        // it is not thread safe to destroy a split-sender and copy it at the same time
5903
        // this is similar to how a shared_ptr is not thread safe to copy and destroy at the same time
5904
        void dec_ref() noexcept {
5905
            std::size_t count = ref_count.load();
5906
            if (count == 2 && waiting_states.empty_and_not_shutdown()) {
5907
                assert(op_state);
5908
                [[maybe_unused]] auto listeners = waiting_states.pop_all_and_shutdown();
5909
                assert(listeners.empty());
5910
                op_state.reset();
5911
            }
5912
            if (ref_count.fetch_sub(1) == 1) {
5913
                delete this;
5914
            }
5915
        }
5916

5917
        ::beman::execution::inplace_stop_source stop_src{};
5918
        variant_type                            result{};
5919
        state_list_type                         waiting_states{};
5920
        ::std::atomic<::std::size_t>            ref_count{0};
5921
        ::std::optional<child_operation_state>  op_state{};
5922
    };
5923

5924
    template <class Sndr, class Receiver>
5925
    struct local_state final : local_state_base {
5926
        using stop_token_type = ::beman::execution::stop_token_of_t<::beman::execution::env_of_t<Receiver>>;
5927

5928
        struct on_stop_type {
5929
            shared_state<Sndr>* sh_state;
5930
            void                operator()() noexcept { sh_state->stop_src.request_stop(); }
5931
        };
5932

5933
        using on_stop_callback = ::beman::execution::stop_callback_for_t<stop_token_type, on_stop_type>;
5934

5935
        explicit local_state(shared_state<Sndr>* state, Receiver& rcvr) noexcept
5936
            : sh_state(state), receiver{std::addressof(rcvr)} {
5937
            sh_state->inc_ref();
5938
        }
5939

5940
        ~local_state() noexcept { sh_state->dec_ref(); }
5941

5942
        local_state(const local_state&)            = delete;
5943
        local_state& operator=(const local_state&) = delete;
5944
        local_state(local_state&&)                 = delete;
5945
        local_state& operator=(local_state&&)      = delete;
5946

5947
        auto notify() noexcept -> void override {
5948
            on_stop.reset();
5949
            auto stop_token = ::beman::execution::get_stop_token(::beman::execution::get_env(receiver));
5950
            if (stop_token.stop_requested()) {
5951
                ::beman::execution::set_stopped(std::move(*receiver));
5952
            } else {
5953
                assert(sh_state->result.index() > 0);
5954
                assert(!sh_state->result.valueless_by_exception());
5955
                try {
5956
                    ::std::visit(
5957
                        [&]<class Arg>(const Arg& arg) noexcept -> void {
5958
                            if constexpr (!::std::same_as<::std::decay_t<Arg>, ::std::monostate>) {
5959
                                ::std::apply(
5960
                                    [&](auto tag, const auto&... args) noexcept -> void {
5961
                                        tag(::std::move(*receiver), args...);
5962
                                    },
5963
                                    arg);
5964
                            }
5965
                        },
5966
                        sh_state->result);
5967
                } catch (...) {
5968
                    // required by clang-tidy although it is not necessary here
5969
                    // see valueless_by_exception() check above
5970
                    std::terminate();
5971
                }
5972
            }
5973
        }
5974

5975
        void start() noexcept {
5976
            on_stop.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(*receiver)),
5977
                            on_stop_type{sh_state});
5978
            sh_state->add_listener(this);
5979
        }
5980

5981
        std::optional<on_stop_callback> on_stop;
5982
        shared_state<Sndr>*             sh_state;
5983
        Receiver*                       receiver;
5984
    };
5985

5986
    static constexpr auto get_state = []<typename Sender, typename Receiver>(Sender&&  sender,
5987
                                                                             Receiver& receiver) noexcept {
5988
        auto&& wrapper = sender.template get<1>();
5989
        return local_state(wrapper.sh_state, receiver);
5990
    };
5991

5992
    static constexpr auto start = []<class Sndr, class Rcvr>(local_state<Sndr, Rcvr>& state, Rcvr&) noexcept {
5993
        state.start();
5994
    };
5995
};
5996

5997
template <class Sndr>
5998
struct shared_wrapper {
5999
    explicit shared_wrapper(impls_for<split_impl_t>::shared_state<Sndr>* state) noexcept : sh_state(state) {
6000
        if (sh_state) {
6001
            sh_state->inc_ref();
6002
        }
6003
    }
6004

6005
    ~shared_wrapper() noexcept {
6006
        if (sh_state) {
6007
            sh_state->dec_ref();
6008
        }
6009
    }
6010

6011
    shared_wrapper(const shared_wrapper& other) noexcept : sh_state(other.sh_state) {
6012
        if (sh_state) {
6013
            sh_state->inc_ref();
6014
        }
6015
    }
6016

6017
    shared_wrapper(shared_wrapper&& other) noexcept : sh_state(::std::exchange(other.sh_state, nullptr)) {}
6018

6019
    shared_wrapper& operator=(const shared_wrapper& other) noexcept {
6020
        // check for self-assignment was required by clang-tidy
6021
        // although it is not necessary here
6022
        if (this == &other) {
6023
            return *this;
6024
        }
6025
        auto tmp = other;
6026
        ::std::swap(sh_state, tmp.sh_state);
6027
        return *this;
6028
    }
6029

6030
    shared_wrapper& operator=(shared_wrapper&& other) noexcept {
6031
        auto tmp = ::std::move(other);
6032
        ::std::swap(sh_state, tmp.sh_state);
6033
        return *this;
6034
    }
6035

6036
    impls_for<split_impl_t>::shared_state<Sndr>* sh_state;
6037
};
6038

6039
struct split_t {
6040
    template <class Sndr>
6041
    auto transform_sender(Sndr&& sndr) const {
6042
        auto&& child       = ::std::forward<Sndr>(sndr).template get<2>();
6043
        using child_type   = decltype(child);
6044
        using shared_state = ::beman::execution::detail::impls_for<split_impl_t>::shared_state<child_type>;
6045
        auto* sh_state     = new shared_state{::beman::execution::detail::forward_like<Sndr>(child)};
6046
        return ::beman::execution::detail::make_sender(split_impl_t{}, shared_wrapper<child_type>{sh_state});
6047
    }
6048

6049
    template <class Sender>
6050
        requires beman::execution::sender_in<Sender, impls_for<split_impl_t>::split_env>
6051
    auto operator()(Sender&& sender) const {
6052
        auto domain{::beman::execution::detail::get_domain_early(sender)};
6053
        return ::beman::execution::transform_sender(
6054
            domain, ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender)));
6055
    }
6056
};
6057

6058
template <class Sndr, class Env>
6059
struct completion_signatures_for_impl<
6060
    ::beman::execution::detail::basic_sender<::beman::execution::detail::split_impl_t,
6061
                                             ::beman::execution::detail::shared_wrapper<Sndr>>,
6062
    Env> {
6063
    template <class... Args>
6064
    using make_value_completions =
6065
        ::beman::execution::completion_signatures<::beman::execution::set_value_t(const std::decay_t<Args>&...)>;
6066

6067
    template <class... Args>
6068
    using make_error_completions =
6069
        ::beman::execution::completion_signatures<::beman::execution::set_error_t(const std::decay_t<Args>&)...>;
6070

6071
    using value_completions = ::beman::execution::
6072
        value_types_of_t<Sndr, Env, make_value_completions, ::beman::execution::detail::meta::combine>;
6073

6074
    using error_completions = ::beman::execution::error_types_of_t<Sndr, Env, make_error_completions>;
6075

6076
    using fixed_completions =
6077
        ::beman::execution::completion_signatures<::beman::execution::set_stopped_t(),
6078
                                                  ::beman::execution::set_error_t(std::exception_ptr)>;
6079

6080
    using type = ::beman::execution::detail::meta::unique<
6081
        ::beman::execution::detail::meta::combine<fixed_completions, value_completions, error_completions>>;
6082
};
6083

6084
} // namespace beman::execution::detail
6085

6086
namespace beman::execution {
6087
export using split_t = ::beman::execution::detail::split_t;
6088

6089
export inline constexpr ::beman::execution::split_t split{};
6090
} // namespace beman::execution
6091

6092
// ----------------------------------------------------------------------------
6093

6094
namespace beman::execution::detail {
6095
template <typename Completion>
6096
struct then_t : ::beman::execution::sender_adaptor_closure<then_t<Completion>> {
6097
    template <::beman::execution::detail::movable_value Fun>
6098
    auto operator()(Fun&& fun) const {
6099
        return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Fun>(fun)};
6100
    }
6101
    template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
6102
    auto operator()(Sender&& sender, Fun&& fun) const {
6103
        auto domain{::beman::execution::detail::get_domain_early(sender)};
6104
        return ::beman::execution::transform_sender(
6105
            domain,
6106
            ::beman::execution::detail::make_sender(*this, ::std::forward<Fun>(fun), ::std::forward<Sender>(sender)));
6107
    }
6108
    template <::beman::execution::sender Sender, typename Env>
6109
        requires ::beman::execution::detail::nested_sender_has_affine_on<Sender, Env>
6110
    static auto affine_on(Sender&& sndr, const Env&) noexcept {
6111
        return ::std::forward<Sender>(sndr);
6112
    }
6113
};
6114

6115
template <typename Completion>
6116
struct impls_for<then_t<Completion>> : ::beman::execution::detail::default_impls {
6117
    // NOLINTBEGIN(bugprone-exception-escape)
6118
    static constexpr auto complete =
6119
        []<typename Tag, typename... Args>(auto, auto& fun, auto& receiver, Tag, Args&&... args) noexcept -> void {
6120
        if constexpr (::std::same_as<Completion, Tag>) {
6121
            try {
6122
                auto invoke = [&] { return ::std::invoke(::std::move(fun), ::std::forward<Args>(args)...); };
6123
                if constexpr (::std::same_as<void, decltype(invoke())>) {
6124
                    invoke();
6125
                    ::beman::execution::set_value(::std::move(receiver));
6126
                } else {
6127
                    ::beman::execution::set_value(::std::move(receiver), invoke());
6128
                }
6129
            } catch (...) {
6130
                if constexpr (not noexcept(::std::invoke(::std::move(fun), ::std::forward<Args>(args)...)
6131

6132
                                               )) {
6133
                    static_assert(
6134
                        noexcept(::beman::execution::set_error(::std::move(receiver), ::std::current_exception())));
6135
                    ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
6136
                }
6137
            }
6138
        } else {
6139
            static_assert(noexcept(Tag()(::std::move(receiver), ::std::forward<Args>(args)...)));
6140
            Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
6141
        }
6142
    };
6143
    // NOLINTEND(bugprone-exception-escape)
6144
};
6145

6146
template <typename T>
6147
struct then_set_value {
6148
    using type = ::beman::execution::set_value_t(T);
6149
};
6150
template <>
6151
struct then_set_value<void> {
6152
    using type = ::beman::execution::set_value_t();
6153
};
6154

6155
template <typename, typename, typename Completion>
6156
struct then_transform {
6157
    using type = Completion;
6158
};
6159

6160
template <typename Fun, typename Completion, typename... T>
6161
struct then_transform<Fun, Completion, Completion(T...)> {
6162
    using type = typename ::beman::execution::detail::then_set_value<
6163
        ::beman::execution::detail::call_result_t<Fun, T...>>::type;
6164
};
6165

6166
template <typename Fun, typename Replace>
6167
struct then_transform_t {
6168
    template <typename Completion>
6169
    using transform = typename ::beman::execution::detail::then_transform<Fun, Replace, Completion>::type;
6170
};
6171

6172
template <typename, typename, typename>
6173
struct then_exception_fun : ::std::false_type {};
6174
template <typename Comp, typename Fun, typename... A>
6175
struct then_exception_fun<Comp, Fun, Comp(A...)>
6176
    : ::std::bool_constant<not noexcept(::std::declval<Fun>()(::std::declval<A>()...))> {};
6177

6178
template <typename, typename, typename>
6179
struct then_exception : ::std::false_type {};
6180
template <typename Comp, typename Fun, typename Completion, typename... Completions>
6181
struct then_exception<Comp, Fun, ::beman::execution::completion_signatures<Completion, Completions...>> {
6182
    static constexpr bool value{
6183
        then_exception_fun<Comp, Fun, Completion>::value ||
6184
        then_exception<Comp, Fun, ::beman::execution::completion_signatures<Completions...>>::value};
6185
};
6186

6187
template <typename Completion, typename Fun, typename Sender, typename Env>
6188
struct completion_signatures_for_impl<
6189
    ::beman::execution::detail::basic_sender<::beman::execution::detail::then_t<Completion>, Fun, Sender>,
6190
    Env> {
6191
    using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
6192
        ::beman::execution::detail::meta::transform<
6193
            ::beman::execution::detail::then_transform_t<Fun, Completion>::template transform,
6194
            ::beman::execution::completion_signatures_of_t<Sender, Env>>,
6195
        ::std::conditional_t<
6196
            ::beman::execution::detail::
6197
                then_exception<Completion, Fun, ::beman::execution::completion_signatures_of_t<Sender, Env>>::value,
6198
            ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>,
6199
            ::beman::execution::completion_signatures<>>>>;
6200
};
6201
} // namespace beman::execution::detail
6202

6203
namespace beman::execution {
6204
/*!
6205
 * \brief <code>then_t</code> is the type of <code>then</code>.
6206
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6207
 */
6208
export using then_t = ::beman::execution::detail::then_t<::beman::execution::set_value_t>;
6209
/*!
6210
 * \brief <code>upon_error_t</code> is the type of <code>upon_error</code>.
6211
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6212
 */
6213
export using upon_error_t = ::beman::execution::detail::then_t<::beman::execution::set_error_t>;
6214
/*!
6215
 * \brief <code>upon_stopped_t</code> is the type of <code>upon_stopped</code>.
6216
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6217
 */
6218
export using upon_stopped_t = ::beman::execution::detail::then_t<::beman::execution::set_stopped_t>;
6219

6220
/*!
6221
 * \brief <code>then(_sender_, _fun_)</code> yields a sender transforming a <code>set_value_t(_A_...)</code> completion
6222
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6223
 *
6224
 * \details
6225
 * `then` is a callable object of type `then_t`. Invoking <code>then(_sender_, _fun_)</code> or
6226
 * <code>_sender_ | then(_fun_)</code> yields a sender
6227
 * which, when `start`ed starts <code>_sender_</code> and awaits its completion. When
6228
 * <code>_sender_</code> completes `then` proceeds according to this completion:
6229
 * - If the completion is <code>set_value(_a_...)</code>, <code>_fun_(_a_...)</code> is invoked:
6230
 *     - if that invocation throws, `then` completes with <code>set_error(_r_, std::current_exception())</code>;
6231
 * otherwise
6232
 *     - if the invocation returns `void`, `then` completes with <code>set_value(_r_)</code>; otherwise
6233
 *     - if the invocation returns <code>_v_</code>, `then` completes with <code>set_value(_r_, _v_)</code>.
6234
 * - Otherwise, if the completion is <code>set_error(_e_)</code>, `then` completes with <code>set_error(_r_,
6235
 * _e_)</code>
6236
 * - Otherwise, if the completion is <code>set_stopped()</code>, `then` completes with <code>set_stopped(_r_)</code>.
6237
 *
6238
 * <h4>Usage</h4>
6239
 * <pre>
6240
 * then(<i>sender</i>, <i>fun</i>)
6241
 * <i>sender</i> | then(<i>fun</i>)
6242
 * </pre>
6243
 *
6244
 * <h4>Completions Signatures</h4>
6245
 * The completion signatures depends on the completion signatures <code>_CS_</code> of <code>_sender_</code> (the
6246
 * completion signatures will be deduplicated):
6247
 * - For each <code>set_value_t(_A_...)</code> in <code>_CS_</code>,
6248
 *     there is a completion signature
6249
 *     <code>set_value_t(decltype(_fun_(std::declval<_A_>()...)))</code>.
6250
 * - If for any of the <code>set_value_t(_A_...)</code> in
6251
 *     <code>_CS_</code> the expression <code>noexcept(_fun_(std::declval<_A_>()...))</code>
6252
 *     is `false` there is a completion signature <code>set_error_t(std::exception_ptr)</code>.
6253
 * - Each <code>set_error_t(_Error_)</code> in <code>_CS_</code> is copied.
6254
 * - If <code>set_stopped_t()</code> is in <code>_CS_</code> it is copied.
6255
 *
6256
 * <h4>Example</h4>
6257
 *
6258
 * <pre example="doc-then.cpp">
6259
 * #include <beman/execution/execution.hpp>
6260
 * #include <cassert>
6261
 * namespace ex = beman::execution;
6262
 *
6263
 * int main() {
6264
 *     auto result = ex::sync_wait(ex::just(10) | ex::then([](int v) { return v == 3; }));
6265
 *     assert(result);
6266
 *     assert(*result == std::tuple(false));
6267
 * }
6268
 * </pre>
6269
 */
6270
export inline constexpr ::beman::execution::then_t then{};
6271

6272
/*!
6273
 * \brief <code>upon_error(_sender_, _fun_)</code> yields a sender transforming a <code>set_error_t(_E_)</code>
6274
 * completion
6275
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6276
 *
6277
 * \details
6278
 * `upon_error` is a callable object of type `upon_error_t`. Invoking <code>upon_error(_sender_, _fun_)</code> or
6279
 * <code>_sender_ | upon_error(_fun_)</code> yields a sender
6280
 * which, when `start`ed starts <code>_sender_</code> and awaits its completion. When
6281
 * <code>_sender_</code> completes `upon_error` proceeds according to this completion:
6282
 * - If the completion is <code>set_error(_e_)</code>, <code>_fun_(_e_)</code> is invoked:
6283
 *     - if that invocation throws, `upon_error` completes with <code>set_error(_r_, std::current_exception())</code>;
6284
 * otherwise
6285
 *     - if the invocation returns `void`, `upon_error` completes with <code>set_value(_r_)</code>; otherwise
6286
 *     - if the invocation returns <code>_v_</code>, `upon_error` completes with <code>set_value(_r_, _v_)</code>.
6287
 * - Otherwise, if the completion is <code>set_value(_a_...)</code>, `upon_error` completes with <code>set_value(_r_,
6288
 * _a_...)</code>
6289
 * - Otherwise, if the completion is <code>set_stopped()</code>, `upon_error` completes with
6290
 * <code>set_stopped(_r_)</code>.
6291
 *
6292
 * <h4>Usage</h4>
6293
 * <pre>
6294
 * upon_error(<i>sender</i>, <i>fun</i>)
6295
 * <i>sender</i> | upon_error(<i>fun</i>)
6296
 * </pre>
6297
 *
6298
 * <h4>Completions Signatures</h4>
6299
 * The completion signatures depend on the completion signatures <code>_CS_</code> of <code>_sender_</code> (the
6300
 * completion signatures will be deduplicated):
6301
 * - For each <code>set_error_t(_E_)</code> in <code>_CS_</code>,
6302
 *     there is a completion signature
6303
 *     <code>set_value_t(decltype(_fun_(std::declval<_E_>())))</code>.
6304
 * - If for any of the <code>set_error_t(_E_)</code> in
6305
 *     <code>_CS_</code> the expression <code>noexcept(_fun_(_std::declval<E>()_))</code>
6306
 *     is `false` there is a completion signature <code>set_error_t(std::exception_ptr)</code>.
6307
 * - Each <code>set_value_t(_A_...)</code> in <code>_CS_</code> is copied.
6308
 * - If <code>set_stopped_t()</code> is in <code>_CS_</code> it is copied.
6309
 *
6310
 * <h4>Example</h4>
6311
 *
6312
 * <pre example="doc-upon_error.cpp">
6313
 * #include <beman/execution/execution.hpp>
6314
 * #include <cassert>
6315
 * namespace ex = beman::execution;
6316
 *
6317
 * int main() {
6318
 *     auto result = ex::sync_wait(ex::just_error(10) | ex::upon_error([](int v) { return v == 3; }));
6319
 *     assert(result);
6320
 *     assert(*result == std::tuple(false));
6321
 * }
6322
 * </pre>
6323
 */
6324
export inline constexpr ::beman::execution::upon_error_t upon_error{};
6325

6326
/*!
6327
 * \brief <code>upon_stopped(_sender_, _fun_)</code> yields a sender transforming a <code>set_stopped_t()</code>
6328
 * completion
6329
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6330
 *
6331
 * \details
6332
 * `upon_stopped` is a callable object of type `upon_stopped_t`. Invoking <code>upon_stopped(_sender_, _fun_)</code> or
6333
 * <code>_sender_ | upon_stopped(_fun_)</code> yields a sender
6334
 * which, when `start`ed starts <code>_sender_</code> and awaits its completion. When
6335
 * <code>_sender_</code> completes `upon_stopped` proceeds according to this completion:
6336
 * - If the completion is <code>set_stopped(_e_)</code>, <code>_fun_(_e_)</code> is invoked:
6337
 *     - if that invocation throws, `upon_stopped` completes with <code>set_error(_r_,
6338
 * std::current_exception())</code>; otherwise
6339
 *     - if the invocation returns `void`, `upon_stopped` completes with <code>set_value(_r_)</code>; otherwise
6340
 *     - if the invocation returns <code>_v_</code>, `upon_stopped` completes with <code>set_value(_r_, _v_)</code>.
6341
 * - Otherwise, if the completion is <code>set_value(_a_...)</code>, `upon_stopped` completes with <code>set_value(_r_,
6342
 * _a_...)</code>
6343
 * - Otherwise, if the completion is <code>set_error(_e_)</code>, `upon_stopped` completes with <code>set_error(_r_,
6344
 * _e_)</code>.
6345
 *
6346
 * <h4>Usage</h4>
6347
 * <pre>
6348
 * upon_stopped(<i>sender</i>, <i>fun</i>)
6349
 * <i>sender</i> | upon_stopped(<i>fun</i>)
6350
 * </pre>
6351
 *
6352
 * <h4>Completions Signatures</h4>
6353
 * The completion signatures depend on the completion signatures <code>_CS_</code> of <code>_sender_</code> (the
6354
 * completion signatures will be deduplicated):
6355
 * - There is a completion signature <code>set_value_t(decltype(_fun_()))</code>.
6356
 * - If the expression <code>noexcept(_fun_())</code> is `false` there is a completion signature
6357
 * <code>set_error_t(std::exception_ptr)</code>.
6358
 * - Each <code>set_value_t(_A_...)</code> in <code>_CS_</code> is copied.
6359
 * - Each <code>set_error_t(_A_...)</code> in <code>_CS_</code> is copied.
6360
 *
6361
 * <h4>Example</h4>
6362
 *
6363
 * <pre example="doc-upon_stopped.cpp">
6364
 * #include <beman/execution/execution.hpp>
6365
 * #include <cassert>
6366
 * namespace ex = beman::execution;
6367
 *
6368
 * int main() {
6369
 *     auto result = ex::sync_wait(ex::just_stopped() | ex::upon_stopped([]() { return true; }));
6370
 *     assert(result);
6371
 *     assert(*result == std::tuple(true));
6372
 * }
6373
 * </pre>
6374
 */
6375
export inline constexpr ::beman::execution::upon_stopped_t upon_stopped{};
6376
} // namespace beman::execution
6377

6378
// ----------------------------------------------------------------------------
6379

6380
// ----------------------------------------------------------------------------
6381

6382
namespace beman::execution::detail {
6383
struct when_all_t {
6384
    template <::beman::execution::sender... Sender>
6385
        requires(0u != sizeof...(Sender)) &&
6386
                ((::beman::execution::detail::meta::size_v<
6387
                      ::beman::execution::value_types_of_t<Sender,
6388
                                                           ::beman::execution::env<>,
6389
                                                           ::std::tuple,
6390
                                                           ::beman::execution::detail::type_list>> == 1u) &&
6391
                 ...) &&
6392
                requires(Sender&&... s) {
6393
                    typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(s))...>;
6394
                }
6395
    auto operator()(Sender&&... sender) const {
6396
        using common_t =
6397
            typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(sender))...>;
6398
        return ::beman::execution::transform_sender(
6399
            common_t(), ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender)...));
6400
    }
6401
};
6402

6403
template <typename>
6404
struct when_all_value_types;
6405
template <typename... T>
6406
struct when_all_value_types<::beman::execution::detail::type_list<T...>> {
6407
    using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t(T...)>;
6408
};
6409

6410
template <>
6411
struct impls_for<::beman::execution::detail::when_all_t> : ::beman::execution::detail::default_impls {
6412
    static constexpr auto get_attrs{[](auto&&, auto&&... sender) {
6413
        using common_t =
6414
            typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(sender))...>;
6415
        if constexpr (::std::same_as<common_t, ::beman::execution::default_domain>)
6416
            return ::beman::execution::env<>{};
6417
        else
6418
            return ::beman::execution::detail::make_env(::beman::execution::get_domain, common_t{});
6419
    }};
6420
    static constexpr auto get_env{
6421
        []<typename State, typename Receiver>(auto&&, State& state, const Receiver& receiver) noexcept {
6422
            return ::beman::execution::detail::join_env(
6423
                ::beman::execution::detail::make_env(::beman::execution::get_stop_token, state.stop_src.get_token()),
6424
                ::beman::execution::get_env(receiver));
6425
        }};
6426

6427
    enum class disposition : unsigned char { started, error, stopped };
6428

6429
    template <typename Receiver, typename... Sender>
6430
    struct state_type {
6431
        struct nonesuch {};
6432
        using env_t        = ::beman::execution::env_of_t<Receiver>;
6433
        using values_tuple = ::std::tuple<
6434
            ::beman::execution::
6435
                value_types_of_t<Sender, env_t, ::beman::execution::detail::decayed_tuple, ::std::optional>...>;
6436
        using errors_variant = ::beman::execution::detail::meta::to<
6437
            ::std::variant,
6438
            ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
6439
                nonesuch,
6440
                ::beman::execution::detail::meta::prepend<
6441
                    ::std::exception_ptr,
6442
                    ::beman::execution::detail::meta::combine<::beman::execution::detail::meta::to<
6443
                        ::beman::execution::detail::type_list,
6444
                        ::beman::execution::detail::meta::combine<::beman::execution::error_types_of_t<
6445
                            Sender,
6446
                            env_t,
6447
                            ::beman::execution::detail::decayed_type_list>...>>>>>>>;
6448
        using stop_callback = ::beman::execution::stop_callback_for_t<
6449
            ::beman::execution::stop_token_of_t<::beman::execution::env_of_t<Receiver>>,
6450
            ::beman::execution::detail::on_stop_request<state_type>>;
6451

6452
        void arrive(Receiver& recvr) noexcept {
6453
            if (0u == --count)
6454
                this->complete(recvr);
6455
        }
6456

6457
        void complete(Receiver& recvr) noexcept {
6458
            switch (disposition(this->disp)) {
6459
            case disposition::started: {
6460
                auto tie = []<typename... T>(::std::tuple<T...>& t) noexcept {
6461
                    return ::std::apply([](auto&... a) { return ::std::tie(a...); }, t);
6462
                };
6463
                auto set = [&](auto&... t) noexcept {
6464
                    ::beman::execution::set_value(::std::move(recvr), ::std::move(t)...);
6465
                };
6466

6467
                this->on_stop.reset();
6468
                ::std::apply([&](auto&... opts) noexcept { ::std::apply(set, ::std::tuple_cat(tie(*opts)...)); },
6469
                             this->values);
6470
            } break;
6471
            case disposition::error:
6472
                this->on_stop.reset();
6473
                try {
6474
                    ::std::visit(
6475
                        [&]<typename Error>(Error& error) noexcept {
6476
                            if constexpr (!::std::same_as<Error, nonesuch>) {
6477
                                ::beman::execution::set_error(::std::move(recvr), ::std::move(error));
6478
                            }
6479
                        },
6480
                        this->errors);
6481
                } catch (...) {
6482
                    ::beman::execution::set_error(::std::move(recvr), ::std::current_exception());
6483
                }
6484
                break;
6485
            case disposition::stopped:
6486
                this->on_stop.reset();
6487
                ::beman::execution::set_stopped(::std::move(recvr));
6488
                break;
6489
            }
6490
        }
6491

6492
        auto request_stop() -> void {
6493
            if (1u == ++this->count)
6494
                --this->count;
6495
            else {
6496
                this->stop_src.request_stop();
6497
                this->arrive(*this->receiver);
6498
            }
6499
        }
6500

6501
        Receiver*                               receiver{};
6502
        ::std::atomic<::std::size_t>            count{sizeof...(Sender)};
6503
        ::beman::execution::inplace_stop_source stop_src{};
6504
        ::std::atomic<disposition>              disp{disposition::started};
6505
        errors_variant                          errors{};
6506
        values_tuple                            values{};
6507
        ::std::optional<stop_callback>          on_stop{::std::nullopt};
6508
    };
6509

6510
    template <typename Receiver>
6511
    struct make_state {
6512
        template <::beman::execution::sender_in<::beman::execution::env_of_t<Receiver>>... Sender>
6513
        auto operator()(auto, auto, Sender&&...) const {
6514
            return state_type<Receiver, Sender...>{};
6515
        }
6516
    };
6517
    static constexpr auto get_state{[]<typename Sender, typename Receiver>(Sender&& sender, Receiver&) noexcept(
6518
                                        noexcept(std::forward<Sender>(sender).apply(make_state<Receiver>{}))) {
6519
        return std::forward<Sender>(sender).apply(make_state<Receiver>{});
6520
    }};
6521
    static constexpr auto start{[]<typename State, typename Receiver, typename... Ops>(
6522
                                    State& state, Receiver& receiver, Ops&... ops) noexcept -> void {
6523
        state.receiver = &receiver;
6524
        state.on_stop.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(receiver)),
6525
                              ::beman::execution::detail::on_stop_request{state});
6526
        if (state.stop_src.stop_requested()) {
6527
            state.on_stop.reset();
6528
            ::beman::execution::set_stopped(std::move(receiver));
6529
        } else {
6530
            (::beman::execution::start(ops), ...);
6531
        }
6532
    }};
6533
    static constexpr auto complete{
6534
        []<typename Index, typename State, typename Receiver, typename Set, typename... Args>(
6535
            Index, State& state, Receiver& receiver, Set, Args&&... args) noexcept -> void {
6536
            if constexpr (::std::same_as<Set, ::beman::execution::set_error_t>) {
6537
                if (disposition::error != state.disp.exchange(disposition::error)) {
6538
                    state.stop_src.request_stop();
6539
                    try {
6540
                        state.errors.template emplace<typename ::std::decay<Args...>::type>(
6541
                            ::std::forward<Args>(args)...);
6542
                    } catch (...) {
6543
                        state.errors.template emplace<::std::exception_ptr>(::std::current_exception());
6544
                    }
6545
                }
6546
            } else if constexpr (::std::same_as<Set, ::beman::execution::set_stopped_t>) {
6547
                auto expected = disposition::started;
6548
                if (state.disp.compare_exchange_strong(expected, disposition::stopped)) {
6549
                    state.stop_src.request_stop();
6550
                }
6551
            } else if constexpr (!::std::same_as<decltype(State::values), ::std::tuple<>>) {
6552
                if (state.disp == disposition::started) {
6553
                    auto& opt = ::std::get<Index::value>(state.values);
6554
                    try {
6555
                        opt.emplace(::std::forward<Args>(args)...);
6556
                    } catch (...) {
6557
                        if (disposition::error != state.disp.exchange(disposition::error)) {
6558
                            state.stop_src.request_stop();
6559
                            state.errors.template emplace<::std::exception_ptr>(::std::current_exception());
6560
                        }
6561
                    }
6562
                }
6563
            }
6564
            state.arrive(receiver);
6565
        }};
6566
};
6567

6568
template <typename Data, typename Env, typename... Sender>
6569
struct completion_signatures_for_impl<
6570
    ::beman::execution::detail::basic_sender<::beman::execution::detail::when_all_t, Data, Sender...>,
6571
    Env> {
6572
    template <typename... E>
6573
    struct error_comps_t {
6574
        using type = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
6575
    };
6576
    template <typename... E>
6577
    using error_comps = typename error_comps_t<E...>::type;
6578

6579
    using value_types =
6580
        typename ::beman::execution::detail::when_all_value_types<::beman::execution::detail::meta::combine<
6581
            ::beman::execution::
6582
                value_types_of_t<Sender, Env, ::beman::execution::detail::type_list, ::std::type_identity_t>...>>::
6583
            type;
6584
    using error_types = ::beman::execution::detail::meta::unique<
6585
        ::beman::execution::detail::meta::combine<::beman::execution::error_types_of_t<Sender, Env, error_comps>...>>;
6586
    using stopped_types =
6587
        ::std::conditional_t<(false || ... || ::beman::execution::sends_stopped<Sender, Env>),
6588
                             ::beman::execution::completion_signatures<::beman::execution::set_stopped_t()>,
6589
                             ::beman::execution::completion_signatures<>>;
6590
    using type = ::beman::execution::detail::meta::combine<value_types, error_types, stopped_types>;
6591
};
6592
} // namespace beman::execution::detail
6593

6594
namespace beman::execution {
6595
export using when_all_t = ::beman::execution::detail::when_all_t;
6596
export inline constexpr ::beman::execution::when_all_t when_all{};
6597
} // namespace beman::execution
6598

6599
// ----------------------------------------------------------------------------
6600

6601
// ----------------------------------------------------------------------------
6602

6603
namespace beman::execution::detail {
6604
struct write_env_t {
6605
    template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env>
6606
    constexpr auto operator()(Sender&& sender, Env&& env) const {
6607
        return ::beman::execution::detail::make_sender(
6608
            *this, ::std::forward<Env>(env), ::std::forward<Sender>(sender));
6609
    }
NEW
6610
    static auto name() { return "write_env_t"; }
×
6611
    template <::beman::execution::sender Sender, typename Env>
6612
        requires ::beman::execution::detail::nested_sender_has_affine_on<Sender, Env>
6613
    static auto affine_on(Sender&& sndr, const Env&) noexcept {
6614
        return ::std::forward<Sender>(sndr);
6615
    }
6616
};
6617

6618
template <typename NewEnv, typename Child, typename Env>
6619
struct completion_signatures_for_impl<
6620
    ::beman::execution::detail::basic_sender<::beman::execution::detail::write_env_t, NewEnv, Child>,
6621
    Env> {
6622
    using type = decltype(::beman::execution::get_completion_signatures(
6623
        ::std::declval<Child>(),
6624
        ::beman::execution::detail::join_env(::std::declval<NewEnv>(), ::std::declval<Env>())));
6625
};
6626

6627
template <>
6628
struct impls_for<write_env_t> : ::beman::execution::detail::default_impls {
6629
    static constexpr auto get_env = [](auto, const auto& state, const auto& receiver) noexcept {
6630
        return ::beman::execution::detail::join_env(state, ::beman::execution::get_env(receiver));
6631
    };
6632
};
6633

6634
inline constexpr write_env_t write_env{};
6635
} // namespace beman::execution::detail
6636

6637
namespace beman::execution {
6638
export using write_env_t = ::beman::execution::detail::write_env_t;
6639
export inline constexpr write_env_t write_env{};
6640
} // namespace beman::execution
6641

6642
// ----------------------------------------------------------------------------
6643

6644
// ----------------------------------------------------------------------------
6645

6646
namespace beman::execution::detail {
6647
template <::beman::execution::scope_token Token, ::beman::execution::sender Sender>
6648
struct associate_data {
6649
    using wrap_sender = ::std::remove_cvref_t<decltype(::std::declval<Token&>().wrap(::std::declval<Sender>()))>;
6650

6651
    explicit associate_data(Token t, Sender&& s) : token(t), sender(this->token.wrap(::std::forward<Sender>(s))) {
6652
        if (!token.try_associate()) {
6653
            this->sender.reset();
6654
        }
6655
    }
6656
    associate_data(const associate_data& other) noexcept(::std::is_nothrow_copy_constructible_v<wrap_sender> &&
6657
                                                         noexcept(token.try_associate()))
6658
        : token(other.token), sender() {
6659
        if (other.sender && this->token.try_associate()) {
6660
            try {
6661
                this->sender.emplace(*other.sender);
6662
            } catch (...) {
6663
                this->token.disassociate();
6664
            }
6665
        }
6666
    }
6667
    associate_data(associate_data&& other) noexcept(::std::is_nothrow_move_constructible_v<wrap_sender>)
6668
        : token(other.token), sender(::std::move(other.sender)) {
6669
        other.sender.reset();
6670
    }
6671
    auto operator=(const associate_data&) -> associate_data& = delete;
6672
    auto operator=(associate_data&&) -> associate_data&      = delete;
6673
    ~associate_data() {
6674
        if (this->sender) {
6675
            this->sender.reset();
6676
            this->token.disassociate();
6677
        }
6678
    }
6679

6680
    auto release() -> ::std::optional<::std::pair<Token, wrap_sender>> {
6681
        return this->sender ? (std::unique_ptr<std::optional<wrap_sender>, decltype([](auto* opt) { opt->reset(); })>(
6682
                                   &this->sender),
6683
                               ::std::optional{::std::pair{::std::move(this->token), ::std::move(*this->sender)}})
6684
                            : ::std::optional<::std::pair<Token, wrap_sender>>{};
6685
    }
6686

6687
    Token                        token;
6688
    ::std::optional<wrap_sender> sender;
6689
};
6690
template <::beman::execution::scope_token Token, ::beman::execution::sender Sender>
6691
associate_data(Token, Sender&&) -> associate_data<Token, Sender>;
6692

6693
struct associate_t {
6694
    template <::beman::execution::sender Sender, ::beman::execution::scope_token Token>
6695
    auto operator()(Sender&& sender, Token&& token) const {
6696
        auto domain(::beman::execution::detail::get_domain_early(sender));
6697
        return ::beman::execution::transform_sender(
6698
            domain,
6699
            ::beman::execution::detail::make_sender(
6700
                *this,
6701
                ::beman::execution::detail::associate_data(::std::forward<Token>(token),
6702
                                                           ::std::forward<Sender>(sender))));
6703
    }
6704
};
6705

6706
template <>
6707
struct impls_for<associate_t> : ::beman::execution::detail::default_impls {
6708
    template <typename, typename>
6709
    struct get_noexcept : ::std::false_type {};
6710
    template <typename Tag, typename Data, typename Receiver>
6711
    struct get_noexcept<::beman::execution::detail::basic_sender<Tag, Data>, Receiver>
6712
        : ::std::bool_constant<
6713
              ::std::is_nothrow_move_constructible_v<typename ::std::remove_cvref_t<Data>::wrap_sender>&& ::beman::
6714
                  execution::detail::nothrow_callable<::beman::execution::connect_t,
6715
                                                      typename ::std::remove_cvref_t<Data>::wrap_sender,
6716
                                                      Receiver>> {};
6717

6718
    static constexpr auto get_state =
6719
        []<typename Sender, typename Receiver>(Sender&& sender, Receiver& receiver) noexcept(
6720
            ::std::is_nothrow_constructible_v<::std::remove_cvref_t<Sender>, Sender>&&
6721
                get_noexcept<::std::remove_cvref_t<Sender>, Receiver>::value) {
6722
            auto [_, data] = ::std::forward<Sender>(sender);
6723
            auto dataParts{data.release()};
6724

6725
            using scope_token = decltype(dataParts->first);
6726
            using wrap_sender = decltype(dataParts->second);
6727
            using op_t        = decltype(::beman::execution::connect(::std::move(dataParts->second),
6728
                                                              ::std::forward<Receiver>(receiver)));
6729

6730
            struct op_state {
6731
                using sop_t        = op_t;
6732
                using sscope_token = scope_token;
6733
                struct assoc_t {
6734
                    sscope_token tok;
6735
                    sop_t        op;
6736
                };
6737

6738
                bool associated{false};
6739
                union {
6740
                    Receiver* rcvr;
6741
                    assoc_t   assoc;
6742
                };
6743
                explicit op_state(Receiver& r) noexcept : rcvr(::std::addressof(r)) {}
6744
                explicit op_state(sscope_token tk, wrap_sender&& sndr, Receiver& r) try
6745
                    : associated(true), assoc(tk, ::beman::execution::connect(::std::move(sndr), ::std::move(r))) {
6746
                } catch (...) {
6747
                    tk.disassociate();
6748
                    throw;
6749
                }
6750
                op_state(op_state&&) = delete;
6751
                ~op_state() {
6752
                    if (this->associated) {
6753
                        this->assoc.op.~sop_t();
6754
                        this->assoc.tok.disassociate();
6755
                        this->assoc.tok.~sscope_token();
6756
                    }
6757
                }
6758
                auto run() noexcept -> void {
6759
                    if (this->associated) {
6760
                        ::beman::execution::start(this->assoc.op);
6761
                    } else {
6762
                        ::beman::execution::set_stopped(::std::move(*this->rcvr));
6763
                    }
6764
                }
6765
            };
6766
            return dataParts ? op_state(::std::move(dataParts->first), ::std::move(dataParts->second), receiver)
6767
                             : op_state(receiver);
6768
        };
6769
    static constexpr auto start = [](auto& state, auto&&) noexcept -> void { state.run(); };
6770
};
6771

6772
template <typename Data, typename Env>
6773
struct completion_signatures_for_impl<
6774
    ::beman::execution::detail::basic_sender<::beman::execution::detail::associate_t, Data>,
6775
    Env> {
6776
    using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>;
6777
};
6778
} // namespace beman::execution::detail
6779

6780
namespace beman::execution {
6781
export using associate_t = ::beman::execution::detail::associate_t;
6782
export inline constexpr associate_t associate{};
6783
} // namespace beman::execution
6784

6785
// ----------------------------------------------------------------------------
6786

6787
// ----------------------------------------------------------------------------
6788

6789
namespace beman::execution {
6790
/*!
6791
 * \brief Turn an entity, e.g., a sender, into an awaitable.
6792
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6793
 */
6794
export struct as_awaitable_t {
6795
    template <typename Expr, typename Promise>
6796
    auto operator()(Expr&& expr, Promise& promise) const {
6797
        if constexpr (requires { ::std::forward<Expr>(expr).as_awaitable(promise); }) {
6798
            static_assert(
6799
                ::beman::execution::detail::is_awaitable<decltype(::std::forward<Expr>(expr).as_awaitable(promise)),
6800
                                                         Promise>,
6801
                "as_awaitable must return an awaitable");
6802
            return ::std::forward<Expr>(expr).as_awaitable(promise);
6803
        } else if constexpr (::beman::execution::detail::
6804
                                 is_awaitable<Expr, ::beman::execution::detail::unspecified_promise> ||
6805
                             !::beman::execution::detail::awaitable_sender<Expr, Promise>) {
6806
            return ::std::forward<Expr>(expr);
6807
        } else {
6808
            return ::beman::execution::detail::sender_awaitable<Expr, Promise>{::std::forward<Expr>(expr), promise};
6809
        }
6810
    }
6811
};
6812
export inline constexpr ::beman::execution::as_awaitable_t as_awaitable{};
6813
} // namespace beman::execution
6814

6815
// ----------------------------------------------------------------------------
6816

6817
// ----------------------------------------------------------------------------
6818

6819
namespace beman::execution::detail {
6820
struct counting_scope_join_t {
6821
    template <::beman::execution::receiver>
6822
    struct state;
6823

NEW
6824
    auto operator()(::beman::execution::detail::counting_scope_base* ptr) const {
×
NEW
6825
        return ::beman::execution::detail::make_sender(*this, ptr);
×
6826
    }
6827
};
6828
inline constexpr counting_scope_join_t counting_scope_join{};
6829

6830
template <typename Env>
6831
struct completion_signatures_for_impl<
6832
    ::beman::execution::detail::basic_sender<::beman::execution::detail::counting_scope_join_t,
6833
                                             ::beman::execution::detail::counting_scope_base*>,
6834
    Env> {
6835
    using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>;
6836
};
6837

6838
} // namespace beman::execution::detail
6839

6840
// ----------------------------------------------------------------------------
6841

6842
template <::beman::execution::receiver Receiver>
6843
struct beman::execution::detail::counting_scope_join_t::state : ::beman::execution::detail::counting_scope_base::node {
6844
    using op_t = decltype(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
6845
                                                          ::beman::execution::get_env(::std::declval<Receiver&>()))),
6846
                                                      ::std::declval<Receiver&>()));
6847

6848
    ::beman::execution::detail::counting_scope_base* scope;
6849
    explicit state(::beman::execution::detail::counting_scope_base* s, Receiver& r)
6850
        : scope(s),
6851
          receiver(r),
6852
          op(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
6853
                                             ::beman::execution::get_env(this->receiver))),
6854
                                         this->receiver)) {}
6855
    virtual ~state() = default;
6856

6857
    auto complete() noexcept -> void override { ::beman::execution::start(this->op); }
6858
    auto complete_inline() noexcept -> void override { ::beman::execution::set_value(::std::move(this->receiver)); }
6859

6860
    auto start() noexcept -> void { this->scope->start_node(this); }
6861

6862
    ::std::remove_cvref_t<Receiver>& receiver;
6863
    op_t                             op;
6864
};
6865

6866
// ----------------------------------------------------------------------------
6867

6868
namespace beman::execution::detail {
6869
template <>
6870
struct impls_for<::beman::execution::detail::counting_scope_join_t> : ::beman::execution::detail::default_impls {
6871
    static constexpr auto get_state = []<typename Receiver>(auto&& sender, Receiver& receiver) noexcept(false) {
6872
        auto [_, self] = sender;
6873
        return ::beman::execution::detail::counting_scope_join_t::state<Receiver>(self, receiver);
6874
    };
6875
    static constexpr auto start = [](auto& s, auto&) noexcept { s.start(); };
6876
};
6877
} // namespace beman::execution::detail
6878

6879
// ----------------------------------------------------------------------------
6880

6881
// ----------------------------------------------------------------------------
6882

6883
namespace beman::execution::detail {
6884

6885
/**
6886
 * @brief The affine_on_t struct is a sender adaptor closure that transforms a sender
6887
 *        to complete on the scheduler obtained from the receiver's environment.
6888
 *
6889
 * This adaptor implements scheduler affinity to adapt a sender to complete on the
6890
 * scheduler obtained the receiver's environment. The get_scheduler query is used
6891
 * to obtain the scheduler on which the sender gets started.
6892
 */
6893
struct affine_on_t : ::beman::execution::sender_adaptor_closure<affine_on_t> {
6894
    /**
6895
     * @brief Adapt a sender with affine_on.
6896
     *
6897
     * @tparam Sender The deduced type of the sender to be transformed.
6898
     * @param sender The sender to be transformed.
6899
     * @return An adapted sender to complete on the scheduler it was started on.
6900
     */
6901
    template <::beman::execution::sender Sender>
6902
    auto operator()(Sender&& sender) const {
6903
        return ::beman::execution::detail::transform_sender(
6904
            ::beman::execution::detail::get_domain_early(sender),
6905
            ::beman::execution::detail::make_sender(
6906
                *this, ::beman::execution::env<>{}, ::std::forward<Sender>(sender)));
6907
    }
6908

6909
    /**
6910
     * @brief Overload for creating a sender adaptor from affine_on.
6911
     *
6912
     * @return A sender adaptor for the affine_on_t.
6913
     */
NEW
6914
    auto operator()() const { return ::beman::execution::detail::sender_adaptor{*this}; }
×
6915

6916
    template <typename Ev>
6917
    struct ao_env {
6918
        Ev   ev_;
6919
        auto query(const ::beman::execution::get_stop_token_t&) const noexcept
6920
            -> ::beman::execution::never_stop_token {
6921
            return ::beman::execution::never_stop_token();
6922
        }
6923
        template <typename Q>
6924
        auto query(const Q& q) const noexcept -> decltype(q(this->ev_)) {
6925
            return q(this->ev_);
6926
        }
6927
    };
6928
    template <typename Ev>
6929
    ao_env(const Ev&) -> ao_env<Ev>;
6930

6931
    /**
6932
     * @brief affine_on is implemented by transforming it into a use of schedule_from.
6933
     *
6934
     * The constraints ensure that the environment provides a scheduler which is
6935
     * infallible and, thus, can be used to guarantee completion on the correct
6936
     * scheduler.
6937
     *
6938
     * The implementation first tries to see if the child sender's tag has a custom
6939
     * affine_on implementation. If it does, that is used. Otherwise, the default
6940
     * implementation gets a scheduler from the environment and uses schedule_from
6941
     * to adapt the sender to complete on that scheduler.
6942
     *
6943
     * @tparam Sender The type of the sender to be transformed.
6944
     * @tparam Env The type of the environment providing the scheduler.
6945
     * @param sender The sender to be transformed.
6946
     * @param env The environment providing the scheduler.
6947
     * @return A transformed sender that is affined to the scheduler.
6948
     */
6949
    template <::beman::execution::sender Sender, typename Env>
6950
        requires ::beman::execution::detail::sender_for<Sender, affine_on_t> && requires(const Env& env) {
6951
            { ::beman::execution::get_scheduler(env) } -> ::beman::execution::scheduler;
6952
            { ::beman::execution::schedule(::beman::execution::get_scheduler(env)) } -> ::beman::execution::sender;
6953
            {
6954
                ::beman::execution::get_completion_signatures(
6955
                    ::beman::execution::schedule(::beman::execution::get_scheduler(env)),
6956
                    ::beman::execution::detail::join_env(
6957
                        ::beman::execution::env{::beman::execution::prop{
6958
                            ::beman::execution::get_stop_token, ::beman::execution::never_stop_token{}, {}}},
6959
                        env))
6960
            } -> ::std::same_as<::beman::execution::completion_signatures<::beman::execution::set_value_t()>>;
6961
        }
6962
    static auto transform_sender(Sender&& sender, const Env& ev) {
6963
        [[maybe_unused]] auto& [tag, data, child] = sender;
6964
        using child_tag_t = ::beman::execution::tag_of_t<::std::remove_cvref_t<decltype(child)>>;
6965

6966
        if constexpr (::beman::execution::detail::nested_sender_has_affine_on<Sender, Env>) {
6967
            constexpr child_tag_t t{};
6968
            return t.affine_on(::beman::execution::detail::forward_like<Sender>(child), ev);
6969
        } else {
6970
            return ::beman::execution::write_env(
6971
                ::beman::execution::schedule_from(
6972
                    ::beman::execution::get_scheduler(ev),
6973
                    ::beman::execution::write_env(::beman::execution::detail::forward_like<Sender>(child), ev)),
6974
                ao_env(ev));
6975
        }
6976
    }
6977
};
6978

6979
} // namespace beman::execution::detail
6980

6981
namespace beman::execution {
6982
/**
6983
 * @brief affine_on is a CPO, used to adapt a sender to complete on the scheduler
6984
 *      it got started on which is derived from get_scheduler on the receiver's environment.
6985
 */
6986
export using affine_on_t = beman::execution::detail::affine_on_t;
6987
export inline constexpr affine_on_t affine_on{};
6988
} // namespace beman::execution
6989

6990
// ----------------------------------------------------------------------------
6991

6992
// ----------------------------------------------------------------------------
6993

6994
namespace beman::execution::detail {
6995
// specialize default_domain appropriately
6996
/*!
6997
 * \brief The actual implementation of the continues_on customization point object
6998
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6999
 * \internal
7000
 */
7001
struct continues_on_t {
7002
    template <::beman::execution::detail::sender_for<continues_on_t> Sender, typename... Env>
7003
    static auto transform_sender(Sender&& sender, Env&&...) {
7004
        auto&& data{sender.template get<1>()};
7005
        auto&& child{sender.template get<2>()};
7006
        return ::beman::execution::schedule_from(std::move(data), std::move(child));
7007
    }
7008
    template <::beman::execution::scheduler Scheduler>
7009
    auto operator()(Scheduler&& scheduler) const {
7010
        return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Scheduler>(scheduler)};
7011
    }
7012
    template <::beman::execution::sender Sender, ::beman::execution::scheduler Scheduler>
7013
    auto operator()(Sender&& sender, Scheduler&& scheduler) const {
7014
        auto domain(::beman::execution::detail::get_domain_early(sender));
7015
        return ::beman::execution::transform_sender(
7016
            domain,
7017
            ::beman::execution::detail::make_sender(
7018
                *this, std::forward<Scheduler>(scheduler), ::std::forward<Sender>(sender)));
7019
    }
7020
};
7021

7022
/*!
7023
 * \brief Specialization of impls_for to implement the continues_on functionality
7024
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7025
 * \internal
7026
 */
7027
template <>
7028
struct impls_for<::beman::execution::detail::continues_on_t> : ::beman::execution::detail::default_impls {
7029
    static constexpr auto get_attrs{[](const auto& data, const auto& child) noexcept -> decltype(auto) {
7030
        return ::beman::execution::detail::join_env(
7031
            ::beman::execution::detail::sched_attrs(data),
7032
            ::beman::execution::detail::fwd_env(::beman::execution::get_env(child)));
7033
    }};
7034
};
7035

7036
/*!
7037
 * \brief Get the sender's domain when the sender is continue_on
7038
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7039
 * \internal
7040
 */
7041
template <::beman::execution::detail::sender_for<::beman::execution::detail::continues_on_t> Sender, typename Env>
7042
auto get_domain_late(Sender&& sender, Env&&) {
7043
    auto scheduler{sender.template get<1>()};
7044
    return ::beman::execution::detail::query_with_default(
7045
        ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{});
7046
}
7047
} // namespace beman::execution::detail
7048

7049
namespace beman::execution {
7050
export using continues_on_t = ::beman::execution::detail::continues_on_t;
7051
/*!
7052
 * \brief Customization point object to create a `continues_on` sender.
7053
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7054
 */
7055
export inline constexpr continues_on_t continues_on{};
7056
} // namespace beman::execution
7057

7058
// ----------------------------------------------------------------------------
7059

7060
// ----------------------------------------------------------------------------
7061

7062
namespace beman::execution::detail {
7063
struct starts_on_t {
7064
    template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename Env>
7065
    auto transform_env(Sender&& sender, Env&& env) const noexcept {
7066
        auto&& scheduler{sender.template get<1>()};
7067
        return ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(scheduler),
7068
                                                    ::beman::execution::detail::fwd_env(env));
7069
    }
7070
    template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename... Env>
7071
    auto transform_sender(Sender&& sender, Env&&...) const noexcept {
7072
        auto&& scheduler{sender.template get<1>()};
7073
        auto&& new_sender{sender.template get<2>()};
7074
        return ::beman::execution::let_value(
7075
            ::beman::execution::schedule(scheduler),
7076
            [new_sender = ::beman::execution::detail::forward_like<Sender>(new_sender)]() mutable noexcept(
7077
                ::std::is_nothrow_constructible_v<::std::decay_t<Sender>>) { return ::std::move(new_sender); });
7078
    }
7079

7080
    template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender>
7081
    auto operator()(Scheduler&& scheduler, Sender&& sender) const {
7082
        auto domain{::beman::execution::detail::query_with_default(
7083
            ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})};
7084
        return ::beman::execution::transform_sender(
7085
            domain,
7086
            ::beman::execution::detail::make_sender(
7087
                *this, ::std::forward<Scheduler>(scheduler), ::std::forward<Sender>(sender)));
7088
    }
7089
};
7090
} // namespace beman::execution::detail
7091

7092
namespace beman::execution {
7093
export using starts_on_t = ::beman::execution::detail::starts_on_t;
7094
export inline constexpr ::beman::execution::detail::starts_on_t starts_on{};
7095
} // namespace beman::execution
7096

7097
// ----------------------------------------------------------------------------
7098

7099
// ----------------------------------------------------------------------------
7100

7101
namespace beman::execution::detail {
7102
struct when_all_with_variant_t {
7103
    // template <::beman::execution::detail::sender_for<when_all_with_variant_t> Sender>
7104
    template <::beman::execution::sender Sender>
7105
    auto transform_sender(Sender&& sender, auto&&...) const noexcept {
7106
        return ::std::forward<Sender>(sender).apply([](auto&&, auto&&, auto&&... child) {
7107
            return ::beman::execution::when_all(
7108
                ::beman::execution::into_variant(::beman::execution::detail::forward_like<Sender>(child))...);
7109
        });
7110
    }
7111

7112
    template <::beman::execution::sender... Sender>
7113
    auto operator()(Sender&&... sender) const {
7114
        using domain_t =
7115
            typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(sender))...>;
7116
        return ::beman::execution::transform_sender(
7117
            domain_t{}, ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender)...));
7118
    }
7119
};
7120
} // namespace beman::execution::detail
7121

7122
namespace beman::execution {
7123
export using when_all_with_variant_t = ::beman::execution::detail::when_all_with_variant_t;
7124
export inline constexpr ::beman::execution::when_all_with_variant_t when_all_with_variant{};
7125
} // namespace beman::execution
7126

7127
// ----------------------------------------------------------------------------
7128

7129
namespace beman::execution {
7130
export template <::beman::execution::detail::class_type Promise>
7131
struct with_awaitable_senders {
7132
    template <class OtherPromise>
7133
        requires(!::std::same_as<OtherPromise, void>)
7134
    void set_continuation(::std::coroutine_handle<OtherPromise> h) noexcept {
7135
        contination_ = h;
7136
        if constexpr (requires(OtherPromise& other) { other.unhandled_stopped(); }) {
7137
            stopped_handler_ = [](void* p) noexcept -> ::std::coroutine_handle<> {
7138
                return ::std::coroutine_handle<OtherPromise>::from_address(p).promise().unhandled_stopped();
7139
            };
7140
        } else {
7141
            stopped_handler_ = &default_unhandled_stopped;
7142
        }
7143
    }
7144

7145
    ::std::coroutine_handle<> continuation() const noexcept { return contination_; }
7146

7147
    ::std::coroutine_handle<> unhandled_stopped() noexcept { return stopped_handler_(contination_.address()); }
7148

7149
    template <class Value>
7150
    auto await_transform(Value&& value)
7151
        -> ::beman::execution::detail::call_result_t<::beman::execution::as_awaitable_t, Value, Promise&> {
7152
        return ::beman::execution::as_awaitable(::std::forward<Value>(value), static_cast<Promise&>(*this));
7153
    }
7154

7155
  private:
7156
    friend Promise;
7157
    with_awaitable_senders() = default;
7158

7159
    [[noreturn]] static auto default_unhandled_stopped(void*) noexcept -> ::std::coroutine_handle<> {
7160
        ::std::terminate();
7161
    }
7162

7163
    ::std::coroutine_handle<> contination_{};
7164
    ::std::coroutine_handle<> (*stopped_handler_)(void*) noexcept = &default_unhandled_stopped;
7165
};
7166

7167
} // namespace beman::execution
7168

7169
// ----------------------------------------------------------------------------
7170

7171
namespace beman::execution {
7172
export class counting_scope;
7173
}
7174

7175
// ----------------------------------------------------------------------------
7176

7177
class beman::execution::counting_scope : public ::beman::execution::detail::counting_scope_base {
7178
  public:
7179
    class token;
7180

NEW
7181
    auto join() noexcept -> ::beman::execution::sender auto {
×
NEW
7182
        return ::beman::execution::detail::counting_scope_join(this);
×
7183
    }
7184
    auto get_token() noexcept -> token;
NEW
7185
    auto request_stop() noexcept -> void { this->stop_source.request_stop(); }
×
7186

7187
  private:
7188
    ::beman::execution::inplace_stop_source stop_source{};
7189
};
7190

7191
// ----------------------------------------------------------------------------
7192

7193
class beman::execution::counting_scope::token : public ::beman::execution::detail::counting_scope_base::token {
7194
  public:
7195
    template <::beman::execution::sender Sender>
7196
    auto wrap(Sender&& sender) const noexcept -> ::beman::execution::sender auto {
7197
        return ::beman::execution::detail::stop_when(
7198
            ::std::forward<Sender>(sender),
7199
            static_cast<::beman::execution::counting_scope*>(this->scope)->stop_source.get_token());
7200
    }
7201

7202
  private:
7203
    friend class beman::execution::counting_scope;
NEW
7204
    explicit token(::beman::execution::counting_scope* s)
×
NEW
7205
        : ::beman::execution::detail::counting_scope_base::token(s) {}
×
7206
};
7207
static_assert(::beman::execution::scope_token<::beman::execution::counting_scope::token>);
7208

7209
// ----------------------------------------------------------------------------
7210

7211
inline auto beman::execution::counting_scope::get_token() noexcept -> beman::execution::counting_scope::token {
7212
    return beman::execution::counting_scope::token(this);
7213
}
7214

7215
// ----------------------------------------------------------------------------
7216

7217
namespace beman::execution {
7218
export class simple_counting_scope;
7219
}
7220

7221
// ----------------------------------------------------------------------------
7222

7223
class beman::execution::simple_counting_scope : public ::beman::execution::detail::counting_scope_base {
7224
  public:
7225
    class token;
7226

7227
    auto get_token() noexcept -> token;
NEW
7228
    auto join() noexcept -> ::beman::execution::sender auto {
×
NEW
7229
        return ::beman::execution::detail::counting_scope_join(this);
×
7230
    }
7231
};
7232

7233
// ----------------------------------------------------------------------------
7234

7235
class beman::execution::simple_counting_scope::token : public ::beman::execution::detail::counting_scope_base::token {
7236
  public:
7237
    template <::beman::execution::sender Sender>
7238
    auto wrap(Sender&& sender) const noexcept -> Sender&& {
7239
        return ::std::forward<Sender>(sender);
7240
    }
7241

7242
  private:
7243
    friend class beman::execution::simple_counting_scope;
NEW
7244
    explicit token(::beman::execution::detail::counting_scope_base* s)
×
NEW
7245
        : ::beman::execution::detail::counting_scope_base::token(s) {}
×
7246
};
7247

7248
// ----------------------------------------------------------------------------
7249

7250
inline auto beman::execution::simple_counting_scope::get_token() noexcept
7251
    -> beman::execution::simple_counting_scope::token {
7252
    return beman::execution::simple_counting_scope::token(this);
7253
}
7254

7255
// ----------------------------------------------------------------------------
7256

7257
// ----------------------------------------------------------------------------
7258

7259
namespace beman::execution::detail {
7260
template <typename>
7261
struct non_throwing_args_copy;
7262
template <typename Rc, typename... A>
7263
struct non_throwing_args_copy<Rc(A...)> {
7264
    static constexpr bool value = (true && ... && ::std::is_nothrow_constructible_v<::std::decay_t<A>, A>);
7265
};
7266
template <typename S>
7267
inline constexpr bool non_throwing_args_copy_v{non_throwing_args_copy<S>::value};
7268

7269
template <typename Completions>
7270
struct spawn_future_state_base;
7271
template <typename... Sigs>
7272
struct spawn_future_state_base<::beman::execution::completion_signatures<Sigs...>> {
7273
    static constexpr bool has_non_throwing_args_copy = (true && ... && non_throwing_args_copy_v<Sigs>);
7274
    using result_t                                   = ::beman::execution::detail::meta::unique<
7275
                                          ::std::conditional_t<has_non_throwing_args_copy,
7276
                                                               ::std::variant<::std::monostate, ::beman::execution::detail::as_tuple_t<Sigs>...>,
7277
                                                               ::std::variant<::std::monostate,
7278
                                                                              ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>,
7279
                                                                              ::beman::execution::detail::as_tuple_t<Sigs>...>>>;
7280

7281
    result_t result{};
7282
    virtual ~spawn_future_state_base()       = default;
7283
    virtual auto complete() noexcept -> void = 0;
7284
};
7285

7286
template <typename Completions>
7287
struct spawn_future_receiver {
7288
    using receiver_concept = ::beman::execution::receiver_t;
7289
    using state_t          = ::beman::execution::detail::spawn_future_state_base<Completions>;
7290

7291
    state_t* state{};
7292

7293
    template <typename... A>
7294
    auto set_value(A&&... a) && noexcept -> void {
7295
        this->set_complete<::beman::execution::set_value_t>(::std::forward<A>(a)...);
7296
    }
7297
    template <typename E>
7298
    auto set_error(E&& e) && noexcept -> void {
7299
        this->set_complete<::beman::execution::set_error_t>(::std::forward<E>(e));
7300
    }
7301
    auto set_stopped() && noexcept -> void { this->set_complete<::beman::execution::set_stopped_t>(); }
7302

7303
    template <typename Tag, typename... T>
7304
    auto set_complete(T&&... t) noexcept {
7305
        try {
7306
            this->state->result.template emplace<::beman::execution::detail::decayed_tuple<Tag, T...>>(
7307
                Tag(), ::std::forward<T>(t)...);
7308
        } catch (...) {
7309
            if constexpr (!state_t::has_non_throwing_args_copy) {
7310
                this->state->result
7311
                    .template emplace<::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>>(
7312
                        ::beman::execution::set_error_t{}, ::std::current_exception());
7313
            }
7314
        }
7315
        this->state->complete();
7316
    }
7317
};
7318

7319
template <::beman::execution::sender Sndr, typename Env>
7320
using future_spawned_sender = decltype(::beman::execution::write_env(
7321
    ::beman::execution::detail::stop_when(::std::declval<Sndr>(),
7322
                                          ::std::declval<::beman::execution::inplace_stop_token>()),
7323
    ::std::declval<Env>()));
7324

7325
template <::beman::execution::sender Sndr, typename Env>
7326
using spawn_future_sigs = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
7327
    ::beman::execution::set_stopped_t(),
7328
    ::beman::execution::completion_signatures_of_t<::beman::execution::detail::future_spawned_sender<Sndr, Env>>>>;
7329

7330
template <typename Allocator, ::beman::execution::scope_token Token, ::beman::execution::sender Sndr, typename Env>
7331
struct spawn_future_state
7332
    : ::beman::execution::detail::spawn_future_state_base<::beman::execution::detail::spawn_future_sigs<Sndr, Env>> {
7333
    using alloc_t          = typename ::std::allocator_traits<Allocator>::template rebind_alloc<spawn_future_state>;
7334
    using traits_t         = ::std::allocator_traits<alloc_t>;
7335
    using spawned_sender_t = ::beman::execution::detail::future_spawned_sender<Sndr, Env>;
7336
    using sigs_t           = ::beman::execution::detail::spawn_future_sigs<Sndr, Env>;
7337
    using receiver_t       = ::beman::execution::detail::spawn_future_receiver<sigs_t>;
7338
    static_assert(::beman::execution::sender<spawned_sender_t>);
7339
    static_assert(::beman::execution::receiver<receiver_t>);
7340
    using op_t = ::beman::execution::connect_result_t<spawned_sender_t, receiver_t>;
7341

7342
    template <::beman::execution::sender S>
7343
    spawn_future_state(auto a, S&& s, Token tok, Env env)
7344
        : alloc(::std::move(a)),
7345
          op(::beman::execution::write_env(
7346
                 ::beman::execution::detail::stop_when(::std::forward<S>(s), source.get_token()), env),
7347
             receiver_t{this}),
7348
          token(::std::move(tok)),
7349
          associated(token.try_associate()) {
7350
        if (this->associated) {
7351
            ::beman::execution::start(this->op);
7352
        } else {
7353
            ::beman::execution::set_stopped(receiver_t{this});
7354
        }
7355
    }
7356
    auto complete() noexcept -> void override {
7357
        {
7358
            ::std::lock_guard cerberos(this->gate);
7359
            if (this->fun == nullptr) {
7360
                this->receiver = this;
7361
                return;
7362
            }
7363
        }
7364
        this->fun(this->receiver, *this);
7365
    }
7366
    auto abandon() noexcept -> void {
7367
        bool ready{[&] {
7368
            ::std::lock_guard cerberos(this->gate);
7369
            if (this->receiver == nullptr) {
7370
                this->receiver = this;
7371
                this->fun      = [](void*, spawn_future_state& state) noexcept { state.destroy(); };
7372
                return false;
7373
            }
7374
            return true;
7375
        }()};
7376
        if (ready) {
7377
            this->destroy();
7378
        } else {
7379
            this->source.request_stop();
7380
        }
7381
    }
7382
    template <::beman::execution::receiver Rcvr>
7383
    static auto complete_receiver(Rcvr& rcvr, typename spawn_future_state::result_t& res) noexcept {
7384
        std::visit(
7385
            [&rcvr]<typename Tuplish>(Tuplish&& tuplish) noexcept {
7386
                if constexpr (!::std::same_as<::std::remove_cvref_t<decltype(tuplish)>, ::std::monostate>) {
7387
                    ::std::apply(
7388
                        [&rcvr]<typename... Args>(auto cpo, Args&&... args) {
7389
                            cpo(::std::move(rcvr), ::std::forward<Args>(args)...);
7390
                        },
7391
                        ::std::forward<Tuplish>(tuplish));
7392
                }
7393
            },
7394
            ::std::move(res));
7395
    }
7396
    template <::beman::execution::receiver Rcvr>
7397
    auto consume(Rcvr& rcvr) noexcept -> void {
7398
        {
7399
            ::std::lock_guard cerberos(this->gate);
7400
            if (this->receiver == nullptr) {
7401
                this->receiver = &rcvr;
7402
                this->fun      = [](void* ptr, spawn_future_state& state) noexcept {
7403
                    spawn_future_state::complete_receiver(*static_cast<Rcvr*>(ptr), state.result);
7404
                };
7405
                return;
7406
            }
7407
        }
7408
        spawn_future_state::complete_receiver(rcvr, this->result);
7409
    }
7410
    auto destroy() noexcept -> void {
7411
        Token tok{this->token};
7412
        bool  assoc{this->associated};
7413
        {
7414
            alloc_t a{this->alloc};
7415
            traits_t::destroy(a, this);
7416
            traits_t::deallocate(a, this, 1u);
7417
        }
7418
        if (assoc) {
7419
            tok.disassociate();
7420
        }
7421
    }
7422

7423
    ::std::mutex                            gate{};
7424
    alloc_t                                 alloc;
7425
    ::beman::execution::inplace_stop_source source{};
7426
    op_t                                    op;
7427
    Token                                   token;
7428
    bool                                    associated{false};
7429
    void*                                   receiver{};
7430
    auto (*fun)(void*, spawn_future_state&) noexcept -> void = nullptr;
7431
};
7432

7433
class spawn_future_t {
7434
  public:
7435
    template <::beman::execution::sender Sndr, ::beman::execution::scope_token Tok, typename Ev>
7436
        requires ::beman::execution::detail::queryable<::std::remove_cvref_t<Ev>>
7437
    auto operator()(Sndr&& sndr, Tok&& tok, Ev&& ev) const {
7438
        auto make{[&]() -> decltype(auto) { //-dk:TODO why decltype(auto) instead of auto?
7439
            return tok.wrap(::std::forward<Sndr>(sndr));
7440
        }};
7441
        using sndr_t = decltype(make());
7442
        static_assert(::beman::execution::sender<Sndr>);
7443

7444
        auto [alloc, senv] = spawn_get_allocator(sndr, ev);
7445
        using state_t = ::beman::execution::detail::spawn_future_state<decltype(alloc), Tok, sndr_t, decltype(senv)>;
7446
        using state_alloc_t  = typename ::std::allocator_traits<decltype(alloc)>::template rebind_alloc<state_t>;
7447
        using state_traits_t = ::std::allocator_traits<state_alloc_t>;
7448
        state_alloc_t state_alloc(alloc);
7449
        state_t*      op{state_traits_t::allocate(state_alloc, 1u)};
7450
        try {
7451
            state_traits_t::construct(state_alloc, op, alloc, make(), tok, senv);
7452
        } catch (...) {
7453
            state_traits_t::deallocate(state_alloc, op, 1u);
7454
            throw;
7455
        }
7456

7457
        using deleter = decltype([](state_t* p) noexcept { p->abandon(); });
7458
        return ::beman::execution::detail::make_sender(*this, ::std::unique_ptr<state_t, deleter>{op});
7459
    }
7460
    template <::beman::execution::sender Sndr, ::beman::execution::scope_token Tok>
7461
    auto operator()(Sndr&& sndr, Tok&& tok) const {
7462
        return (*this)(::std::forward<Sndr>(sndr), ::std::forward<Tok>(tok), ::beman::execution::env<>{});
7463
    }
7464
};
7465

7466
template <typename State, typename Deleter, typename Env>
7467
struct completion_signatures_for_impl<
7468
    ::beman::execution::detail::basic_sender<::beman::execution::detail::spawn_future_t,
7469
                                             ::std::unique_ptr<State, Deleter>>,
7470
    Env> {
7471
    using type = typename State::sigs_t;
7472
};
7473

7474
template <>
7475
struct impls_for<spawn_future_t> : ::beman::execution::detail::default_impls {
7476
    static constexpr auto start{[](auto& state, auto& rcvr) noexcept -> void { state->consume(rcvr); }};
7477
};
7478
} // namespace beman::execution::detail
7479

7480
namespace beman::execution {
7481
export using spawn_future_t = ::beman::execution::detail::spawn_future_t;
7482
export inline constexpr spawn_future_t spawn_future{};
7483
} // namespace beman::execution
7484

7485
// ----------------------------------------------------------------------------
7486

7487
// ----------------------------------------------------------------------------
7488

7489
namespace beman::execution::detail {
7490
struct spawn_t {
7491
    struct state_base {
7492
        virtual ~state_base()                    = default;
7493
        virtual auto complete() noexcept -> void = 0;
7494
    };
7495

7496
    struct receiver {
7497
        using receiver_concept = ::beman::execution::receiver_t;
7498
        state_base* state{};
7499

NEW
7500
        auto set_value() && noexcept -> void { this->state->complete(); }
×
NEW
7501
        auto set_stopped() && noexcept -> void { this->state->complete(); }
×
7502
    };
1✔
7503

1✔
7504
    template <typename Alloc, ::beman::execution::scope_token Tok, ::beman::execution::sender Sndr>
1✔
7505
    struct state : state_base {
2✔
7506
        using op_t     = ::beman::execution::connect_result_t<Sndr, receiver>;
1✔
7507
        using alloc_t  = typename ::std::allocator_traits<Alloc>::template rebind_alloc<state>;
7508
        using traits_t = ::std::allocator_traits<alloc_t>;
7509

7510
        state(Alloc a, Sndr&& sndr, Tok tok)
7511
            : alloc(a), op(::beman::execution::connect(::std::forward<Sndr>(sndr), receiver{this})), token(tok) {
7512
            if (this->token.try_associate()) {
7513
                ::beman::execution::start(this->op);
7514
            } else {
7515
                this->destroy();
7516
            }
7517
        }
7518
        auto complete() noexcept -> void override {
7519
            Tok tok(this->token);
7520
            this->destroy();
7521
            tok.disassociate();
7522
        }
7523
        auto destroy() noexcept -> void {
7524
            alloc_t all(this->alloc);
7525
            traits_t::destroy(all, this);
7526
            traits_t::deallocate(all, this, 1);
7527
        }
7528

7529
        alloc_t alloc;
7530
        op_t    op;
7531
        Tok     token;
7532
    };
7533

7534
    template <::beman::execution::sender Sender, ::beman::execution::scope_token Token, typename Env>
7535
    auto operator()(Sender&& sender, Token&& tok, Env&& env) const {
7536
        auto new_sender{tok.wrap(::std::forward<Sender>(sender))};
7537
        auto [all, senv] = ::beman::execution::detail::spawn_get_allocator(new_sender, env);
7538

7539
        using sender_t = decltype(::beman::execution::write_env(::std::move(new_sender), senv));
7540
        using state_t  = state<decltype(all), Token, sender_t>;
7541
        using alloc_t  = typename ::std::allocator_traits<decltype(all)>::template rebind_alloc<state_t>;
7542
        using traits_t = ::std::allocator_traits<alloc_t>;
7543
        alloc_t  alloc(all);
7544
        state_t* op{traits_t::allocate(alloc, 1u)};
7545
        traits_t::construct(alloc, op, all, ::beman::execution::write_env(::std::move(new_sender), senv), tok);
7546
    }
7547
    template <::beman::execution::sender Sender, ::beman::execution::scope_token Token>
7548
    auto operator()(Sender&& sender, Token&& token) const {
7549
        return (*this)(::std::forward<Sender>(sender), ::std::forward<Token>(token), ::beman::execution::env<>{});
7550
    }
7551
};
7552
} // namespace beman::execution::detail
7553

7554
namespace beman::execution {
7555
export using spawn_t = ::beman::execution::detail::spawn_t;
7556
export inline constexpr spawn_t spawn{};
7557
} // namespace beman::execution
7558

7559
// ----------------------------------------------------------------------------
7560

7561
// ----------------------------------------------------------------------------
7562

7563
namespace beman::execution::detail {
7564
struct on_t : ::beman::execution::sender_adaptor_closure<on_t> {
7565
    template <::beman::execution::detail::sender_for<on_t> OutSndr, typename Env>
7566
    auto transform_env(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) {
7567
        auto&& data{out_sndr.template get<1>()};
7568

7569
        if constexpr (::beman::execution::scheduler<decltype(data)>)
7570
            return ::beman::execution::detail::join_env(
7571
                ::beman::execution::detail::sched_env(::beman::execution::detail::forward_like<OutSndr>(data)
7572

7573
                                                          ),
7574
                ::beman::execution::detail::fwd_env(::std::forward<Env>(env)));
7575
        else
7576
            return std::forward<Env>(env);
7577
    }
7578

7579
    template <typename>
7580
    struct env_needs_get_scheduler {
7581
        using sender_concept = ::beman::execution::sender_t;
7582
        template <typename Env>
7583
        auto get_completion_signatures(Env&&) const {
7584
            return env_needs_get_scheduler<Env>{};
7585
        }
7586
    };
7587

7588
    template <::beman::execution::detail::sender_for<on_t> OutSndr, typename Env>
7589
    auto transform_sender(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) {
7590
        struct not_a_scheduler {};
7591
        auto&& [_, data, child] = out_sndr;
7592

7593
        if constexpr (::beman::execution::scheduler<decltype(data)>) {
7594
            auto sch{::beman::execution::detail::query_with_default(
7595
                ::beman::execution::get_scheduler, env, not_a_scheduler{})};
7596
            if constexpr (::std::same_as<not_a_scheduler, decltype(sch)>) {
7597
                return env_needs_get_scheduler<Env>{};
7598
            } else {
7599
                return ::beman::execution::continues_on(
7600
                    ::beman::execution::starts_on(::beman::execution::detail::forward_like<OutSndr>(data),
7601
                                                  ::beman::execution::detail::forward_like<OutSndr>(child)),
7602
                    ::std::move(sch));
7603
            }
7604
        } else {
7605
            auto& [sch, closure] = data;
7606
            auto orig_sch{::beman::execution::detail::query_with_default(
7607
                ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>,
7608
                ::beman::execution::get_env(child),
7609
                ::beman::execution::detail::query_with_default(
7610
                    ::beman::execution::get_scheduler, env, not_a_scheduler{}))};
7611

7612
            if constexpr (::std::same_as<not_a_scheduler, decltype(orig_sch)>) {
7613
                return env_needs_get_scheduler<Env>{};
7614
            } else {
7615
                return ::beman::execution::detail::write_env(
7616
                    ::beman::execution::continues_on(
7617
                        ::beman::execution::detail::forward_like<OutSndr>(closure)(::beman::execution::continues_on(
7618
                            ::beman::execution::detail::write_env(
7619
                                ::beman::execution::detail::forward_like<OutSndr>(child),
7620
                                ::beman::execution::detail::sched_env(orig_sch)),
7621
                            sch)),
7622
                        orig_sch),
7623
                    ::beman::execution::detail::sched_env(env));
7624
            }
7625
        }
7626
    }
7627

7628
    template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr>
7629
        requires ::beman::execution::detail::is_sender_adaptor_closure<Sndr>
7630
    auto operator()(Sch&&, Sndr&&) const -> void =
7631
        BEMAN_EXECUTION_DELETE("on(sch, sndr) requires that sndr isn't both a sender and sender adaptor closure");
7632

7633
    template <::beman::execution::scheduler                         Sch,
7634
              ::beman::execution::sender                            Sndr,
7635
              ::beman::execution::detail::is_sender_adaptor_closure Closure>
7636
        requires ::beman::execution::detail::is_sender_adaptor_closure<Sndr>
7637
    auto operator()(Sndr&&, Sch&&, Closure&&) const -> void =
7638
        BEMAN_EXECUTION_DELETE("on(sch, sndr) requires that sndr isn't both a sender and sender adaptor closure");
7639

7640
    template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr>
7641
    auto operator()(Sch&& sch, Sndr&& sndr) const {
7642
        auto domain{::beman::execution::detail::query_with_default(
7643
            ::beman::execution::get_domain, sch, ::beman::execution::default_domain{})};
7644
        return ::beman::execution::transform_sender(
7645
            domain,
7646
            ::beman::execution::detail::make_sender(*this, ::std::forward<Sch>(sch), ::std::forward<Sndr>(sndr)));
7647
    }
7648
    template <::beman::execution::scheduler                         Sch,
7649
              ::beman::execution::sender                            Sndr,
7650
              ::beman::execution::detail::is_sender_adaptor_closure Closure>
7651
    auto operator()(Sndr&& sndr, Sch&& sch, Closure&& closure) const {
7652
        auto domain{::beman::execution::detail::get_domain_early(sndr)};
7653
        return ::beman::execution::transform_sender(
7654
            domain,
7655
            ::beman::execution::detail::make_sender(
7656
                *this,
7657
                ::beman::execution::detail::product_type{::std::forward<Sch>(sch), ::std::forward<Closure>(closure)},
7658
                ::std::forward<Sndr>(sndr)));
7659
    }
7660
    template <::beman::execution::scheduler Sch, ::beman::execution::detail::is_sender_adaptor_closure Closure>
7661
    auto operator()(Sch&& sch, Closure&& closure) const {
7662
        return ::beman::execution::detail::sender_adaptor{
7663
            *this, ::std::forward<Sch>(sch), ::std::forward<Closure>(closure)};
7664
    }
7665
};
7666

7667
} // namespace beman::execution::detail
7668

7669
namespace beman::execution {
7670
export using on_t = ::beman::execution::detail::on_t;
7671
export inline constexpr ::beman::execution::on_t on{};
7672
} // namespace beman::execution
7673

7674
// ----------------------------------------------------------------------------
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc