Audacity 3.2.0
Observer.h
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file Observer.h
6 @brief Publisher-subscriber pattern, also known as Observer
7
8 Paul Licameli
9
10**********************************************************************/
11#ifndef __AUDACITY_OBSERVER__
12#define __AUDACITY_OBSERVER__
13
14#include <cassert>
15#include <functional>
16#include <memory>
17#include <type_traits>
18
19namespace Observer {
20
21// See below
22template<typename Message, bool NotifyAll>
23class Publisher;
24
26struct Message {};
27
29struct UTILITY_API ExceptionPolicy {
30 virtual ~ExceptionPolicy() noexcept;
32 virtual void OnBeginPublish() = 0;
33 // In a catch block, can rethrow or store std::current_exception()
35 virtual bool OnEachFailedCallback() noexcept(false) = 0;
37 virtual void OnEndPublish() noexcept(false) = 0;
38};
39
40class Subscription;
41
43namespace detail {
44struct RecordBase;
46 std::shared_ptr<RecordBase> next;
47};
49struct UTILITY_API RecordBase : RecordLink {
50 std::weak_ptr<RecordLink> prev;
51 void Unlink() noexcept;
52};
53struct UTILITY_API RecordList
54 : RecordLink, std::enable_shared_from_this<RecordLink> {
56 using Visitor = bool(*)(const RecordBase &record, const void *arg);
58 explicit RecordList(ExceptionPolicy *pPolicy, Visitor visitor);
59 ~RecordList() noexcept;
61 Subscription Subscribe(std::shared_ptr<RecordBase> pRecord);
62 bool Visit(const void *arg);
63private:
64 ExceptionPolicy *const m_pPolicy;
65 const Visitor m_visitor;
66};
67}
68
70class UTILITY_API Subscription {
71public:
74 Subscription &operator=(Subscription &&);
75
77 ~Subscription() noexcept { Reset(); }
78
80 void Reset() noexcept;
81
87 bool Expired() const { return m_wRecord.expired(); }
88
90 explicit operator bool() const { return !Expired(); }
91
92private:
93 friend detail::RecordList;
94 explicit Subscription(std::weak_ptr<detail::RecordBase> pRecord);
95 std::weak_ptr<detail::RecordBase> m_wRecord;
96};
97
99
107template<typename Message = Message, bool NotifyAll = true>
109public:
111 struct Record;
112
113 static constexpr bool notifies_all = NotifyAll;
115
117
121 template<typename Alloc = std::allocator<Record>>
122 explicit Publisher(ExceptionPolicy *pPolicy = nullptr, Alloc a = {});
123
124 Publisher(Publisher&&) = default;
126
127 using CallbackReturn = std::conditional_t<NotifyAll, void, bool>;
128
130 using Callback = std::function< CallbackReturn(const Message&) >;
131
133
140 [[nodiscard]] Subscription Subscribe(Callback callback);
141
143 template<typename Object, typename Return, typename... Args>
145 Object &obj, Return (Object::*callback)(Args...))
146 {
147 return Subscribe( [&obj, callback](const Message &message){
148 return (obj.*callback)(message);
149 } );
150 }
151
153 explicit Record(Callback callback) : callback{ move(callback) } {}
155 };
156
157protected:
159
167
168private:
169 // RecordList needs to be non-relocating but the Publisher object is movable
170 std::shared_ptr<detail::RecordList> m_list;
171 std::function<std::shared_ptr<detail::RecordBase>(Callback)> m_factory;
172};
173
174template<typename Message, bool NotifyAll>
175template<typename Alloc> inline
177: m_list{ std::allocate_shared<detail::RecordList>( a, pPolicy,
178 []( // The visitor. Lambda with no capture converts to pointer-to-function
179 const detail::RecordBase &recordBase, const void *arg){
180 auto &record = static_cast<const Record&>(recordBase);
181 assert(arg);
182 auto &message = *static_cast<const Message*>(arg);
183 assert(record.callback);
184 // Calling foreign code! Which is why we have an exception policy.
185 if constexpr (NotifyAll)
186 return (record.callback(message), false);
187 else
188 return record.callback(message);
189 }
190) }
191, m_factory( [a = move(a)](Callback callback) {
192 return std::allocate_shared<Record>(a, move(callback));
193} )
194{}
195
196// Thin wrappers of type-erased worker functions:
197
198template<typename Message, bool NotifyAll>
200 -> Subscription
201{
202 assert(callback); // precondition
203 return m_list->Subscribe(m_factory(move(callback)));
204}
205
206template<typename Message, bool NotifyAll> inline
209{
210 bool result = m_list->Visit(&message);
211 if constexpr (!NotifyAll)
212 return result;
213}
214
215}
216
217#endif
An object that sends messages to an open-ended list of subscribed callbacks.
Definition: Observer.h:108
Subscription Subscribe(Object &obj, Return(Object::*callback)(Args...))
Overload of Subscribe takes an object and pointer-to-member-function.
Definition: Observer.h:144
Publisher(Publisher &&)=default
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
std::shared_ptr< detail::RecordList > m_list
Definition: Observer.h:170
std::conditional_t< NotifyAll, void, bool > CallbackReturn
Definition: Observer.h:127
Publisher & operator=(Publisher &&)=default
std::function< std::shared_ptr< detail::RecordBase >(Callback)> m_factory
Definition: Observer.h:171
CallbackReturn Publish(const Message &message)
Send a message to connected callbacks.
Definition: Observer.h:207
Publisher(ExceptionPolicy *pPolicy=nullptr, Alloc a={})
Constructor supporting type-erased custom allocation/deletion.
Definition: Observer.h:176
std::function< CallbackReturn(const Message &) > Callback
Type of functions that can be connected to the Publisher.
Definition: Observer.h:130
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
~Subscription() noexcept
Calls Reset.
Definition: Observer.h:77
Subscription(Subscription &&)
std::weak_ptr< detail::RecordBase > m_wRecord
Definition: Observer.h:95
MENUS_API void Visit(Visitor< Traits > &visitor, AudacityProject &project)
TranslatableString Message(unsigned trackCount)
STL namespace.
May be supplied to constructor of Publisher to customize exception handling.
Definition: Observer.h:29
virtual ~ExceptionPolicy() noexcept
Default message type for Publisher.
Definition: Observer.h:26
Record(Callback callback)
Definition: Observer.h:153
doubly-linked list cell using shared and weak pointers
Definition: Observer.h:49
std::weak_ptr< RecordLink > prev
Definition: Observer.h:50
bool(*)(const RecordBase &record, const void *arg) Visitor
Type of function visiting the list; stop visit on true return.
Definition: Observer.h:56