11#include "unfair_mutex.hpp"
17namespace hi::inline
v1 {
36template<
typename T,
typename... Proto>
39template<
typename T,
typename... Args>
45 hi_assert(_enable_group_ptr_owners.empty());
55 hilet owners_copy = [&] {
56 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
57 return _enable_group_ptr_owners;
60 for (
auto owner : owners_copy) {
61 hi_axiom(owner !=
nullptr);
63 owner->_notify(args...);
69 using _enable_group_ptr_notify_proto = void(Args...);
74 [[nodiscard]]
bool _enable_group_ptr_holds_invariant() const noexcept
76 hi_axiom(_enable_group_ptr_mutex.is_locked());
78 for (
auto owner : _enable_group_ptr_owners) {
79 if (owner ==
nullptr or owner->_ptr ==
nullptr or owner->_ptr.get() !=
this or
80 owner->_ptr.use_count() < _enable_group_ptr_owners.
size()) {
87 void _enable_group_ptr_add_owner(group_ptr<T> *owner)
noexcept
89 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
91 _enable_group_ptr_owners.
push_back(owner);
92 hi_axiom(_enable_group_ptr_holds_invariant());
95 void _enable_group_ptr_remove_owner(group_ptr<T> *owner)
noexcept
97 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
99 hilet num_removed = std::erase(_enable_group_ptr_owners, owner);
100 hi_axiom(num_removed == 1);
101 hi_axiom(_enable_group_ptr_holds_invariant());
112 hilet lock = std::scoped_lock(_enable_group_ptr_mutex);
114 hi_axiom(replacement !=
nullptr);
115 hi_axiom(replacement.get() !=
this);
117 while (not _enable_group_ptr_owners.
empty()) {
118 auto *owner = _enable_group_ptr_owners.
back();
119 _enable_group_ptr_owners.
pop_back();
120 owner->_ptr = replacement;
121 owner->_ptr->_enable_group_ptr_add_owner(owner);
123 hi_axiom(_enable_group_ptr_holds_invariant());
126 friend class group_ptr<T>;
148 using notify_proto = T::_enable_group_ptr_notify_proto;
149 using element_type = T;
156 _ptr->_enable_group_ptr_remove_owner(
this);
172 _ptr->_enable_group_ptr_add_owner(
this);
193 if (_ptr == other._ptr) {
196 }
else if (_ptr and other._ptr) {
199 tmp->_enable_group_ptr_reseat(other._ptr);
203 _ptr->_enable_group_ptr_remove_owner(
this);
209 _ptr->_enable_group_ptr_add_owner(
this);
227 _ptr->_enable_group_ptr_remove_owner(&other);
228 _ptr->_enable_group_ptr_add_owner(
this);
250 hi_return_on_self_assignment(other);
252 if (_ptr == other._ptr) {
253 other._ptr->_enable_group_ptr_remove_owner(&other);
254 other._ptr =
nullptr;
257 }
else if (_ptr and other._ptr) {
258 other._ptr->_enable_group_ptr_remove_owner(&other);
261 tmp->_enable_group_ptr_reseat(std::exchange(other._ptr,
nullptr));
265 _ptr->_enable_group_ptr_remove_owner(
this);
270 other._ptr->_enable_group_ptr_remove_owner(&other);
271 _ptr = std::exchange(other._ptr,
nullptr);
272 _ptr->_enable_group_ptr_add_owner(
this);
294 _ptr->_enable_group_ptr_remove_owner(
this);
306 template<forward_of<std::shared_ptr<enable_group_ptr<T, notify_proto>>> Ptr>
307 group_ptr(Ptr&& ptr) noexcept : _ptr(std::forward<Ptr>(ptr))
310 _ptr->_enable_group_ptr_add_owner(
this);
322 template<forward_of<std::shared_ptr<enable_group_ptr<T, notify_proto>>> Ptr>
325 return *
this =
group_ptr{std::forward<Ptr>(ptr)};
333 [[nodiscard]] T *
get() const noexcept
335 return static_cast<T *
>(_ptr.get());
363 explicit operator bool() const noexcept
365 return to_bool(_ptr);
394 friend class enable_group_ptr<T, notify_proto>;
397template<
typename Context,
typename Expected>
399 std::conditional_t<std::is_convertible_v<Context, group_ptr<Expected>>, std::true_type, std::false_type> {
#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:15
A smart pointer which manages ownership as a group.
Definition group_ptr.hpp:146
group_ptr & operator=(group_ptr &&other) noexcept
Move assign from another group_ptr.
Definition group_ptr.hpp:248
group_ptr & operator=(Ptr &&ptr) noexcept
Construct a group_ptr from a shared_ptr.
Definition group_ptr.hpp:323
void reset() noexcept
Reset the group_ptr and make it empty.
Definition group_ptr.hpp:291
group_ptr(group_ptr const &other) noexcept
Copy construct from another group_ptr.
Definition group_ptr.hpp:169
virtual ~group_ptr()
Destroy this group_ptr.
Definition group_ptr.hpp:153
constexpr group_ptr() noexcept=default
Construct an empty group_ptr.
void unsubscribe() noexcept
Unsubscribe the callback function.
Definition group_ptr.hpp:385
T * operator->() const noexcept
Dereference to member of the object that is owned by this group_ptr.
Definition group_ptr.hpp:343
group_ptr & operator=(group_ptr const &other) noexcept
Copy assign from another group_ptr.
Definition group_ptr.hpp:191
T * get() const noexcept
Get the pointer to the object that this group_ptr owns.
Definition group_ptr.hpp:333
T & operator*() const noexcept
Dereference the object that is owned by this group_ptr.
Definition group_ptr.hpp:353
void subscribe(forward_of< notify_proto > auto &&func) noexcept
Subscribe a callback function.
Definition group_ptr.hpp:378
group_ptr(group_ptr &&other) noexcept
Move construct from another group_ptr.
Definition group_ptr.hpp:224
group_ptr(Ptr &&ptr) noexcept
Construct a group_ptr from a shared_ptr.
Definition group_ptr.hpp:307
Enable a class to be used in a group_ptr.
Definition group_ptr.hpp:37
void notify_group_ptr(Args const &...args) const noexcept
Call the callback which are registered with the owning group_ptrs.
Definition group_ptr.hpp:53
Is context a form of the expected type.
Definition type_traits.hpp:481
True if T is a forwarded type of Forward.
Definition concepts.hpp:130