7#include "utility/module.hpp"
8#include "concurrency/module.hpp"
14namespace hi::inline
v1 {
33template<
typename T,
typename... Proto>
36template<
typename T,
typename... Args>
42 hi_assert(_enable_group_ptr_owners.empty());
52 hilet owners_copy = [&] {
53 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
54 return _enable_group_ptr_owners;
57 for (
auto owner : owners_copy) {
60 owner->_notify(args...);
66 using _enable_group_ptr_notify_proto = void(Args...);
69 mutable unfair_mutex _enable_group_ptr_mutex;
71 [[nodiscard]]
bool _enable_group_ptr_holds_invariant() const noexcept
73 hi_axiom(_enable_group_ptr_mutex.is_locked());
75 for (
auto owner : _enable_group_ptr_owners) {
76 if (owner ==
nullptr or owner->_ptr ==
nullptr or owner->_ptr.get() !=
this or
77 owner->_ptr.use_count() < _enable_group_ptr_owners.
size()) {
84 void _enable_group_ptr_add_owner(group_ptr<T> *owner)
noexcept
86 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
88 _enable_group_ptr_owners.
push_back(owner);
89 hi_axiom(_enable_group_ptr_holds_invariant());
92 void _enable_group_ptr_remove_owner(group_ptr<T> *owner)
noexcept
94 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
96 hilet num_removed = std::erase(_enable_group_ptr_owners, owner);
98 hi_axiom(_enable_group_ptr_holds_invariant());
109 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
114 while (not _enable_group_ptr_owners.
empty()) {
115 auto *owner = _enable_group_ptr_owners.
back();
116 _enable_group_ptr_owners.
pop_back();
117 owner->_ptr = replacement;
118 owner->_ptr->_enable_group_ptr_add_owner(owner);
120 hi_axiom(_enable_group_ptr_holds_invariant());
123 friend class group_ptr<T>;
145 using notify_proto = T::_enable_group_ptr_notify_proto;
146 using element_type = T;
153 _ptr->_enable_group_ptr_remove_owner(
this);
169 _ptr->_enable_group_ptr_add_owner(
this);
190 if (_ptr == other._ptr) {
193 }
else if (_ptr and other._ptr) {
196 tmp->_enable_group_ptr_reseat(other._ptr);
200 _ptr->_enable_group_ptr_remove_owner(
this);
206 _ptr->_enable_group_ptr_add_owner(
this);
224 _ptr->_enable_group_ptr_remove_owner(&other);
225 _ptr->_enable_group_ptr_add_owner(
this);
247 hi_return_on_self_assignment(other);
249 if (_ptr == other._ptr) {
250 other._ptr->_enable_group_ptr_remove_owner(&other);
251 other._ptr =
nullptr;
254 }
else if (_ptr and other._ptr) {
255 other._ptr->_enable_group_ptr_remove_owner(&other);
258 tmp->_enable_group_ptr_reseat(std::exchange(other._ptr,
nullptr));
262 _ptr->_enable_group_ptr_remove_owner(
this);
267 other._ptr->_enable_group_ptr_remove_owner(&other);
268 _ptr = std::exchange(other._ptr,
nullptr);
269 _ptr->_enable_group_ptr_add_owner(
this);
291 _ptr->_enable_group_ptr_remove_owner(
this);
303 template<forward_of<std::shared_ptr<enable_group_ptr<T, notify_proto>>> Ptr>
304 group_ptr(Ptr&& ptr) noexcept : _ptr(std::forward<Ptr>(ptr))
307 _ptr->_enable_group_ptr_add_owner(
this);
319 template<forward_of<std::shared_ptr<enable_group_ptr<T, notify_proto>>> Ptr>
322 return *
this =
group_ptr{std::forward<Ptr>(ptr)};
330 [[nodiscard]] T *
get() const noexcept
332 return static_cast<T *
>(_ptr.get());
360 explicit operator bool() const noexcept
362 return to_bool(_ptr);
391 friend class enable_group_ptr<T, notify_proto>;
394template<
typename Context,
typename Expected>
396 std::conditional_t<std::is_convertible_v<Context, group_ptr<Expected>>, std::true_type, std::false_type> {
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:184
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:223
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition utility.hpp:29
DOXYGEN BUG.
Definition algorithm.hpp:13
A smart pointer which manages ownership as a group.
Definition group_ptr.hpp:143
group_ptr & operator=(group_ptr &&other) noexcept
Move assign from another group_ptr.
Definition group_ptr.hpp:245
group_ptr & operator=(Ptr &&ptr) noexcept
Construct a group_ptr from a shared_ptr.
Definition group_ptr.hpp:320
void reset() noexcept
Reset the group_ptr and make it empty.
Definition group_ptr.hpp:288
group_ptr(group_ptr const &other) noexcept
Copy construct from another group_ptr.
Definition group_ptr.hpp:166
virtual ~group_ptr()
Destroy this group_ptr.
Definition group_ptr.hpp:150
constexpr group_ptr() noexcept=default
Construct an empty group_ptr.
void unsubscribe() noexcept
Unsubscribe the callback function.
Definition group_ptr.hpp:382
T * operator->() const noexcept
Dereference to member of the object that is owned by this group_ptr.
Definition group_ptr.hpp:340
group_ptr & operator=(group_ptr const &other) noexcept
Copy assign from another group_ptr.
Definition group_ptr.hpp:188
T * get() const noexcept
Get the pointer to the object that this group_ptr owns.
Definition group_ptr.hpp:330
T & operator*() const noexcept
Dereference the object that is owned by this group_ptr.
Definition group_ptr.hpp:350
void subscribe(forward_of< notify_proto > auto &&func) noexcept
Subscribe a callback function.
Definition group_ptr.hpp:375
group_ptr(group_ptr &&other) noexcept
Move construct from another group_ptr.
Definition group_ptr.hpp:221
group_ptr(Ptr &&ptr) noexcept
Construct a group_ptr from a shared_ptr.
Definition group_ptr.hpp:304
Enable a class to be used in a group_ptr.
Definition group_ptr.hpp:34
void notify_group_ptr(Args const &...args) const noexcept
Call the callback which are registered with the owning group_ptrs.
Definition group_ptr.hpp:50
Is context a form of the expected type.
Definition type_traits.hpp:531
True if T is a forwarded type of Forward.
Definition concepts.hpp:130