7#include "../utility/utility.hpp"
8#include "../concurrency/concurrency.hpp"
10#include "../macros.hpp"
17hi_export_module(hikogui.observer.group_ptr);
20hi_export
namespace hi::inline
v1 {
39template<
typename T,
typename... Proto>
42template<
typename T,
typename... Args>
48 hi_assert(_enable_group_ptr_owners.empty());
58 auto const owners_copy = [&] {
59 auto const lock = std::scoped_lock(_enable_group_ptr_mutex);
60 return _enable_group_ptr_owners;
63 for (
auto owner : owners_copy) {
64 hi_assert_not_null(owner);
66 owner->_notify(args...);
72 using _enable_group_ptr_notify_proto = void(Args...);
75 mutable unfair_mutex _enable_group_ptr_mutex;
77 [[nodiscard]]
bool _enable_group_ptr_holds_invariant() const noexcept
79 hi_axiom(_enable_group_ptr_mutex.is_locked());
81 for (
auto owner : _enable_group_ptr_owners) {
82 if (owner ==
nullptr or owner->_ptr ==
nullptr or owner->_ptr.get() !=
this or
83 owner->_ptr.use_count() < _enable_group_ptr_owners.
size()) {
90 void _enable_group_ptr_add_owner(group_ptr<T> *owner)
noexcept
92 auto const lock = std::scoped_lock(_enable_group_ptr_mutex);
94 _enable_group_ptr_owners.
push_back(owner);
95 hi_axiom(_enable_group_ptr_holds_invariant());
98 void _enable_group_ptr_remove_owner(group_ptr<T> *owner)
noexcept
100 auto const lock = std::scoped_lock(_enable_group_ptr_mutex);
102 auto const num_removed = std::erase(_enable_group_ptr_owners, owner);
103 hi_assert(num_removed == 1);
104 hi_axiom(_enable_group_ptr_holds_invariant());
115 auto const lock = std::scoped_lock(_enable_group_ptr_mutex);
117 hi_assert_not_null(replacement);
118 hi_assert(replacement.get() !=
this);
120 while (not _enable_group_ptr_owners.
empty()) {
121 auto *owner = _enable_group_ptr_owners.
back();
122 _enable_group_ptr_owners.
pop_back();
123 owner->_ptr = replacement;
124 owner->_ptr->_enable_group_ptr_add_owner(owner);
126 hi_axiom(_enable_group_ptr_holds_invariant());
129 friend class group_ptr<T>;
151 using notify_proto = T::_enable_group_ptr_notify_proto;
152 using element_type = T;
159 _ptr->_enable_group_ptr_remove_owner(
this);
175 _ptr->_enable_group_ptr_add_owner(
this);
196 if (_ptr == other._ptr) {
199 }
else if (_ptr and other._ptr) {
202 tmp->_enable_group_ptr_reseat(other._ptr);
206 _ptr->_enable_group_ptr_remove_owner(
this);
212 _ptr->_enable_group_ptr_add_owner(
this);
230 _ptr->_enable_group_ptr_remove_owner(&other);
231 _ptr->_enable_group_ptr_add_owner(
this);
253 hi_return_on_self_assignment(other);
255 if (_ptr == other._ptr) {
256 other._ptr->_enable_group_ptr_remove_owner(&other);
257 other._ptr =
nullptr;
260 }
else if (_ptr and other._ptr) {
261 other._ptr->_enable_group_ptr_remove_owner(&other);
264 tmp->_enable_group_ptr_reseat(std::exchange(other._ptr,
nullptr));
268 _ptr->_enable_group_ptr_remove_owner(
this);
273 other._ptr->_enable_group_ptr_remove_owner(&other);
274 _ptr = std::exchange(other._ptr,
nullptr);
275 _ptr->_enable_group_ptr_add_owner(
this);
297 _ptr->_enable_group_ptr_remove_owner(
this);
309 template<forward_of<std::shared_ptr<enable_group_ptr<T, notify_proto>>> Ptr>
310 group_ptr(Ptr&& ptr) noexcept : _ptr(std::forward<Ptr>(ptr))
313 _ptr->_enable_group_ptr_add_owner(
this);
325 template<forward_of<std::shared_ptr<enable_group_ptr<T, notify_proto>>> Ptr>
328 return *
this =
group_ptr{std::forward<Ptr>(ptr)};
336 [[nodiscard]] T *
get() const noexcept
338 return static_cast<T *
>(_ptr.get());
366 explicit operator bool() const noexcept
368 return to_bool(_ptr);
381 template<forward_of<notify_proto> Func>
384 _notify = std::forward<Func>(func);
398 friend class enable_group_ptr<T, notify_proto>;
401template<
typename Context,
typename Expected>
403 std::conditional_t<std::is_convertible_v<Context, group_ptr<Expected>>, std::true_type, std::false_type> {
Definition of the unfair_mutex.
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A smart pointer which manages ownership as a group.
Definition group_ptr.hpp:149
group_ptr & operator=(group_ptr &&other) noexcept
Move assign from another group_ptr.
Definition group_ptr.hpp:251
group_ptr & operator=(Ptr &&ptr) noexcept
Construct a group_ptr from a shared_ptr.
Definition group_ptr.hpp:326
void reset() noexcept
Reset the group_ptr and make it empty.
Definition group_ptr.hpp:294
group_ptr(group_ptr const &other) noexcept
Copy construct from another group_ptr.
Definition group_ptr.hpp:172
virtual ~group_ptr()
Destroy this group_ptr.
Definition group_ptr.hpp:156
constexpr group_ptr() noexcept=default
Construct an empty group_ptr.
void unsubscribe() noexcept
Unsubscribe the callback function.
Definition group_ptr.hpp:389
T * operator->() const noexcept
Dereference to member of the object that is owned by this group_ptr.
Definition group_ptr.hpp:346
void subscribe(Func &&func) noexcept
Subscribe a callback function.
Definition group_ptr.hpp:382
group_ptr & operator=(group_ptr const &other) noexcept
Copy assign from another group_ptr.
Definition group_ptr.hpp:194
T * get() const noexcept
Get the pointer to the object that this group_ptr owns.
Definition group_ptr.hpp:336
T & operator*() const noexcept
Dereference the object that is owned by this group_ptr.
Definition group_ptr.hpp:356
group_ptr(group_ptr &&other) noexcept
Move construct from another group_ptr.
Definition group_ptr.hpp:227
group_ptr(Ptr &&ptr) noexcept
Construct a group_ptr from a shared_ptr.
Definition group_ptr.hpp:310
Enable a class to be used in a group_ptr.
Definition group_ptr.hpp:40
void notify_group_ptr(Args const &...args) const noexcept
Call the callback which are registered with the owning group_ptrs.
Definition group_ptr.hpp:56