HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
notifier.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "required.hpp"
8#include "generator.hpp"
9#include "loop.hpp"
10#include <vector>
11#include <tuple>
12#include <functional>
13#include <coroutine>
14
15namespace hi::inline v1 {
16
22template<typename T = void()>
23class notifier {
24};
25
26// The partial template specialization allows the use of a `std::function`-like template
27// argument, that looks like a function prototype.
28template<typename Result, typename... Args>
29class notifier<Result(Args...)> {
30public:
31 static_assert(std::is_same_v<Result, void>, "Result of a notifier must be void.");
32
33 using result_type = Result;
34 using callback_type = std::function<Result(Args const&...)>;
35
38
45 class awaiter_type {
46 public:
47 constexpr awaiter_type() noexcept = default;
48 constexpr awaiter_type(awaiter_type const&) noexcept = default;
49 constexpr awaiter_type(awaiter_type&&) noexcept = default;
50 constexpr awaiter_type& operator=(awaiter_type const&) noexcept = default;
51 constexpr awaiter_type& operator=(awaiter_type&&) noexcept = default;
52
53 constexpr awaiter_type(notifier& notifier) noexcept : _notifier(&notifier) {}
54
55 [[nodiscard]] constexpr bool await_ready() noexcept
56 {
57 return false;
58 }
59
60 void await_suspend(std::coroutine_handle<> handle) noexcept
61 {
62 hi_axiom(_notifier != nullptr);
63
64 // We can use the this pointer in the callback, as `await_suspend()` is called by
65 // the co-routine on the same object as `await_resume()`.
66 _cbt = _notifier->subscribe([this, handle](Args const&...args) {
67 _args = {args...};
68 handle.resume();
69 });
70 }
71
72 constexpr void await_resume() const noexcept requires(sizeof...(Args) == 0) {}
73
74 constexpr auto await_resume() const noexcept requires(sizeof...(Args) == 1)
75 {
76 return std::get<0>(_args);
77 }
78
79 constexpr auto await_resume() const noexcept requires(sizeof...(Args) > 1)
80 {
81 return _args;
82 }
83
84 [[nodiscard]] bool operator==(awaiter_type const& rhs) const noexcept
85 {
86 return _notifier == rhs._notifier;
87 }
88
89 private:
90 notifier *_notifier = nullptr;
91 token_type _cbt;
92 std::tuple<Args...> _args;
93 };
94
97 constexpr notifier() noexcept = default;
98 notifier(notifier&&) = delete;
99 notifier(notifier const&) = delete;
100 notifier& operator=(notifier&&) = delete;
101 notifier& operator=(notifier const&) = delete;
102
105 awaiter_type operator co_await() const noexcept
106 {
107 return awaiter_type{const_cast<notifier&>(*this)};
108 }
109
118 [[nodiscard]] token_type subscribe(std::invocable<Args...> auto&& callback) noexcept
119 {
120 auto token = std::make_shared<callback_type>(hi_forward(callback));
121 _callbacks.emplace_back(token);
122 return token;
123 }
124
130 void post(Args const&...args) const noexcept requires(std::is_same_v<result_type, void>)
131 {
132 for (auto& weak_callback : _callbacks) {
133 loop::local().post_function([=] {
134 if (auto callback = weak_callback.lock()) {
135 (*callback)(args...);
136 }
137 });
138 }
139 clean_up();
140 }
141
147 void post_on_main(Args const&...args) const noexcept requires(std::is_same_v<result_type, void>)
148 {
149 for (auto& weak_callback : _callbacks) {
150 loop::main().post_function([=] {
151 if (auto callback = weak_callback.lock()) {
152 (*callback)(args...);
153 }
154 });
155 }
156 clean_up();
157 }
158
164 auto operator()(Args const&...args) const noexcept
165 {
166 return post(args...);
167 }
168
169private:
172 mutable std::vector<weak_token_type> _callbacks;
173
174 void clean_up() const noexcept
175 {
176 std::erase_if(_callbacks, [](hilet& item) {
177 return item.expired();
178 });
179 }
180
181#if HI_BUILD_TYPE == HI_BT_DEBUG
184 mutable bool _notifying = false;
185#endif
186};
187
188} // namespace hi::inline v1
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition required.hpp:29
A notifier which can be used to call a set of registered callbacks.
Definition notifier.hpp:23
auto operator()(Args const &...args) const noexcept
Call the subscribed callbacks with the given arguments.
Definition notifier.hpp:164
constexpr notifier() noexcept=default
Create a notifier.
token_type subscribe(std::invocable< Args... > auto &&callback) noexcept
Add a callback to the notifier.
Definition notifier.hpp:118
void post(Args const &...args) const noexcept
Post the subscribed callbacks on the current thread's event loop with the given arguments.
Definition notifier.hpp:130
void post_on_main(Args const &...args) const noexcept
Post the subscribed callbacks on the main thread's event loop with the given arguments.
Definition notifier.hpp:147