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

bemanproject / execution / 16679323791

31 Jul 2025 09:10PM UTC coverage: 92.436% (-0.006%) from 92.442%
16679323791

push

github

web-flow
Fix issues with xcode 15.4 (#177)

4 of 5 new or added lines in 2 files covered. (80.0%)

1161 of 1256 relevant lines covered (92.44%)

156.65 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_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
5
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
6

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

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

41
// ----------------------------------------------------------------------------
42

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

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

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

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

75
    state_t* state{};
76

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

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

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

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

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

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

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

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

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

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

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

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

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

269
// ----------------------------------------------------------------------------
270

271
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc