CallbackList: Add support for removing receivers
Bug: webrtc:11943
Change-Id: I7a646729dd1e4f5abe20900412f4105414e1a98f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/195332
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32700}
diff --git a/rtc_base/callback_list.cc b/rtc_base/callback_list.cc
index ac947e2..88d0b6f 100644
--- a/rtc_base/callback_list.cc
+++ b/rtc_base/callback_list.cc
@@ -21,17 +21,76 @@
RTC_CHECK(!send_in_progress_);
}
+void CallbackListReceivers::RemoveReceivers(const void* removal_tag) {
+ RTC_CHECK(!send_in_progress_);
+ RTC_DCHECK(removal_tag != nullptr);
+
+ // We divide the receivers_ vector into three regions: from right to left, the
+ // "keep" region, the "todo" region, and the "remove" region. The "todo"
+ // region initially covers the whole vector.
+ size_t first_todo = 0; // First element of the "todo"
+ // region.
+ size_t first_remove = receivers_.size(); // First element of the "remove"
+ // region.
+
+ // Loop until the "todo" region is empty.
+ while (first_todo != first_remove) {
+ if (receivers_[first_todo].removal_tag != removal_tag) {
+ // The first element of the "todo" region should be kept. Move the
+ // "keep"/"todo" boundary.
+ ++first_todo;
+ } else if (receivers_[first_remove - 1].removal_tag == removal_tag) {
+ // The last element of the "todo" region should be removed. Move the
+ // "todo"/"remove" boundary.
+ --first_remove;
+ } else {
+ // The first element of the "todo" region should be removed, and the last
+ // element of the "todo" region should be kept. Swap them, and then shrink
+ // the "todo" region from both ends.
+ RTC_DCHECK_NE(first_todo, first_remove - 1);
+ using std::swap;
+ swap(receivers_[first_todo], receivers_[first_remove - 1]);
+ RTC_DCHECK_NE(receivers_[first_todo].removal_tag, removal_tag);
+ ++first_todo;
+ RTC_DCHECK_EQ(receivers_[first_remove - 1].removal_tag, removal_tag);
+ --first_remove;
+ }
+ }
+
+ // Discard the remove region.
+ receivers_.resize(first_remove);
+}
+
void CallbackListReceivers::Foreach(
rtc::FunctionView<void(UntypedFunction&)> fv) {
RTC_CHECK(!send_in_progress_);
send_in_progress_ = true;
for (auto& r : receivers_) {
- fv(r);
+ fv(r.function);
}
send_in_progress_ = false;
}
template void CallbackListReceivers::AddReceiver(
+ const void*,
+ UntypedFunction::TrivialUntypedFunctionArgs<1>);
+template void CallbackListReceivers::AddReceiver(
+ const void*,
+ UntypedFunction::TrivialUntypedFunctionArgs<2>);
+template void CallbackListReceivers::AddReceiver(
+ const void*,
+ UntypedFunction::TrivialUntypedFunctionArgs<3>);
+template void CallbackListReceivers::AddReceiver(
+ const void*,
+ UntypedFunction::TrivialUntypedFunctionArgs<4>);
+template void CallbackListReceivers::AddReceiver(
+ const void*,
+ UntypedFunction::NontrivialUntypedFunctionArgs);
+template void CallbackListReceivers::AddReceiver(
+ const void*,
+ UntypedFunction::FunctionPointerUntypedFunctionArgs);
+
+template void CallbackListReceivers::AddReceiver(
UntypedFunction::TrivialUntypedFunctionArgs<1>);
template void CallbackListReceivers::AddReceiver(
UntypedFunction::TrivialUntypedFunctionArgs<2>);