summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/callback_list.h
blob: a9d71a6562a7c99785af1ffe4727dd2f74dabbd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
 *  Copyright 2020 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef RTC_BASE_CALLBACK_LIST_H_
#define RTC_BASE_CALLBACK_LIST_H_

#include <utility>
#include <vector>

#include "api/function_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/assume.h"
#include "rtc_base/system/inline.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/untyped_function.h"

namespace webrtc {
namespace callback_list_impl {

class RTC_EXPORT CallbackListReceivers {
 public:
  CallbackListReceivers();
  CallbackListReceivers(const CallbackListReceivers&) = delete;
  CallbackListReceivers& operator=(const CallbackListReceivers&) = delete;
  CallbackListReceivers(CallbackListReceivers&&) = delete;
  CallbackListReceivers& operator=(CallbackListReceivers&&) = delete;
  ~CallbackListReceivers();

  template <typename UntypedFunctionArgsT>
  RTC_NO_INLINE void AddReceiver(const void* removal_tag,
                                 UntypedFunctionArgsT args) {
    RTC_CHECK(!send_in_progress_);
    RTC_DCHECK(removal_tag != nullptr);
    receivers_.push_back({removal_tag, UntypedFunction::Create(args)});
  }

  template <typename UntypedFunctionArgsT>
  RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
    RTC_CHECK(!send_in_progress_);
    receivers_.push_back({nullptr, UntypedFunction::Create(args)});
  }

  void RemoveReceivers(const void* removal_tag);

  void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);

 private:
  // Special protected pointer value that's used as a removal_tag for
  // receivers that want to unsubscribe from within a callback.
  // Note we could use `&receivers_` too, but since it's the first member
  // variable of the class, its address will be the same as the instance
  // CallbackList instance, so we take an extra step to avoid collision.
  const void* pending_removal_tag() const { return &send_in_progress_; }

  struct Callback {
    const void* removal_tag;
    UntypedFunction function;
  };

  std::vector<Callback> receivers_;
  bool send_in_progress_ = false;
};

extern template void CallbackListReceivers::AddReceiver(
    const void*,
    UntypedFunction::TrivialUntypedFunctionArgs<1>);
extern template void CallbackListReceivers::AddReceiver(
    const void*,
    UntypedFunction::TrivialUntypedFunctionArgs<2>);
extern template void CallbackListReceivers::AddReceiver(
    const void*,
    UntypedFunction::TrivialUntypedFunctionArgs<3>);
extern template void CallbackListReceivers::AddReceiver(
    const void*,
    UntypedFunction::TrivialUntypedFunctionArgs<4>);
extern template void CallbackListReceivers::AddReceiver(
    const void*,
    UntypedFunction::NontrivialUntypedFunctionArgs);
extern template void CallbackListReceivers::AddReceiver(
    const void*,
    UntypedFunction::FunctionPointerUntypedFunctionArgs);

extern template void CallbackListReceivers::AddReceiver(
    UntypedFunction::TrivialUntypedFunctionArgs<1>);
extern template void CallbackListReceivers::AddReceiver(
    UntypedFunction::TrivialUntypedFunctionArgs<2>);
extern template void CallbackListReceivers::AddReceiver(
    UntypedFunction::TrivialUntypedFunctionArgs<3>);
extern template void CallbackListReceivers::AddReceiver(
    UntypedFunction::TrivialUntypedFunctionArgs<4>);
extern template void CallbackListReceivers::AddReceiver(
    UntypedFunction::NontrivialUntypedFunctionArgs);
extern template void CallbackListReceivers::AddReceiver(
    UntypedFunction::FunctionPointerUntypedFunctionArgs);

}  // namespace callback_list_impl

// A collection of receivers (callable objects) that can be called all at once.
// Optimized for minimal binary size. The template arguments dictate what
// signature the callbacks must have; for example, a CallbackList<int, float>
// will require callbacks with signature void(int, float).
//
// CallbackList is neither copyable nor movable (could easily be made movable if
// necessary). Callbacks must be movable, but need not be copyable.
//
// Usage example:
//
//   // Declaration (usually a member variable).
//   CallbackList<int, float> foo_;
//
//   // Register callbacks. This can be done zero or more times. The
//   // callbacks must accept the arguments types listed in the CallbackList's
//   // template argument list, and must return void.
//   foo_.AddReceiver([...](int a, float b) {...});  // Lambda.
//   foo_.AddReceiver(SomeFunction);                 // Function pointer.
//
//   // Call the zero or more receivers, one after the other.
//   foo_.Send(17, 3.14);
//
// Callback lifetime considerations
// --------------------------------
//
// CallbackList::AddReceiver() takes ownership of the given callback by moving
// it in place. The callback can be any callable object; in particular, it may
// have a nontrivial destructor, which will be run when the CallbackList is
// destroyed. The callback may thus access data via any type of smart pointer,
// expressing e.g. unique, shared, or weak ownership. Of course, if the data is
// guaranteed to outlive the callback, a plain raw pointer can be used.
//
// Take care when trying to have the callback own reference-counted data. The
// CallbackList will keep the callback alive, and the callback will keep its
// data alive, so as usual with reference-counted ownership, keep an eye out for
// cycles!
//
// Thread safety
// -------------
//
// Like most C++ types, CallbackList is thread compatible: it's not safe to
// access it concurrently from multiple threads, but it can be made safe if it
// is protected by a mutex, for example.
//
// Excercise some care when deciding what mutexes to hold when you call
// CallbackList::Send(). In particular, do not hold mutexes that callbacks may
// need to grab. If a larger object has a CallbackList member and a single mutex
// that protects all of its data members, this may e.g. make it necessary to
// protect its CallbackList with a separate mutex; otherwise, there will be a
// deadlock if the callbacks try to access the object.
//
// CallbackList as a class data member
// -----------------------------------
//
// CallbackList is a normal C++ data type, and should be private when it is a
// data member of a class. For thread safety reasons (see above), it is likely
// best to not have an accessor for the entire CallbackList, and instead only
// allow callers to add callbacks:
//
//   template <typename F>
//   void AddFooCallback(F&& callback) {
//     // Maybe grab a mutex here?
//     foo_callbacks_.AddReceiver(std::forward<F>(callback));
//   }
//
template <typename... ArgT>
class CallbackList {
 public:
  CallbackList() = default;
  CallbackList(const CallbackList&) = delete;
  CallbackList& operator=(const CallbackList&) = delete;
  CallbackList(CallbackList&&) = delete;
  CallbackList& operator=(CallbackList&&) = delete;

  // Adds a new receiver. The receiver (a callable object or a function pointer)
  // must be movable, but need not be copyable. Its call signature should be
  // `void(ArgT...)`. The removal tag is a pointer to an arbitrary object that
  // you own, and that will stay alive until the CallbackList is gone, or until
  // all receivers using it as a removal tag have been removed; you can use it
  // to remove the receiver.
  template <typename F>
  void AddReceiver(const void* removal_tag, F&& f) {
    receivers_.AddReceiver(
        removal_tag,
        UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
  }

  // Adds a new receiver with no removal tag.
  template <typename F>
  void AddReceiver(F&& f) {
    receivers_.AddReceiver(
        UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
  }

  // Removes all receivers that were added with the given removal tag.
  void RemoveReceivers(const void* removal_tag) {
    receivers_.RemoveReceivers(removal_tag);
  }

  // Calls all receivers with the given arguments. While the Send is in
  // progress, no method calls are allowed; specifically, this means that the
  // callbacks may not do anything with this CallbackList instance.
  //
  // Note: Receivers are called serially, but not necessarily in the same order
  // they were added.
  template <typename... ArgU>
  void Send(ArgU&&... args) {
    receivers_.Foreach([&](UntypedFunction& f) {
      f.Call<void(ArgT...)>(std::forward<ArgU>(args)...);
    });
  }

 private:
  callback_list_impl::CallbackListReceivers receivers_;
};

}  // namespace webrtc

#endif  // RTC_BASE_CALLBACK_LIST_H_