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

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

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

75.0
/libs/full/components_base/include/hpx/components_base/server/managed_component_base.hpp
1
//  Copyright (c) 2007-2025 Hartmut Kaiser
2
//  Copyright (c) 2011-2017 Thomas Heller
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/assert.hpp>
12
#include <hpx/components_base/agas_interface.hpp>
13
#include <hpx/components_base/component_type.hpp>
14
#include <hpx/components_base/components_base_fwd.hpp>
15
#include <hpx/components_base/server/component_heap.hpp>
16
#include <hpx/components_base/server/create_component_fwd.hpp>
17
#include <hpx/components_base/server/wrapper_heap.hpp>
18
#include <hpx/components_base/server/wrapper_heap_list.hpp>
19
#include <hpx/components_base/traits/is_component.hpp>
20
#include <hpx/components_base/traits/managed_component_policies.hpp>
21
#include <hpx/modules/errors.hpp>
22

23
#include <cstddef>
24
#include <cstdint>
25
#include <type_traits>
26
#include <utility>
27

28
///////////////////////////////////////////////////////////////////////////////
29
namespace hpx::components {
30

31
    ///////////////////////////////////////////////////////////////////////////
32
    namespace detail_adl_barrier {
33

34
        template <typename BackPtrTag>
35
        struct init;
36

37
        template <>
38
        struct init<traits::construct_with_back_ptr>
39
        {
40
            template <typename Component, typename Managed>
41
            static constexpr void call(
42
                Component* /* component */, Managed* /* this_ */) noexcept
43
            {
44
            }
45

46
            template <typename Component, typename Managed, typename... Ts>
47
            static void call_new(
48
                Component*& component, Managed* this_, Ts&&... vs)
49
            {
50
                using wrapped_type = typename Managed::wrapped_type;
51
                component = new wrapped_type(this_, HPX_FORWARD(Ts, vs)...);
52
            }
53
        };
54

55
        template <>
56
        struct init<traits::construct_without_back_ptr>
57
        {
58
            template <typename Component, typename Managed>
59
            static void call(Component* component, Managed* this_)
60
            {
61
                component->set_back_ptr(this_);
62
            }
63

64
            template <typename Component, typename Managed, typename... Ts>
65
            static void call_new(
×
66
                Component*& component, Managed* this_, Ts&&... vs)
67
            {
68
                using wrapped_type = typename Managed::wrapped_type;
69
                component = new wrapped_type(HPX_FORWARD(Ts, vs)...);
×
70
                component->set_back_ptr(this_);
71
            }
×
72
        };
73

74
        ///////////////////////////////////////////////////////////////////////
75
        // This is used by the component implementation to decide whether to
76
        // delete the managed_component instance it depends on.
77
        template <typename DtorTag>
78
        struct destroy_backptr;
79

80
        template <>
81
        struct destroy_backptr<traits::managed_object_is_lifetime_controlled>
82
        {
83
            template <typename BackPtr>
84
            static void call(BackPtr* back_ptr)
85
            {
86
                // The managed_component's controls the lifetime of the
87
                // component implementation.
88
                back_ptr->finalize();
89
                std::destroy_at(back_ptr);
90
                component_heap<typename BackPtr::wrapped_type>().free(back_ptr);
91
            }
92
        };
93

94
        template <>
95
        struct destroy_backptr<traits::managed_object_controls_lifetime>
96
        {
97
            template <typename BackPtr>
98
            static constexpr void call(BackPtr*) noexcept
99
            {
100
                // The managed_component's lifetime is controlled by the
101
                // component implementation. Do nothing.
102
            }
103
        };
104

105
        ///////////////////////////////////////////////////////////////////////
106
        // This is used by the managed_component to decide whether to
107
        // delete the component implementation depending on it.
108
        template <typename DtorTag>
109
        struct manage_lifetime;
110

111
        template <>
112
        struct manage_lifetime<traits::managed_object_is_lifetime_controlled>
113
        {
114
            template <typename Component>
115
            static constexpr void call(Component*) noexcept
116
            {
117
                // The managed_component's lifetime is controlled by the
118
                // component implementation. Do nothing.
119
            }
120

121
            template <typename Component>
122
            static void addref(Component* component) noexcept
123
            {
124
                intrusive_ptr_add_ref(component);
125
            }
126

127
            template <typename Component>
128
            static void release(Component* component) noexcept
129
            {
130
                intrusive_ptr_release(component);
64✔
131
            }
132
        };
133

134
        template <>
135
        struct manage_lifetime<traits::managed_object_controls_lifetime>
136
        {
137
            template <typename Component>
138
            static void call(Component* component) noexcept(
139
                noexcept(component->finalize()))
140
            {
141
                // The managed_component controls the lifetime of the
142
                // component implementation.
143
                component->finalize();
144
                delete component;
2✔
145
            }
146

147
            template <typename Component>
148
            static constexpr void addref(Component*) noexcept
149
            {
150
            }
151

152
            template <typename Component>
153
            static constexpr void release(Component*) noexcept
154
            {
155
            }
156
        };
157
    }    // namespace detail_adl_barrier
158

159
    ///////////////////////////////////////////////////////////////////////////
160
    namespace detail {
161

162
        struct base_managed_component : traits::detail::managed_component_tag
163
        {
164
            // finalize() will be called just before the instance gets destructed
165
            static constexpr void finalize() noexcept {}
166

167
            static void mark_as_migrated() noexcept
168
            {
169
                // If this assertion is triggered then this component instance
170
                // is being migrated even if the component type has not been
171
                // enabled to support migration.
172
                HPX_ASSERT(false);
173
            }
174

175
            static void on_migrated() noexcept
176
            {
177
                // If this assertion is triggered then this component instance
178
                // is being migrated even if the component type has not been
179
                // enabled to support migration.
180
                HPX_ASSERT(false);
181
            }
182
        };
183
    }    // namespace detail
184

185
    template <typename Component, typename Wrapper, typename CtorPolicy,
186
        typename DtorPolicy>
187
    // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
188
    class managed_component_base : public detail::base_managed_component
189
    {
190
    public:
191
        // NOLINTBEGIN(bugprone-crtp-constructor-accessibility)
192
        managed_component_base(managed_component_base const&) = delete;
193
        managed_component_base(managed_component_base&&) = delete;
194
        // NOLINTEND(bugprone-crtp-constructor-accessibility)
195

196
        managed_component_base& operator=(
197
            managed_component_base const&) = delete;
198
        managed_component_base& operator=(managed_component_base&&) = delete;
199

200
        using this_component_type =
201
            std::conditional_t<std::is_void_v<Component>,
202
                managed_component_base, Component>;
203

204
        using wrapped_type = this_component_type;
205

206
        using has_managed_component_base = void;
207
        using ctor_policy = CtorPolicy;
208
        using dtor_policy = DtorPolicy;
209

210
        // make sure that we have a back_ptr whenever we need to control the
211
        // lifetime of the managed_component
212
        static_assert(
213
            (std::is_same_v<ctor_policy, traits::construct_without_back_ptr> ||
2✔
214
                std::is_same_v<dtor_policy,
215
                    traits::managed_object_controls_lifetime>),
216
            "std::is_same_v<ctor_policy, construct_without_back_ptr> || "
217
            "std::is_same_v<dtor_policy, managed_object_controls_lifetime>");
218

219
        // NOLINTBEGIN(bugprone-crtp-constructor-accessibility)
220
        constexpr managed_component_base() noexcept = default;
221

222
        explicit managed_component_base(
223
            managed_component<Component, Wrapper>* back_ptr) noexcept
224
          : back_ptr_(back_ptr)
225
        {
226
            HPX_ASSERT(back_ptr);
227
        }
228
        // NOLINTEND(bugprone-crtp-constructor-accessibility)
229

230
        // The implementation of the component is responsible for deleting the
231
        // actual managed component object
232
        ~managed_component_base()
233
        {
234
            detail_adl_barrier::destroy_backptr<dtor_policy>::call(back_ptr_);
235
        }
236

237
        // components must contain a typedef for wrapping_type defining the
238
        // managed_component type used to encapsulate instances of this
239
        // component
240
        using wrapping_type = managed_component<Component, Wrapper>;
241
        using base_type_holder = Component;
242

243
        hpx::id_type get_unmanaged_id() const;
244
        hpx::id_type get_id() const;
245

246
    protected:
247
        naming::gid_type get_base_gid() const;
248

249
        template <typename>
250
        friend struct detail_adl_barrier::init;
251

252
        void set_back_ptr(
253
            components::managed_component<Component, Wrapper>* bp) noexcept
2✔
254
        {
255
            HPX_ASSERT(nullptr == back_ptr_);
256
            HPX_ASSERT(bp);
257
            back_ptr_ = bp;
258
        }
259

260
    private:
261
        managed_component<Component, Wrapper>* back_ptr_ = nullptr;
262
    };
263

264
    // reference counting
265
    template <typename Component, typename Derived>
266
    void intrusive_ptr_add_ref(
267
        managed_component<Component, Derived>* p) noexcept
64✔
268
    {
×
269
        detail_adl_barrier::manage_lifetime<
270
            traits::managed_component_dtor_policy_t<Component>>::addref(p
64✔
271
                ->component_);
272
    }
273
    template <typename Component, typename Derived>
274
    void intrusive_ptr_release(
275
        managed_component<Component, Derived>* p) noexcept
64✔
276
    {
×
277
        detail_adl_barrier::manage_lifetime<
278
            traits::managed_component_dtor_policy_t<Component>>::release(p
279
                ->component_);
280
    }
281

282
    namespace detail {
283

284
        template <typename T>
285
        class fixed_wrapper_heap;
286
    }
287

288
    ///////////////////////////////////////////////////////////////////////////
289
    /// The managed_component template is used as an indirection layer
290
    /// for components allowing to gracefully handle the access to non-existing
291
    /// components.
292
    ///
293
    /// Additionally, it provides memory management capabilities for the
294
    /// wrapping instances, and it integrates the memory management with the
295
    /// AGAS service. Every instance of a managed_component gets assigned
296
    /// a global id.
297
    /// The provided memory management allocates the managed_component
298
    /// instances from a special heap, ensuring fast allocation and avoids a
299
    /// full network round trip to the AGAS service for each of the allocated
300
    /// instances.
301
    ///
302
    /// \tparam Component Component type
303
    /// \tparam Derived Most derived component type
304
    ///
305
    template <typename Component, typename Derived>
306
    class managed_component
307
    {
308
    public:
309
        managed_component(managed_component const&) = delete;
310
        managed_component(managed_component&&) = delete;
311
        managed_component& operator=(managed_component const&) = delete;
312
        managed_component& operator=(managed_component&&) = delete;
313

314
        using derived_type = std::conditional_t<std::is_void_v<Derived>,
315
            managed_component, Derived>;
316

317
        using wrapped_type = Component;
318
        using type_holder = Component;
319
        using base_type_holder = typename Component::base_type_holder;
320

321
        using heap_type =
322
            detail::wrapper_heap_list<detail::fixed_wrapper_heap<derived_type>>;
323
        using value_type = derived_type;
324

325
        /// Construct a managed_component instance holding a
326
        /// wrapped instance. This constructor takes ownership of the
327
        /// passed pointer.
328
        ///
40,738✔
329
        /// \param comp [in] The pointer to the wrapped instance. The
40,738✔
330
        ///             managed_component takes ownership of this pointer.
331
        explicit managed_component(Component* comp)
332
          : component_(comp)
333
        {
334
            detail_adl_barrier::
335
                init<traits::managed_component_ctor_policy_t<Component>>::call(
336
                    component_, this);
337
            intrusive_ptr_add_ref(this);
338
        }
339

340
        // Construct a managed_component instance holding a new wrapped instance
341
        managed_component()
342
        {
343
            detail_adl_barrier::init<traits::managed_component_ctor_policy_t<
344
                Component>>::call_new(component_, this);
345
            intrusive_ptr_add_ref(this);
346
        }
347

348
        template <typename T, typename... Ts,
349
            typename Enable = std::enable_if_t<
2✔
350
                !std::is_same_v<std::decay_t<T>, managed_component>>>
2✔
351
        explicit managed_component(T&& t, Ts&&... ts)
352
        {
353
            detail_adl_barrier::init<traits::managed_component_ctor_policy_t<
2✔
354
                Component>>::call_new(component_, this, HPX_FORWARD(T, t),
355
                HPX_FORWARD(Ts, ts)...);
356
            intrusive_ptr_add_ref(this);
2✔
357
        }
358

359
        // The destructor releases any wrapped instances
360
        ~managed_component()
361
        {
362
            intrusive_ptr_release(this);
363
            detail_adl_barrier::manage_lifetime<
364
                traits::managed_component_dtor_policy_t<Component>>::
2✔
365
                call(component_);
40,676✔
366
        }
367

368
        //finalize() will be called just before the instance gets destructed
369
        static constexpr void finalize() noexcept {}
370

371
        /// \brief Return a pointer to the wrapped instance
372
        /// \note  Caller must check validity of returned pointer
373
        constexpr Component* get() noexcept
374
        {
81,422✔
375
            return component_;
376
        }
377
        constexpr Component const* get() const noexcept
378
        {
×
379
            return component_;
380
        }
381

686✔
382
        Component* get_checked()
383
        {
686✔
384
            if (!component_)
385
            {
×
386
                HPX_THROW_EXCEPTION(hpx::error::invalid_status,
387
                    "managed_component<Component, Derived>::get_checked",
388
                    "component pointer ({}) is invalid (gid: {})",
389
                    components::get_component_type_name(
390
                        components::get_component_type<wrapped_type>()),
391
                    get_base_gid());
392
            }
686✔
393
            return get();
394
        }
395

396
        Component const* get_checked() const
397
        {
398
            if (!component_)
399
            {
400
                HPX_THROW_EXCEPTION(hpx::error::invalid_status,
401
                    "managed_component<Component, Derived>::get_checked",
402
                    "component pointer ({}) is invalid (gid: {})",
403
                    components::get_component_type_name(
404
                        components::get_component_type<wrapped_type>()),
405
                    get_base_gid());
406
            }
407
            return get();
408
        }
409

410
        ///////////////////////////////////////////////////////////////////////
411
        // The managed_component behaves just like the wrapped object
412
        Component* operator->()
413
        {
500✔
414
            return get_checked();
415
        }
416

417
        Component const* operator->() const
418
        {
419
            return get_checked();
420
        }
421

422
        ///////////////////////////////////////////////////////////////////////
423
        Component& operator*()
424
        {
425
            return *get_checked();
426
        }
427

428
        Component const& operator*() const
429
        {
430
            return *get_checked();
431
        }
432

433
        ///////////////////////////////////////////////////////////////////////
434
        /// \brief Return the global id of this \a future instance
40,445✔
435
        hpx::id_type get_unmanaged_id() const
436
        {
437
            return hpx::id_type(
40,445✔
438
                get_base_gid(), hpx::id_type::management_type::unmanaged);
439
        }
440

40,447✔
441
        naming::gid_type get_base_gid(
442
            naming::gid_type const& assign_gid = naming::invalid_gid) const
443
        {
444
            if (assign_gid)
445
            {
×
446
                HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
447
                    "managed_component::get_base_gid",
448
                    "managed_components must be assigned new gids on creation");
449
            }
450

451
            return component_heap<managed_component>().get_gid(
40,447✔
452
                const_cast<managed_component*>(this));
453
        }
454

455
        // reference counting
456
        template <typename C, typename D>
457
        friend void intrusive_ptr_add_ref(managed_component<C, D>* p) noexcept;
458

459
        template <typename C, typename D>
460
        friend void intrusive_ptr_release(managed_component<C, D>* p) noexcept;
461

462
    protected:
463
        Component* component_ = nullptr;
464
    };
465

466
    ///////////////////////////////////////////////////////////////////////////
467
    template <typename Component, typename Wrapper, typename CtorPolicy,
468
        typename DtorPolicy>
469
    hpx::id_type managed_component_base<Component, Wrapper, CtorPolicy,
470
        DtorPolicy>::get_unmanaged_id() const
471
    {
472
        HPX_ASSERT(back_ptr_);
473
        return back_ptr_->get_unmanaged_id();
474
    }
475

476
    template <typename Component, typename Wrapper, typename CtorPolicy,
477
        typename DtorPolicy>
478
    hpx::id_type managed_component_base<Component, Wrapper, CtorPolicy,
479
        DtorPolicy>::get_id() const
480
    {
481
        // all credits should have been taken already
482
        naming::gid_type gid =
483
            static_cast<Component const&>(*this).get_base_gid();
484

485
        // The underlying heap will always give us a full set of credits, but
486
        // those are valid for the first invocation of get_base_gid() only. We
487
        // have to get rid of those credits and properly replenish those.
488
        naming::detail::strip_credits_from_gid(gid);
489

490
        // any invocation causes the credits to be replenished
491
        agas::replenish_credits(gid);
492
        return hpx::id_type(gid, hpx::id_type::management_type::managed);
493
    }
494

495
    template <typename Component, typename Wrapper, typename CtorPolicy,
496
        typename DtorPolicy>
497
    naming::gid_type managed_component_base<Component, Wrapper, CtorPolicy,
498
        DtorPolicy>::get_base_gid() const
499
    {
500
        HPX_ASSERT(back_ptr_);
501
        return back_ptr_->get_base_gid();
502
    }
503
}    // namespace hpx::components
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