7#include "observable_value.hpp"
8#include "observable.hpp"
9#include "../coroutine/module.hpp"
10#include "../utility/utility.hpp"
11#include "../macros.hpp"
30 using callback_token = notifier_type::callback_token;
31 using callback_proto = notifier_type::callback_proto;
32 using awaiter_type = notifier_type::awaiter_type;
43 template<
bool IsWriting>
46 constexpr static bool is_writing = IsWriting;
48 using void_pointer = std::conditional_t<is_writing, void *, void const *>;
49 using const_void_pointer =
void const *;
51 using reference = std::conditional_t<is_writing, value_type&, value_type const&>;
52 using const_reference = value_type
const&;
53 using pointer = std::conditional_t<is_writing, value_type *, value_type const *>;
54 using const_pointer = value_type
const *;
70 requires(not is_writing)
71 : _observer(other._observer), _base(other._base), _value(other._value)
73 _observer->read_lock();
76 _proxy& operator=(_proxy
const& other)
noexcept
77 requires(not is_writing)
80 _observer = other._observer;
82 _value = other._value;
83 _observer->read_lock();
87 _proxy(_proxy&& other) noexcept :
88 _observer(std::exchange(other._observer,
nullptr)),
89 _base(std::exchange(other._base,
nullptr)),
90 _value(std::exchange(other._value,
nullptr))
94 _proxy& operator=(_proxy&& other)
noexcept
97 _observer = std::exchange(
other._observer,
nullptr);
98 _base = std::exchange(
other._base,
nullptr);
99 _value = std::exchange(
other._value,
nullptr);
113 reference operator*() noexcept
115 hi_assert_not_null(_value);
127 hi_assert_not_null(_value);
140 hi_assert_not_null(_value);
153 hi_assert_not_null(_value);
166 hi_assert_not_null(_value);
204 template<typename Rhs> \
205 decltype(auto) operator op() noexcept \
206 requires is_writing and requires(value_type& a) { op a; } \
208 return op (*_value); \
217 template<typename Rhs> \
218 auto operator op(int) noexcept \
219 requires is_writing and requires(value_type& a) { a op; } \
221 return (*_value) op; \
230 template<typename Rhs> \
231 decltype(auto) operator op(Rhs const& rhs) noexcept \
232 requires is_writing and requires(value_type& a, Rhs const& b) { a op b; } \
234 return (*_value) op rhs; \
251 template<typename Rhs> \
252 auto operator op() const noexcept \
253 requires requires(value_type const& a) { op a; } \
255 return op (*_value); \
266 template<typename Rhs> \
267 auto operator op(Rhs const& rhs) const noexcept \
268 requires requires(value_type const& a, Rhs const& b) { a op b; } \
270 return (*_value) op rhs; \
288 template<
typename... Args>
289 auto operator()(Args &&... args)
const noexcept
290 requires requires(value_type
const & a, Args &&...args) { a(std::forward<Args>(args)...); }
292 return (*_value)(std::forward<Args>(args)...);
295 template<
typename... Args>
296 decltype(
auto)
operator()(Args &&... args)
noexcept
297 requires is_writing and
requires(value_type & a, Args &&...args) { a(std::forward<Args>(args)...); }
299 return (*_value)(std::forward<Args>(args)...);
304 template<
typename Arg>
305 auto operator[](Arg && arg)
const noexcept
306 requires requires(value_type
const & a, Arg &&arg) { a[std::forward<Arg>(arg)]; }
308 return (*_value)[std::forward<Arg>(arg)];
311 template<
typename Arg>
312 decltype(
auto)
operator[](Arg && arg)
noexcept
313 requires is_writing and
requires(value_type & a, Arg &&arg) { a[std::forward<Arg>(arg)]; }
315 return (*_value)[std::forward<Arg>(arg)];
321 observer
const *_observer =
nullptr;
322 void_pointer _base =
nullptr;
323 pointer _value =
nullptr;
334 _observer(
observer), _base(base), _value(value)
336 hi_assert_not_null(_observer);
337 hi_assert_not_null(_base);
338 hi_assert_not_null(_value);
341 void _commit() noexcept
343 if (_observer !=
nullptr) {
344 if constexpr (is_writing) {
345 _observer->commit(_base);
347 _observer->read_unlock();
352 void _abort() noexcept
354 if (_observer !=
nullptr) {
355 if constexpr (is_writing) {
356 _observer->abort(_base);
358 _observer->read_unlock();
363 friend class observer;
366 using proxy = _proxy<true>;
367 using const_proxy = _proxy<false>;
369 constexpr ~observer() =
default;
392 constexpr observer(std::convertible_to<value_type>
auto&& value) noexcept :
423 _observed = other._observed;
425 _convert = other._convert;
428 update_state_callback();
429 _observed->read_lock();
430 _observed->notify_group_ptr(
observable_msg{_observed->read(), _path});
431 _observed->read_unlock();
450 update_state_callback();
451 _observed->read_lock();
452 _observed->notify_group_ptr({_observed->read(), _path});
453 _observed->read_unlock();
463 _observed = std::make_shared<observable_value<value_type>>();
465 _convert = [](
void *base) {
468 update_state_callback();
477 _observed->read_lock();
478 void const *base = _observed->read();
481 const_proxy read() && =
delete;
489 _observed->write_lock();
490 void const *old_base = _observed->read();
491 void *new_base = _observed->copy(old_base);
492 return proxy(
this, new_base, convert(new_base));
501 [[nodiscard]] callback_token
504 return _notifier.subscribe(hi_forward(
function), flags);
507 awaiter_type
operator co_await()
const noexcept
509 return _notifier.operator
co_await();
517 [[nodiscard]]
auto get(
auto const& index)
const noexcept
518 requires(
requires() { std::declval<value_type>()[index]; })
520 using result_type = std::decay_t<decltype(std::declval<value_type>()[index])>;
522 auto new_path = _path;
523 new_path.push_back(std::format(
"[{}]", index));
525 _observed,
std::move(new_path), [convert_copy = this->_convert, index](
void *base) ->
void * {
526 return std::addressof((*std::launder(
static_cast<value_type *
>(convert_copy(base))))[index]);
536 template<fixed_
string Name>
537 [[nodiscard]]
auto get() const noexcept
539 using result_type = std::decay_t<
decltype(
selector<value_type>{}.get<Name>(std::declval<value_type&>()))>;
541 auto new_path = _path;
547 [convert_copy = this->_convert](
void *base) ->
void * {
549 *std::launder(
static_cast<value_type *
>(convert_copy(base)))));
562 template<
typename Rhs>
564 requires requires (value_type &a, Rhs &&b) { a = std::forward<Rhs>(b); }
566 *copy() = std::forward<Rhs>(rhs);
585 const_proxy operator->() && =
delete;
589 template<typename Rhs> \
590 observer& operator op() noexcept \
591 requires requires(value_type& a) { op a; } \
603 template<typename Rhs> \
604 auto operator op(int) noexcept \
605 requires requires(value_type& a) { a op; } \
616 template<typename Rhs> \
617 observer& operator op(Rhs const& rhs) noexcept \
618 requires requires(value_type& a, Rhs const& b) { a op b; } \
638 template<typename Rhs> \
639 auto operator op() const noexcept \
640 requires requires(value_type const& a) { op a; } \
653 template<typename Rhs> \
654 auto operator op(Rhs const& rhs) const noexcept \
655 requires requires(value_type const& a, Rhs const& b) { a op b; } \
657 return *read() op rhs; \
675 template<
typename... Args>
676 auto operator()(Args &&... args)
const noexcept
677 requires requires(value_type
const & a, Args &&...args) { a(std::forward<Args>(args)...); }
679 return (*read())(std::forward<Args>(args)...);
684 template<
typename Arg>
685 auto operator[](Arg && arg)
const noexcept
686 requires requires(value_type
const & a, Arg &&arg) { a[std::forward<Arg>(arg)]; }
688 return (*read())[std::forward<Arg>(arg)];
694 using observed_type = group_ptr<observable>;
695 observed_type _observed = {};
696 path_type _path = {};
698 notifier_type _notifier;
700 value_type _debug_value;
706 forward_of<observed_type>
auto&& observed,
707 forward_of<path_type>
auto&& path,
708 forward_of<
void *(
void *)>
auto&& converter) noexcept :
709 _observed(hi_forward(observed)), _path(hi_forward(path)), _convert(hi_forward(converter)), _notifier()
711 update_state_callback();
714 void read_unlock() const noexcept
716 _observed->read_unlock();
719 void commit(
void *base)
const noexcept
721 if constexpr (
requires(value_type
const& a, value_type
const& b) { a == b; }) {
724 if (*convert(_observed->read()) != *convert(base)) {
725 _observed->commit(base);
726 _observed->notify_group_ptr({base, _path});
728 _observed->abort(base);
731 _observed->commit(base);
732 _observed->notify_group_ptr({base, _path});
734 _observed->write_unlock();
737 void abort(
void *base)
const noexcept
739 _observed->abort(base);
740 _observed->write_unlock();
743 value_type *convert(
void *base)
const noexcept
745 return std::launder(
static_cast<value_type *
>(_convert(base)));
748 value_type
const *convert(
void const *base)
const noexcept
750 return std::launder(
static_cast<value_type
const *
>(_convert(
const_cast<void *
>(base))));
753 void update_state_callback() noexcept
755 _observed.subscribe([
this](observable_msg
const& msg) {
756 hilet [msg_it, this_it] =
std::mismatch(msg.path.cbegin(), msg.path.cend(), _path.cbegin(), _path.cend());
759 if (msg_it == msg.path.cend() or this_it == _path.cend()) {
761 _notifier(_debug_value = *convert(msg.ptr));
763 _notifier(*convert(msg.ptr));
769 _observed->read_lock();
770 _debug_value = *convert(_observed->read());
771 _observed->read_unlock();
777 friend class observer;
794 using type = std::decay_t<T>;
806using observer_decay_t = observer_decay<T>::type;
808template<
typename Context,
typename Expected>
810 std::conditional_t<std::is_convertible_v<Context, observer<Expected>>, std::true_type, std::false_type> {};
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:16
callback_flags
Definition callback_flags.hpp:14
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Definition functional.hpp:17
A smart pointer which manages ownership as a group.
Definition group_ptr.hpp:146
Definition observable.hpp:16
A observer pointing to the whole or part of a observable.
Definition observer.hpp:26
observer(forward_of< std::shared_ptr< observable > > auto &&observed) noexcept
Create an observer from an observable.
Definition observer.hpp:377
value_type operator*() const noexcept
Get a copy of the value being observed.
Definition observer.hpp:572
proxy copy() const &noexcept
Make a copy of the observed value for modification.
Definition observer.hpp:487
void reset() noexcept
Reset the observer.
Definition observer.hpp:461
observer(forward_of< observed_type > auto &&observed, forward_of< path_type > auto &&path, forward_of< void *(void *)> auto &&converter) noexcept
Construct an observer from an observable.
Definition observer.hpp:705
auto get(auto const &index) const noexcept
Create a sub-observer by indexing into the value.
Definition observer.hpp:517
auto get() const noexcept
Create a sub-observer by selecting a member-variable of the value.
Definition observer.hpp:537
const_proxy operator->() const &noexcept
Constant pointer-to-member of the value being observed.
Definition observer.hpp:581
constexpr observer & operator=(observer const &other) noexcept
Copy assign.
Definition observer.hpp:421
constexpr observer(observer &&other) noexcept
Move construct.
Definition observer.hpp:409
constexpr observer(observer const &other) noexcept
Copy construct.
Definition observer.hpp:402
observer & operator=(Rhs &&rhs) noexcept
Assign a new value to the observed value.
Definition observer.hpp:563
constexpr observer() noexcept
Create a observer linked to an anonymous default initialized observed-value.
Definition observer.hpp:388
const_proxy read() const &noexcept
Read the observed value.
Definition observer.hpp:475
callback_token subscribe(forward_of< callback_proto > auto &&function, callback_flags flags=callback_flags::synchronous) noexcept
Subscribe a callback to this observer.
Definition observer.hpp:502
constexpr observer & operator=(observer &&other) noexcept
Move assign.
Definition observer.hpp:442
constexpr observer(std::convertible_to< value_type > auto &&value) noexcept
Create a observer linked to an anonymous observed-value.
Definition observer.hpp:392
Definition observable_value.hpp:19
A proxy object of the observer.
Definition observer.hpp:44
~_proxy() noexcept
Commits and destruct the proxy object.
Definition observer.hpp:61
pointer operator->() noexcept
Pointer dereference the value.
Definition observer.hpp:138
const_reference operator*() const noexcept
Dereference the value.
Definition observer.hpp:125
const_pointer operator->() const noexcept
Pointer dereference the value.
Definition observer.hpp:164
void abort() noexcept
Revert any changes to the value.
Definition observer.hpp:191
_proxy(observer const *observer, void_pointer base, pointer value) noexcept
Create a proxy object.
Definition observer.hpp:333
pointer operator&() noexcept
Pointer dereference the value.
Definition observer.hpp:151
void commit() noexcept
Commit the changes to the value early.
Definition observer.hpp:176
constexpr _proxy() noexcept=default
Construct an empty proxy object.
A type-trait for observer arguments.
Definition observer.hpp:793
Is context a form of the expected type.
Definition type_traits.hpp:534
This selector allows access to member variable by name.
Definition type_traits.hpp:645