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