• 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

96.34
/include/beman/execution/detail/spawn_future.hpp
1
// include/beman/execution/detail/spawn_future.hpp                    -*-C++-*-
2
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3

4
#ifndef INCLUDED_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
5
#define INCLUDED_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
6

7
#include <beman/execution/detail/common.hpp>
8
#include <beman/execution/detail/spawn_get_allocator.hpp>
9
#include <beman/execution/detail/as_tuple.hpp>
10
#include <beman/execution/detail/scope_token.hpp>
11
#include <beman/execution/detail/completion_signatures_of_t.hpp>
12
#include <beman/execution/detail/connect_result_t.hpp>
13
#include <beman/execution/detail/default_impls.hpp>
14
#include <beman/execution/detail/env.hpp>
15
#include <beman/execution/detail/get_allocator.hpp>
16
#include <beman/execution/detail/get_env.hpp>
17
#include <beman/execution/detail/impls_for.hpp>
18
#include <beman/execution/detail/inplace_stop_source.hpp>
19
#include <beman/execution/detail/join_env.hpp>
20
#include <beman/execution/detail/make_sender.hpp>
21
#include <beman/execution/detail/meta_unique.hpp>
22
#include <beman/execution/detail/meta_combine.hpp>
23
#include <beman/execution/detail/prop.hpp>
24
#include <beman/execution/detail/queryable.hpp>
25
#include <beman/execution/detail/receiver.hpp>
26
#include <beman/execution/detail/sender.hpp>
27
#include <beman/execution/detail/set_error.hpp>
28
#include <beman/execution/detail/set_stopped.hpp>
29
#include <beman/execution/detail/set_value.hpp>
30
#include <beman/execution/detail/stop_when.hpp>
31
#include <beman/execution/detail/start.hpp>
32
#include <beman/execution/detail/write_env.hpp>
33

34
#include <exception>
35
#include <memory>
36
#include <mutex>
37
#include <tuple>
38
#include <type_traits>
39
#include <utility>
40
#include <variant>
41

42
// ----------------------------------------------------------------------------
43

44
namespace beman::execution::detail {
45
template <typename>
46
struct non_throwing_args_copy;
47
template <typename Rc, typename... A>
48
struct non_throwing_args_copy<Rc(A...)> {
49
    static constexpr bool value = (true && ... && ::std::is_nothrow_constructible_v<::std::decay_t<A>, A>);
50
};
51
template <typename S>
52
inline constexpr bool non_throwing_args_copy_v{non_throwing_args_copy<S>::value};
53

54
template <typename Completions>
55
struct spawn_future_state_base;
56
template <typename... Sigs>
57
struct spawn_future_state_base<::beman::execution::completion_signatures<Sigs...>> {
58
    static constexpr bool has_non_throwing_args_copy = (true && ... && non_throwing_args_copy_v<Sigs>);
59
    using result_t                                   = ::beman::execution::detail::meta::unique<
60
                                          ::std::conditional_t<has_non_throwing_args_copy,
61
                                                               ::std::variant<::std::monostate, ::beman::execution::detail::as_tuple_t<Sigs>...>,
62
                                                               ::std::variant<::std::monostate,
63
                                                                              ::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>,
64
                                                                              ::beman::execution::detail::as_tuple_t<Sigs>...>>>;
65

66
    result_t result{};
67
    virtual ~spawn_future_state_base()       = default;
14✔
68
    virtual auto complete() noexcept -> void = 0;
69
};
70

71
template <typename Completions>
72
struct spawn_future_receiver {
73
    using receiver_concept = ::beman::execution::receiver_t;
74
    using state_t          = ::beman::execution::detail::spawn_future_state_base<Completions>;
75

76
    state_t* state{};
77

78
    template <typename... A>
79
    auto set_value(A&&... a) && noexcept -> void {
6✔
80
        this->set_complete<::beman::execution::set_value_t>(::std::forward<A>(a)...);
10✔
81
    }
6✔
82
    template <typename E>
83
    auto set_error(E&& e) && noexcept -> void {
1✔
84
        this->set_complete<::beman::execution::set_error_t>(::std::forward<E>(e));
1✔
85
    }
1✔
86
    auto set_stopped() && noexcept -> void { this->set_complete<::beman::execution::set_stopped_t>(); }
1✔
87

88
    template <typename Tag, typename... T>
89
    auto set_complete(T&&... t) noexcept {
8✔
90
        try {
91
            this->state->result.template emplace<::beman::execution::detail::decayed_tuple<Tag, T...>>(
19✔
92
                Tag(), ::std::forward<T>(t)...);
8✔
93
        } catch (...) {
1✔
94
            if constexpr (!state_t::has_non_throwing_args_copy) {
95
                this->state->result
96
                    .template emplace<::std::tuple<::beman::execution::set_error_t, ::std::exception_ptr>>(
97
                        ::beman::execution::set_error_t{}, ::std::current_exception());
98
            }
99
        }
100
        this->state->complete();
8✔
101
    }
8✔
102
};
1✔
103

1✔
104
template <::beman::execution::sender Sndr, typename Env>
2✔
105
using future_spawned_sender = decltype(::beman::execution::write_env(
106
    ::beman::execution::detail::stop_when(::std::declval<Sndr>(),
107
                                          ::std::declval<::beman::execution::inplace_stop_token>()),
108
    ::std::declval<Env>()));
109

110
template <::beman::execution::sender Sndr, typename Env>
111
using spawn_future_sigs = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::prepend<
112
    ::beman::execution::set_stopped_t(),
113
    ::beman::execution::completion_signatures_of_t<::beman::execution::detail::future_spawned_sender<Sndr, Env>>>>;
114

115
template <typename Allocator, ::beman::execution::scope_token Token, ::beman::execution::sender Sndr, typename Env>
116
struct spawn_future_state
117
    : ::beman::execution::detail::spawn_future_state_base<::beman::execution::detail::spawn_future_sigs<Sndr, Env>> {
118
    using alloc_t          = typename ::std::allocator_traits<Allocator>::template rebind_alloc<spawn_future_state>;
119
    using traits_t         = ::std::allocator_traits<alloc_t>;
120
    using spawned_sender_t = ::beman::execution::detail::future_spawned_sender<Sndr, Env>;
121
    using sigs_t           = ::beman::execution::detail::spawn_future_sigs<Sndr, Env>;
122
    using receiver_t       = ::beman::execution::detail::spawn_future_receiver<sigs_t>;
123
    static_assert(::beman::execution::sender<spawned_sender_t>);
124
    static_assert(::beman::execution::receiver<receiver_t>);
125
    using op_t = ::beman::execution::connect_result_t<spawned_sender_t, receiver_t>;
126

127
    template <::beman::execution::sender S>
128
    spawn_future_state(auto a, S&& s, Token tok, Env env)
4✔
129
        : alloc(::std::move(a)),
8✔
130
          op(::beman::execution::write_env(
4✔
131
                 ::beman::execution::detail::stop_when(::std::forward<S>(s), source.get_token()), env),
12✔
132
             receiver_t{this}),
133
          token(::std::move(tok)),
4✔
134
          associated(token.try_associate()) {
12✔
135
        if (this->associated) {
4✔
136
            ::beman::execution::start(this->op);
4✔
137
        } else {
138
            ::beman::execution::set_stopped(receiver_t{this});
×
139
        }
140
    }
4✔
141
    auto complete() noexcept -> void override {
4✔
142
        {
143
            ::std::lock_guard cerberos(this->gate);
4✔
144
            if (this->fun == nullptr) {
4✔
145
                this->receiver = this;
2✔
146
                return;
2✔
147
            }
148
        }
4✔
149
        this->fun(this->receiver, *this);
2✔
150
    }
151
    auto abandon() noexcept -> void {
4✔
152
        bool ready{[&] {
12✔
153
            ::std::lock_guard cerberos(this->gate);
154
            if (this->receiver == nullptr) {
155
                this->receiver = this;
156
                this->fun      = [](void*, spawn_future_state& state) noexcept { state.destroy(); };
157
                return false;
158
            }
159
            return true;
160
        }()};
8✔
161
        if (ready) {
4✔
162
            this->destroy();
3✔
163
        } else {
164
            this->source.request_stop();
1✔
165
        }
166
    }
4✔
167
    template <::beman::execution::receiver Rcvr>
4✔
168
    static auto complete_receiver(Rcvr& rcvr, typename spawn_future_state::result_t& res) noexcept {
4✔
169
        std::visit(
1✔
170
            [&rcvr]<typename Tuplish>(Tuplish&& tuplish) noexcept {
2✔
171
                if constexpr (!::std::same_as<::std::remove_cvref_t<decltype(tuplish)>, ::std::monostate>) {
1✔
172
                    ::std::apply(
3✔
173
                        [&rcvr]<typename... Args>(auto cpo, Args&&... args) {
2✔
174
                            cpo(::std::move(rcvr), ::std::forward<Args>(args)...);
2✔
175
                        },
6✔
176
                        ::std::forward<Tuplish>(tuplish));
177
                }
178
            },
179
            ::std::move(res));
2✔
180
    }
2✔
181
    template <::beman::execution::receiver Rcvr>
2✔
182
    auto consume(Rcvr& rcvr) noexcept -> void {
4✔
183
        {
4✔
184
            ::std::lock_guard cerberos(this->gate);
2✔
185
            if (this->receiver == nullptr) {
2✔
186
                this->receiver = &rcvr;
2✔
187
                this->fun      = [](void* ptr, spawn_future_state& state) noexcept {
1✔
188
                    spawn_future_state::complete_receiver(*static_cast<Rcvr*>(ptr), state.result);
3✔
189
                };
190
                return;
1✔
191
            }
192
        }
2✔
193
        spawn_future_state::complete_receiver(rcvr, this->result);
1✔
194
    }
1✔
195
    auto destroy() noexcept -> void {
4✔
196
        Token tok{this->token};
4✔
197
        bool  assoc{this->associated};
4✔
198
        {
199
            alloc_t a{this->alloc};
4✔
200
            traits_t::destroy(a, this);
201
            traits_t::deallocate(a, this, 1u);
202
        }
203
        if (assoc) {
4✔
204
            tok.disassociate();
4✔
205
        }
206
    }
4✔
207

208
    ::std::mutex                            gate{};
209
    alloc_t                                 alloc;
210
    ::beman::execution::inplace_stop_source source{};
211
    op_t                                    op;
212
    Token                                   token;
213
    bool                                    associated{false};
214
    void*                                   receiver{};
215
    auto (*fun)(void*, spawn_future_state&) noexcept -> void = nullptr;
216
};
217

218
class spawn_future_t {
219
  public:
220
    template <::beman::execution::sender Sndr, ::beman::execution::scope_token Tok, typename Ev>
221
        requires ::beman::execution::detail::queryable<::std::remove_cvref_t<Ev>>
222
    auto operator()(Sndr&& sndr, Tok&& tok, Ev&& ev) const {
4✔
223
        auto make{[&]() -> decltype(auto) { //-dk:TODO why decltype(auto) instead of auto?
8✔
224
            return tok.wrap(::std::forward<Sndr>(sndr));
225
        }};
226
        using sndr_t = decltype(make());
227
        static_assert(::beman::execution::sender<Sndr>);
228

229
        auto [alloc, senv] = spawn_get_allocator(sndr, ev);
4✔
230
        using state_t = ::beman::execution::detail::spawn_future_state<decltype(alloc), Tok, sndr_t, decltype(senv)>;
231
        using state_alloc_t  = typename ::std::allocator_traits<decltype(alloc)>::template rebind_alloc<state_t>;
232
        using state_traits_t = ::std::allocator_traits<state_alloc_t>;
233
        state_alloc_t state_alloc(alloc);
234
        state_t*      op{state_traits_t::allocate(state_alloc, 1u)};
4✔
235
        try {
236
            state_traits_t::construct(state_alloc, op, alloc, make(), tok, senv);
4✔
UNCOV
237
        } catch (...) {
×
238
            state_traits_t::deallocate(state_alloc, op, 1u);
UNCOV
239
            throw;
×
240
        }
241

242
        using deleter = decltype([](state_t* p) noexcept { p->abandon(); });
243
        return ::beman::execution::detail::make_sender(*this, ::std::unique_ptr<state_t, deleter>{op});
8✔
244
    }
8✔
245
    template <::beman::execution::sender Sndr, ::beman::execution::scope_token Tok>
4✔
246
    auto operator()(Sndr&& sndr, Tok&& tok) const {
247
        return (*this)(::std::forward<Sndr>(sndr), ::std::forward<Tok>(tok), ::beman::execution::env<>{});
248
    }
249
};
250

251
template <typename State, typename Deleter, typename Env>
252
struct completion_signatures_for_impl<
253
    ::beman::execution::detail::basic_sender<::beman::execution::detail::spawn_future_t,
254
                                             ::std::unique_ptr<State, Deleter>>,
255
    Env> {
256
    using type = typename State::sigs_t;
257
};
258

259
template <>
260
struct impls_for<spawn_future_t> : ::beman::execution::detail::default_impls {
261
    static constexpr auto start{[](auto& state, auto& rcvr) noexcept -> void { state->consume(rcvr); }};
2✔
262
};
263
} // namespace beman::execution::detail
264

265
namespace beman::execution {
266
BEMAN_EXECUTION_EXPORT using spawn_future_t = ::beman::execution::detail::spawn_future_t;
267
BEMAN_EXECUTION_EXPORT inline constexpr spawn_future_t spawn_future{};
268
} // namespace beman::execution
269

270
// ----------------------------------------------------------------------------
271

272
#endif // INCLUDED_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
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