OpenShot Library | OpenShotAudio  0.2.1
juce_ListenerList.h
1 
2 /** @weakgroup juce_core-containers
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  The code included in this file is provided under the terms of the ISC license
15  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16  To use, copy, modify, and/or distribute this software for any purpose with or
17  without fee is hereby granted provided that the above copyright notice and
18  this permission notice appear in all copies.
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 //==============================================================================
31 /**
32  Holds a set of objects and can invoke a member function callback on each object
33  in the set with a single call.
34 
35  Use a ListenerList to manage a set of objects which need a callback, and you
36  can invoke a member function by simply calling call() or callChecked().
37 
38  E.g.
39  @code
40  class MyListenerType
41  {
42  public:
43  void myCallbackMethod (int foo, bool bar);
44  };
45 
46  ListenerList<MyListenerType> listeners;
47  listeners.add (someCallbackObjects...);
48 
49  // This will invoke myCallbackMethod (1234, true) on each of the objects
50  // in the list...
51  listeners.call ([] (MyListenerType& l) { l.myCallbackMethod (1234, true); });
52  @endcode
53 
54  If you add or remove listeners from the list during one of the callbacks - i.e. while
55  it's in the middle of iterating the listeners, then it's guaranteed that no listeners
56  will be mistakenly called after they've been removed, but it may mean that some of the
57  listeners could be called more than once, or not at all, depending on the list's order.
58 
59  Sometimes, there's a chance that invoking one of the callbacks might result in the
60  list itself being deleted while it's still iterating - to survive this situation, you can
61  use callChecked() instead of call(), passing it a local object to act as a "BailOutChecker".
62  The BailOutChecker must implement a method of the form "bool shouldBailOut()", and
63  the list will check this after each callback to determine whether it should abort the
64  operation. For an example of a bail-out checker, see the Component::BailOutChecker class,
65  which can be used to check when a Component has been deleted. See also
66  ListenerList::DummyBailOutChecker, which is a dummy checker that always returns false.
67 
68  @tags{Core}
69 */
70 template <class ListenerClass,
71  class ArrayType = Array<ListenerClass*>>
73 {
74 public:
75  //==============================================================================
76  /** Creates an empty list. */
77  ListenerList() = default;
78 
79  /** Destructor. */
80  ~ListenerList() = default;
81 
82  //==============================================================================
83  /** Adds a listener to the list.
84  A listener can only be added once, so if the listener is already in the list,
85  this method has no effect.
86  @see remove
87  */
88  void add (ListenerClass* listenerToAdd)
89  {
90  if (listenerToAdd != nullptr)
91  listeners.addIfNotAlreadyThere (listenerToAdd);
92  else
93  jassertfalse; // Listeners can't be null pointers!
94  }
95 
96  /** Removes a listener from the list.
97  If the listener wasn't in the list, this has no effect.
98  */
99  void remove (ListenerClass* listenerToRemove)
100  {
101  jassert (listenerToRemove != nullptr); // Listeners can't be null pointers!
102  listeners.removeFirstMatchingValue (listenerToRemove);
103  }
104 
105  /** Returns the number of registered listeners. */
106  int size() const noexcept { return listeners.size(); }
107 
108  /** Returns true if no listeners are registered, false otherwise. */
109  bool isEmpty() const noexcept { return listeners.isEmpty(); }
110 
111  /** Clears the list. */
112  void clear() { listeners.clear(); }
113 
114  /** Returns true if the specified listener has been added to the list. */
115  bool contains (ListenerClass* listener) const noexcept { return listeners.contains (listener); }
116 
117  /** Returns the raw array of listeners. */
118  const ArrayType& getListeners() const noexcept { return listeners; }
119 
120  //==============================================================================
121  /** Calls a member function on each listener in the list, with multiple parameters. */
122  template <typename Callback>
123  void call (Callback&& callback)
124  {
125  typename ArrayType::ScopedLockType lock (listeners.getLock());
126 
127  for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
128  callback (*iter.getListener());
129  }
130 
131  /** Calls a member function with 1 parameter, on all but the specified listener in the list.
132  This can be useful if the caller is also a listener and needs to exclude itself.
133  */
134  template <typename Callback>
135  void callExcluding (ListenerClass* listenerToExclude, Callback&& callback)
136  {
137  typename ArrayType::ScopedLockType lock (listeners.getLock());
138 
139  for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
140  {
141  auto* l = iter.getListener();
142 
143  if (l != listenerToExclude)
144  callback (*l);
145  }
146  }
147 
148  /** Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
149  See the class description for info about writing a bail-out checker.
150  */
151  template <typename Callback, typename BailOutCheckerType>
152  void callChecked (const BailOutCheckerType& bailOutChecker, Callback&& callback)
153  {
154  typename ArrayType::ScopedLockType lock (listeners.getLock());
155 
156  for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
157  callback (*iter.getListener());
158  }
159 
160  /** Calls a member function, with 1 parameter, on all but the specified listener in the list
161  with a bail-out-checker. This can be useful if the caller is also a listener and needs to
162  exclude itself. See the class description for info about writing a bail-out checker.
163  */
164  template <typename Callback, typename BailOutCheckerType>
165  void callCheckedExcluding (ListenerClass* listenerToExclude,
166  const BailOutCheckerType& bailOutChecker,
167  Callback&& callback)
168  {
169  typename ArrayType::ScopedLockType lock (listeners.getLock());
170 
171  for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
172  {
173  auto* l = iter.getListener();
174 
175  if (l != listenerToExclude)
176  callback (*l);
177  }
178  }
179 
180  //==============================================================================
181  /** A dummy bail-out checker that always returns false.
182  See the ListenerList notes for more info about bail-out checkers.
183  */
185  {
186  bool shouldBailOut() const noexcept { return false; }
187  };
188 
190  using ListenerType = ListenerClass;
191 
192  //==============================================================================
193  /** Iterates the listeners in a ListenerList. */
194  template <class BailOutCheckerType, class ListType>
195  struct Iterator
196  {
197  Iterator (const ListType& listToIterate) noexcept
198  : list (listToIterate), index (listToIterate.size())
199  {}
200 
201  ~Iterator() = default;
202 
203  //==============================================================================
204  bool next() noexcept
205  {
206  if (index <= 0)
207  return false;
208 
209  auto listSize = list.size();
210 
211  if (--index < listSize)
212  return true;
213 
214  index = listSize - 1;
215  return index >= 0;
216  }
217 
218  bool next (const BailOutCheckerType& bailOutChecker) noexcept
219  {
220  return (! bailOutChecker.shouldBailOut()) && next();
221  }
222 
223  typename ListType::ListenerType* getListener() const noexcept
224  {
225  return list.getListeners().getUnchecked (index);
226  }
227 
228  //==============================================================================
229  private:
230  const ListType& list;
231  int index;
232 
233  JUCE_DECLARE_NON_COPYABLE (Iterator)
234  };
235 
236  //==============================================================================
237  #ifndef DOXYGEN
238  // There are now lambda-based call functions that can be used to replace these old method-based versions.
239  // We'll eventually deprecate these old ones, so please begin moving your code to use lambdas!
240  void call (void (ListenerClass::*callbackFunction) ())
241  {
242  call ([=] (ListenerClass& l) { (l.*callbackFunction)(); });
243  }
244 
245  void callExcluding (ListenerClass* listenerToExclude, void (ListenerClass::*callbackFunction) ())
246  {
247  callExcluding (listenerToExclude, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
248  }
249 
250  template <class BailOutCheckerType>
251  void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) ())
252  {
253  callChecked (bailOutChecker, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
254  }
255 
256  template <class BailOutCheckerType>
257  void callCheckedExcluding (ListenerClass* listenerToExclude,
258  const BailOutCheckerType& bailOutChecker,
259  void (ListenerClass::*callbackFunction) ())
260  {
261  callCheckedExcluding (listenerToExclude, bailOutChecker, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
262  }
263 
264  template <typename... MethodArgs, typename... Args>
265  void call (void (ListenerClass::*callbackFunction) (MethodArgs...), Args&&... args)
266  {
267  typename ArrayType::ScopedLockType lock (listeners.getLock());
268 
269  for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
270  (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
271  }
272 
273  template <typename... MethodArgs, typename... Args>
274  void callExcluding (ListenerClass* listenerToExclude,
275  void (ListenerClass::*callbackFunction) (MethodArgs...),
276  Args&&... args)
277  {
278  typename ArrayType::ScopedLockType lock (listeners.getLock());
279 
280  for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
281  if (iter.getListener() != listenerToExclude)
282  (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
283  }
284 
285  template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
286  void callChecked (const BailOutCheckerType& bailOutChecker,
287  void (ListenerClass::*callbackFunction) (MethodArgs...),
288  Args&&... args)
289  {
290  typename ArrayType::ScopedLockType lock (listeners.getLock());
291 
292  for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
293  (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
294  }
295 
296  template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
297  void callCheckedExcluding (ListenerClass* listenerToExclude,
298  const BailOutCheckerType& bailOutChecker,
299  void (ListenerClass::*callbackFunction) (MethodArgs...),
300  Args&&... args)
301  {
302  typename ArrayType::ScopedLockType lock (listeners.getLock());
303 
304  for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
305  if (iter.getListener() != listenerToExclude)
306  (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
307  }
308  #endif
309 
310 private:
311  //==============================================================================
312  ArrayType listeners;
313 
314  JUCE_DECLARE_NON_COPYABLE (ListenerList)
315 };
316 
317 } // namespace juce
318 
319 /** @}*/
void callCheckedExcluding(ListenerClass *listenerToExclude, const BailOutCheckerType &bailOutChecker, Callback &&callback)
Calls a member function, with 1 parameter, on all but the specified listener in the list with a bail-...
void callExcluding(ListenerClass *listenerToExclude, Callback &&callback)
Calls a member function with 1 parameter, on all but the specified listener in the list...
~ListenerList()=default
Destructor.
bool isEmpty() const noexcept
Returns true if no listeners are registered, false otherwise.
Iterates the listeners in a ListenerList.
bool contains(ListenerClass *listener) const noexcept
Returns true if the specified listener has been added to the list.
Holds a set of objects and can invoke a member function callback on each object in the set with a sin...
const ArrayType & getListeners() const noexcept
Returns the raw array of listeners.
int size() const noexcept
Returns the number of registered listeners.
A dummy bail-out checker that always returns false.
void callChecked(const BailOutCheckerType &bailOutChecker, Callback &&callback)
Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
ListenerList()=default
Creates an empty list.
void call(Callback &&callback)
Calls a member function on each listener in the list, with multiple parameters.
void add(ListenerClass *listenerToAdd)
Adds a listener to the list.
void clear()
Clears the list.