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

bemanproject / execution / 21516687584

30 Jan 2026 01:00PM UTC coverage: 86.6% (-6.0%) from 92.63%
21516687584

Pull #203

github

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

11 of 119 new or added lines in 6 files covered. (9.24%)

2 existing lines in 1 file now uncovered.

1215 of 1403 relevant lines covered (86.6%)

419.59 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
    struct get_attrs_impl {
2731
        auto operator()(const auto&, const auto&... child) const noexcept -> decltype(auto) {
2732
            if constexpr (1 == sizeof...(child))
2733
                return (::beman::execution::detail::fwd_env(::beman::execution::get_env(child)), ...);
2734
            else
2735
                return ::beman::execution::env<>{};
2736
        }
2737
    };
2738
    static constexpr auto get_attrs = get_attrs_impl{};
2739
    static constexpr auto get_env   = [](auto, auto&, const auto& receiver) noexcept -> decltype(auto) {
2740
        return ::beman::execution::detail::fwd_env(::beman::execution::get_env(receiver));
2741
    };
2742
    static constexpr auto get_state =
2743
        []<typename Sender, typename Receiver>(Sender&& sender, Receiver& receiver) noexcept -> decltype(auto) {
2744
        auto&& data{[&sender]() -> decltype(auto) {
2745
            if constexpr (requires {
2746
                              sender.size();
2747
                              sender.template get<1>();
2748
                          })
2749
                return sender.template get<1>();
2750
            else
2751
                return ::beman::execution::detail::get_sender_data(::std::forward<Sender>(sender)).data;
2752
        }()};
2753

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

2770
// ----------------------------------------------------------------------------
2771

2772
// ----------------------------------------------------------------------------
2773

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

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

2792
// ----------------------------------------------------------------------------
2793

2794
// ----------------------------------------------------------------------------
2795

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

2802
// ----------------------------------------------------------------------------
2803

2804
// ----------------------------------------------------------------------------
2805

2806
namespace beman::execution::detail {
2807
template <typename...>
2808
concept always_true = true;
2809

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

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

2835
template <::beman::execution::detail::valid_completion_signatures,
2836
          template <typename...> class,
2837
          template <typename...> class>
2838
struct gather_signatures_helper;
2839

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

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

2873
// ----------------------------------------------------------------------------
2874

2875
// ----------------------------------------------------------------------------
2876

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

2895
// ----------------------------------------------------------------------------
2896

2897
// ----------------------------------------------------------------------------
2898

2899
namespace beman::execution::detail {
2900
template <typename Tag>
2901
struct impls_for : ::beman::execution::detail::default_impls {};
2902
} // namespace beman::execution::detail
2903

2904
// ----------------------------------------------------------------------------
2905

2906
// ----------------------------------------------------------------------------
2907

2908
namespace beman::execution::detail {
2909
template <typename Receiver>
2910
struct operation_state_task;
2911

2912
template <typename Receiver>
2913
struct connect_awaitable_promise;
2914
} // namespace beman::execution::detail
2915

2916
// ----------------------------------------------------------------------------
2917

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

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

2932
    auto get_env() const noexcept -> ::beman::execution::env_of_t<Receiver> {
2933
        return ::beman::execution::get_env(this->receiver);
2934
    }
2935

2936
    auto get_return_object() noexcept -> ::beman::execution::detail::operation_state_task<Receiver>;
2937

2938
  private:
2939
    Receiver& receiver;
2940
};
2941

2942
// ----------------------------------------------------------------------------
2943

2944
template <typename Receiver>
2945
struct beman::execution::detail::operation_state_task {
2946
    using operation_state_concept = ::beman::execution::operation_state_t;
2947
    using promise_type            = ::beman::execution::detail::connect_awaitable_promise<Receiver>;
2948

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

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

2961
    ::std::coroutine_handle<> handle;
2962
};
2963

2964
// ----------------------------------------------------------------------------
2965

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

2973
// ----------------------------------------------------------------------------
2974

2975
// ----------------------------------------------------------------------------
2976

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

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

2999
// ----------------------------------------------------------------------------
3000

3001
// ----------------------------------------------------------------------------
3002

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

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

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

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

3070
// ----------------------------------------------------------------------------
3071

3072
// ----------------------------------------------------------------------------
3073

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

3082
// ----------------------------------------------------------------------------
3083

3084
// ----------------------------------------------------------------------------
3085

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

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

3104
export inline constexpr ::beman::execution::schedule_t schedule{};
3105
} // namespace beman::execution
3106

3107
// ----------------------------------------------------------------------------
3108

3109
// ----------------------------------------------------------------------------
3110

3111
namespace beman::execution::detail::pipeable {
3112
struct sender_adaptor_closure_base {};
3113
} // namespace beman::execution::detail::pipeable
3114

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

3121
} // namespace beman::execution
3122

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

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

3142
// ----------------------------------------------------------------------------
3143

3144
// ----------------------------------------------------------------------------
3145

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

3151
// ----------------------------------------------------------------------------
3152

3153
// ----------------------------------------------------------------------------
3154

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

3164
// ----------------------------------------------------------------------------
3165

3166
// ----------------------------------------------------------------------------
3167

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

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

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

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

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

3236
// ----------------------------------------------------------------------------
3237

3238
// ----------------------------------------------------------------------------
3239

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

3255
} // namespace beman::execution::detail
3256

3257
// ----------------------------------------------------------------------------
3258

3259
// ----------------------------------------------------------------------------
3260

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

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

3281
// ----------------------------------------------------------------------------
3282

3283
// ----------------------------------------------------------------------------
3284

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

3299
// ----------------------------------------------------------------------------
3300

3301
// ----------------------------------------------------------------------------
3302

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

3322
// ----------------------------------------------------------------------------
3323

3324
// ----------------------------------------------------------------------------
3325

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

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

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

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

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

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

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

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

3438
// ----------------------------------------------------------------------------
3439

3440
// ----------------------------------------------------------------------------
3441

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

3467
// ----------------------------------------------------------------------------
3468

3469
// ----------------------------------------------------------------------------
3470

3471
namespace beman::execution::detail {
3472
template <typename Scheduler>
3473
class sched_env {
3474
  private:
3475
    Scheduler sched;
3476

3477
  public:
3478
    template <typename S>
3479
    explicit sched_env(S sch) : sched(::std::move(sch)) {}
3480

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

3490
template <typename Scheduler>
3491
sched_env(Scheduler&&) -> sched_env<::std::remove_cvref_t<Scheduler>>;
3492
} // namespace beman::execution::detail
3493

3494
// ----------------------------------------------------------------------------
3495

3496
// ----------------------------------------------------------------------------
3497

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

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

3531
} // namespace beman::execution
3532

3533
// ----------------------------------------------------------------------------
3534

3535
// ----------------------------------------------------------------------------
3536

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

3544
// ----------------------------------------------------------------------------
3545

3546
// ----------------------------------------------------------------------------
3547

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

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

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

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

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

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

3607
// ----------------------------------------------------------------------------
3608

3609
// ----------------------------------------------------------------------------
3610

3611
namespace beman::execution {
3612
export template <typename Tag>
3613
struct get_completion_scheduler_t;
3614

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

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

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

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

3667
export template <::beman::execution::detail::completion_tag Tag>
3668
inline constexpr get_completion_scheduler_t<Tag> get_completion_scheduler{};
3669
} // namespace beman::execution
3670

3671
// ----------------------------------------------------------------------------
3672

3673
// ----------------------------------------------------------------------------
3674

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

3685
// ----------------------------------------------------------------------------
3686

3687
// ----------------------------------------------------------------------------
3688

3689
namespace beman::execution::detail {
3690

3691
template <typename Scheduler>
3692
class sched_attrs {
3693
  private:
3694
    Scheduler sched;
3695

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

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

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

3713
template <typename Scheduler>
3714
sched_attrs(Scheduler&&) -> sched_attrs<::std::remove_cvref_t<Scheduler>>;
3715
} // namespace beman::execution::detail
3716

3717
// ----------------------------------------------------------------------------
3718

3719
// ----------------------------------------------------------------------------
3720

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

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

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

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

3771
// ----------------------------------------------------------------------------
3772

3773
// ----------------------------------------------------------------------------
3774

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

3787
export inline constexpr get_delegation_scheduler_t get_delegation_scheduler{};
3788
} // namespace beman::execution
3789

3790
// ----------------------------------------------------------------------------
3791

3792
// ----------------------------------------------------------------------------
3793

3794
namespace beman::execution::detail {
3795
template <typename T>
3796
concept not_void = !::std::same_as<T, void>;
3797

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

3835
// ----------------------------------------------------------------------------
3836

3837
// ----------------------------------------------------------------------------
3838

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

3851
// ----------------------------------------------------------------------------
3852

3853
// ----------------------------------------------------------------------------
3854

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

3860
// ----------------------------------------------------------------------------
3861

3862
// ----------------------------------------------------------------------------
3863

3864
namespace beman::execution {
3865
export class run_loop {
3866
  private:
3867
    struct scheduler;
3868

3869
    struct env {
3870
        run_loop* loop;
3871

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

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

3883
    template <typename Receiver>
3884
    struct opstate : opstate_base {
3885
        using operation_state_concept = ::beman::execution::operation_state_t;
3886

3887
        run_loop* loop;
3888
        Receiver  receiver;
3889

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

3917
        run_loop* loop;
3918

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

3928
        run_loop* loop;
3929

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

3934
    enum class state : unsigned char { starting, running, finishing };
3935

3936
    state                     current_state{state::starting};
3937
    ::std::mutex              mutex{};
3938
    ::std::condition_variable condition{};
3939
    opstate_base*             front{};
3940
    opstate_base*             back{};
3941

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

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

NEW
3973
    auto get_scheduler() -> scheduler { return {this}; }
×
3974

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

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

3996
// ----------------------------------------------------------------------------
3997

3998
// ----------------------------------------------------------------------------
3999

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

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

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

4045
// ----------------------------------------------------------------------------
4046

4047
// ----------------------------------------------------------------------------
4048

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

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

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

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

4129
// ----------------------------------------------------------------------------
4130

4131
// ----------------------------------------------------------------------------
4132

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

4144
// ----------------------------------------------------------------------------
4145

4146
// ----------------------------------------------------------------------------
4147

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

4157
// ----------------------------------------------------------------------------
4158

4159
// ----------------------------------------------------------------------------
4160

4161
namespace beman::execution::detail {
4162
inline constexpr struct stop_when_t {
4163
    template <::beman::execution::sender Sndr, ::beman::execution::stoppable_token Tok>
4164
    struct sender;
4165

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

4171
template <::beman::execution::sender Sndr, ::beman::execution::stoppable_token Tok>
4172
struct beman::execution::detail::stop_when_t::sender {
4173
    using sender_concept = ::beman::execution::sender_t;
4174

4175
    stop_when_t               stop_when{};
4176
    std::remove_cvref_t<Tok>  tok;
4177
    std::remove_cvref_t<Sndr> sndr;
4178

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

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

4209
        struct receiver {
4210
            using receiver_concept = ::beman::execution::receiver_t;
4211
            base_state* st;
4212

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

4227
        token1_t                                                               tok;
4228
        base_state                                                             base;
4229
        std::optional<::beman::execution::stop_callback_for_t<token1_t, cb_t>> cb1;
4230
        std::optional<::beman::execution::stop_callback_for_t<token2_t, cb_t>> cb2;
4231
        inner_state_t                                                          inner_state;
4232

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

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

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

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

4266
// ----------------------------------------------------------------------------
4267

4268
// ----------------------------------------------------------------------------
4269

4270
namespace beman::execution::detail {
4271
struct token_test_env {};
4272

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

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

4296
// ----------------------------------------------------------------------------
4297

4298
// ----------------------------------------------------------------------------
4299

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

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

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

4331
// ----------------------------------------------------------------------------
4332

4333
// ----------------------------------------------------------------------------
4334

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

4346
// ----------------------------------------------------------------------------
4347

4348
// ----------------------------------------------------------------------------
4349

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

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

4401
    template <typename Sender, typename Receiver>
4402
    struct connect_helper {
4403
        ::beman::execution::detail::basic_state<Sender, Receiver>* op;
4404

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

4419
    static auto use(auto&&...) {}
4420

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

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

4455
// ----------------------------------------------------------------------------
4456

4457
// ----------------------------------------------------------------------------
4458

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

4475
// ----------------------------------------------------------------------------
4476

4477
// ----------------------------------------------------------------------------
4478

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

4490
// ----------------------------------------------------------------------------
4491

4492
// ----------------------------------------------------------------------------
4493

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

4508
// ----------------------------------------------------------------------------
4509

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

4524
// ----------------------------------------------------------------------------
4525

4526
// ----------------------------------------------------------------------------
4527

4528
namespace beman::execution::detail {
4529
struct sync_wait_env {
4530
    ::beman::execution::run_loop* loop{};
4531

NEW
4532
    auto query(::beman::execution::get_scheduler_t) const noexcept { return this->loop->get_scheduler(); }
×
NEW
4533
    auto query(::beman::execution::get_delegation_scheduler_t) const noexcept { return this->loop->get_scheduler(); }
×
4534
};
4535

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

4543
template <typename Sender>
4544
struct sync_wait_state {
4545
    ::beman::execution::run_loop loop{};
4546
    ::std::exception_ptr         error{};
4547

4548
    ::beman::execution::detail::sync_wait_result_type<Sender> result{};
4549
};
4550

4551
template <typename Sender>
4552
struct sync_wait_receiver {
4553
    using receiver_concept = ::beman::execution::receiver_t;
4554

4555
    ::beman::execution::detail::sync_wait_state<Sender>* state{};
4556

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

4573
    auto get_env() const noexcept -> ::beman::execution::detail::sync_wait_env {
4574
        return ::beman::execution::detail::sync_wait_env{&this->state->loop};
4575
    }
4576
};
4577

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

4586
        state.loop.run();
4587
        if (state.error) {
4588
            ::std::rethrow_exception(state.error);
4589
        }
4590
        return ::std::move(state.result);
4591
    }
4592

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

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

4662
// ----------------------------------------------------------------------------
4663

4664
// ----------------------------------------------------------------------------
4665

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

4682
    using inner_ops_t = ::beman::execution::detail::connect_all_result<Sender, Receiver>;
4683
    inner_ops_t inner_ops;
4684

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

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

4712
// ----------------------------------------------------------------------------
4713

4714
// ----------------------------------------------------------------------------
4715

4716
namespace beman::execution::detail {
4717
template <typename Sender, typename Env>
4718
struct single_sender_value_type_helper;
4719

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

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

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

4752
template <typename Sender, typename Env>
4753
using single_sender_value_type = typename single_sender_value_type_helper<Sender, Env>::type;
4754
} // namespace beman::execution::detail
4755

4756
// ----------------------------------------------------------------------------
4757

4758
// ----------------------------------------------------------------------------
4759

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

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

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

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

4845
// ----------------------------------------------------------------------------
4846

4847
// ----------------------------------------------------------------------------
4848

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

4855
// ----------------------------------------------------------------------------
4856

4857
// ----------------------------------------------------------------------------
4858

4859
namespace beman::execution::detail {
4860
struct make_sender_empty {};
4861

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

4871
// ----------------------------------------------------------------------------
4872

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

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

4891
    struct awaitable_receiver {
4892
        using receiver_concept = ::beman::execution::receiver_t;
4893

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

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

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

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

4929
        data_type* result_ptr_;
4930
    };
4931
    using op_state_type = ::beman::execution::connect_result_t<Sndr, awaitable_receiver>;
4932

4933
    data_type     result{};
4934
    op_state_type state;
4935

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

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

4966
namespace beman::execution::detail {
4967

4968
struct bulk_t : ::beman::execution::sender_adaptor_closure<bulk_t> {
4969

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

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

4981
        auto domain{::beman::execution::detail::get_domain_early(sndr)};
4982

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

4990
template <>
4991
struct impls_for<bulk_t> : ::beman::execution::detail::default_impls {
4992

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

5004
            using s_type = std::remove_cvref_t<decltype(shape)>;
5005

5006
            constexpr bool nothrow = noexcept(f(s_type(shape), args...));
5007

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

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

5027
template <typename, typename, typename>
5028
struct fixed_completions_helper;
5029

5030
template <typename F, typename Shape, typename... Args>
5031
struct fixed_completions_helper<F, Shape, completion_signatures<Args...>> {
5032

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

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

5050
template <typename F, typename Shape, typename Completions>
5051
using fixed_completions = typename fixed_completions_helper<F, Shape, Completions>::type;
5052

5053
template <class Shape, class F, class Sender, class Env>
5054
struct completion_signatures_for_impl<
5055
    ::beman::execution::detail::
5056
        basic_sender<::beman::execution::detail::bulk_t, ::beman::execution::detail::product_type<Shape, F>, Sender>,
5057
    Env> {
5058

5059
    using completions = decltype(get_completion_signatures(std::declval<Sender>(), std::declval<Env>()));
5060
    using type        = ::beman::execution::detail::meta::unique<
5061
               ::beman::execution::detail::meta::combine<fixed_completions<F, Shape, completions>>>;
5062
};
5063

5064
} // namespace beman::execution::detail
5065

5066
namespace beman::execution {
5067

5068
export using bulk_t = ::beman::execution::detail::bulk_t;
5069
export inline constexpr ::beman::execution::bulk_t bulk{};
5070

5071
} // namespace beman::execution
5072

5073
// ----------------------------------------------------------------------------
5074

5075
namespace beman::execution::detail {
5076
export struct into_variant_t {
5077
    template <::beman::execution::sender Sender>
5078
    auto operator()(Sender&& sender) const {
5079
        auto domain{::beman::execution::detail::get_domain_early(sender)};
5080
        (void)domain;
5081
        return ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender));
5082
        // return ::beman::execution::transform_sender(
5083
        //     ::std::move(domain),
5084
        //     ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender))
5085
        //);
5086
    }
5087
};
5088

5089
template <>
5090
struct impls_for<::beman::execution::detail::into_variant_t> : ::beman::execution::detail::default_impls {
5091
    static constexpr auto get_state = []<typename Sender, typename Receiver>(Sender&&, Receiver&&) noexcept
5092
        -> ::std::type_identity<::beman::execution::value_types_of_t<::beman::execution::detail::child_type<Sender>,
5093
                                                                     ::beman::execution::env_of_t<Receiver>>> {
5094
        return {};
5095
    };
5096
    static constexpr auto complete = []<typename State, typename Tag, typename... Args>(
5097
                                         auto, State, auto& receiver, Tag, Args&&... args) noexcept -> void {
5098
        if constexpr (::std::same_as<Tag, ::beman::execution::set_value_t>) {
5099
            using variant_type = typename State::type;
5100
            using tuple_type   = ::beman::execution::detail::decayed_tuple<Args...>;
5101
            try {
5102
                if constexpr (sizeof...(Args) == 0u)
5103
                    ::beman::execution::set_value(::std::move(receiver));
5104
                else
5105
                    ::beman::execution::set_value(::std::move(receiver),
5106
                                                  variant_type(tuple_type{::std::forward<Args>(args)...}));
5107
            } catch (...) {
5108
                ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5109
            }
5110

5111
        } else {
5112
            Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
5113
        }
5114
    };
5115
};
5116

5117
template <typename Sender, typename State, typename Env>
5118
struct completion_signatures_for_impl<
5119
    ::beman::execution::detail::basic_sender<::beman::execution::detail::into_variant_t, State, Sender>,
5120
    Env> {
5121
    using variant_type = ::beman::execution::value_types_of_t<Sender, Env>;
5122
    using value_types =
5123
        ::std::conditional_t<::std::same_as<variant_type, ::beman::execution::detail::empty_variant>,
5124
                             ::beman::execution::completion_signatures<>,
5125
                             ::beman::execution::completion_signatures<::beman::execution::set_value_t(variant_type)>>;
5126
    template <typename... E>
5127
    using make_error_types = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
5128

5129
    using error_types = ::beman::execution::error_types_of_t<Sender, Env, make_error_types>;
5130
    using stopped_types =
5131
        ::std::conditional_t<::beman::execution::sends_stopped<Sender, Env>,
5132
                             ::beman::execution::completion_signatures<::beman::execution::set_stopped_t()>,
5133
                             ::beman::execution::completion_signatures<>>;
5134
    using type = ::beman::execution::detail::meta::
5135
        combine<value_types, ::beman::execution::detail::meta::combine<error_types, stopped_types>>;
5136
};
5137
} // namespace beman::execution::detail
5138

5139
namespace beman::execution {
5140
export using into_variant_t = ::beman::execution::detail::into_variant_t;
5141
export inline constexpr into_variant_t into_variant{};
5142
} // namespace beman::execution
5143

5144
// ----------------------------------------------------------------------------
5145

5146
// ----------------------------------------------------------------------------
5147

5148
namespace beman::execution::detail {
5149
template <typename Completion, typename... T>
5150
concept just_size = (!::std::same_as<Completion, ::beman::execution::set_error_t> or 1u == sizeof...(T)) &&
5151
                    (!::std::same_as<Completion, ::beman::execution::set_stopped_t> or 0u == sizeof...(T));
5152
template <typename Completion>
5153
struct just_t {
5154
    template <typename... T>
5155
        requires ::beman::execution::detail::just_size<Completion, T...> &&
5156
                 (::beman::execution::detail::movable_value<T> && ...)
5157
    auto operator()(T&&... arg) const {
5158
        return ::beman::execution::detail::make_sender(
5159
            *this, ::beman::execution::detail::product_type{::std::forward<T>(arg)...});
5160
    }
5161
    template <::beman::execution::sender Sender>
5162
    static auto affine_on(Sender&& sndr, const auto&) noexcept {
5163
        return ::std::forward<Sender>(sndr);
5164
    }
5165
};
5166

5167
template <typename Completion, typename... T, typename Env>
5168
struct completion_signatures_for_impl<
5169
    ::beman::execution::detail::basic_sender<just_t<Completion>, ::beman::execution::detail::product_type<T...>>,
5170
    Env> {
5171
    using type = ::beman::execution::completion_signatures<Completion(T...)>;
5172
};
5173

5174
template <typename Completion>
5175
struct impls_for<just_t<Completion>> : ::beman::execution::detail::default_impls {
5176
    static constexpr auto start = []<typename State>(State& state, auto& receiver) noexcept -> void {
5177
        [&state, &receiver]<::std::size_t... I>(::std::index_sequence<I...>) {
5178
            Completion()(::std::move(receiver), ::std::move(state.template get<I>())...);
5179
        }(::std::make_index_sequence<State::size()>{});
5180
    };
5181
};
5182
} // namespace beman::execution::detail
5183

5184
namespace beman::execution {
5185
export using just_t         = ::beman::execution::detail::just_t<::beman::execution::set_value_t>;
5186
export using just_error_t   = ::beman::execution::detail::just_t<::beman::execution::set_error_t>;
5187
export using just_stopped_t = ::beman::execution::detail::just_t<::beman::execution::set_stopped_t>;
5188

5189
/*!
5190
 * \brief <code>just(_arg_...)</code> yields a sender completing with <code>set_value_t(_Arg_...)</code>
5191
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
5192
 *
5193
 * \details
5194
 * `just` is a callable object of type `just_t`. Invoking <code>just(_arg_...)</code> yields a sender which stores its
5195
 * arguments and produces a value completion with these arguments when started. This sender completes synchronously
5196
 * when started.
5197
 *
5198
 * <h4>Usage</h4>
5199
 * <pre>
5200
 * just(<i>arg</i>...)
5201
 * </pre>
5202
 *
5203
 * Above <code>_Arg_...</code> is a pack of the types of <code>_arg_...</code>
5204
 * after removing top-level `const` and reference qualifications
5205
 * (<code>std::remove_cvref_t&lt;decltype(_arg_)&gt;...</code>).
5206
 *
5207
 * <h4>Completions Signatures</h4>
5208
 * <pre>
5209
 * completion_signatures<
5210
 *     set_value_t(<i>Arg</i>...)
5211
 * >;
5212
 * </pre>
5213
 *
5214
 * <h4>Example</h4>
5215
 *
5216
 * The normal use of <code>just(_args_...)</code> is as the starting
5217
 * point of a work graph. Various other examples will use `just` as
5218
 * their starting. The example below create a sender yielding three
5219
 * values and awaits the completion using <code>sync_wait(_sender_)</code>:
5220
 * for a value completion of <code>_sender_</code> it will yield an
5221
 * <code>std::optional&lt;std::tuple&lt;_Args_...&gt;&gt;</code> with the
5222
 * `tuple` containing the value copied/moved from the original arguments
5223
 * (an `optional` is returned to indicate cancellation).
5224
 *
5225
 * <pre example="doc-just.cpp">
5226
 * #include <beman/execution/execution.hpp>
5227
 * #include <cassert>
5228
 * #include <string>
5229
 * using namespace std::string_literals;
5230
 *
5231
 * int main() {
5232
 *     auto result = ex::sync_wait(ex::just(17, "hello"s, true));
5233
 *     assert(result);
5234
 *     assert(*result == std::tuple(17, "hello"s, true));
5235
 * }
5236
 * </pre>
5237
 */
5238
export inline constexpr ::beman::execution::just_t just{};
5239

5240
/*!
5241
 * \brief <code>just_error(_error_)</code> yields a sender completing with <code>set_error_t(_Error_)</code>
5242
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
5243
 *
5244
 * \details
5245
 * `just_error` is a callable object of type `just_error_t`. Invoking <code>just_error(_error_)</code> yields a sender
5246
 * which stores its argument and produces an error completion with this error when started. This sender completes
5247
 * synchronously when started.
5248
 *
5249
 * <h4>Usage</h4>
5250
 * <pre>
5251
 * just_error(<i>error</i>)
5252
 * </pre>
5253
 *
5254
 * The type <code>_Error_</code> used above is the type of <code>_error_</code>
5255
 * after removing top-level `const` and reference qualifications
5256
 * (<code>std::remove_cvref_t&lt;decltype(error)&gt;</code>).
5257
 *
5258
 * <h4>Completions Signatures</h4>
5259
 * <pre>
5260
 * completion_signatures<
5261
 *     set_error_t(<i>Error</i>)
5262
 * >;
5263
 * </pre>
5264
 *
5265
 * <h4>Example</h4>
5266
 *
5267
 * The normal use of <code>just_error(_error_)</code> is to report an
5268
 * error as the result of some work in a work graph. It would, e.g., be
5269
 * used as the completion produced by `let_value`.
5270
 * The example below creates a sender yielding an `std::error_code` on the error
5271
 * channel and
5272
 * uses that as the input for `upon_error` consuming the error and producing
5273
 * a value completion: using <code>sync_wait(just_error(_error_))</code>
5274
 * directly doesn't work because `sync_wait` requires exactly one value completion
5275
 * from its argument and `set_error` only has an error completion. The function used with `upon_error` verifies that
5276
 * the expected code was produced and also sets the flag `had_error` indicating it was called at all. This flag is
5277
 * checked after waiting for the result in `sync_wait`.
5278
 *
5279
 * <pre example="doc-just_error.cpp">
5280
 * #include <beman/execution/execution.hpp>
5281
 * #include <system_error>
5282
 * #include <cassert>
5283
 * namespace ex = beman::execution;
5284
 *
5285
 * int main() {
5286
 *     bool had_error{false};
5287
 *     auto result = ex::sync_wait(ex::just_error(std::error_code(17, std::system_category())) |
5288
 *                                 ex::upon_error([&](std::error_code ec) {
5289
 *                                     assert(ec.value() == 17);
5290
 *                                     had_error = true;
5291
 *                                 }));
5292
 *     assert(had_error);
5293
 * }
5294
 * </pre>
5295
 */
5296
export inline constexpr ::beman::execution::just_error_t just_error{};
5297

5298
/*!
5299
 * \brief <code>just_stopped()</code> yields a sender completing with <code>set_stopped_t()</code>
5300
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
5301
 *
5302
 * \details
5303
 * `just_stopped` is a callable object of type `just_stopped_t`. Invoking <code>just_stopped()</code> yields a sender
5304
 * which produces a cancellation completion when started. This sender completes synchronously when started.
5305
 *
5306
 * <h4>Usage</h4>
5307
 * <pre>
5308
 * just_stopped()
5309
 * </pre>
5310
 *
5311
 * <h4>Completions Signatures</h4>
5312
 * <pre>
5313
 * completion_signatures<
5314
 *     set_stopped_t()
5315
 * >;
5316
 * </pre>
5317
 *
5318
 * <h4>Example</h4>
5319
 *
5320
 * The normal use of <code>just_stopped()</code> is to report a
5321
 * cancellation as the result of some work in a work graph. It would, e.g., be
5322
 * used as the completion produced by `let_value`.
5323
 * The example below creates a sender yielding a completion on the cancellation
5324
 * channel and
5325
 * uses that as the input for `upon_stopped` consuming the cancellation and producing
5326
 * a value completion: using <code>sync_wait(just_stopped())</code>
5327
 * directly doesn't work because `sync_wait` requires exactly one value completion
5328
 * from its argument and `set_stopped` only has a cancellation completion. The function used with `upon_stopped`
5329
 * sets the flag `had_stopped` indicating it
5330
 * was called at all. This flag is checked after waiting for the result
5331
 * in `sync_wait`.
5332
 *
5333
 * <pre example="doc-just_error.cpp">
5334
 * #include <beman/execution/execution.hpp>
5335
 * #include <system_error>
5336
 * #include <cassert>
5337
 * namespace ex = beman::execution;
5338
 *
5339
 * int main() {
5340
 *     bool had_stopped{false};
5341
 *     auto result = ex::sync_wait(ex::just_error(std::error_code(17, std::system_category())) |
5342
 *                                 ex::upon_error([&](std::error_code ec) {
5343
 *                                     assert(ec.value() == 17);
5344
 *                                     had_stopped = true;
5345
 *                                 }));
5346
 *     assert(had_stopped);
5347
 * }
5348
 * </pre>
5349
 */
5350
export inline constexpr ::beman::execution::just_stopped_t just_stopped{};
5351
} // namespace beman::execution
5352

5353
// ----------------------------------------------------------------------------
5354

5355
// ----------------------------------------------------------------------------
5356

5357
namespace beman::execution::detail {
5358
template <typename Completion>
5359
struct let_t {
5360
    template <::beman::execution::detail::movable_value Fun>
5361
    auto operator()(Fun&& fun) const {
5362
        return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Fun>(fun)};
5363
    }
5364
    template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
5365
    auto operator()(Sender&& sender, Fun&& fun) const {
5366
        auto domain(::beman::execution::detail::get_domain_early(sender));
5367
        return ::beman::execution::detail::transform_sender(
5368
            domain,
5369
            ::beman::execution::detail::make_sender(*this, ::std::forward<Fun>(fun), std::forward<Sender>(sender)));
5370
    }
5371

5372
    template <typename Sender>
5373
    static auto env(Sender&& sender) {
5374
        if constexpr (requires {
5375
                          ::beman::execution::detail::sched_env(
5376
                              ::beman::execution::get_completion_scheduler<Completion>(
5377
                                  ::beman::execution::get_env(sender)));
5378
                      })
5379
            return ::beman::execution::detail::sched_env(
5380
                ::beman::execution::get_completion_scheduler<Completion>(::beman::execution::get_env(sender)));
5381
        else if constexpr (requires {
5382
                               ::beman::execution::detail::make_env(
5383
                                   ::beman::execution::get_domain,
5384
                                   ::beman::execution::get_domain(::beman::execution::get_env(sender)));
5385
                           })
5386
            return ::beman::execution::detail::make_env(
5387
                ::beman::execution::get_domain, ::beman::execution::get_domain(::beman::execution::get_env(sender)));
5388
        else
5389
            return ::beman::execution::env<>{};
5390
    }
5391
    template <typename Sender, typename Env>
5392
    static auto join_env(Sender&& sender, Env&& e) -> decltype(auto) {
5393
        return ::beman::execution::detail::join_env(env(sender), ::beman::execution::detail::fwd_env(e));
5394
    }
5395
};
5396

5397
template <typename Completion>
5398
struct impls_for<::beman::execution::detail::let_t<Completion>> : ::beman::execution::detail::default_impls {
5399

5400
    template <typename Receiver, typename Env>
5401
    struct let_receiver {
5402
        using receiver_concept = ::beman::execution::receiver_t;
5403

5404
        Receiver& receiver;
5405
        Env       env;
5406

5407
        auto get_env() const noexcept -> decltype(auto) {
5408
            return ::beman::execution::detail::join_env(
5409
                this->env, ::beman::execution::detail::fwd_env(::beman::execution::get_env(this->receiver)));
5410
        }
5411
        template <typename Error>
5412
        auto set_error(Error&& error) && noexcept -> void {
5413
            ::beman::execution::set_error(::std::move(this->receiver), ::std::forward<Error>(error));
5414
        }
5415
        auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(::std::move(this->receiver)); }
5416
        template <typename... Args>
5417
        auto set_value(Args&&... args) && noexcept -> void {
5418
            ::beman::execution::set_value(::std::move(this->receiver), ::std::forward<Args>(args)...);
5419
        }
5420
    };
5421

5422
    template <typename>
5423
    struct filter_pred : ::std::false_type {};
5424
    template <typename... A>
5425
    struct filter_pred<Completion(A...)> : ::std::true_type {};
5426
    template <typename>
5427
    struct to_tuple;
5428
    template <typename C, typename... A>
5429
    struct to_tuple<C(A...)> {
5430
        using type = ::beman::execution::detail::decayed_tuple<A...>;
5431
    };
5432
    template <typename T>
5433
    using to_tuple_t = typename to_tuple<T>::type;
5434
    template <typename Fun, typename Receiver, typename Env>
5435
    struct to_state {
5436
        template <typename Tuple>
5437
        using trans =
5438
            decltype(::beman::execution::connect(::std::apply(::std::declval<Fun>(), ::std::declval<Tuple>()),
5439
                                                 ::std::declval<let_receiver<Receiver, Env>>()));
5440
    };
5441

5442
    static constexpr auto get_state{[]<typename Sender, typename Receiver>(Sender&& sender, Receiver&& receiver) {
5443
        auto& fun{sender.template get<1>()};
5444
        auto& child{sender.template get<2>()};
5445

5446
        using fun_t   = ::std::remove_cvref_t<decltype(fun)>;
5447
        using child_t = ::std::remove_cvref_t<decltype(child)>;
5448
        using env_t   = decltype(::beman::execution::detail::let_t<Completion>::env(child));
5449
        using sigs_t = ::beman::execution::completion_signatures_of_t<child_t, ::beman::execution::env_of_t<Receiver>>;
5450
        using comp_sigs_t = ::beman::execution::detail::meta::filter<filter_pred, sigs_t>;
5451
        using type_list_t = ::beman::execution::detail::meta::to<::std::variant, comp_sigs_t>;
5452
        using tuples_t    = ::beman::execution::detail::meta::transform<to_tuple_t, type_list_t>;
5453
        using unique_t    = ::beman::execution::detail::meta::unique<tuples_t>;
5454
        using args_t      = ::beman::execution::detail::meta::prepend<std::monostate, unique_t>;
5455
        using ops_t       = ::beman::execution::detail::meta::prepend<
5456
                  ::std::monostate,
5457
                  ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::transform<
5458
                      to_state<fun_t, ::std::remove_cvref_t<Receiver>, env_t>::template trans,
5459
                      tuples_t>>>;
5460

5461
        struct state_t {
5462
            fun_t  fun;
5463
            env_t  env;
5464
            args_t args;
5465
            ops_t  ops2;
5466
        };
5467
        return state_t{beman::execution::detail::allocator_aware_move(
5468
                           ::beman::execution::detail::forward_like<Sender>(fun), receiver),
5469
                       ::beman::execution::detail::let_t<Completion>::env(child),
5470
                       {},
5471
                       {}};
5472
    }};
5473
    template <typename Receiver, typename... Args>
5474
    static auto
5475
    let_bind(auto& state, Receiver& receiver, Args&&... args) noexcept(noexcept(::beman::execution::connect(
5476
        ::std::apply(::std::move(state.fun),
5477
                     ::std::move(state.args.template emplace<::beman::execution::detail::decayed_tuple<Args...>>(
5478
                         ::std::forward<Args>(args)...))),
5479
        let_receiver<Receiver, decltype(state.env)>{receiver, state.env}))) {
5480
        using args_t = ::beman::execution::detail::decayed_tuple<Args...>;
5481
        auto mkop{[&] {
5482
            return ::beman::execution::connect(
5483
                ::std::apply(::std::move(state.fun),
5484
                             ::std::move(state.args.template emplace<args_t>(::std::forward<Args>(args)...))),
5485
                let_receiver<Receiver, decltype(state.env)>{receiver, state.env});
5486
        }};
5487
        ::beman::execution::start(
5488
            state.ops2.template emplace<decltype(mkop())>(beman::execution::detail::emplace_from{mkop}));
5489
    }
5490
    static constexpr auto complete{
5491
        []<class Tag, class... Args>(auto, auto& state, auto& receiver, Tag, Args&&... args) {
5492
            if constexpr (::std::same_as<Tag, Completion>) {
5493
                try {
5494
                    let_bind(state, receiver, ::std::forward<Args>(args)...);
5495
                } catch (...) {
5496
                    if constexpr (not noexcept(let_bind(state, receiver, ::std::forward<Args>(args)...)))
5497
                        ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5498
                }
5499
            } else {
5500
                Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
5501
            }
5502
        }};
5503
};
5504

5505
template <typename Completion, typename Fun, typename Sender, typename Env>
5506
struct completion_signatures_for_impl<
5507
    ::beman::execution::detail::basic_sender<::beman::execution::detail::let_t<Completion>, Fun, Sender>,
5508
    Env> {
5509
    template <typename>
5510
    struct other_completion : ::std::true_type {};
5511
    template <typename... A>
5512
    struct other_completion<Completion(A...)> : ::std::false_type {};
5513
    template <typename>
5514
    struct matching_completion : ::std::false_type {};
5515
    template <typename... A>
5516
    struct matching_completion<Completion(A...)> : ::std::true_type {};
5517

5518
    template <typename>
5519
    struct apply_decayed;
5520
    template <typename C, typename... A>
5521
    struct apply_decayed<C(A...)> {
5522
        using sender_type = ::beman::execution::detail::call_result_t<Fun, ::std::decay_t<A>...>;
5523
    };
5524
    template <typename>
5525
    struct get_completions;
5526
    template <template <typename...> class L, typename... C>
5527
    struct get_completions<L<C...>> {
5528
        using type = ::beman::execution::detail::meta::unique<
5529
            ::beman::execution::detail::meta::combine<decltype(::beman::execution::get_completion_signatures(
5530
                std::declval<typename apply_decayed<C>::sender_type>(), std::declval<Env>()))...>>;
5531
    };
5532

5533
    using upstream_env = decltype(::beman::execution::detail::let_t<Completion>::join_env(::std::declval<Sender>(),
5534
                                                                                          ::std::declval<Env>()));
5535
    using upstream_completions = decltype(::beman::execution::get_completion_signatures(
5536
        ::std::declval<Sender>(), ::std::declval<upstream_env>()));
5537
    using other_completions    = ::beman::execution::detail::meta::filter<other_completion, upstream_completions>;
5538
    using matching_completions = ::beman::execution::detail::meta::filter<matching_completion, upstream_completions>;
5539
    using type = ::beman::execution::detail::meta::combine<typename get_completions<matching_completions>::type,
5540
                                                           other_completions>;
5541
};
5542
} // namespace beman::execution::detail
5543

5544
namespace beman::execution {
5545
export using let_error_t   = ::beman::execution::detail::let_t<::beman::execution::set_error_t>;
5546
export using let_stopped_t = ::beman::execution::detail::let_t<::beman::execution::set_stopped_t>;
5547
export using let_value_t   = ::beman::execution::detail::let_t<::beman::execution::set_value_t>;
5548

5549
export inline constexpr ::beman::execution::let_error_t   let_error{};
5550
export inline constexpr ::beman::execution::let_stopped_t let_stopped{};
5551
export inline constexpr ::beman::execution::let_value_t   let_value{};
5552
} // namespace beman::execution
5553

5554
// ----------------------------------------------------------------------------
5555

5556
// ----------------------------------------------------------------------------
5557

5558
namespace beman::execution::detail {
5559
struct read_env_t {
5560
    auto operator()(auto&& query) const { return ::beman::execution::detail::make_sender(*this, query); }
5561
    template <::beman::execution::sender Sender>
5562
    static auto affine_on(Sender&& sndr, const auto&) noexcept {
5563
        return ::std::forward<Sender>(sndr);
5564
    }
5565
};
5566

5567
template <>
5568
struct impls_for<::beman::execution::detail::read_env_t> : ::beman::execution::detail::default_impls {
5569
    static constexpr auto start = [](auto query, auto& receiver) noexcept -> void {
5570
        try {
5571
            auto env{::beman::execution::get_env(receiver)};
5572
            ::beman::execution::set_value(::std::move(receiver), query(env));
5573
        } catch (...) {
5574
            ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5575
        }
5576
    };
5577
};
5578

5579
template <typename Query, typename Env>
5580
struct completion_signatures_for_impl<
5581
    ::beman::execution::detail::basic_sender<::beman::execution::detail::read_env_t, Query>,
5582
    Env> {
5583
    using set_value_type =
5584
        ::beman::execution::set_value_t(decltype(::std::declval<Query>()(::std::as_const(::std::declval<Env>()))));
5585
    using set_error_type = ::beman::execution::set_error_t(::std::exception_ptr);
5586
    using type           = ::std::conditional_t<noexcept(::std::declval<Query>()(::std::declval<const Env&>())),
5587
                                                ::beman::execution::completion_signatures<set_value_type>,
5588
                                                ::beman::execution::completion_signatures<set_value_type, set_error_type>>;
5589
};
5590
} // namespace beman::execution::detail
5591

5592
namespace beman::execution {
5593
export using read_env_t = beman::execution::detail::read_env_t;
5594
export inline constexpr read_env_t read_env{};
5595
} // namespace beman::execution
5596

5597
// ----------------------------------------------------------------------------
5598

5599
// ----------------------------------------------------------------------------
5600

5601
namespace beman::execution::detail {
5602
struct schedule_from_t {
5603
    template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender>
5604
    auto operator()(Scheduler&& scheduler, Sender&& sender) const {
5605
        auto domain{::beman::execution::detail::query_with_default(
5606
            ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})};
5607
        return ::beman::execution::transform_sender(
5608
            domain,
5609
            ::beman::execution::detail::make_sender(
5610
                *this, ::std::forward<Scheduler>(scheduler), ::std::forward<Sender>(sender)));
5611
    }
5612
};
5613

5614
template <>
5615
struct impls_for<::beman::execution::detail::schedule_from_t> : ::beman::execution::detail::default_impls {
5616
    template <typename State>
5617
    struct upstream_receiver {
5618
        using receiver_concept = ::beman::execution::receiver_t;
5619
        State* state;
5620

5621
        auto set_value() && noexcept -> void {
5622
            try {
5623
                ::std::visit(
5624
                    [this]<typename Tuple>(Tuple& result) noexcept -> void {
5625
                        if constexpr (!::std::same_as<::std::monostate, Tuple>) {
5626
                            ::std::apply(
5627
                                [this](auto&& tag, auto&&... args) {
5628
                                    tag(::std::move(this->state->receiver), ::std::move(args)...);
5629
                                },
5630
                                result);
5631
                        }
5632
                    },
5633
                    state->async_result);
5634
            } catch (...) {
5635
                ::beman::execution::set_error(::std::move(state->receiver), ::std::current_exception());
5636
            }
5637
        }
5638

5639
        template <typename Error>
5640
        auto set_error(Error&& err) && noexcept -> void {
5641
            ::beman::execution::set_error(std::move(state->receiver), std::forward<Error>(err));
5642
        }
5643

5644
        auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(std::move(state->receiver)); }
5645

5646
        auto get_env() const noexcept -> decltype(auto) {
5647
            return ::beman::execution::detail::fwd_env(::beman::execution::get_env(state->receiver));
5648
        }
5649
    };
5650
    template <typename Receiver, typename Variant>
5651
    struct state_base {
5652
        Receiver receiver;
5653
        Variant  async_result{};
5654
    };
5655
    template <typename Receiver, typename Scheduler, typename Variant>
5656
    struct state_type : state_base<Receiver, Variant> {
5657
        using receiver_t = upstream_receiver<state_base<Receiver, Variant>>;
5658
        using operation_t =
5659
            ::beman::execution::connect_result_t<::beman::execution::schedule_result_t<Scheduler>, receiver_t>;
5660
        operation_t op_state;
5661

5662
        static constexpr bool nothrow() {
5663
            return noexcept(::beman::execution::connect(::beman::execution::schedule(::std::declval<Scheduler>()),
5664
                                                        receiver_t{nullptr}));
5665
        }
5666
        explicit state_type(Scheduler& sch, Receiver& rcvr) noexcept(nothrow())
5667
            : state_base<Receiver, Variant>{rcvr},
5668
              op_state(::beman::execution::connect(::beman::execution::schedule(sch), receiver_t{this})) {}
5669
    };
5670

5671
    static constexpr auto get_attrs{[](const auto& data, const auto& child) noexcept -> decltype(auto) {
5672
        return ::beman::execution::detail::join_env(
5673
            ::beman::execution::detail::sched_attrs(data),
5674
            ::beman::execution::detail::fwd_env(::beman::execution::get_env(child)));
5675
    }};
5676
    static constexpr auto get_state{
5677
        []<typename Sender, typename Receiver>(Sender&& sender, Receiver& receiver) //-dk:TODO noexcept(see below)
5678
            requires ::beman::execution::sender_in<::beman::execution::detail::child_type<Sender>,
5679
                                                   ::beman::execution::env_of_t<Receiver>>
5680
        {
5681
            auto sch{sender.template get<1>()};
5682

5683
            using sched_t   = ::std::remove_cvref_t<decltype(sch)>;
5684
            using variant_t = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
5685
                ::std::monostate,
5686
                ::beman::execution::detail::meta::transform<
5687
                    ::beman::execution::detail::as_tuple_t,
5688
                    ::beman::execution::detail::meta::to<::std::variant,
5689
                                                         ::beman::execution::detail::meta::combine<
5690
                                                             ::beman::execution::completion_signatures_of_t<
5691
                                                                 ::beman::execution::detail::child_type<Sender>,
5692
                                                                 ::beman::execution::env_of_t<Receiver>>,
5693
                                                             //-dk:TODO get proper error completion signatures
5694
                                                             ::beman::execution::completion_signatures<
5695
                                                                 ::beman::execution::set_error_t(::std::exception_ptr),
5696
                                                                 ::beman::execution::set_stopped_t()>>>>>>;
5697

5698
            return state_type<Receiver, sched_t, variant_t>(sch, receiver);
5699
        }};
5700
    static constexpr auto complete{
5701
        []<typename Tag, typename... Args>(auto, auto& state, auto& receiver, Tag, Args&&... args) noexcept -> void {
5702
            using result_t         = ::beman::execution::detail::decayed_tuple<Tag, Args...>;
5703
            constexpr bool nothrow = ::std::is_nothrow_constructible_v<result_t, Tag, Args...>;
5704

5705
            try {
5706
                [&]() noexcept(nothrow) {
5707
                    state.async_result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
5708
                }();
5709
            } catch (...) {
5710
                if constexpr (not nothrow)
5711
                    ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
5712
            }
5713

5714
            if (state.async_result.index() == 0)
5715
                return;
5716

5717
            ::beman::execution::start(state.op_state);
5718
        }};
5719
};
5720

5721
template <typename Scheduler, typename Sender, typename Env>
5722
struct completion_signatures_for_impl<
5723
    ::beman::execution::detail::basic_sender<::beman::execution::detail::schedule_from_t, Scheduler, Sender>,
5724
    Env> {
5725
    using scheduler_sender = decltype(::beman::execution::schedule(::std::declval<Scheduler>()));
5726
    template <typename... E>
5727
    using as_set_error = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
5728
    using type         = ::beman::execution::detail::meta::combine<
5729
                decltype(::beman::execution::get_completion_signatures(::std::declval<Sender>(), ::std::declval<Env>())),
5730
                ::beman::execution::error_types_of_t<scheduler_sender, Env, as_set_error>,
5731
                ::beman::execution::completion_signatures<::beman::execution::set_error_t(
5732
            ::std::exception_ptr)> //-dk:TODO this one should be deduced
5733
                >;
5734
};
5735
} // namespace beman::execution::detail
5736

5737
namespace beman::execution {
5738
export using schedule_from_t = beman::execution::detail::schedule_from_t;
5739
export inline constexpr ::beman::execution::schedule_from_t schedule_from{};
5740
} // namespace beman::execution
5741

5742
// ----------------------------------------------------------------------------
5743

5744
// ----------------------------------------------------------------------------
5745

5746
namespace beman::execution::detail {
5747

5748
struct split_impl_t {};
5749
template <>
5750
struct impls_for<split_impl_t> : ::beman::execution::detail::default_impls {
5751

5752
    template <class Sndr>
5753
    struct shared_state;
5754

5755
    struct split_env {
5756
        ::beman::execution::inplace_stop_source* stop_source;
5757

NEW
5758
        ::beman::execution::inplace_stop_token query(::beman::execution::get_stop_token_t) const noexcept {
×
NEW
5759
            return stop_source->get_token();
×
5760
        }
5761
    };
5762

5763
    struct local_state_base {
5764
        local_state_base* next{nullptr};
5765
        virtual auto      notify() noexcept -> void = 0;
5766

5767
        local_state_base() noexcept                                  = default;
5768
        local_state_base(const local_state_base&)                    = delete;
5769
        local_state_base(local_state_base&&)                         = delete;
5770
        auto operator=(const local_state_base&) -> local_state_base& = delete;
5771
        auto operator=(local_state_base&&) -> local_state_base&      = delete;
5772

5773
      protected:
5774
        ~local_state_base() = default;
5775
    };
5776

5777
    template <class Sndr>
5778
    struct split_receiver {
5779
        using receiver_concept = ::beman::execution::receiver_t;
5780

5781
        explicit split_receiver(shared_state<Sndr>* state) noexcept : sh_state(state) {
5782
            if (sh_state) {
5783
                sh_state->inc_ref();
5784
            }
5785
        }
5786

5787
        ~split_receiver() noexcept {
5788
            if (sh_state) {
5789
                sh_state->dec_ref();
5790
            }
5791
        }
5792

5793
        split_receiver(split_receiver&& other) noexcept : sh_state(::std::exchange(other.sh_state, nullptr)) {}
5794
        split_receiver& operator=(split_receiver&& other) noexcept {
5795
            sh_state = ::std::exchange(other.sh_state, nullptr);
5796
            return *this;
5797
        }
5798

5799
        split_receiver(const split_receiver&)            = delete;
5800
        split_receiver& operator=(const split_receiver&) = delete;
5801

5802
        template <class Tag, class... Args>
5803
        void complete(Tag, Args&&... args) noexcept {
5804
            using tuple_t = ::beman::execution::detail::decayed_tuple<Tag, Args...>;
5805
            try {
5806
                sh_state->result.template emplace<tuple_t>(Tag(), ::std::forward<Args>(args)...);
5807
            } catch (...) {
5808
                using tuple_err = ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>;
5809
                sh_state->result.template emplace<tuple_err>(::beman::execution::set_error,
5810
                                                             ::std::current_exception());
5811
            }
5812
            sh_state->notify();
5813
        }
5814

5815
        template <class... Args>
5816
        void set_value(Args&&... args) && noexcept {
5817
            complete(::beman::execution::set_value, ::std::forward<Args>(args)...);
5818
        }
5819

5820
        template <class Error>
5821
        void set_error(Error&& err) && noexcept {
5822
            complete(::beman::execution::set_error, ::std::forward<Error>(err));
5823
        }
5824

5825
        void set_stopped() && noexcept { complete(::beman::execution::set_stopped); }
5826

5827
        split_env get_env() const noexcept { return split_env{&sh_state->stop_src}; }
5828

5829
        shared_state<Sndr>* sh_state;
5830
    };
5831

5832
    // [exec.split-10]
5833
    template <class Sndr>
5834
    struct shared_state {
5835
        template <class... Args>
5836
        using value_tuple = ::std::tuple<::beman::execution::set_value_t, ::std::decay_t<Args>...>;
5837

5838
        template <class... Args>
5839
        using error_tuples = ::std::variant<::std::tuple<::beman::execution::set_error_t, ::std::decay_t<Args>>...>;
5840

5841
        using variant_type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
5842
            ::std::variant<::std::monostate>,
5843
            ::std::variant<::std::tuple<::beman::execution::set_stopped_t>>,
5844
            ::std::variant<::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>>,
5845
            ::beman::execution::error_types_of_t<Sndr, split_env, error_tuples>,
5846
            ::beman::execution::value_types_of_t<Sndr, split_env, value_tuple>>>;
5847

5848
        using state_list_type = ::beman::execution::detail::atomic_intrusive_stack<&local_state_base::next>;
5849

5850
        using child_operation_state = ::beman::execution::connect_result_t<Sndr, split_receiver<Sndr>>;
5851

5852
        explicit shared_state(Sndr&& sndr) {
5853
            try {
5854
                op_state.emplace(::beman::execution::detail::emplace_from{[&] {
5855
                    return ::beman::execution::connect(::std::forward<Sndr>(sndr), split_receiver<Sndr>{this});
5856
                }});
5857
            } catch (...) {
5858
                using error_tuple_t = ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>;
5859
                result.template emplace<error_tuple_t>(::beman::execution::set_error, ::std::current_exception());
5860
                [[maybe_unused]] auto queue = waiting_states.pop_all_and_shutdown();
5861
                assert(queue.empty());
5862
            }
5863
        }
5864

5865
        // We use an intrusive list to store the listeners that are waiting for the operation to complete.
5866
        // if the intrusive list is empty, we start the operation
5867
        // if the intrusive list is not empty, we push the listener to the intrusive list
5868
        // if the intrusive list is shutdown, we immediately notify the listener
5869
        void add_listener(local_state_base* listener) noexcept {
5870
            // try to push the listener to the intrusive list, if the intrusive list is empty and not shutdown, start
5871
            // the operation
5872
            if (auto maybe_ptr = waiting_states.try_push(listener); !maybe_ptr) {
5873
                // the queue is shutdown, immediately notify the listener
5874
                listener->notify();
5875
            } else if (!(*maybe_ptr)) {
5876
                // the operation was not started yet, we are first, and we start it
5877
                assert(op_state);
5878
                if (op_state)
5879
                    ::beman::execution::start(*op_state);
5880
                else
5881
                    std::terminate();
5882
            }
5883
        }
5884

5885
        void notify() noexcept {
5886
            // note: this is different from stdexec.
5887
            // we discussed lifetime durations of operation at LEWG and haven't decided yet
5888
            // whether we should keep the operation alive as long as possible
5889
            op_state.reset();
5890
            auto listeners = waiting_states.pop_all_and_shutdown();
5891
            while (auto listener = listeners.pop()) {
5892
                listener->notify();
5893
            }
5894
        }
5895

5896
        void inc_ref() noexcept { ref_count.fetch_add(1); }
5897

5898
        // This is the most complicated part of the split implementation.
5899
        // On construction, the operation state increments the ref count.
5900
        // Before the operation is started, at least one listener is added to the queue.
5901
        // If the ref count is decreased to one and the there are no listeners in the queue
5902
        // the operation state is the last object holding the shared state and we can safely
5903
        // destroy it
5904
        //
5905
        // it is not thread safe to destroy a split-sender and copy it at the same time
5906
        // this is similar to how a shared_ptr is not thread safe to copy and destroy at the same time
5907
        void dec_ref() noexcept {
5908
            std::size_t count = ref_count.load();
5909
            if (count == 2 && waiting_states.empty_and_not_shutdown()) {
5910
                assert(op_state);
5911
                [[maybe_unused]] auto listeners = waiting_states.pop_all_and_shutdown();
5912
                assert(listeners.empty());
5913
                op_state.reset();
5914
            }
5915
            if (ref_count.fetch_sub(1) == 1) {
5916
                delete this;
5917
            }
5918
        }
5919

5920
        ::beman::execution::inplace_stop_source stop_src{};
5921
        variant_type                            result{};
5922
        state_list_type                         waiting_states{};
5923
        ::std::atomic<::std::size_t>            ref_count{0};
5924
        ::std::optional<child_operation_state>  op_state{};
5925
    };
5926

5927
    template <class Sndr, class Receiver>
5928
    struct local_state final : local_state_base {
5929
        using stop_token_type = ::beman::execution::stop_token_of_t<::beman::execution::env_of_t<Receiver>>;
5930

5931
        struct on_stop_type {
5932
            shared_state<Sndr>* sh_state;
5933
            void                operator()() noexcept { sh_state->stop_src.request_stop(); }
5934
        };
5935

5936
        using on_stop_callback = ::beman::execution::stop_callback_for_t<stop_token_type, on_stop_type>;
5937

5938
        explicit local_state(shared_state<Sndr>* state, Receiver& rcvr) noexcept
5939
            : sh_state(state), receiver{std::addressof(rcvr)} {
5940
            sh_state->inc_ref();
5941
        }
5942

5943
        ~local_state() noexcept { sh_state->dec_ref(); }
5944

5945
        local_state(const local_state&)            = delete;
5946
        local_state& operator=(const local_state&) = delete;
5947
        local_state(local_state&&)                 = delete;
5948
        local_state& operator=(local_state&&)      = delete;
5949

5950
        auto notify() noexcept -> void override {
5951
            on_stop.reset();
5952
            auto stop_token = ::beman::execution::get_stop_token(::beman::execution::get_env(receiver));
5953
            if (stop_token.stop_requested()) {
5954
                ::beman::execution::set_stopped(std::move(*receiver));
5955
            } else {
5956
                assert(sh_state->result.index() > 0);
5957
                assert(!sh_state->result.valueless_by_exception());
5958
                try {
5959
                    ::std::visit(
5960
                        [&]<class Arg>(const Arg& arg) noexcept -> void {
5961
                            if constexpr (!::std::same_as<::std::decay_t<Arg>, ::std::monostate>) {
5962
                                ::std::apply(
5963
                                    [&](auto tag, const auto&... args) noexcept -> void {
5964
                                        tag(::std::move(*receiver), args...);
5965
                                    },
5966
                                    arg);
5967
                            }
5968
                        },
5969
                        sh_state->result);
5970
                } catch (...) {
5971
                    // required by clang-tidy although it is not necessary here
5972
                    // see valueless_by_exception() check above
5973
                    std::terminate();
5974
                }
5975
            }
5976
        }
5977

5978
        void start() noexcept {
5979
            on_stop.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(*receiver)),
5980
                            on_stop_type{sh_state});
5981
            sh_state->add_listener(this);
5982
        }
5983

5984
        std::optional<on_stop_callback> on_stop;
5985
        shared_state<Sndr>*             sh_state;
5986
        Receiver*                       receiver;
5987
    };
5988

5989
    static constexpr auto get_state = []<typename Sender, typename Receiver>(Sender&&  sender,
5990
                                                                             Receiver& receiver) noexcept {
5991
        auto&& wrapper = sender.template get<1>();
5992
        return local_state(wrapper.sh_state, receiver);
5993
    };
5994

5995
    static constexpr auto start = []<class Sndr, class Rcvr>(local_state<Sndr, Rcvr>& state, Rcvr&) noexcept {
5996
        state.start();
5997
    };
5998
};
5999

6000
template <class Sndr>
6001
struct shared_wrapper {
6002
    explicit shared_wrapper(impls_for<split_impl_t>::shared_state<Sndr>* state) noexcept : sh_state(state) {
6003
        if (sh_state) {
6004
            sh_state->inc_ref();
6005
        }
6006
    }
6007

6008
    ~shared_wrapper() noexcept {
6009
        if (sh_state) {
6010
            sh_state->dec_ref();
6011
        }
6012
    }
6013

6014
    shared_wrapper(const shared_wrapper& other) noexcept : sh_state(other.sh_state) {
6015
        if (sh_state) {
6016
            sh_state->inc_ref();
6017
        }
6018
    }
6019

6020
    shared_wrapper(shared_wrapper&& other) noexcept : sh_state(::std::exchange(other.sh_state, nullptr)) {}
6021

6022
    shared_wrapper& operator=(const shared_wrapper& other) noexcept {
6023
        // check for self-assignment was required by clang-tidy
6024
        // although it is not necessary here
6025
        if (this == &other) {
6026
            return *this;
6027
        }
6028
        auto tmp = other;
6029
        ::std::swap(sh_state, tmp.sh_state);
6030
        return *this;
6031
    }
6032

6033
    shared_wrapper& operator=(shared_wrapper&& other) noexcept {
6034
        auto tmp = ::std::move(other);
6035
        ::std::swap(sh_state, tmp.sh_state);
6036
        return *this;
6037
    }
6038

6039
    impls_for<split_impl_t>::shared_state<Sndr>* sh_state;
6040
};
6041

6042
struct split_t {
6043
    template <class Sndr>
6044
    auto transform_sender(Sndr&& sndr) const {
6045
        auto&& child       = ::std::forward<Sndr>(sndr).template get<2>();
6046
        using child_type   = decltype(child);
6047
        using shared_state = ::beman::execution::detail::impls_for<split_impl_t>::shared_state<child_type>;
6048
        auto* sh_state     = new shared_state{::beman::execution::detail::forward_like<Sndr>(child)};
6049
        return ::beman::execution::detail::make_sender(split_impl_t{}, shared_wrapper<child_type>{sh_state});
6050
    }
6051

6052
    template <class Sender>
6053
        requires beman::execution::sender_in<Sender, impls_for<split_impl_t>::split_env>
6054
    auto operator()(Sender&& sender) const {
6055
        auto domain{::beman::execution::detail::get_domain_early(sender)};
6056
        return ::beman::execution::transform_sender(
6057
            domain, ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender)));
6058
    }
6059
};
6060

6061
template <class Sndr, class Env>
6062
struct completion_signatures_for_impl<
6063
    ::beman::execution::detail::basic_sender<::beman::execution::detail::split_impl_t,
6064
                                             ::beman::execution::detail::shared_wrapper<Sndr>>,
6065
    Env> {
6066
    template <class... Args>
6067
    using make_value_completions =
6068
        ::beman::execution::completion_signatures<::beman::execution::set_value_t(const std::decay_t<Args>&...)>;
6069

6070
    template <class... Args>
6071
    using make_error_completions =
6072
        ::beman::execution::completion_signatures<::beman::execution::set_error_t(const std::decay_t<Args>&)...>;
6073

6074
    using value_completions = ::beman::execution::
6075
        value_types_of_t<Sndr, Env, make_value_completions, ::beman::execution::detail::meta::combine>;
6076

6077
    using error_completions = ::beman::execution::error_types_of_t<Sndr, Env, make_error_completions>;
6078

6079
    using fixed_completions =
6080
        ::beman::execution::completion_signatures<::beman::execution::set_stopped_t(),
6081
                                                  ::beman::execution::set_error_t(std::exception_ptr)>;
6082

6083
    using type = ::beman::execution::detail::meta::unique<
6084
        ::beman::execution::detail::meta::combine<fixed_completions, value_completions, error_completions>>;
6085
};
6086

6087
} // namespace beman::execution::detail
6088

6089
namespace beman::execution {
6090
export using split_t = ::beman::execution::detail::split_t;
6091

6092
export inline constexpr ::beman::execution::split_t split{};
6093
} // namespace beman::execution
6094

6095
// ----------------------------------------------------------------------------
6096

6097
namespace beman::execution::detail {
6098
template <typename Completion>
6099
struct then_t : ::beman::execution::sender_adaptor_closure<then_t<Completion>> {
6100
    template <::beman::execution::detail::movable_value Fun>
6101
    auto operator()(Fun&& fun) const {
6102
        return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Fun>(fun)};
6103
    }
6104
    template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
6105
    auto operator()(Sender&& sender, Fun&& fun) const {
6106
        auto domain{::beman::execution::detail::get_domain_early(sender)};
6107
        return ::beman::execution::transform_sender(
6108
            domain,
6109
            ::beman::execution::detail::make_sender(*this, ::std::forward<Fun>(fun), ::std::forward<Sender>(sender)));
6110
    }
6111
    template <::beman::execution::sender Sender, typename Env>
6112
        requires ::beman::execution::detail::nested_sender_has_affine_on<Sender, Env>
6113
    static auto affine_on(Sender&& sndr, const Env&) noexcept {
6114
        return ::std::forward<Sender>(sndr);
6115
    }
6116
};
6117

6118
template <typename Completion>
6119
struct impls_for<then_t<Completion>> : ::beman::execution::detail::default_impls {
6120
    // NOLINTBEGIN(bugprone-exception-escape)
6121
    static constexpr auto complete =
6122
        []<typename Tag, typename... Args>(auto, auto& fun, auto& receiver, Tag, Args&&... args) noexcept -> void {
6123
        if constexpr (::std::same_as<Completion, Tag>) {
6124
            try {
6125
                auto invoke = [&] { return ::std::invoke(::std::move(fun), ::std::forward<Args>(args)...); };
6126
                if constexpr (::std::same_as<void, decltype(invoke())>) {
6127
                    invoke();
6128
                    ::beman::execution::set_value(::std::move(receiver));
6129
                } else {
6130
                    ::beman::execution::set_value(::std::move(receiver), invoke());
6131
                }
6132
            } catch (...) {
6133
                if constexpr (not noexcept(::std::invoke(::std::move(fun), ::std::forward<Args>(args)...)
6134

6135
                                               )) {
6136
                    static_assert(
6137
                        noexcept(::beman::execution::set_error(::std::move(receiver), ::std::current_exception())));
6138
                    ::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
6139
                }
6140
            }
6141
        } else {
6142
            static_assert(noexcept(Tag()(::std::move(receiver), ::std::forward<Args>(args)...)));
6143
            Tag()(::std::move(receiver), ::std::forward<Args>(args)...);
6144
        }
6145
    };
6146
    // NOLINTEND(bugprone-exception-escape)
6147
};
6148

6149
template <typename T>
6150
struct then_set_value {
6151
    using type = ::beman::execution::set_value_t(T);
6152
};
6153
template <>
6154
struct then_set_value<void> {
6155
    using type = ::beman::execution::set_value_t();
6156
};
6157

6158
template <typename, typename, typename Completion>
6159
struct then_transform {
6160
    using type = Completion;
6161
};
6162

6163
template <typename Fun, typename Completion, typename... T>
6164
struct then_transform<Fun, Completion, Completion(T...)> {
6165
    using type = typename ::beman::execution::detail::then_set_value<
6166
        ::beman::execution::detail::call_result_t<Fun, T...>>::type;
6167
};
6168

6169
template <typename Fun, typename Replace>
6170
struct then_transform_t {
6171
    template <typename Completion>
6172
    using transform = typename ::beman::execution::detail::then_transform<Fun, Replace, Completion>::type;
6173
};
6174

6175
template <typename, typename, typename>
6176
struct then_exception_fun : ::std::false_type {};
6177
template <typename Comp, typename Fun, typename... A>
6178
struct then_exception_fun<Comp, Fun, Comp(A...)>
6179
    : ::std::bool_constant<not noexcept(::std::declval<Fun>()(::std::declval<A>()...))> {};
6180

6181
template <typename, typename, typename>
6182
struct then_exception : ::std::false_type {};
6183
template <typename Comp, typename Fun, typename Completion, typename... Completions>
6184
struct then_exception<Comp, Fun, ::beman::execution::completion_signatures<Completion, Completions...>> {
6185
    static constexpr bool value{
6186
        then_exception_fun<Comp, Fun, Completion>::value ||
6187
        then_exception<Comp, Fun, ::beman::execution::completion_signatures<Completions...>>::value};
6188
};
6189

6190
template <typename Completion, typename Fun, typename Sender, typename Env>
6191
struct completion_signatures_for_impl<
6192
    ::beman::execution::detail::basic_sender<::beman::execution::detail::then_t<Completion>, Fun, Sender>,
6193
    Env> {
6194
    using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
6195
        ::beman::execution::detail::meta::transform<
6196
            ::beman::execution::detail::then_transform_t<Fun, Completion>::template transform,
6197
            ::beman::execution::completion_signatures_of_t<Sender, Env>>,
6198
        ::std::conditional_t<
6199
            ::beman::execution::detail::
6200
                then_exception<Completion, Fun, ::beman::execution::completion_signatures_of_t<Sender, Env>>::value,
6201
            ::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>,
6202
            ::beman::execution::completion_signatures<>>>>;
6203
};
6204
} // namespace beman::execution::detail
6205

6206
namespace beman::execution {
6207
/*!
6208
 * \brief <code>then_t</code> is the type of <code>then</code>.
6209
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6210
 */
6211
export using then_t = ::beman::execution::detail::then_t<::beman::execution::set_value_t>;
6212
/*!
6213
 * \brief <code>upon_error_t</code> is the type of <code>upon_error</code>.
6214
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6215
 */
6216
export using upon_error_t = ::beman::execution::detail::then_t<::beman::execution::set_error_t>;
6217
/*!
6218
 * \brief <code>upon_stopped_t</code> is the type of <code>upon_stopped</code>.
6219
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6220
 */
6221
export using upon_stopped_t = ::beman::execution::detail::then_t<::beman::execution::set_stopped_t>;
6222

6223
/*!
6224
 * \brief <code>then(_sender_, _fun_)</code> yields a sender transforming a <code>set_value_t(_A_...)</code> completion
6225
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6226
 *
6227
 * \details
6228
 * `then` is a callable object of type `then_t`. Invoking <code>then(_sender_, _fun_)</code> or
6229
 * <code>_sender_ | then(_fun_)</code> yields a sender
6230
 * which, when `start`ed starts <code>_sender_</code> and awaits its completion. When
6231
 * <code>_sender_</code> completes `then` proceeds according to this completion:
6232
 * - If the completion is <code>set_value(_a_...)</code>, <code>_fun_(_a_...)</code> is invoked:
6233
 *     - if that invocation throws, `then` completes with <code>set_error(_r_, std::current_exception())</code>;
6234
 * otherwise
6235
 *     - if the invocation returns `void`, `then` completes with <code>set_value(_r_)</code>; otherwise
6236
 *     - if the invocation returns <code>_v_</code>, `then` completes with <code>set_value(_r_, _v_)</code>.
6237
 * - Otherwise, if the completion is <code>set_error(_e_)</code>, `then` completes with <code>set_error(_r_,
6238
 * _e_)</code>
6239
 * - Otherwise, if the completion is <code>set_stopped()</code>, `then` completes with <code>set_stopped(_r_)</code>.
6240
 *
6241
 * <h4>Usage</h4>
6242
 * <pre>
6243
 * then(<i>sender</i>, <i>fun</i>)
6244
 * <i>sender</i> | then(<i>fun</i>)
6245
 * </pre>
6246
 *
6247
 * <h4>Completions Signatures</h4>
6248
 * The completion signatures depends on the completion signatures <code>_CS_</code> of <code>_sender_</code> (the
6249
 * completion signatures will be deduplicated):
6250
 * - For each <code>set_value_t(_A_...)</code> in <code>_CS_</code>,
6251
 *     there is a completion signature
6252
 *     <code>set_value_t(decltype(_fun_(std::declval<_A_>()...)))</code>.
6253
 * - If for any of the <code>set_value_t(_A_...)</code> in
6254
 *     <code>_CS_</code> the expression <code>noexcept(_fun_(std::declval<_A_>()...))</code>
6255
 *     is `false` there is a completion signature <code>set_error_t(std::exception_ptr)</code>.
6256
 * - Each <code>set_error_t(_Error_)</code> in <code>_CS_</code> is copied.
6257
 * - If <code>set_stopped_t()</code> is in <code>_CS_</code> it is copied.
6258
 *
6259
 * <h4>Example</h4>
6260
 *
6261
 * <pre example="doc-then.cpp">
6262
 * #include <beman/execution/execution.hpp>
6263
 * #include <cassert>
6264
 * namespace ex = beman::execution;
6265
 *
6266
 * int main() {
6267
 *     auto result = ex::sync_wait(ex::just(10) | ex::then([](int v) { return v == 3; }));
6268
 *     assert(result);
6269
 *     assert(*result == std::tuple(false));
6270
 * }
6271
 * </pre>
6272
 */
6273
export inline constexpr ::beman::execution::then_t then{};
6274

6275
/*!
6276
 * \brief <code>upon_error(_sender_, _fun_)</code> yields a sender transforming a <code>set_error_t(_E_)</code>
6277
 * completion
6278
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6279
 *
6280
 * \details
6281
 * `upon_error` is a callable object of type `upon_error_t`. Invoking <code>upon_error(_sender_, _fun_)</code> or
6282
 * <code>_sender_ | upon_error(_fun_)</code> yields a sender
6283
 * which, when `start`ed starts <code>_sender_</code> and awaits its completion. When
6284
 * <code>_sender_</code> completes `upon_error` proceeds according to this completion:
6285
 * - If the completion is <code>set_error(_e_)</code>, <code>_fun_(_e_)</code> is invoked:
6286
 *     - if that invocation throws, `upon_error` completes with <code>set_error(_r_, std::current_exception())</code>;
6287
 * otherwise
6288
 *     - if the invocation returns `void`, `upon_error` completes with <code>set_value(_r_)</code>; otherwise
6289
 *     - if the invocation returns <code>_v_</code>, `upon_error` completes with <code>set_value(_r_, _v_)</code>.
6290
 * - Otherwise, if the completion is <code>set_value(_a_...)</code>, `upon_error` completes with <code>set_value(_r_,
6291
 * _a_...)</code>
6292
 * - Otherwise, if the completion is <code>set_stopped()</code>, `upon_error` completes with
6293
 * <code>set_stopped(_r_)</code>.
6294
 *
6295
 * <h4>Usage</h4>
6296
 * <pre>
6297
 * upon_error(<i>sender</i>, <i>fun</i>)
6298
 * <i>sender</i> | upon_error(<i>fun</i>)
6299
 * </pre>
6300
 *
6301
 * <h4>Completions Signatures</h4>
6302
 * The completion signatures depend on the completion signatures <code>_CS_</code> of <code>_sender_</code> (the
6303
 * completion signatures will be deduplicated):
6304
 * - For each <code>set_error_t(_E_)</code> in <code>_CS_</code>,
6305
 *     there is a completion signature
6306
 *     <code>set_value_t(decltype(_fun_(std::declval<_E_>())))</code>.
6307
 * - If for any of the <code>set_error_t(_E_)</code> in
6308
 *     <code>_CS_</code> the expression <code>noexcept(_fun_(_std::declval<E>()_))</code>
6309
 *     is `false` there is a completion signature <code>set_error_t(std::exception_ptr)</code>.
6310
 * - Each <code>set_value_t(_A_...)</code> in <code>_CS_</code> is copied.
6311
 * - If <code>set_stopped_t()</code> is in <code>_CS_</code> it is copied.
6312
 *
6313
 * <h4>Example</h4>
6314
 *
6315
 * <pre example="doc-upon_error.cpp">
6316
 * #include <beman/execution/execution.hpp>
6317
 * #include <cassert>
6318
 * namespace ex = beman::execution;
6319
 *
6320
 * int main() {
6321
 *     auto result = ex::sync_wait(ex::just_error(10) | ex::upon_error([](int v) { return v == 3; }));
6322
 *     assert(result);
6323
 *     assert(*result == std::tuple(false));
6324
 * }
6325
 * </pre>
6326
 */
6327
export inline constexpr ::beman::execution::upon_error_t upon_error{};
6328

6329
/*!
6330
 * \brief <code>upon_stopped(_sender_, _fun_)</code> yields a sender transforming a <code>set_stopped_t()</code>
6331
 * completion
6332
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6333
 *
6334
 * \details
6335
 * `upon_stopped` is a callable object of type `upon_stopped_t`. Invoking <code>upon_stopped(_sender_, _fun_)</code> or
6336
 * <code>_sender_ | upon_stopped(_fun_)</code> yields a sender
6337
 * which, when `start`ed starts <code>_sender_</code> and awaits its completion. When
6338
 * <code>_sender_</code> completes `upon_stopped` proceeds according to this completion:
6339
 * - If the completion is <code>set_stopped(_e_)</code>, <code>_fun_(_e_)</code> is invoked:
6340
 *     - if that invocation throws, `upon_stopped` completes with <code>set_error(_r_,
6341
 * std::current_exception())</code>; otherwise
6342
 *     - if the invocation returns `void`, `upon_stopped` completes with <code>set_value(_r_)</code>; otherwise
6343
 *     - if the invocation returns <code>_v_</code>, `upon_stopped` completes with <code>set_value(_r_, _v_)</code>.
6344
 * - Otherwise, if the completion is <code>set_value(_a_...)</code>, `upon_stopped` completes with <code>set_value(_r_,
6345
 * _a_...)</code>
6346
 * - Otherwise, if the completion is <code>set_error(_e_)</code>, `upon_stopped` completes with <code>set_error(_r_,
6347
 * _e_)</code>.
6348
 *
6349
 * <h4>Usage</h4>
6350
 * <pre>
6351
 * upon_stopped(<i>sender</i>, <i>fun</i>)
6352
 * <i>sender</i> | upon_stopped(<i>fun</i>)
6353
 * </pre>
6354
 *
6355
 * <h4>Completions Signatures</h4>
6356
 * The completion signatures depend on the completion signatures <code>_CS_</code> of <code>_sender_</code> (the
6357
 * completion signatures will be deduplicated):
6358
 * - There is a completion signature <code>set_value_t(decltype(_fun_()))</code>.
6359
 * - If the expression <code>noexcept(_fun_())</code> is `false` there is a completion signature
6360
 * <code>set_error_t(std::exception_ptr)</code>.
6361
 * - Each <code>set_value_t(_A_...)</code> in <code>_CS_</code> is copied.
6362
 * - Each <code>set_error_t(_A_...)</code> in <code>_CS_</code> is copied.
6363
 *
6364
 * <h4>Example</h4>
6365
 *
6366
 * <pre example="doc-upon_stopped.cpp">
6367
 * #include <beman/execution/execution.hpp>
6368
 * #include <cassert>
6369
 * namespace ex = beman::execution;
6370
 *
6371
 * int main() {
6372
 *     auto result = ex::sync_wait(ex::just_stopped() | ex::upon_stopped([]() { return true; }));
6373
 *     assert(result);
6374
 *     assert(*result == std::tuple(true));
6375
 * }
6376
 * </pre>
6377
 */
6378
export inline constexpr ::beman::execution::upon_stopped_t upon_stopped{};
6379
} // namespace beman::execution
6380

6381
// ----------------------------------------------------------------------------
6382

6383
// ----------------------------------------------------------------------------
6384

6385
namespace beman::execution::detail {
6386
struct when_all_t {
6387
    template <::beman::execution::sender... Sender>
6388
        requires(0u != sizeof...(Sender)) &&
6389
                ((::beman::execution::detail::meta::size_v<
6390
                      ::beman::execution::value_types_of_t<Sender,
6391
                                                           ::beman::execution::env<>,
6392
                                                           ::std::tuple,
6393
                                                           ::beman::execution::detail::type_list>> == 1u) &&
6394
                 ...) &&
6395
                requires(Sender&&... s) {
6396
                    typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(s))...>;
6397
                }
6398
    auto operator()(Sender&&... sender) const {
6399
        using common_t =
6400
            typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(sender))...>;
6401
        return ::beman::execution::transform_sender(
6402
            common_t(), ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender)...));
6403
    }
6404
};
6405

6406
template <typename>
6407
struct when_all_value_types;
6408
template <typename... T>
6409
struct when_all_value_types<::beman::execution::detail::type_list<T...>> {
6410
    using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t(T...)>;
6411
};
6412

6413
template <>
6414
struct impls_for<::beman::execution::detail::when_all_t> : ::beman::execution::detail::default_impls {
6415
    static constexpr auto get_attrs{[](auto&&, auto&&... sender) {
6416
        using common_t =
6417
            typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(sender))...>;
6418
        if constexpr (::std::same_as<common_t, ::beman::execution::default_domain>)
6419
            return ::beman::execution::env<>{};
6420
        else
6421
            return ::beman::execution::detail::make_env(::beman::execution::get_domain, common_t{});
6422
    }};
6423
    static constexpr auto get_env{
6424
        []<typename State, typename Receiver>(auto&&, State& state, const Receiver& receiver) noexcept {
6425
            return ::beman::execution::detail::join_env(
6426
                ::beman::execution::detail::make_env(::beman::execution::get_stop_token, state.stop_src.get_token()),
6427
                ::beman::execution::get_env(receiver));
6428
        }};
6429

6430
    enum class disposition : unsigned char { started, error, stopped };
6431

6432
    template <typename Receiver, typename... Sender>
6433
    struct state_type {
6434
        struct nonesuch {};
6435
        using env_t        = ::beman::execution::env_of_t<Receiver>;
6436
        using values_tuple = ::std::tuple<
6437
            ::beman::execution::
6438
                value_types_of_t<Sender, env_t, ::beman::execution::detail::decayed_tuple, ::std::optional>...>;
6439
        using errors_variant = ::beman::execution::detail::meta::to<
6440
            ::std::variant,
6441
            ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
6442
                nonesuch,
6443
                ::beman::execution::detail::meta::prepend<
6444
                    ::std::exception_ptr,
6445
                    ::beman::execution::detail::meta::combine<::beman::execution::detail::meta::to<
6446
                        ::beman::execution::detail::type_list,
6447
                        ::beman::execution::detail::meta::combine<::beman::execution::error_types_of_t<
6448
                            Sender,
6449
                            env_t,
6450
                            ::beman::execution::detail::decayed_type_list>...>>>>>>>;
6451
        using stop_callback = ::beman::execution::stop_callback_for_t<
6452
            ::beman::execution::stop_token_of_t<::beman::execution::env_of_t<Receiver>>,
6453
            ::beman::execution::detail::on_stop_request<state_type>>;
6454

6455
        void arrive(Receiver& recvr) noexcept {
6456
            if (0u == --count)
6457
                this->complete(recvr);
6458
        }
6459

6460
        void complete(Receiver& recvr) noexcept {
6461
            switch (disposition(this->disp)) {
6462
            case disposition::started: {
6463
                auto tie = []<typename... T>(::std::tuple<T...>& t) noexcept {
6464
                    return ::std::apply([](auto&... a) { return ::std::tie(a...); }, t);
6465
                };
6466
                auto set = [&](auto&... t) noexcept {
6467
                    ::beman::execution::set_value(::std::move(recvr), ::std::move(t)...);
6468
                };
6469

6470
                this->on_stop.reset();
6471
                ::std::apply([&](auto&... opts) noexcept { ::std::apply(set, ::std::tuple_cat(tie(*opts)...)); },
6472
                             this->values);
6473
            } break;
6474
            case disposition::error:
6475
                this->on_stop.reset();
6476
                try {
6477
                    ::std::visit(
6478
                        [&]<typename Error>(Error& error) noexcept {
6479
                            if constexpr (!::std::same_as<Error, nonesuch>) {
6480
                                ::beman::execution::set_error(::std::move(recvr), ::std::move(error));
6481
                            }
6482
                        },
6483
                        this->errors);
6484
                } catch (...) {
6485
                    ::beman::execution::set_error(::std::move(recvr), ::std::current_exception());
6486
                }
6487
                break;
6488
            case disposition::stopped:
6489
                this->on_stop.reset();
6490
                ::beman::execution::set_stopped(::std::move(recvr));
6491
                break;
6492
            }
6493
        }
6494

6495
        auto request_stop() -> void {
6496
            if (1u == ++this->count)
6497
                --this->count;
6498
            else {
6499
                this->stop_src.request_stop();
6500
                this->arrive(*this->receiver);
6501
            }
6502
        }
6503

6504
        Receiver*                               receiver{};
6505
        ::std::atomic<::std::size_t>            count{sizeof...(Sender)};
6506
        ::beman::execution::inplace_stop_source stop_src{};
6507
        ::std::atomic<disposition>              disp{disposition::started};
6508
        errors_variant                          errors{};
6509
        values_tuple                            values{};
6510
        ::std::optional<stop_callback>          on_stop{::std::nullopt};
6511
    };
6512

6513
    template <typename Receiver>
6514
    struct make_state {
6515
        template <::beman::execution::sender_in<::beman::execution::env_of_t<Receiver>>... Sender>
6516
        auto operator()(auto, auto, Sender&&...) const {
6517
            return state_type<Receiver, Sender...>{};
6518
        }
6519
    };
6520
    static constexpr auto get_state{[]<typename Sender, typename Receiver>(Sender&& sender, Receiver&) noexcept(
6521
                                        noexcept(std::forward<Sender>(sender).apply(make_state<Receiver>{}))) {
6522
        return std::forward<Sender>(sender).apply(make_state<Receiver>{});
6523
    }};
6524
    static constexpr auto start{[]<typename State, typename Receiver, typename... Ops>(
6525
                                    State& state, Receiver& receiver, Ops&... ops) noexcept -> void {
6526
        state.receiver = &receiver;
6527
        state.on_stop.emplace(::beman::execution::get_stop_token(::beman::execution::get_env(receiver)),
6528
                              ::beman::execution::detail::on_stop_request{state});
6529
        if (state.stop_src.stop_requested()) {
6530
            state.on_stop.reset();
6531
            ::beman::execution::set_stopped(std::move(receiver));
6532
        } else {
6533
            (::beman::execution::start(ops), ...);
6534
        }
6535
    }};
6536
    static constexpr auto complete{
6537
        []<typename Index, typename State, typename Receiver, typename Set, typename... Args>(
6538
            Index, State& state, Receiver& receiver, Set, Args&&... args) noexcept -> void {
6539
            if constexpr (::std::same_as<Set, ::beman::execution::set_error_t>) {
6540
                if (disposition::error != state.disp.exchange(disposition::error)) {
6541
                    state.stop_src.request_stop();
6542
                    try {
6543
                        state.errors.template emplace<typename ::std::decay<Args...>::type>(
6544
                            ::std::forward<Args>(args)...);
6545
                    } catch (...) {
6546
                        state.errors.template emplace<::std::exception_ptr>(::std::current_exception());
6547
                    }
6548
                }
6549
            } else if constexpr (::std::same_as<Set, ::beman::execution::set_stopped_t>) {
6550
                auto expected = disposition::started;
6551
                if (state.disp.compare_exchange_strong(expected, disposition::stopped)) {
6552
                    state.stop_src.request_stop();
6553
                }
6554
            } else if constexpr (!::std::same_as<decltype(State::values), ::std::tuple<>>) {
6555
                if (state.disp == disposition::started) {
6556
                    auto& opt = ::std::get<Index::value>(state.values);
6557
                    try {
6558
                        opt.emplace(::std::forward<Args>(args)...);
6559
                    } catch (...) {
6560
                        if (disposition::error != state.disp.exchange(disposition::error)) {
6561
                            state.stop_src.request_stop();
6562
                            state.errors.template emplace<::std::exception_ptr>(::std::current_exception());
6563
                        }
6564
                    }
6565
                }
6566
            }
6567
            state.arrive(receiver);
6568
        }};
6569
};
6570

6571
template <typename Data, typename Env, typename... Sender>
6572
struct completion_signatures_for_impl<
6573
    ::beman::execution::detail::basic_sender<::beman::execution::detail::when_all_t, Data, Sender...>,
6574
    Env> {
6575
    template <typename... E>
6576
    struct error_comps_t {
6577
        using type = ::beman::execution::completion_signatures<::beman::execution::set_error_t(E)...>;
6578
    };
6579
    template <typename... E>
6580
    using error_comps = typename error_comps_t<E...>::type;
6581

6582
    using value_types =
6583
        typename ::beman::execution::detail::when_all_value_types<::beman::execution::detail::meta::combine<
6584
            ::beman::execution::
6585
                value_types_of_t<Sender, Env, ::beman::execution::detail::type_list, ::std::type_identity_t>...>>::
6586
            type;
6587
    using error_types = ::beman::execution::detail::meta::unique<
6588
        ::beman::execution::detail::meta::combine<::beman::execution::error_types_of_t<Sender, Env, error_comps>...>>;
6589
    using stopped_types =
6590
        ::std::conditional_t<(false || ... || ::beman::execution::sends_stopped<Sender, Env>),
6591
                             ::beman::execution::completion_signatures<::beman::execution::set_stopped_t()>,
6592
                             ::beman::execution::completion_signatures<>>;
6593
    using type = ::beman::execution::detail::meta::combine<value_types, error_types, stopped_types>;
6594
};
6595
} // namespace beman::execution::detail
6596

6597
namespace beman::execution {
6598
export using when_all_t = ::beman::execution::detail::when_all_t;
6599
export inline constexpr ::beman::execution::when_all_t when_all{};
6600
} // namespace beman::execution
6601

6602
// ----------------------------------------------------------------------------
6603

6604
// ----------------------------------------------------------------------------
6605

6606
namespace beman::execution::detail {
6607
struct write_env_t {
6608
    template <::beman::execution::sender Sender, ::beman::execution::detail::queryable Env>
6609
    constexpr auto operator()(Sender&& sender, Env&& env) const {
6610
        return ::beman::execution::detail::make_sender(
6611
            *this, ::std::forward<Env>(env), ::std::forward<Sender>(sender));
6612
    }
NEW
6613
    static auto name() { return "write_env_t"; }
×
6614
    template <::beman::execution::sender Sender, typename Env>
6615
        requires ::beman::execution::detail::nested_sender_has_affine_on<Sender, Env>
6616
    static auto affine_on(Sender&& sndr, const Env&) noexcept {
6617
        return ::std::forward<Sender>(sndr);
6618
    }
6619
};
6620

6621
template <typename NewEnv, typename Child, typename Env>
6622
struct completion_signatures_for_impl<
6623
    ::beman::execution::detail::basic_sender<::beman::execution::detail::write_env_t, NewEnv, Child>,
6624
    Env> {
6625
    using type = decltype(::beman::execution::get_completion_signatures(
6626
        ::std::declval<Child>(),
6627
        ::beman::execution::detail::join_env(::std::declval<NewEnv>(), ::std::declval<Env>())));
6628
};
6629

6630
template <>
6631
struct impls_for<write_env_t> : ::beman::execution::detail::default_impls {
6632
    static constexpr auto get_env = [](auto, const auto& state, const auto& receiver) noexcept {
6633
        return ::beman::execution::detail::join_env(state, ::beman::execution::get_env(receiver));
6634
    };
6635
};
6636

6637
inline constexpr write_env_t write_env{};
6638
} // namespace beman::execution::detail
6639

6640
namespace beman::execution {
6641
export using write_env_t = ::beman::execution::detail::write_env_t;
6642
export inline constexpr write_env_t write_env{};
6643
} // namespace beman::execution
6644

6645
// ----------------------------------------------------------------------------
6646

6647
// ----------------------------------------------------------------------------
6648

6649
namespace beman::execution::detail {
6650
template <::beman::execution::scope_token Token, ::beman::execution::sender Sender>
6651
struct associate_data {
6652
    using wrap_sender = ::std::remove_cvref_t<decltype(::std::declval<Token&>().wrap(::std::declval<Sender>()))>;
6653

6654
    explicit associate_data(Token t, Sender&& s) : token(t), sender(this->token.wrap(::std::forward<Sender>(s))) {
6655
        if (!token.try_associate()) {
6656
            this->sender.reset();
6657
        }
6658
    }
6659
    associate_data(const associate_data& other) noexcept(::std::is_nothrow_copy_constructible_v<wrap_sender> &&
6660
                                                         noexcept(token.try_associate()))
6661
        : token(other.token), sender() {
6662
        if (other.sender && this->token.try_associate()) {
6663
            try {
6664
                this->sender.emplace(*other.sender);
6665
            } catch (...) {
6666
                this->token.disassociate();
6667
            }
6668
        }
6669
    }
6670
    associate_data(associate_data&& other) noexcept(::std::is_nothrow_move_constructible_v<wrap_sender>)
6671
        : token(other.token), sender(::std::move(other.sender)) {
6672
        other.sender.reset();
6673
    }
6674
    auto operator=(const associate_data&) -> associate_data& = delete;
6675
    auto operator=(associate_data&&) -> associate_data&      = delete;
6676
    ~associate_data() {
6677
        if (this->sender) {
6678
            this->sender.reset();
6679
            this->token.disassociate();
6680
        }
6681
    }
6682

6683
    auto release() -> ::std::optional<::std::pair<Token, wrap_sender>> {
6684
        return this->sender ? (std::unique_ptr<std::optional<wrap_sender>, decltype([](auto* opt) { opt->reset(); })>(
6685
                                   &this->sender),
6686
                               ::std::optional{::std::pair{::std::move(this->token), ::std::move(*this->sender)}})
6687
                            : ::std::optional<::std::pair<Token, wrap_sender>>{};
6688
    }
6689

6690
    Token                        token;
6691
    ::std::optional<wrap_sender> sender;
6692
};
6693
template <::beman::execution::scope_token Token, ::beman::execution::sender Sender>
6694
associate_data(Token, Sender&&) -> associate_data<Token, Sender>;
6695

6696
struct associate_t {
6697
    template <::beman::execution::sender Sender, ::beman::execution::scope_token Token>
6698
    auto operator()(Sender&& sender, Token&& token) const {
6699
        auto domain(::beman::execution::detail::get_domain_early(sender));
6700
        return ::beman::execution::transform_sender(
6701
            domain,
6702
            ::beman::execution::detail::make_sender(
6703
                *this,
6704
                ::beman::execution::detail::associate_data(::std::forward<Token>(token),
6705
                                                           ::std::forward<Sender>(sender))));
6706
    }
6707
};
6708

6709
template <>
6710
struct impls_for<associate_t> : ::beman::execution::detail::default_impls {
6711
    template <typename, typename>
6712
    struct get_noexcept : ::std::false_type {};
6713
    template <typename Tag, typename Data, typename Receiver>
6714
    struct get_noexcept<::beman::execution::detail::basic_sender<Tag, Data>, Receiver>
6715
        : ::std::bool_constant<
6716
              ::std::is_nothrow_move_constructible_v<typename ::std::remove_cvref_t<Data>::wrap_sender>&& ::beman::
6717
                  execution::detail::nothrow_callable<::beman::execution::connect_t,
6718
                                                      typename ::std::remove_cvref_t<Data>::wrap_sender,
6719
                                                      Receiver>> {};
6720

6721
    static constexpr auto get_state =
6722
        []<typename Sender, typename Receiver>(Sender&& sender, Receiver& receiver) noexcept(
6723
            ::std::is_nothrow_constructible_v<::std::remove_cvref_t<Sender>, Sender>&&
6724
                get_noexcept<::std::remove_cvref_t<Sender>, Receiver>::value) {
6725
            auto [_, data] = ::std::forward<Sender>(sender);
6726
            auto dataParts{data.release()};
6727

6728
            using scope_token = decltype(dataParts->first);
6729
            using wrap_sender = decltype(dataParts->second);
6730
            using op_t        = decltype(::beman::execution::connect(::std::move(dataParts->second),
6731
                                                              ::std::forward<Receiver>(receiver)));
6732

6733
            struct op_state {
6734
                using sop_t        = op_t;
6735
                using sscope_token = scope_token;
6736
                struct assoc_t {
6737
                    sscope_token tok;
6738
                    sop_t        op;
6739
                };
6740

6741
                bool associated{false};
6742
                union {
6743
                    Receiver* rcvr;
6744
                    assoc_t   assoc;
6745
                };
6746
                explicit op_state(Receiver& r) noexcept : rcvr(::std::addressof(r)) {}
6747
                explicit op_state(sscope_token tk, wrap_sender&& sndr, Receiver& r) try
6748
                    : associated(true), assoc(tk, ::beman::execution::connect(::std::move(sndr), ::std::move(r))) {
6749
                } catch (...) {
6750
                    tk.disassociate();
6751
                    throw;
6752
                }
6753
                op_state(op_state&&) = delete;
6754
                ~op_state() {
6755
                    if (this->associated) {
6756
                        this->assoc.op.~sop_t();
6757
                        this->assoc.tok.disassociate();
6758
                        this->assoc.tok.~sscope_token();
6759
                    }
6760
                }
6761
                auto run() noexcept -> void {
6762
                    if (this->associated) {
6763
                        ::beman::execution::start(this->assoc.op);
6764
                    } else {
6765
                        ::beman::execution::set_stopped(::std::move(*this->rcvr));
6766
                    }
6767
                }
6768
            };
6769
            return dataParts ? op_state(::std::move(dataParts->first), ::std::move(dataParts->second), receiver)
6770
                             : op_state(receiver);
6771
        };
6772
    static constexpr auto start = [](auto& state, auto&&) noexcept -> void { state.run(); };
6773
};
6774

6775
template <typename Data, typename Env>
6776
struct completion_signatures_for_impl<
6777
    ::beman::execution::detail::basic_sender<::beman::execution::detail::associate_t, Data>,
6778
    Env> {
6779
    using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>;
6780
};
6781
} // namespace beman::execution::detail
6782

6783
namespace beman::execution {
6784
export using associate_t = ::beman::execution::detail::associate_t;
6785
export inline constexpr associate_t associate{};
6786
} // namespace beman::execution
6787

6788
// ----------------------------------------------------------------------------
6789

6790
// ----------------------------------------------------------------------------
6791

6792
namespace beman::execution {
6793
/*!
6794
 * \brief Turn an entity, e.g., a sender, into an awaitable.
6795
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
6796
 */
6797
export struct as_awaitable_t {
6798
    template <typename Expr, typename Promise>
6799
    auto operator()(Expr&& expr, Promise& promise) const {
6800
        if constexpr (requires { ::std::forward<Expr>(expr).as_awaitable(promise); }) {
6801
            static_assert(
6802
                ::beman::execution::detail::is_awaitable<decltype(::std::forward<Expr>(expr).as_awaitable(promise)),
6803
                                                         Promise>,
6804
                "as_awaitable must return an awaitable");
6805
            return ::std::forward<Expr>(expr).as_awaitable(promise);
6806
        } else if constexpr (::beman::execution::detail::
6807
                                 is_awaitable<Expr, ::beman::execution::detail::unspecified_promise> ||
6808
                             !::beman::execution::detail::awaitable_sender<Expr, Promise>) {
6809
            return ::std::forward<Expr>(expr);
6810
        } else {
6811
            return ::beman::execution::detail::sender_awaitable<Expr, Promise>{::std::forward<Expr>(expr), promise};
6812
        }
6813
    }
6814
};
6815
export inline constexpr ::beman::execution::as_awaitable_t as_awaitable{};
6816
} // namespace beman::execution
6817

6818
// ----------------------------------------------------------------------------
6819

6820
// ----------------------------------------------------------------------------
6821

6822
namespace beman::execution::detail {
6823
struct counting_scope_join_t {
6824
    template <::beman::execution::receiver>
6825
    struct state;
6826

NEW
6827
    auto operator()(::beman::execution::detail::counting_scope_base* ptr) const {
×
NEW
6828
        return ::beman::execution::detail::make_sender(*this, ptr);
×
6829
    }
6830
};
6831
inline constexpr counting_scope_join_t counting_scope_join{};
6832

6833
template <typename Env>
6834
struct completion_signatures_for_impl<
6835
    ::beman::execution::detail::basic_sender<::beman::execution::detail::counting_scope_join_t,
6836
                                             ::beman::execution::detail::counting_scope_base*>,
6837
    Env> {
6838
    using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>;
6839
};
6840

6841
} // namespace beman::execution::detail
6842

6843
// ----------------------------------------------------------------------------
6844

6845
template <::beman::execution::receiver Receiver>
6846
struct beman::execution::detail::counting_scope_join_t::state : ::beman::execution::detail::counting_scope_base::node {
6847
    using op_t = decltype(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
6848
                                                          ::beman::execution::get_env(::std::declval<Receiver&>()))),
6849
                                                      ::std::declval<Receiver&>()));
6850

6851
    ::beman::execution::detail::counting_scope_base* scope;
6852
    explicit state(::beman::execution::detail::counting_scope_base* s, Receiver& r)
6853
        : scope(s),
6854
          receiver(r),
6855
          op(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
6856
                                             ::beman::execution::get_env(this->receiver))),
6857
                                         this->receiver)) {}
6858
    virtual ~state() = default;
6859

6860
    auto complete() noexcept -> void override { ::beman::execution::start(this->op); }
6861
    auto complete_inline() noexcept -> void override { ::beman::execution::set_value(::std::move(this->receiver)); }
6862

6863
    auto start() noexcept -> void { this->scope->start_node(this); }
6864

6865
    ::std::remove_cvref_t<Receiver>& receiver;
6866
    op_t                             op;
6867
};
6868

6869
// ----------------------------------------------------------------------------
6870

6871
namespace beman::execution::detail {
6872
template <>
6873
struct impls_for<::beman::execution::detail::counting_scope_join_t> : ::beman::execution::detail::default_impls {
6874
    static constexpr auto get_state = []<typename Receiver>(auto&& sender, Receiver& receiver) noexcept(false) {
6875
        auto [_, self] = sender;
6876
        return ::beman::execution::detail::counting_scope_join_t::state<Receiver>(self, receiver);
6877
    };
6878
    static constexpr auto start = [](auto& s, auto&) noexcept { s.start(); };
6879
};
6880
} // namespace beman::execution::detail
6881

6882
// ----------------------------------------------------------------------------
6883

6884
// ----------------------------------------------------------------------------
6885

6886
namespace beman::execution::detail {
6887

6888
/**
6889
 * @brief The affine_on_t struct is a sender adaptor closure that transforms a sender
6890
 *        to complete on the scheduler obtained from the receiver's environment.
6891
 *
6892
 * This adaptor implements scheduler affinity to adapt a sender to complete on the
6893
 * scheduler obtained the receiver's environment. The get_scheduler query is used
6894
 * to obtain the scheduler on which the sender gets started.
6895
 */
6896
struct affine_on_t : ::beman::execution::sender_adaptor_closure<affine_on_t> {
6897
    /**
6898
     * @brief Adapt a sender with affine_on.
6899
     *
6900
     * @tparam Sender The deduced type of the sender to be transformed.
6901
     * @param sender The sender to be transformed.
6902
     * @return An adapted sender to complete on the scheduler it was started on.
6903
     */
6904
    template <::beman::execution::sender Sender>
6905
    auto operator()(Sender&& sender) const {
6906
        return ::beman::execution::detail::transform_sender(
6907
            ::beman::execution::detail::get_domain_early(sender),
6908
            ::beman::execution::detail::make_sender(
6909
                *this, ::beman::execution::env<>{}, ::std::forward<Sender>(sender)));
6910
    }
6911

6912
    /**
6913
     * @brief Overload for creating a sender adaptor from affine_on.
6914
     *
6915
     * @return A sender adaptor for the affine_on_t.
6916
     */
NEW
6917
    auto operator()() const { return ::beman::execution::detail::sender_adaptor{*this}; }
×
6918

6919
    template <typename Ev>
6920
    struct ao_env {
6921
        Ev   ev_;
6922
        auto query(const ::beman::execution::get_stop_token_t&) const noexcept
6923
            -> ::beman::execution::never_stop_token {
6924
            return ::beman::execution::never_stop_token();
6925
        }
6926
        template <typename Q>
6927
        auto query(const Q& q) const noexcept -> decltype(q(this->ev_)) {
6928
            return q(this->ev_);
6929
        }
6930
    };
6931
    template <typename Ev>
6932
    ao_env(const Ev&) -> ao_env<Ev>;
6933

6934
    /**
6935
     * @brief affine_on is implemented by transforming it into a use of schedule_from.
6936
     *
6937
     * The constraints ensure that the environment provides a scheduler which is
6938
     * infallible and, thus, can be used to guarantee completion on the correct
6939
     * scheduler.
6940
     *
6941
     * The implementation first tries to see if the child sender's tag has a custom
6942
     * affine_on implementation. If it does, that is used. Otherwise, the default
6943
     * implementation gets a scheduler from the environment and uses schedule_from
6944
     * to adapt the sender to complete on that scheduler.
6945
     *
6946
     * @tparam Sender The type of the sender to be transformed.
6947
     * @tparam Env The type of the environment providing the scheduler.
6948
     * @param sender The sender to be transformed.
6949
     * @param env The environment providing the scheduler.
6950
     * @return A transformed sender that is affined to the scheduler.
6951
     */
6952
    template <::beman::execution::sender Sender, typename Env>
6953
        requires ::beman::execution::detail::sender_for<Sender, affine_on_t> && requires(const Env& env) {
6954
            { ::beman::execution::get_scheduler(env) } -> ::beman::execution::scheduler;
6955
            { ::beman::execution::schedule(::beman::execution::get_scheduler(env)) } -> ::beman::execution::sender;
6956
            {
6957
                ::beman::execution::get_completion_signatures(
6958
                    ::beman::execution::schedule(::beman::execution::get_scheduler(env)),
6959
                    ::beman::execution::detail::join_env(
6960
                        ::beman::execution::env{::beman::execution::prop{
6961
                            ::beman::execution::get_stop_token, ::beman::execution::never_stop_token{}, {}}},
6962
                        env))
6963
            } -> ::std::same_as<::beman::execution::completion_signatures<::beman::execution::set_value_t()>>;
6964
        }
6965
    static auto transform_sender(Sender&& sender, const Env& ev) {
6966
        [[maybe_unused]] auto& [tag, data, child] = sender;
6967
        using child_tag_t = ::beman::execution::tag_of_t<::std::remove_cvref_t<decltype(child)>>;
6968

6969
        if constexpr (::beman::execution::detail::nested_sender_has_affine_on<Sender, Env>) {
6970
            constexpr child_tag_t t{};
6971
            return t.affine_on(::beman::execution::detail::forward_like<Sender>(child), ev);
6972
        } else {
6973
            return ::beman::execution::write_env(
6974
                ::beman::execution::schedule_from(
6975
                    ::beman::execution::get_scheduler(ev),
6976
                    ::beman::execution::write_env(::beman::execution::detail::forward_like<Sender>(child), ev)),
6977
                ao_env(ev));
6978
        }
6979
    }
6980
};
6981

6982
} // namespace beman::execution::detail
6983

6984
namespace beman::execution {
6985
/**
6986
 * @brief affine_on is a CPO, used to adapt a sender to complete on the scheduler
6987
 *      it got started on which is derived from get_scheduler on the receiver's environment.
6988
 */
6989
export using affine_on_t = beman::execution::detail::affine_on_t;
6990
export inline constexpr affine_on_t affine_on{};
6991
} // namespace beman::execution
6992

6993
// ----------------------------------------------------------------------------
6994

6995
// ----------------------------------------------------------------------------
6996

6997
namespace beman::execution::detail {
6998
// specialize default_domain appropriately
6999
/*!
7000
 * \brief The actual implementation of the continues_on customization point object
7001
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7002
 * \internal
7003
 */
7004
struct continues_on_t {
7005
    template <::beman::execution::detail::sender_for<continues_on_t> Sender, typename... Env>
7006
    static auto transform_sender(Sender&& sender, Env&&...) {
7007
        auto&& data{sender.template get<1>()};
7008
        auto&& child{sender.template get<2>()};
7009
        return ::beman::execution::schedule_from(std::move(data), std::move(child));
7010
    }
7011
    template <::beman::execution::scheduler Scheduler>
7012
    auto operator()(Scheduler&& scheduler) const {
7013
        return ::beman::execution::detail::sender_adaptor{*this, ::std::forward<Scheduler>(scheduler)};
7014
    }
7015
    template <::beman::execution::sender Sender, ::beman::execution::scheduler Scheduler>
7016
    auto operator()(Sender&& sender, Scheduler&& scheduler) const {
7017
        auto domain(::beman::execution::detail::get_domain_early(sender));
7018
        return ::beman::execution::transform_sender(
7019
            domain,
7020
            ::beman::execution::detail::make_sender(
7021
                *this, std::forward<Scheduler>(scheduler), ::std::forward<Sender>(sender)));
7022
    }
7023
};
7024

7025
/*!
7026
 * \brief Specialization of impls_for to implement the continues_on functionality
7027
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7028
 * \internal
7029
 */
7030
template <>
7031
struct impls_for<::beman::execution::detail::continues_on_t> : ::beman::execution::detail::default_impls {
7032
    static constexpr auto get_attrs{[](const auto& data, const auto& child) noexcept -> decltype(auto) {
7033
        return ::beman::execution::detail::join_env(
7034
            ::beman::execution::detail::sched_attrs(data),
7035
            ::beman::execution::detail::fwd_env(::beman::execution::get_env(child)));
7036
    }};
7037
};
7038

7039
/*!
7040
 * \brief Get the sender's domain when the sender is continue_on
7041
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7042
 * \internal
7043
 */
7044
template <::beman::execution::detail::sender_for<::beman::execution::detail::continues_on_t> Sender, typename Env>
7045
auto get_domain_late(Sender&& sender, Env&&) {
7046
    auto scheduler{sender.template get<1>()};
7047
    return ::beman::execution::detail::query_with_default(
7048
        ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{});
7049
}
7050
} // namespace beman::execution::detail
7051

7052
namespace beman::execution {
7053
export using continues_on_t = ::beman::execution::detail::continues_on_t;
7054
/*!
7055
 * \brief Customization point object to create a `continues_on` sender.
7056
 * \headerfile beman/execution/execution.hpp <beman/execution/execution.hpp>
7057
 */
7058
export inline constexpr continues_on_t continues_on{};
7059
} // namespace beman::execution
7060

7061
// ----------------------------------------------------------------------------
7062

7063
// ----------------------------------------------------------------------------
7064

7065
namespace beman::execution::detail {
7066
struct starts_on_t {
7067
    template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename Env>
7068
    auto transform_env(Sender&& sender, Env&& env) const noexcept {
7069
        auto&& scheduler{sender.template get<1>()};
7070
        return ::beman::execution::detail::join_env(::beman::execution::detail::sched_env(scheduler),
7071
                                                    ::beman::execution::detail::fwd_env(env));
7072
    }
7073
    template <::beman::execution::detail::sender_for<::beman::execution::detail::starts_on_t> Sender, typename... Env>
7074
    auto transform_sender(Sender&& sender, Env&&...) const noexcept {
7075
        auto&& scheduler{sender.template get<1>()};
7076
        auto&& new_sender{sender.template get<2>()};
7077
        return ::beman::execution::let_value(
7078
            ::beman::execution::schedule(scheduler),
7079
            [new_sender = ::beman::execution::detail::forward_like<Sender>(new_sender)]() mutable noexcept(
7080
                ::std::is_nothrow_constructible_v<::std::decay_t<Sender>>) { return ::std::move(new_sender); });
7081
    }
7082

7083
    template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender>
7084
    auto operator()(Scheduler&& scheduler, Sender&& sender) const {
7085
        auto domain{::beman::execution::detail::query_with_default(
7086
            ::beman::execution::get_domain, scheduler, ::beman::execution::default_domain{})};
7087
        return ::beman::execution::transform_sender(
7088
            domain,
7089
            ::beman::execution::detail::make_sender(
7090
                *this, ::std::forward<Scheduler>(scheduler), ::std::forward<Sender>(sender)));
7091
    }
7092
};
7093
} // namespace beman::execution::detail
7094

7095
namespace beman::execution {
7096
export using starts_on_t = ::beman::execution::detail::starts_on_t;
7097
export inline constexpr ::beman::execution::detail::starts_on_t starts_on{};
7098
} // namespace beman::execution
7099

7100
// ----------------------------------------------------------------------------
7101

7102
// ----------------------------------------------------------------------------
7103

7104
namespace beman::execution::detail {
7105
struct when_all_with_variant_t {
7106
    // template <::beman::execution::detail::sender_for<when_all_with_variant_t> Sender>
7107
    template <::beman::execution::sender Sender>
7108
    auto transform_sender(Sender&& sender, auto&&...) const noexcept {
7109
        return ::std::forward<Sender>(sender).apply([](auto&&, auto&&, auto&&... child) {
7110
            return ::beman::execution::when_all(
7111
                ::beman::execution::into_variant(::beman::execution::detail::forward_like<Sender>(child))...);
7112
        });
7113
    }
7114

7115
    template <::beman::execution::sender... Sender>
7116
    auto operator()(Sender&&... sender) const {
7117
        using domain_t =
7118
            typename ::std::common_type_t<decltype(::beman::execution::detail::get_domain_early(sender))...>;
7119
        return ::beman::execution::transform_sender(
7120
            domain_t{}, ::beman::execution::detail::make_sender(*this, {}, ::std::forward<Sender>(sender)...));
7121
    }
7122
};
7123
} // namespace beman::execution::detail
7124

7125
namespace beman::execution {
7126
export using when_all_with_variant_t = ::beman::execution::detail::when_all_with_variant_t;
7127
export inline constexpr ::beman::execution::when_all_with_variant_t when_all_with_variant{};
7128
} // namespace beman::execution
7129

7130
// ----------------------------------------------------------------------------
7131

7132
namespace beman::execution {
7133
export template <::beman::execution::detail::class_type Promise>
7134
struct with_awaitable_senders {
7135
    template <class OtherPromise>
7136
        requires(!::std::same_as<OtherPromise, void>)
7137
    void set_continuation(::std::coroutine_handle<OtherPromise> h) noexcept {
7138
        contination_ = h;
7139
        if constexpr (requires(OtherPromise& other) { other.unhandled_stopped(); }) {
7140
            stopped_handler_ = [](void* p) noexcept -> ::std::coroutine_handle<> {
7141
                return ::std::coroutine_handle<OtherPromise>::from_address(p).promise().unhandled_stopped();
7142
            };
7143
        } else {
7144
            stopped_handler_ = &default_unhandled_stopped;
7145
        }
7146
    }
7147

7148
    ::std::coroutine_handle<> continuation() const noexcept { return contination_; }
7149

7150
    ::std::coroutine_handle<> unhandled_stopped() noexcept { return stopped_handler_(contination_.address()); }
7151

7152
    template <class Value>
7153
    auto await_transform(Value&& value)
7154
        -> ::beman::execution::detail::call_result_t<::beman::execution::as_awaitable_t, Value, Promise&> {
7155
        return ::beman::execution::as_awaitable(::std::forward<Value>(value), static_cast<Promise&>(*this));
7156
    }
7157

7158
  private:
7159
    friend Promise;
7160
    with_awaitable_senders() = default;
7161

7162
    [[noreturn]] static auto default_unhandled_stopped(void*) noexcept -> ::std::coroutine_handle<> {
7163
        ::std::terminate();
7164
    }
7165

7166
    ::std::coroutine_handle<> contination_{};
7167
    ::std::coroutine_handle<> (*stopped_handler_)(void*) noexcept = &default_unhandled_stopped;
7168
};
7169

7170
} // namespace beman::execution
7171

7172
// ----------------------------------------------------------------------------
7173

7174
namespace beman::execution {
7175
export class counting_scope;
7176
}
7177

7178
// ----------------------------------------------------------------------------
7179

7180
class beman::execution::counting_scope : public ::beman::execution::detail::counting_scope_base {
7181
  public:
7182
    class token;
7183

NEW
7184
    auto join() noexcept -> ::beman::execution::sender auto {
×
NEW
7185
        return ::beman::execution::detail::counting_scope_join(this);
×
7186
    }
7187
    auto get_token() noexcept -> token;
NEW
7188
    auto request_stop() noexcept -> void { this->stop_source.request_stop(); }
×
7189

7190
  private:
7191
    ::beman::execution::inplace_stop_source stop_source{};
7192
};
7193

7194
// ----------------------------------------------------------------------------
7195

7196
class beman::execution::counting_scope::token : public ::beman::execution::detail::counting_scope_base::token {
7197
  public:
7198
    template <::beman::execution::sender Sender>
7199
    auto wrap(Sender&& sender) const noexcept -> ::beman::execution::sender auto {
7200
        return ::beman::execution::detail::stop_when(
7201
            ::std::forward<Sender>(sender),
7202
            static_cast<::beman::execution::counting_scope*>(this->scope)->stop_source.get_token());
7203
    }
7204

7205
  private:
7206
    friend class beman::execution::counting_scope;
NEW
7207
    explicit token(::beman::execution::counting_scope* s)
×
NEW
7208
        : ::beman::execution::detail::counting_scope_base::token(s) {}
×
7209
};
7210
static_assert(::beman::execution::scope_token<::beman::execution::counting_scope::token>);
7211

7212
// ----------------------------------------------------------------------------
7213

7214
inline auto beman::execution::counting_scope::get_token() noexcept -> beman::execution::counting_scope::token {
7215
    return beman::execution::counting_scope::token(this);
7216
}
7217

7218
// ----------------------------------------------------------------------------
7219

7220
namespace beman::execution {
7221
export class simple_counting_scope;
7222
}
7223

7224
// ----------------------------------------------------------------------------
7225

7226
class beman::execution::simple_counting_scope : public ::beman::execution::detail::counting_scope_base {
7227
  public:
7228
    class token;
7229

7230
    auto get_token() noexcept -> token;
NEW
7231
    auto join() noexcept -> ::beman::execution::sender auto {
×
NEW
7232
        return ::beman::execution::detail::counting_scope_join(this);
×
7233
    }
7234
};
7235

7236
// ----------------------------------------------------------------------------
7237

7238
class beman::execution::simple_counting_scope::token : public ::beman::execution::detail::counting_scope_base::token {
7239
  public:
7240
    template <::beman::execution::sender Sender>
7241
    auto wrap(Sender&& sender) const noexcept -> Sender&& {
7242
        return ::std::forward<Sender>(sender);
7243
    }
7244

7245
  private:
7246
    friend class beman::execution::simple_counting_scope;
NEW
7247
    explicit token(::beman::execution::detail::counting_scope_base* s)
×
NEW
7248
        : ::beman::execution::detail::counting_scope_base::token(s) {}
×
7249
};
7250

7251
// ----------------------------------------------------------------------------
7252

7253
inline auto beman::execution::simple_counting_scope::get_token() noexcept
7254
    -> beman::execution::simple_counting_scope::token {
7255
    return beman::execution::simple_counting_scope::token(this);
7256
}
7257

7258
// ----------------------------------------------------------------------------
7259

7260
// ----------------------------------------------------------------------------
7261

7262
namespace beman::execution::detail {
7263
template <typename>
7264
struct non_throwing_args_copy;
7265
template <typename Rc, typename... A>
7266
struct non_throwing_args_copy<Rc(A...)> {
7267
    static constexpr bool value = (true && ... && ::std::is_nothrow_constructible_v<::std::decay_t<A>, A>);
7268
};
7269
template <typename S>
7270
inline constexpr bool non_throwing_args_copy_v{non_throwing_args_copy<S>::value};
7271

7272
template <typename Completions>
7273
struct spawn_future_state_base;
7274
template <typename... Sigs>
7275
struct spawn_future_state_base<::beman::execution::completion_signatures<Sigs...>> {
7276
    static constexpr bool has_non_throwing_args_copy = (true && ... && non_throwing_args_copy_v<Sigs>);
7277
    using result_t                                   = ::beman::execution::detail::meta::unique<
7278
                                          ::std::conditional_t<has_non_throwing_args_copy,
7279
                                                               ::std::variant<::std::monostate, ::beman::execution::detail::as_tuple_t<Sigs>...>,
7280
                                                               ::std::variant<::std::monostate,
7281
                                                                              ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>,
7282
                                                                              ::beman::execution::detail::as_tuple_t<Sigs>...>>>;
7283

7284
    result_t result{};
7285
    virtual ~spawn_future_state_base()       = default;
7286
    virtual auto complete() noexcept -> void = 0;
7287
};
7288

7289
template <typename Completions>
7290
struct spawn_future_receiver {
7291
    using receiver_concept = ::beman::execution::receiver_t;
7292
    using state_t          = ::beman::execution::detail::spawn_future_state_base<Completions>;
7293

7294
    state_t* state{};
7295

7296
    template <typename... A>
7297
    auto set_value(A&&... a) && noexcept -> void {
7298
        this->set_complete<::beman::execution::set_value_t>(::std::forward<A>(a)...);
7299
    }
7300
    template <typename E>
7301
    auto set_error(E&& e) && noexcept -> void {
7302
        this->set_complete<::beman::execution::set_error_t>(::std::forward<E>(e));
7303
    }
7304
    auto set_stopped() && noexcept -> void { this->set_complete<::beman::execution::set_stopped_t>(); }
7305

7306
    template <typename Tag, typename... T>
7307
    auto set_complete(T&&... t) noexcept {
7308
        try {
7309
            this->state->result.template emplace<::beman::execution::detail::decayed_tuple<Tag, T...>>(
7310
                Tag(), ::std::forward<T>(t)...);
7311
        } catch (...) {
7312
            if constexpr (!state_t::has_non_throwing_args_copy) {
7313
                this->state->result
7314
                    .template emplace<::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>>(
7315
                        ::beman::execution::set_error_t{}, ::std::current_exception());
7316
            }
7317
        }
7318
        this->state->complete();
7319
    }
7320
};
7321

7322
template <::beman::execution::sender Sndr, typename Env>
7323
using future_spawned_sender = decltype(::beman::execution::write_env(
7324
    ::beman::execution::detail::stop_when(::std::declval<Sndr>(),
7325
                                          ::std::declval<::beman::execution::inplace_stop_token>()),
7326
    ::std::declval<Env>()));
7327

7328
template <::beman::execution::sender Sndr, typename Env>
7329
using spawn_future_sigs = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
7330
    ::beman::execution::set_stopped_t(),
7331
    ::beman::execution::completion_signatures_of_t<::beman::execution::detail::future_spawned_sender<Sndr, Env>>>>;
7332

7333
template <typename Allocator, ::beman::execution::scope_token Token, ::beman::execution::sender Sndr, typename Env>
7334
struct spawn_future_state
7335
    : ::beman::execution::detail::spawn_future_state_base<::beman::execution::detail::spawn_future_sigs<Sndr, Env>> {
7336
    using alloc_t          = typename ::std::allocator_traits<Allocator>::template rebind_alloc<spawn_future_state>;
7337
    using traits_t         = ::std::allocator_traits<alloc_t>;
7338
    using spawned_sender_t = ::beman::execution::detail::future_spawned_sender<Sndr, Env>;
7339
    using sigs_t           = ::beman::execution::detail::spawn_future_sigs<Sndr, Env>;
7340
    using receiver_t       = ::beman::execution::detail::spawn_future_receiver<sigs_t>;
7341
    static_assert(::beman::execution::sender<spawned_sender_t>);
7342
    static_assert(::beman::execution::receiver<receiver_t>);
7343
    using op_t = ::beman::execution::connect_result_t<spawned_sender_t, receiver_t>;
7344

7345
    template <::beman::execution::sender S>
7346
    spawn_future_state(auto a, S&& s, Token tok, Env env)
7347
        : alloc(::std::move(a)),
7348
          op(::beman::execution::write_env(
7349
                 ::beman::execution::detail::stop_when(::std::forward<S>(s), source.get_token()), env),
7350
             receiver_t{this}),
7351
          token(::std::move(tok)),
7352
          associated(token.try_associate()) {
7353
        if (this->associated) {
7354
            ::beman::execution::start(this->op);
7355
        } else {
7356
            ::beman::execution::set_stopped(receiver_t{this});
7357
        }
7358
    }
7359
    auto complete() noexcept -> void override {
7360
        {
7361
            ::std::lock_guard cerberos(this->gate);
7362
            if (this->fun == nullptr) {
7363
                this->receiver = this;
7364
                return;
7365
            }
7366
        }
7367
        this->fun(this->receiver, *this);
7368
    }
7369
    auto abandon() noexcept -> void {
7370
        bool ready{[&] {
7371
            ::std::lock_guard cerberos(this->gate);
7372
            if (this->receiver == nullptr) {
7373
                this->receiver = this;
7374
                this->fun      = [](void*, spawn_future_state& state) noexcept { state.destroy(); };
7375
                return false;
7376
            }
7377
            return true;
7378
        }()};
7379
        if (ready) {
7380
            this->destroy();
7381
        } else {
7382
            this->source.request_stop();
7383
        }
7384
    }
7385
    template <::beman::execution::receiver Rcvr>
7386
    static auto complete_receiver(Rcvr& rcvr, typename spawn_future_state::result_t& res) noexcept {
7387
        std::visit(
7388
            [&rcvr]<typename Tuplish>(Tuplish&& tuplish) noexcept {
7389
                if constexpr (!::std::same_as<::std::remove_cvref_t<decltype(tuplish)>, ::std::monostate>) {
7390
                    ::std::apply(
7391
                        [&rcvr]<typename... Args>(auto cpo, Args&&... args) {
7392
                            cpo(::std::move(rcvr), ::std::forward<Args>(args)...);
7393
                        },
7394
                        ::std::forward<Tuplish>(tuplish));
7395
                }
7396
            },
7397
            ::std::move(res));
7398
    }
7399
    template <::beman::execution::receiver Rcvr>
7400
    auto consume(Rcvr& rcvr) noexcept -> void {
7401
        {
7402
            ::std::lock_guard cerberos(this->gate);
7403
            if (this->receiver == nullptr) {
7404
                this->receiver = &rcvr;
7405
                this->fun      = [](void* ptr, spawn_future_state& state) noexcept {
7406
                    spawn_future_state::complete_receiver(*static_cast<Rcvr*>(ptr), state.result);
7407
                };
7408
                return;
7409
            }
7410
        }
7411
        spawn_future_state::complete_receiver(rcvr, this->result);
7412
    }
7413
    auto destroy() noexcept -> void {
7414
        Token tok{this->token};
7415
        bool  assoc{this->associated};
7416
        {
7417
            alloc_t a{this->alloc};
7418
            traits_t::destroy(a, this);
7419
            traits_t::deallocate(a, this, 1u);
7420
        }
7421
        if (assoc) {
7422
            tok.disassociate();
7423
        }
7424
    }
7425

7426
    ::std::mutex                            gate{};
7427
    alloc_t                                 alloc;
7428
    ::beman::execution::inplace_stop_source source{};
7429
    op_t                                    op;
7430
    Token                                   token;
7431
    bool                                    associated{false};
7432
    void*                                   receiver{};
7433
    auto (*fun)(void*, spawn_future_state&) noexcept -> void = nullptr;
7434
};
7435

7436
class spawn_future_t {
7437
  public:
7438
    template <::beman::execution::sender Sndr, ::beman::execution::scope_token Tok, typename Ev>
7439
        requires ::beman::execution::detail::queryable<::std::remove_cvref_t<Ev>>
7440
    auto operator()(Sndr&& sndr, Tok&& tok, Ev&& ev) const {
7441
        auto make{[&]() -> decltype(auto) { //-dk:TODO why decltype(auto) instead of auto?
7442
            return tok.wrap(::std::forward<Sndr>(sndr));
7443
        }};
7444
        using sndr_t = decltype(make());
7445
        static_assert(::beman::execution::sender<Sndr>);
7446

7447
        auto [alloc, senv] = spawn_get_allocator(sndr, ev);
7448
        using state_t = ::beman::execution::detail::spawn_future_state<decltype(alloc), Tok, sndr_t, decltype(senv)>;
7449
        using state_alloc_t  = typename ::std::allocator_traits<decltype(alloc)>::template rebind_alloc<state_t>;
7450
        using state_traits_t = ::std::allocator_traits<state_alloc_t>;
7451
        state_alloc_t state_alloc(alloc);
7452
        state_t*      op{state_traits_t::allocate(state_alloc, 1u)};
7453
        try {
7454
            state_traits_t::construct(state_alloc, op, alloc, make(), tok, senv);
7455
        } catch (...) {
7456
            state_traits_t::deallocate(state_alloc, op, 1u);
7457
            throw;
7458
        }
7459

7460
        using deleter = decltype([](state_t* p) noexcept { p->abandon(); });
7461
        return ::beman::execution::detail::make_sender(*this, ::std::unique_ptr<state_t, deleter>{op});
7462
    }
7463
    template <::beman::execution::sender Sndr, ::beman::execution::scope_token Tok>
7464
    auto operator()(Sndr&& sndr, Tok&& tok) const {
7465
        return (*this)(::std::forward<Sndr>(sndr), ::std::forward<Tok>(tok), ::beman::execution::env<>{});
7466
    }
7467
};
7468

7469
template <typename State, typename Deleter, typename Env>
7470
struct completion_signatures_for_impl<
7471
    ::beman::execution::detail::basic_sender<::beman::execution::detail::spawn_future_t,
7472
                                             ::std::unique_ptr<State, Deleter>>,
7473
    Env> {
7474
    using type = typename State::sigs_t;
7475
};
7476

7477
template <>
7478
struct impls_for<spawn_future_t> : ::beman::execution::detail::default_impls {
7479
    static constexpr auto start{[](auto& state, auto& rcvr) noexcept -> void { state->consume(rcvr); }};
7480
};
7481
} // namespace beman::execution::detail
7482

7483
namespace beman::execution {
7484
export using spawn_future_t = ::beman::execution::detail::spawn_future_t;
7485
export inline constexpr spawn_future_t spawn_future{};
7486
} // namespace beman::execution
7487

7488
// ----------------------------------------------------------------------------
7489

7490
// ----------------------------------------------------------------------------
7491

7492
namespace beman::execution::detail {
7493
struct spawn_t {
7494
    struct state_base {
7495
        virtual ~state_base()                    = default;
7496
        virtual auto complete() noexcept -> void = 0;
7497
    };
7498

7499
    struct receiver {
7500
        using receiver_concept = ::beman::execution::receiver_t;
7501
        state_base* state{};
7502

NEW
7503
        auto set_value() && noexcept -> void { this->state->complete(); }
×
NEW
7504
        auto set_stopped() && noexcept -> void { this->state->complete(); }
×
7505
    };
1✔
7506

1✔
7507
    template <typename Alloc, ::beman::execution::scope_token Tok, ::beman::execution::sender Sndr>
1✔
7508
    struct state : state_base {
2✔
7509
        using op_t     = ::beman::execution::connect_result_t<Sndr, receiver>;
1✔
7510
        using alloc_t  = typename ::std::allocator_traits<Alloc>::template rebind_alloc<state>;
7511
        using traits_t = ::std::allocator_traits<alloc_t>;
7512

7513
        state(Alloc a, Sndr&& sndr, Tok tok)
7514
            : alloc(a), op(::beman::execution::connect(::std::forward<Sndr>(sndr), receiver{this})), token(tok) {
7515
            if (this->token.try_associate()) {
7516
                ::beman::execution::start(this->op);
7517
            } else {
7518
                this->destroy();
7519
            }
7520
        }
7521
        auto complete() noexcept -> void override {
7522
            Tok tok(this->token);
7523
            this->destroy();
7524
            tok.disassociate();
7525
        }
7526
        auto destroy() noexcept -> void {
7527
            alloc_t all(this->alloc);
7528
            traits_t::destroy(all, this);
7529
            traits_t::deallocate(all, this, 1);
7530
        }
7531

7532
        alloc_t alloc;
7533
        op_t    op;
7534
        Tok     token;
7535
    };
7536

7537
    template <::beman::execution::sender Sender, ::beman::execution::scope_token Token, typename Env>
7538
    auto operator()(Sender&& sender, Token&& tok, Env&& env) const {
7539
        auto new_sender{tok.wrap(::std::forward<Sender>(sender))};
7540
        auto [all, senv] = ::beman::execution::detail::spawn_get_allocator(new_sender, env);
7541

7542
        using sender_t = decltype(::beman::execution::write_env(::std::move(new_sender), senv));
7543
        using state_t  = state<decltype(all), Token, sender_t>;
7544
        using alloc_t  = typename ::std::allocator_traits<decltype(all)>::template rebind_alloc<state_t>;
7545
        using traits_t = ::std::allocator_traits<alloc_t>;
7546
        alloc_t  alloc(all);
7547
        state_t* op{traits_t::allocate(alloc, 1u)};
7548
        traits_t::construct(alloc, op, all, ::beman::execution::write_env(::std::move(new_sender), senv), tok);
7549
    }
7550
    template <::beman::execution::sender Sender, ::beman::execution::scope_token Token>
7551
    auto operator()(Sender&& sender, Token&& token) const {
7552
        return (*this)(::std::forward<Sender>(sender), ::std::forward<Token>(token), ::beman::execution::env<>{});
7553
    }
7554
};
7555
} // namespace beman::execution::detail
7556

7557
namespace beman::execution {
7558
export using spawn_t = ::beman::execution::detail::spawn_t;
7559
export inline constexpr spawn_t spawn{};
7560
} // namespace beman::execution
7561

7562
// ----------------------------------------------------------------------------
7563

7564
// ----------------------------------------------------------------------------
7565

7566
namespace beman::execution::detail {
7567
struct on_t : ::beman::execution::sender_adaptor_closure<on_t> {
7568
    template <::beman::execution::detail::sender_for<on_t> OutSndr, typename Env>
7569
    auto transform_env(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) {
7570
        auto&& data{out_sndr.template get<1>()};
7571

7572
        if constexpr (::beman::execution::scheduler<decltype(data)>)
7573
            return ::beman::execution::detail::join_env(
7574
                ::beman::execution::detail::sched_env(::beman::execution::detail::forward_like<OutSndr>(data)
7575

7576
                                                          ),
7577
                ::beman::execution::detail::fwd_env(::std::forward<Env>(env)));
7578
        else
7579
            return std::forward<Env>(env);
7580
    }
7581

7582
    template <typename>
7583
    struct env_needs_get_scheduler {
7584
        using sender_concept = ::beman::execution::sender_t;
7585
        template <typename Env>
7586
        auto get_completion_signatures(Env&&) const {
7587
            return env_needs_get_scheduler<Env>{};
7588
        }
7589
    };
7590

7591
    template <::beman::execution::detail::sender_for<on_t> OutSndr, typename Env>
7592
    auto transform_sender(OutSndr&& out_sndr, Env&& env) const -> decltype(auto) {
7593
        struct not_a_scheduler {};
7594
        auto&& [_, data, child] = out_sndr;
7595

7596
        if constexpr (::beman::execution::scheduler<decltype(data)>) {
7597
            auto sch{::beman::execution::detail::query_with_default(
7598
                ::beman::execution::get_scheduler, env, not_a_scheduler{})};
7599
            if constexpr (::std::same_as<not_a_scheduler, decltype(sch)>) {
7600
                return env_needs_get_scheduler<Env>{};
7601
            } else {
7602
                return ::beman::execution::continues_on(
7603
                    ::beman::execution::starts_on(::beman::execution::detail::forward_like<OutSndr>(data),
7604
                                                  ::beman::execution::detail::forward_like<OutSndr>(child)),
7605
                    ::std::move(sch));
7606
            }
7607
        } else {
7608
            auto& [sch, closure] = data;
7609
            auto orig_sch{::beman::execution::detail::query_with_default(
7610
                ::beman::execution::get_completion_scheduler<::beman::execution::set_value_t>,
7611
                ::beman::execution::get_env(child),
7612
                ::beman::execution::detail::query_with_default(
7613
                    ::beman::execution::get_scheduler, env, not_a_scheduler{}))};
7614

7615
            if constexpr (::std::same_as<not_a_scheduler, decltype(orig_sch)>) {
7616
                return env_needs_get_scheduler<Env>{};
7617
            } else {
7618
                return ::beman::execution::detail::write_env(
7619
                    ::beman::execution::continues_on(
7620
                        ::beman::execution::detail::forward_like<OutSndr>(closure)(::beman::execution::continues_on(
7621
                            ::beman::execution::detail::write_env(
7622
                                ::beman::execution::detail::forward_like<OutSndr>(child),
7623
                                ::beman::execution::detail::sched_env(orig_sch)),
7624
                            sch)),
7625
                        orig_sch),
7626
                    ::beman::execution::detail::sched_env(env));
7627
            }
7628
        }
7629
    }
7630

7631
    template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr>
7632
        requires ::beman::execution::detail::is_sender_adaptor_closure<Sndr>
7633
    auto operator()(Sch&&, Sndr&&) const -> void =
7634
        BEMAN_EXECUTION_DELETE("on(sch, sndr) requires that sndr isn't both a sender and sender adaptor closure");
7635

7636
    template <::beman::execution::scheduler                         Sch,
7637
              ::beman::execution::sender                            Sndr,
7638
              ::beman::execution::detail::is_sender_adaptor_closure Closure>
7639
        requires ::beman::execution::detail::is_sender_adaptor_closure<Sndr>
7640
    auto operator()(Sndr&&, Sch&&, Closure&&) const -> void =
7641
        BEMAN_EXECUTION_DELETE("on(sch, sndr) requires that sndr isn't both a sender and sender adaptor closure");
7642

7643
    template <::beman::execution::scheduler Sch, ::beman::execution::sender Sndr>
7644
    auto operator()(Sch&& sch, Sndr&& sndr) const {
7645
        auto domain{::beman::execution::detail::query_with_default(
7646
            ::beman::execution::get_domain, sch, ::beman::execution::default_domain{})};
7647
        return ::beman::execution::transform_sender(
7648
            domain,
7649
            ::beman::execution::detail::make_sender(*this, ::std::forward<Sch>(sch), ::std::forward<Sndr>(sndr)));
7650
    }
7651
    template <::beman::execution::scheduler                         Sch,
7652
              ::beman::execution::sender                            Sndr,
7653
              ::beman::execution::detail::is_sender_adaptor_closure Closure>
7654
    auto operator()(Sndr&& sndr, Sch&& sch, Closure&& closure) const {
7655
        auto domain{::beman::execution::detail::get_domain_early(sndr)};
7656
        return ::beman::execution::transform_sender(
7657
            domain,
7658
            ::beman::execution::detail::make_sender(
7659
                *this,
7660
                ::beman::execution::detail::product_type{::std::forward<Sch>(sch), ::std::forward<Closure>(closure)},
7661
                ::std::forward<Sndr>(sndr)));
7662
    }
7663
    template <::beman::execution::scheduler Sch, ::beman::execution::detail::is_sender_adaptor_closure Closure>
7664
    auto operator()(Sch&& sch, Closure&& closure) const {
7665
        return ::beman::execution::detail::sender_adaptor{
7666
            *this, ::std::forward<Sch>(sch), ::std::forward<Closure>(closure)};
7667
    }
7668
};
7669

7670
} // namespace beman::execution::detail
7671

7672
namespace beman::execution {
7673
export using on_t = ::beman::execution::detail::on_t;
7674
export inline constexpr ::beman::execution::on_t on{};
7675
} // namespace beman::execution
7676

7677
// ----------------------------------------------------------------------------
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