OpenShot Audio Library | OpenShotAudio 0.4.0
juce_ListenerList.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26//==============================================================================
78template <class ListenerClass,
79 class ArrayType = Array<ListenerClass*>>
81{
82public:
83 //==============================================================================
85 ListenerList() = default;
86
89
90 //==============================================================================
100 void add (ListenerClass* listenerToAdd)
101 {
102 if (listenerToAdd != nullptr)
103 listeners->addIfNotAlreadyThere (listenerToAdd);
104 else
105 jassertfalse; // Listeners can't be null pointers!
106 }
107
114 void remove (ListenerClass* listenerToRemove)
115 {
116 jassert (listenerToRemove != nullptr); // Listeners can't be null pointers!
117
118 const ScopedLockType lock (listeners->getLock());
119
120 if (const auto index = listeners->removeFirstMatchingValue (listenerToRemove); index >= 0)
121 {
122 for (auto* it : *iterators)
123 {
124 --it->end;
125
126 if (index <= it->index)
127 --it->index;
128 }
129 }
130 }
131
138 ErasedScopeGuard addScoped (ListenerClass& listenerToAdd)
139 {
140 add (&listenerToAdd);
141 return ErasedScopeGuard { [this, &listenerToAdd] { remove (&listenerToAdd); } };
142 }
143
145 int size() const noexcept { return listeners->size(); }
146
148 bool isEmpty() const noexcept { return listeners->isEmpty(); }
149
155 void clear()
156 {
157 const ScopedLockType lock (listeners->getLock());
158
159 listeners->clear();
160
161 for (auto* it : *iterators)
162 it->end = 0;
163 }
164
166 bool contains (ListenerClass* listener) const noexcept { return listeners->contains (listener); }
167
177 const ArrayType& getListeners() const noexcept { return *listeners; }
178
179 //==============================================================================
181 template <typename Callback>
182 void call (Callback&& callback)
183 {
184 callCheckedExcluding (nullptr,
186 std::forward<Callback> (callback));
187 }
188
192 template <typename Callback>
193 void callExcluding (ListenerClass* listenerToExclude, Callback&& callback)
194 {
195 callCheckedExcluding (listenerToExclude,
197 std::forward<Callback> (callback));
198
199 }
200
206 template <typename Callback, typename BailOutCheckerType>
207 void callChecked (const BailOutCheckerType& bailOutChecker, Callback&& callback)
208 {
209 callCheckedExcluding (nullptr,
210 bailOutChecker,
211 std::forward<Callback> (callback));
212 }
213
220 template <typename Callback, typename BailOutCheckerType>
221 void callCheckedExcluding (ListenerClass* listenerToExclude,
222 const BailOutCheckerType& bailOutChecker,
223 Callback&& callback)
224 {
225 const auto localListeners = listeners;
226 const ScopedLockType lock { localListeners->getLock() };
227
228 Iterator it{};
229 it.end = localListeners->size();
230
231 iterators->push_back (&it);
232
233 const ScopeGuard scope { [i = iterators, &it]
234 {
235 i->erase (std::remove (i->begin(), i->end(), &it), i->end());
236 } };
237
238 for (; it.index < it.end; ++it.index)
239 {
240 if (bailOutChecker.shouldBailOut())
241 return;
242
243 auto* listener = localListeners->getUnchecked (it.index);
244
245 if (listener == listenerToExclude)
246 continue;
247
248 callback (*listener);
249 }
250 }
251
252 //==============================================================================
254 template <typename... MethodArgs, typename... Args>
255 void call (void (ListenerClass::*callbackFunction) (MethodArgs...), Args&&... args)
256 {
257 callCheckedExcluding (nullptr,
259 callbackFunction,
260 std::forward<Args> (args)...);
261 }
262
266 template <typename... MethodArgs, typename... Args>
267 void callExcluding (ListenerClass* listenerToExclude,
268 void (ListenerClass::*callbackFunction) (MethodArgs...),
269 Args&&... args)
270 {
271 callCheckedExcluding (listenerToExclude,
273 callbackFunction,
274 std::forward<Args> (args)...);
275 }
276
282 template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
283 void callChecked (const BailOutCheckerType& bailOutChecker,
284 void (ListenerClass::*callbackFunction) (MethodArgs...),
285 Args&&... args)
286 {
287 callCheckedExcluding (nullptr,
288 bailOutChecker,
289 callbackFunction,
290 std::forward<Args> (args)...);
291 }
292
299 template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
300 void callCheckedExcluding (ListenerClass* listenerToExclude,
301 const BailOutCheckerType& bailOutChecker,
302 void (ListenerClass::*callbackFunction) (MethodArgs...),
303 Args&&... args)
304 {
305 callCheckedExcluding (listenerToExclude, bailOutChecker, [&] (ListenerClass& l)
306 {
307 (l.*callbackFunction) (args...);
308 });
309 }
310
311 //==============================================================================
316 {
317 constexpr bool shouldBailOut() const noexcept { return false; }
318 };
319
320 //==============================================================================
322 using ListenerType = ListenerClass;
323
324private:
325 //==============================================================================
326 using ScopedLockType = typename ArrayType::ScopedLockType;
327
328 //==============================================================================
329 using SharedListeners = std::shared_ptr<ArrayType>;
330 const SharedListeners listeners = std::make_shared<ArrayType>();
331
332 struct Iterator
333 {
334 int index{};
335 int end{};
336 };
337
338 using SafeIterators = std::vector<Iterator*>;
339 using SharedIterators = std::shared_ptr<SafeIterators>;
340 const SharedIterators iterators = std::make_shared<SafeIterators>();
341
342 //==============================================================================
343 JUCE_DECLARE_NON_COPYABLE (ListenerList)
344};
345
346} // namespace juce
void callChecked(const BailOutCheckerType &bailOutChecker, Callback &&callback)
bool isEmpty() const noexcept
void callCheckedExcluding(ListenerClass *listenerToExclude, const BailOutCheckerType &bailOutChecker, Callback &&callback)
void callChecked(const BailOutCheckerType &bailOutChecker, void(ListenerClass::*callbackFunction)(MethodArgs...), Args &&... args)
void call(Callback &&callback)
void callExcluding(ListenerClass *listenerToExclude, Callback &&callback)
void callCheckedExcluding(ListenerClass *listenerToExclude, const BailOutCheckerType &bailOutChecker, void(ListenerClass::*callbackFunction)(MethodArgs...), Args &&... args)
void call(void(ListenerClass::*callbackFunction)(MethodArgs...), Args &&... args)
void add(ListenerClass *listenerToAdd)
ErasedScopeGuard addScoped(ListenerClass &listenerToAdd)
void remove(ListenerClass *listenerToRemove)
bool contains(ListenerClass *listener) const noexcept
int size() const noexcept
ListenerList()=default
void callExcluding(ListenerClass *listenerToExclude, void(ListenerClass::*callbackFunction)(MethodArgs...), Args &&... args)
const ArrayType & getListeners() const noexcept