1 /*
2  *  Copyright 2020 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef RTC_BASE_CALLBACK_LIST_H_
12 #define RTC_BASE_CALLBACK_LIST_H_
13 
14 #include <utility>
15 #include <vector>
16 
17 #include "api/function_view.h"
18 #include "rtc_base/checks.h"
19 #include "rtc_base/system/assume.h"
20 #include "rtc_base/system/inline.h"
21 #include "rtc_base/untyped_function.h"
22 
23 namespace webrtc {
24 namespace callback_list_impl {
25 
26 class CallbackListReceivers {
27  public:
28   CallbackListReceivers();
29   CallbackListReceivers(const CallbackListReceivers&) = delete;
30   CallbackListReceivers& operator=(const CallbackListReceivers&) = delete;
31   CallbackListReceivers(CallbackListReceivers&&) = delete;
32   CallbackListReceivers& operator=(CallbackListReceivers&&) = delete;
33   ~CallbackListReceivers();
34 
35   template <typename UntypedFunctionArgsT>
AddReceiver(const void * removal_tag,UntypedFunctionArgsT args)36   RTC_NO_INLINE void AddReceiver(const void* removal_tag,
37                                  UntypedFunctionArgsT args) {
38     RTC_CHECK(!send_in_progress_);
39     RTC_DCHECK(removal_tag != nullptr);
40     receivers_.push_back({removal_tag, UntypedFunction::Create(args)});
41   }
42 
43   template <typename UntypedFunctionArgsT>
AddReceiver(UntypedFunctionArgsT args)44   RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
45     RTC_CHECK(!send_in_progress_);
46     receivers_.push_back({nullptr, UntypedFunction::Create(args)});
47   }
48 
49   void RemoveReceivers(const void* removal_tag);
50 
51   void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
52 
53  private:
54   struct Callback {
55     const void* removal_tag;
56     UntypedFunction function;
57   };
58   std::vector<Callback> receivers_;
59   bool send_in_progress_ = false;
60 };
61 
62 extern template void CallbackListReceivers::AddReceiver(
63     const void*,
64     UntypedFunction::TrivialUntypedFunctionArgs<1>);
65 extern template void CallbackListReceivers::AddReceiver(
66     const void*,
67     UntypedFunction::TrivialUntypedFunctionArgs<2>);
68 extern template void CallbackListReceivers::AddReceiver(
69     const void*,
70     UntypedFunction::TrivialUntypedFunctionArgs<3>);
71 extern template void CallbackListReceivers::AddReceiver(
72     const void*,
73     UntypedFunction::TrivialUntypedFunctionArgs<4>);
74 extern template void CallbackListReceivers::AddReceiver(
75     const void*,
76     UntypedFunction::NontrivialUntypedFunctionArgs);
77 extern template void CallbackListReceivers::AddReceiver(
78     const void*,
79     UntypedFunction::FunctionPointerUntypedFunctionArgs);
80 
81 extern template void CallbackListReceivers::AddReceiver(
82     UntypedFunction::TrivialUntypedFunctionArgs<1>);
83 extern template void CallbackListReceivers::AddReceiver(
84     UntypedFunction::TrivialUntypedFunctionArgs<2>);
85 extern template void CallbackListReceivers::AddReceiver(
86     UntypedFunction::TrivialUntypedFunctionArgs<3>);
87 extern template void CallbackListReceivers::AddReceiver(
88     UntypedFunction::TrivialUntypedFunctionArgs<4>);
89 extern template void CallbackListReceivers::AddReceiver(
90     UntypedFunction::NontrivialUntypedFunctionArgs);
91 extern template void CallbackListReceivers::AddReceiver(
92     UntypedFunction::FunctionPointerUntypedFunctionArgs);
93 
94 }  // namespace callback_list_impl
95 
96 // A collection of receivers (callable objects) that can be called all at once.
97 // Optimized for minimal binary size. The template arguments dictate what
98 // signature the callbacks must have; for example, a CallbackList<int, float>
99 // will require callbacks with signature void(int, float).
100 //
101 // CallbackList is neither copyable nor movable (could easily be made movable if
102 // necessary). Callbacks must be movable, but need not be copyable.
103 //
104 // Usage example:
105 //
106 //   // Declaration (usually a member variable).
107 //   CallbackList<int, float> foo_;
108 //
109 //   // Register callbacks. This can be done zero or more times. The
110 //   // callbacks must accept the arguments types listed in the CallbackList's
111 //   // template argument list, and must return void.
112 //   foo_.AddReceiver([...](int a, float b) {...});  // Lambda.
113 //   foo_.AddReceiver(SomeFunction);                 // Function pointer.
114 //
115 //   // Call the zero or more receivers, one after the other.
116 //   foo_.Send(17, 3.14);
117 //
118 // Callback lifetime considerations
119 // --------------------------------
120 //
121 // CallbackList::AddReceiver() takes ownership of the given callback by moving
122 // it in place. The callback can be any callable object; in particular, it may
123 // have a nontrivial destructor, which will be run when the CallbackList is
124 // destroyed. The callback may thus access data via any type of smart pointer,
125 // expressing e.g. unique, shared, or weak ownership. Of course, if the data is
126 // guaranteed to outlive the callback, a plain raw pointer can be used.
127 //
128 // Take care when trying to have the callback own reference-counted data. The
129 // CallbackList will keep the callback alive, and the callback will keep its
130 // data alive, so as usual with reference-counted ownership, keep an eye out for
131 // cycles!
132 //
133 // Thread safety
134 // -------------
135 //
136 // Like most C++ types, CallbackList is thread compatible: it's not safe to
137 // access it concurrently from multiple threads, but it can be made safe if it
138 // is protected by a mutex, for example.
139 //
140 // Excercise some care when deciding what mutexes to hold when you call
141 // CallbackList::Send(). In particular, do not hold mutexes that callbacks may
142 // need to grab. If a larger object has a CallbackList member and a single mutex
143 // that protects all of its data members, this may e.g. make it necessary to
144 // protect its CallbackList with a separate mutex; otherwise, there will be a
145 // deadlock if the callbacks try to access the object.
146 //
147 // CallbackList as a class data member
148 // -----------------------------------
149 //
150 // CallbackList is a normal C++ data type, and should be private when it is a
151 // data member of a class. For thread safety reasons (see above), it is likely
152 // best to not have an accessor for the entire CallbackList, and instead only
153 // allow callers to add callbacks:
154 //
155 //   template <typename F>
156 //   void AddFooCallback(F&& callback) {
157 //     // Maybe grab a mutex here?
158 //     foo_callbacks_.AddReceiver(std::forward<F>(callback));
159 //   }
160 //
161 template <typename... ArgT>
162 class CallbackList {
163  public:
164   CallbackList() = default;
165   CallbackList(const CallbackList&) = delete;
166   CallbackList& operator=(const CallbackList&) = delete;
167   CallbackList(CallbackList&&) = delete;
168   CallbackList& operator=(CallbackList&&) = delete;
169 
170   // Adds a new receiver. The receiver (a callable object or a function pointer)
171   // must be movable, but need not be copyable. Its call signature should be
172   // `void(ArgT...)`. The removal tag is a pointer to an arbitrary object that
173   // you own, and that will stay alive until the CallbackList is gone, or until
174   // all receivers using it as a removal tag have been removed; you can use it
175   // to remove the receiver.
176   template <typename F>
AddReceiver(const void * removal_tag,F && f)177   void AddReceiver(const void* removal_tag, F&& f) {
178     receivers_.AddReceiver(
179         removal_tag,
180         UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
181   }
182 
183   // Adds a new receiver with no removal tag.
184   template <typename F>
AddReceiver(F && f)185   void AddReceiver(F&& f) {
186     receivers_.AddReceiver(
187         UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
188   }
189 
190   // Removes all receivers that were added with the given removal tag.
RemoveReceivers(const void * removal_tag)191   void RemoveReceivers(const void* removal_tag) {
192     receivers_.RemoveReceivers(removal_tag);
193   }
194 
195   // Calls all receivers with the given arguments. While the Send is in
196   // progress, no method calls are allowed; specifically, this means that the
197   // callbacks may not do anything with this CallbackList instance.
198   //
199   // Note: Receivers are called serially, but not necessarily in the same order
200   // they were added.
201   template <typename... ArgU>
Send(ArgU &&...args)202   void Send(ArgU&&... args) {
203     receivers_.Foreach([&](UntypedFunction& f) {
204       f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
205     });
206   }
207 
208  private:
209   callback_list_impl::CallbackListReceivers receivers_;
210 };
211 
212 }  // namespace webrtc
213 
214 #endif  // RTC_BASE_CALLBACK_LIST_H_
215