blob: 18d48b02eee4eb308095181e5340b0504683eefc [file] [log] [blame]
Karl Wiberg3d452cf2020-09-11 14:09:461/*
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
Mirko Bonadei3d259352020-10-23 10:04:4011#ifndef RTC_BASE_CALLBACK_LIST_H_
12#define RTC_BASE_CALLBACK_LIST_H_
Karl Wiberg3d452cf2020-09-11 14:09:4613
14#include <utility>
15#include <vector>
16
17#include "api/function_view.h"
Karl Wiberg01a36f32020-11-11 10:48:0418#include "rtc_base/checks.h"
Karl Wiberg3d452cf2020-09-11 14:09:4619#include "rtc_base/system/assume.h"
Karl Wibergd2c69672020-09-29 11:55:1320#include "rtc_base/system/inline.h"
Karl Wiberg70026f92020-09-18 08:03:1621#include "rtc_base/untyped_function.h"
Karl Wiberg3d452cf2020-09-11 14:09:4622
23namespace webrtc {
Mirko Bonadei3d259352020-10-23 10:04:4024namespace callback_list_impl {
Karl Wiberg3d452cf2020-09-11 14:09:4625
Mirko Bonadei3d259352020-10-23 10:04:4026class CallbackListReceivers {
Karl Wiberg3d452cf2020-09-11 14:09:4627 public:
Mirko Bonadei3d259352020-10-23 10:04:4028 CallbackListReceivers();
29 CallbackListReceivers(const CallbackListReceivers&) = delete;
30 CallbackListReceivers& operator=(const CallbackListReceivers&) = delete;
31 CallbackListReceivers(CallbackListReceivers&&) = delete;
32 CallbackListReceivers& operator=(CallbackListReceivers&&) = delete;
33 ~CallbackListReceivers();
Karl Wiberg8d875582020-09-18 07:59:5034
Karl Wibergd2c69672020-09-29 11:55:1335 template <typename UntypedFunctionArgsT>
Karl Wiberg54b91412020-11-25 20:26:1736 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>
Karl Wibergd2c69672020-09-29 11:55:1344 RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
Karl Wiberg01a36f32020-11-11 10:48:0445 RTC_CHECK(!send_in_progress_);
Karl Wiberg54b91412020-11-25 20:26:1746 receivers_.push_back({nullptr, UntypedFunction::Create(args)});
Karl Wiberg3d452cf2020-09-11 14:09:4647 }
Karl Wiberg8d875582020-09-18 07:59:5048
Karl Wiberg54b91412020-11-25 20:26:1749 void RemoveReceivers(const void* removal_tag);
50
Karl Wiberg3d452cf2020-09-11 14:09:4651 void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
52
53 private:
Karl Wiberg54b91412020-11-25 20:26:1754 struct Callback {
55 const void* removal_tag;
56 UntypedFunction function;
57 };
58 std::vector<Callback> receivers_;
Karl Wiberg01a36f32020-11-11 10:48:0459 bool send_in_progress_ = false;
Karl Wiberg3d452cf2020-09-11 14:09:4660};
61
Mirko Bonadei3d259352020-10-23 10:04:4062extern template void CallbackListReceivers::AddReceiver(
Karl Wiberg54b91412020-11-25 20:26:1763 const void*,
64 UntypedFunction::TrivialUntypedFunctionArgs<1>);
65extern template void CallbackListReceivers::AddReceiver(
66 const void*,
67 UntypedFunction::TrivialUntypedFunctionArgs<2>);
68extern template void CallbackListReceivers::AddReceiver(
69 const void*,
70 UntypedFunction::TrivialUntypedFunctionArgs<3>);
71extern template void CallbackListReceivers::AddReceiver(
72 const void*,
73 UntypedFunction::TrivialUntypedFunctionArgs<4>);
74extern template void CallbackListReceivers::AddReceiver(
75 const void*,
76 UntypedFunction::NontrivialUntypedFunctionArgs);
77extern template void CallbackListReceivers::AddReceiver(
78 const void*,
79 UntypedFunction::FunctionPointerUntypedFunctionArgs);
80
81extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1382 UntypedFunction::TrivialUntypedFunctionArgs<1>);
Mirko Bonadei3d259352020-10-23 10:04:4083extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1384 UntypedFunction::TrivialUntypedFunctionArgs<2>);
Mirko Bonadei3d259352020-10-23 10:04:4085extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1386 UntypedFunction::TrivialUntypedFunctionArgs<3>);
Mirko Bonadei3d259352020-10-23 10:04:4087extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1388 UntypedFunction::TrivialUntypedFunctionArgs<4>);
Mirko Bonadei3d259352020-10-23 10:04:4089extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1390 UntypedFunction::NontrivialUntypedFunctionArgs);
Mirko Bonadei3d259352020-10-23 10:04:4091extern template void CallbackListReceivers::AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:1392 UntypedFunction::FunctionPointerUntypedFunctionArgs);
93
Mirko Bonadei3d259352020-10-23 10:04:4094} // namespace callback_list_impl
Karl Wiberg3d452cf2020-09-11 14:09:4695
96// A collection of receivers (callable objects) that can be called all at once.
Karl Wiberg1a88ea12020-11-09 09:36:3297// 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).
Karl Wiberg3d452cf2020-09-11 14:09:46100//
Karl Wiberg1a88ea12020-11-09 09:36:32101// CallbackList is neither copyable nor movable (could easily be made movable if
102// necessary). Callbacks must be movable, but need not be copyable.
Karl Wiberg8d875582020-09-18 07:59:50103//
Karl Wiberg1a88ea12020-11-09 09:36:32104// 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//
Karl Wiberg3d452cf2020-09-11 14:09:46161template <typename... ArgT>
Mirko Bonadei3d259352020-10-23 10:04:40162class CallbackList {
Karl Wiberg3d452cf2020-09-11 14:09:46163 public:
Mirko Bonadei3d259352020-10-23 10:04:40164 CallbackList() = default;
165 CallbackList(const CallbackList&) = delete;
166 CallbackList& operator=(const CallbackList&) = delete;
167 CallbackList(CallbackList&&) = delete;
168 CallbackList& operator=(CallbackList&&) = delete;
Karl Wiberg8d875582020-09-18 07:59:50169
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
Karl Wiberg54b91412020-11-25 20:26:17172 // `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>
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.
Karl Wiberg3d452cf2020-09-11 14:09:46184 template <typename F>
185 void AddReceiver(F&& f) {
186 receivers_.AddReceiver(
Karl Wibergd2c69672020-09-29 11:55:13187 UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
Karl Wiberg3d452cf2020-09-11 14:09:46188 }
Karl Wiberg8d875582020-09-18 07:59:50189
Karl Wiberg54b91412020-11-25 20:26:17190 // Removes all receivers that were added with the given removal tag.
191 void RemoveReceivers(const void* removal_tag) {
192 receivers_.RemoveReceivers(removal_tag);
193 }
194
Karl Wiberg01a36f32020-11-11 10:48:04195 // 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.
Karl Wiberg54b91412020-11-25 20:26:17198 //
199 // Note: Receivers are called serially, but not necessarily in the same order
200 // they were added.
Karl Wibergd88b1692020-09-25 04:16:12201 template <typename... ArgU>
202 void Send(ArgU&&... args) {
Karl Wiberg3d452cf2020-09-11 14:09:46203 receivers_.Foreach([&](UntypedFunction& f) {
Karl Wibergd88b1692020-09-25 04:16:12204 f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
Karl Wiberg3d452cf2020-09-11 14:09:46205 });
206 }
207
208 private:
Mirko Bonadei3d259352020-10-23 10:04:40209 callback_list_impl::CallbackListReceivers receivers_;
Karl Wiberg3d452cf2020-09-11 14:09:46210};
211
212} // namespace webrtc
213
Mirko Bonadei3d259352020-10-23 10:04:40214#endif // RTC_BASE_CALLBACK_LIST_H_