xref: /aosp_15_r20/external/webrtc/rtc_base/callback_list.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 #include "rtc_base/callback_list.h"
12 
13 #include "rtc_base/checks.h"
14 
15 namespace webrtc {
16 namespace callback_list_impl {
17 
18 CallbackListReceivers::CallbackListReceivers() = default;
19 
~CallbackListReceivers()20 CallbackListReceivers::~CallbackListReceivers() {
21   RTC_CHECK(!send_in_progress_);
22 }
23 
RemoveReceivers(const void * removal_tag)24 void CallbackListReceivers::RemoveReceivers(const void* removal_tag) {
25   RTC_DCHECK(removal_tag);
26 
27   // We divide the receivers_ vector into three regions: from right to left, the
28   // "keep" region, the "todo" region, and the "remove" region. The "todo"
29   // region initially covers the whole vector.
30   size_t first_todo = 0;                    // First element of the "todo"
31                                             // region.
32   size_t first_remove = receivers_.size();  // First element of the "remove"
33                                             // region.
34 
35   // Loop until the "todo" region is empty.
36   while (first_todo != first_remove) {
37     if (receivers_[first_todo].removal_tag != removal_tag) {
38       // The first element of the "todo" region should be kept. Move the
39       // "keep"/"todo" boundary.
40       ++first_todo;
41     } else if (receivers_[first_remove - 1].removal_tag == removal_tag) {
42       // The last element of the "todo" region should be removed. Move the
43       // "todo"/"remove" boundary.
44       if (send_in_progress_) {
45         // Tag this receiver for removal, which will be done when `ForEach`
46         // has completed.
47         receivers_[first_remove - 1].removal_tag = pending_removal_tag();
48       }
49       --first_remove;
50     } else if (!send_in_progress_) {
51       // The first element of the "todo" region should be removed, and the last
52       // element of the "todo" region should be kept. Swap them, and then shrink
53       // the "todo" region from both ends.
54       RTC_DCHECK_NE(first_todo, first_remove - 1);
55       using std::swap;
56       swap(receivers_[first_todo], receivers_[first_remove - 1]);
57       RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag);
58       ++first_todo;
59       RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag);
60       --first_remove;
61     }
62   }
63 
64   if (!send_in_progress_) {
65     // Discard the remove region.
66     receivers_.resize(first_remove);
67   }
68 }
69 
Foreach(rtc::FunctionView<void (UntypedFunction &)> fv)70 void CallbackListReceivers::Foreach(
71     rtc::FunctionView<void(UntypedFunction&)> fv) {
72   RTC_CHECK(!send_in_progress_);
73   bool removals_detected = false;
74   send_in_progress_ = true;
75   for (auto& r : receivers_) {
76     RTC_DCHECK_NE(r.removal_tag, pending_removal_tag());
77     fv(r.function);
78     if (r.removal_tag == pending_removal_tag()) {
79       removals_detected = true;
80     }
81   }
82   send_in_progress_ = false;
83   if (removals_detected) {
84     RemoveReceivers(pending_removal_tag());
85   }
86 }
87 
88 template void CallbackListReceivers::AddReceiver(
89     const void*,
90     UntypedFunction::TrivialUntypedFunctionArgs<1>);
91 template void CallbackListReceivers::AddReceiver(
92     const void*,
93     UntypedFunction::TrivialUntypedFunctionArgs<2>);
94 template void CallbackListReceivers::AddReceiver(
95     const void*,
96     UntypedFunction::TrivialUntypedFunctionArgs<3>);
97 template void CallbackListReceivers::AddReceiver(
98     const void*,
99     UntypedFunction::TrivialUntypedFunctionArgs<4>);
100 template void CallbackListReceivers::AddReceiver(
101     const void*,
102     UntypedFunction::NontrivialUntypedFunctionArgs);
103 template void CallbackListReceivers::AddReceiver(
104     const void*,
105     UntypedFunction::FunctionPointerUntypedFunctionArgs);
106 
107 template void CallbackListReceivers::AddReceiver(
108     UntypedFunction::TrivialUntypedFunctionArgs<1>);
109 template void CallbackListReceivers::AddReceiver(
110     UntypedFunction::TrivialUntypedFunctionArgs<2>);
111 template void CallbackListReceivers::AddReceiver(
112     UntypedFunction::TrivialUntypedFunctionArgs<3>);
113 template void CallbackListReceivers::AddReceiver(
114     UntypedFunction::TrivialUntypedFunctionArgs<4>);
115 template void CallbackListReceivers::AddReceiver(
116     UntypedFunction::NontrivialUntypedFunctionArgs);
117 template void CallbackListReceivers::AddReceiver(
118     UntypedFunction::FunctionPointerUntypedFunctionArgs);
119 
120 }  // namespace callback_list_impl
121 }  // namespace webrtc
122