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

STEllAR-GROUP / hpx / #852

17 Dec 2022 04:43PM UTC coverage: 85.912% (-0.7%) from 86.568%
#852

push

StellarBot
Merge #6106

6106: Modernizing modules of levels 0 to 5 r=hkaiser a=hkaiser

- flyby: HPX_FORWARD/HPX_MOVE now expand to std::forward and std::move if those are implemented as builtin functions

working towards #5497

Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

87 of 87 new or added lines in 24 files covered. (100.0%)

173152 of 201546 relevant lines covered (85.91%)

1910264.28 hits per line

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

60.87
/libs/core/execution/include/hpx/execution/algorithms/start_detached.hpp
1
//  Copyright (c) 2021 ETH Zurich
2
//  Copyright (c) 2022 Hartmut Kaiser
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#pragma once
9

10
#include <hpx/config.hpp>
11
#include <hpx/allocator_support/allocator_deleter.hpp>
12
#include <hpx/allocator_support/internal_allocator.hpp>
13
#include <hpx/allocator_support/traits/is_allocator.hpp>
14
#include <hpx/assert.hpp>
15
#include <hpx/concepts/concepts.hpp>
16
#include <hpx/execution/algorithms/detail/inject_scheduler.hpp>
17
#include <hpx/execution/algorithms/detail/partial_algorithm.hpp>
18
#include <hpx/execution/algorithms/run_loop.hpp>
19
#include <hpx/execution_base/completion_scheduler.hpp>
20
#include <hpx/execution_base/completion_signatures.hpp>
21
#include <hpx/execution_base/operation_state.hpp>
22
#include <hpx/execution_base/receiver.hpp>
23
#include <hpx/execution_base/sender.hpp>
24
#include <hpx/functional/detail/tag_priority_invoke.hpp>
25
#include <hpx/functional/invoke_result.hpp>
26
#include <hpx/modules/memory.hpp>
27
#include <hpx/thread_support/atomic_count.hpp>
28
#include <hpx/type_support/meta.hpp>
29
#include <hpx/type_support/unused.hpp>
30

31
#include <atomic>
32
#include <cstddef>
33
#include <exception>
34
#include <memory>
35
#include <type_traits>
36
#include <utility>
37

38
namespace hpx::execution::experimental {
39

40
    namespace detail {
41

42
        template <typename Derived, typename Sender, typename Allocator>
43
        struct operation_state_holder_base
3,308✔
44
        {
45
            struct start_detached_receiver
42,855✔
46
            {
47
                hpx::intrusive_ptr<Derived> op_state;
48

49
                template <typename Error>
50
                [[noreturn]] friend void tag_invoke(
×
51
                    set_error_t, start_detached_receiver&&, Error&&) noexcept
52
                {
53
                    HPX_ASSERT_MSG(false,
×
54
                        "set_error was called on the receiver of "
55
                        "start_detached, "
56
                        "terminating. If you want to allow errors from the "
57
                        "predecessor sender, handle them first with e.g. "
58
                        "let_error.");
59
                    std::terminate();
×
60
                }
×
61

62
                friend void tag_invoke(
×
63
                    set_stopped_t, start_detached_receiver&& r) noexcept
64
                {
65
                    r.op_state->finish();
×
66
                    r.op_state.reset();
×
67
                };
×
68

69
                template <typename... Ts>
70
                friend void tag_invoke(
3,305✔
71
                    set_value_t, start_detached_receiver&& r, Ts&&...) noexcept
72
                {
73
                    r.op_state->finish();
3,305✔
74
                    r.op_state.reset();
3,305✔
75
                }
3,305✔
76
            };
77

78
        protected:
79
            using allocator_type = typename std::allocator_traits<
80
                Allocator>::template rebind_alloc<Derived>;
81

82
        private:
83
            HPX_NO_UNIQUE_ADDRESS allocator_type alloc;
84
            hpx::util::atomic_count count{0};
3,308✔
85

86
            using operation_state_type =
87
                connect_result_t<Sender, start_detached_receiver>;
88
            std::decay_t<operation_state_type> op_state;
89

90
        public:
91
            template <typename Sender_>
92
            explicit operation_state_holder_base(
3,308✔
93
                Sender_&& sender, allocator_type const& alloc)
94
              : alloc(alloc)
3,308✔
95
              , op_state(connect(HPX_FORWARD(Sender_, sender),
6,616✔
96
                    start_detached_receiver{static_cast<Derived*>(this)}))
3,308✔
97
            {
98
                hpx::execution::experimental::start(op_state);
3,308✔
99
            }
3,308✔
100

101
        private:
102
            friend void intrusive_ptr_add_ref(
3,308✔
103
                operation_state_holder_base* p) noexcept
104
            {
105
                ++p->count;
3,308✔
106
            }
3,308✔
107

108
            friend void intrusive_ptr_release(
3,308✔
109
                operation_state_holder_base* p) noexcept
110
            {
111
                if (--p->count == 0)
3,308✔
112
                {
113
                    allocator_type other_alloc(p->alloc);
3,308✔
114
                    std::allocator_traits<allocator_type>::destroy(
3,308✔
115
                        other_alloc, static_cast<Derived*>(p));
3,308✔
116
                    std::allocator_traits<allocator_type>::deallocate(
3,308✔
117
                        other_alloc, static_cast<Derived*>(p), 1);
3,308✔
118
                }
3,308✔
119
            }
3,308✔
120
        };
121

122
        template <typename Sender, typename Allocator>
123
        struct operation_state_holder
3,308✔
124
          : operation_state_holder_base<
125
                operation_state_holder<Sender, Allocator>, Sender, Allocator>
126
        {
127
            using base_type = operation_state_holder_base<
128
                operation_state_holder<Sender, Allocator>, Sender, Allocator>;
129
            using allocator_type = typename base_type::allocator_type;
130

131
            template <typename Sender_>
132
            explicit operation_state_holder(
3,308✔
133
                Sender_&& sender, allocator_type const& alloc)
134
              : base_type(HPX_FORWARD(Sender_, sender), alloc)
3,308✔
135
            {
3,308✔
136
            }
3,308✔
137

138
            static constexpr void finish() noexcept {}
3,305✔
139
        };
140

141
        template <typename Sender, typename Allocator>
142
        struct operation_state_holder_with_run_loop
×
143
          : operation_state_holder_base<
144
                operation_state_holder_with_run_loop<Sender, Allocator>, Sender,
145
                Allocator>
146
        {
147
        private:
148
            hpx::execution::experimental::run_loop& loop;
149

150
            using base_type = operation_state_holder_base<
151
                operation_state_holder_with_run_loop<Sender, Allocator>, Sender,
152
                Allocator>;
153

154
        public:
155
            template <typename Sender_, typename Allocator_>
156
            explicit operation_state_holder_with_run_loop(
×
157
                hpx::execution::experimental::run_loop_scheduler const& sched,
158
                Sender_&& sender, Allocator_ const& alloc)
159
              : base_type(HPX_FORWARD(Sender_, sender), alloc)
×
160
              , loop(sched.get_run_loop())
×
161
            {
×
162
                // keep ourselves alive
163
                hpx::intrusive_ptr<operation_state_holder_with_run_loop> this_(
×
164
                    this);
165
                loop.run();
×
166
            }
×
167

168
            void finish() noexcept
×
169
            {
170
                loop.finish();
×
171
            }
×
172
        };
173
    }    // namespace detail
174

175
    // execution::start_detached is used to eagerly start a sender without the
176
    // caller needing to manage the lifetimes of any objects.
177
    //
178
    // Like ensure_started, but does not return a value; if the provided sender
179
    // sends an error instead of a value, std::terminate is called.
180
    inline constexpr struct start_detached_t final
181
      : hpx::functional::detail::tag_priority<start_detached_t>
182
    {
183
    private:
184
        // clang-format off
185
        template <typename Sender,
186
            typename Allocator = hpx::util::internal_allocator<>,
187
            HPX_CONCEPT_REQUIRES_(
188
                is_sender_v<Sender> &&
189
                hpx::traits::is_allocator_v<Allocator> &&
190
                experimental::detail::is_completion_scheduler_tag_invocable_v<
191
                    hpx::execution::experimental::set_value_t,
192
                    start_detached_t, Sender, Allocator
193
                >
194
            )>
195
        // clang-format on
196
        friend constexpr HPX_FORCEINLINE auto tag_override_invoke(
197
            start_detached_t, Sender&& sender,
198
            Allocator const& allocator = Allocator{})
199
        {
200
            auto scheduler = get_completion_scheduler<
201
                hpx::execution::experimental::set_value_t>(sender);
202

203
            return hpx::functional::tag_invoke(start_detached_t{},
204
                HPX_MOVE(scheduler), HPX_FORWARD(Sender, sender), allocator);
205
        }
206

207
        // clang-format off
208
        template <typename Sender,
209
            typename Allocator = hpx::util::internal_allocator<>,
210
            HPX_CONCEPT_REQUIRES_(
211
                hpx::execution::experimental::is_sender_v<Sender> &&
212
                hpx::traits::is_allocator_v<Allocator>
213
            )>
214
        // clang-format on
215
        friend constexpr HPX_FORCEINLINE auto tag_invoke(start_detached_t,
×
216
            hpx::execution::experimental::run_loop_scheduler const& sched,
217
            Sender&& sender, Allocator const& allocator = {})
218
        {
219
            using allocator_type = Allocator;
220
            using operation_state_type =
221
                detail::operation_state_holder_with_run_loop<Sender, Allocator>;
222
            using other_allocator = typename std::allocator_traits<
223
                allocator_type>::template rebind_alloc<operation_state_type>;
224
            using allocator_traits = std::allocator_traits<other_allocator>;
225
            using unique_ptr = std::unique_ptr<operation_state_type,
226
                util::allocator_deleter<other_allocator>>;
227

228
            other_allocator alloc(allocator);
×
229
            unique_ptr p(allocator_traits::allocate(alloc, 1),
×
230
                hpx::util::allocator_deleter<other_allocator>{alloc});
×
231

232
            allocator_traits::construct(
×
233
                alloc, p.get(), sched, HPX_FORWARD(Sender, sender), alloc);
×
234
            HPX_UNUSED(p.release());
×
235
        }
×
236

237
        // clang-format off
238
        template <typename Sender,
239
            typename Allocator = hpx::util::internal_allocator<>,
240
            HPX_CONCEPT_REQUIRES_(
241
                is_sender_v<Sender> &&
242
                hpx::traits::is_allocator_v<Allocator>
243
            )>
244
        // clang-format on
245
        friend constexpr HPX_FORCEINLINE void tag_fallback_invoke(
3,308✔
246
            start_detached_t, Sender&& sender,
247
            Allocator const& allocator = Allocator{})
248
        {
249
            using allocator_type = Allocator;
250
            using operation_state_type =
251
                detail::operation_state_holder<Sender, Allocator>;
252
            using other_allocator = typename std::allocator_traits<
253
                allocator_type>::template rebind_alloc<operation_state_type>;
254
            using allocator_traits = std::allocator_traits<other_allocator>;
255
            using unique_ptr = std::unique_ptr<operation_state_type,
256
                util::allocator_deleter<other_allocator>>;
257

258
            other_allocator alloc(allocator);
3,308✔
259
            unique_ptr p(allocator_traits::allocate(alloc, 1),
3,308✔
260
                hpx::util::allocator_deleter<other_allocator>{alloc});
3,308✔
261

262
            allocator_traits::construct(
3,308✔
263
                alloc, p.get(), HPX_FORWARD(Sender, sender), alloc);
3,308✔
264
            HPX_UNUSED(p.release());
3,308✔
265
        }
3,308✔
266

267
        // clang-format off
268
        template <typename Scheduler, typename Allocator,
269
            HPX_CONCEPT_REQUIRES_(
270
                hpx::execution::experimental::is_scheduler_v<Scheduler> &&
271
                hpx::traits::is_allocator_v<Allocator>
272
            )>
273
        // clang-format on
274
        friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(
275
            start_detached_t, Scheduler&& scheduler,
276
            Allocator const& allocator = {})
277
        {
278
            return hpx::execution::experimental::detail::inject_scheduler<
279
                start_detached_t, Scheduler, Allocator>{
280
                HPX_FORWARD(Scheduler, scheduler), allocator};
281
        }
282

283
        // clang-format off
284
        template <typename Allocator = hpx::util::internal_allocator<>,
285
            HPX_CONCEPT_REQUIRES_(
286
                hpx::traits::is_allocator_v<Allocator>
287
            )>
288
        // clang-format on
289
        friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(
3✔
290
            start_detached_t, Allocator const& allocator = Allocator{})
291
        {
292
            return detail::partial_algorithm<start_detached_t, Allocator>{
3✔
293
                allocator};
3✔
294
        }
295
    } start_detached{};
296
}    // namespace hpx::execution::experimental
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

© 2025 Coveralls, Inc