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 "unfair_recursive_mutex.hpp"
9#include "coroutine.hpp"
10#include <mutex>
11#include <vector>
12#include <tuple>
13#include <functional>
14
15namespace tt {
16
17template<typename T>
18class notifier {
19};
20
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 &...)>;
36
44 callback_ptr_type subscribe(callback_ptr_type const &callback_ptr) noexcept
45 {
46 auto lock = std::scoped_lock(_mutex);
47
48 ttlet i = std::find_if(_callbacks.cbegin(), _callbacks.cend(), [&callback_ptr](ttlet &item) {
49 return item.lock() == callback_ptr;
50 });
51
52 if (i == _callbacks.cend()) {
53 _callbacks.emplace_back(callback_ptr);
54 }
55 return callback_ptr;
56 }
57
66 template<typename Callback> requires (std::is_invocable_v<Callback>)
67 [[nodiscard]] callback_ptr_type subscribe(Callback &&callback) noexcept
68 {
69 auto callback_ptr = std::make_shared<callback_type>(std::forward<decltype(callback)>(callback));
70
71 auto lock = std::scoped_lock(_mutex);
72 _callbacks.emplace_back(callback_ptr);
73 return callback_ptr;
74 }
75
79 void unsubscribe(callback_ptr_type const &callback_ptr) noexcept
80 {
81 auto lock = std::scoped_lock(_mutex);
82
83 ttlet new_end = std::remove_if(_callbacks.begin(), _callbacks.end(), [&callback_ptr](ttlet &item) {
84 return item.expired() || item.lock() == callback_ptr;
85 });
86 _callbacks.erase(new_end, _callbacks.cend());
87 }
88
89 std::vector<std::weak_ptr<callback_type>> callbacks() const noexcept
90 {
91 auto lock = std::scoped_lock(_mutex);
92
93 // Clean up all the callbacks that expired.
94 std::erase_if(_callbacks, [](auto &x){ return x.expired(); });
95
96 return _callbacks;
97 }
98
104 void operator()(Args const &...args) const noexcept requires(std::is_same_v<result_type, void>)
105 {
106 auto callbacks_ = callbacks();
107 for (auto &callback : callbacks_) {
108 if (auto callback_ = callback.lock()) {
109 (*callback_)(args...);
110 }
111 };
112 }
113
120 generator<result_type> operator()(Args const &...args) const noexcept requires(not std::is_same_v<result_type,void>)
121 {
122 auto callbacks_ = callbacks();
123 for (auto &callback : callbacks_) {
124 if (auto callback_ = callback.lock()) {
125 co_yield (*callback_)(args...);
126 }
127 };
128 }
129
130private:
131 mutable unfair_recursive_mutex _mutex;
133};
134
135} // namespace tt
A return value for a generator-function.
Definition coroutine.hpp:25
Definition notifier.hpp:18
callback_ptr_type subscribe(callback_ptr_type const &callback_ptr) noexcept
Add a callback to the notifier.
Definition notifier.hpp:44
void unsubscribe(callback_ptr_type const &callback_ptr) noexcept
Remove a callback from the notifier.
Definition notifier.hpp:79
void operator()(Args const &...args) const noexcept
Call the subscribed callbacks with the given arguments.
Definition notifier.hpp:104
generator< result_type > operator()(Args const &...args) const noexcept
Call the subscribed callbacks with the given arguments.
Definition notifier.hpp:120
callback_ptr_type subscribe(Callback &&callback) noexcept
Add a callback to the notifier.
Definition notifier.hpp:67
An unfair recursive-mutex This is a fast implementation of a recursive-mutex which does not fairly ar...
Definition unfair_recursive_mutex.hpp:32
T find_if(T... args)
T forward(T... args)
T remove_if(T... args)