webrtc/rtc_base/callback_list.h
Karl Wiberg 1a88ea1f79 CallbackList: Improve documentation
Bug: webrtc:11943
Change-Id: I86fdad3119d58d4bbd6cb7b28882cbc1d134d7a2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/191966
Reviewed-by: Markus Handell <handellm@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32579}
2020-11-10 19:08:45 +00:00

162 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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/system/assume.h"
#include "rtc_base/system/inline.h"
#include "rtc_base/untyped_function.h"
namespace webrtc {
namespace callback_list_impl {
class 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(UntypedFunctionArgsT args) {
receivers_.push_back(UntypedFunction::Create(args));
}
void Foreach(rtc::FunctionView<void(UntypedFunction&)> fv);
private:
std::vector<UntypedFunction> receivers_;
};
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));
// }
//
// Removing callbacks
// ------------------
//
// TODO(kwiberg): The current design doesnt support removing callbacks, only
// adding them, but removal support can easily be added.
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...)`.
template <typename F>
void AddReceiver(F&& f) {
receivers_.AddReceiver(
UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
}
// Calls all receivers with the given arguments.
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_