diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/callback_list.cc')
-rw-r--r-- | third_party/libwebrtc/rtc_base/callback_list.cc | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/callback_list.cc b/third_party/libwebrtc/rtc_base/callback_list.cc new file mode 100644 index 0000000000..c452c79b38 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/callback_list.cc @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#include "rtc_base/callback_list.h" + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace callback_list_impl { + +CallbackListReceivers::CallbackListReceivers() = default; + +CallbackListReceivers::~CallbackListReceivers() { + RTC_CHECK(!send_in_progress_); +} + +void CallbackListReceivers::RemoveReceivers(const void* removal_tag) { + RTC_DCHECK(removal_tag); + + // 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. + if (send_in_progress_) { + // Tag this receiver for removal, which will be done when `ForEach` + // has completed. + receivers_[first_remove - 1].removal_tag = pending_removal_tag(); + } + --first_remove; + } else if (!send_in_progress_) { + // 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; + } + } + + if (!send_in_progress_) { + // Discard the remove region. + receivers_.resize(first_remove); + } +} + +void CallbackListReceivers::Foreach( + rtc::FunctionView<void(UntypedFunction&)> fv) { + RTC_CHECK(!send_in_progress_); + bool removals_detected = false; + send_in_progress_ = true; + for (auto& r : receivers_) { + RTC_DCHECK_NE(r.removal_tag, pending_removal_tag()); + fv(r.function); + if (r.removal_tag == pending_removal_tag()) { + removals_detected = true; + } + } + send_in_progress_ = false; + if (removals_detected) { + RemoveReceivers(pending_removal_tag()); + } +} + +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>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<3>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::TrivialUntypedFunctionArgs<4>); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::NontrivialUntypedFunctionArgs); +template void CallbackListReceivers::AddReceiver( + UntypedFunction::FunctionPointerUntypedFunctionArgs); + +} // namespace callback_list_impl +} // namespace webrtc |