summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/untyped_function.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/untyped_function.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/untyped_function.h')
-rw-r--r--third_party/libwebrtc/rtc_base/untyped_function.h324
1 files changed, 324 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/untyped_function.h b/third_party/libwebrtc/rtc_base/untyped_function.h
new file mode 100644
index 0000000000..c1f59458b9
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/untyped_function.h
@@ -0,0 +1,324 @@
+/*
+ * 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_UNTYPED_FUNCTION_H_
+#define RTC_BASE_UNTYPED_FUNCTION_H_
+
+#include <cstddef>
+#include <cstring>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "rtc_base/system/assume.h"
+
+namespace webrtc {
+namespace webrtc_function_impl {
+
+using FunVoid = void();
+
+// Inline storage size is this many machine words.
+enum : size_t { kInlineStorageWords = 4 };
+
+union VoidUnion {
+ void* void_ptr;
+ FunVoid* fun_ptr;
+ typename std::aligned_storage<kInlineStorageWords * sizeof(uintptr_t)>::type
+ inline_storage;
+};
+
+// Returns the number of elements of the `inline_storage` array required to
+// store an object of type T.
+template <typename T>
+constexpr size_t InlineStorageSize() {
+ // sizeof(T) / sizeof(uintptr_t), but rounded up.
+ return (sizeof(T) + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
+}
+
+template <typename T>
+struct CallHelpers;
+template <typename RetT, typename... ArgT>
+struct CallHelpers<RetT(ArgT...)> {
+ // Return type of the three helpers below.
+ using return_type = RetT;
+ // Complete function type of the three helpers below.
+ using function_type = RetT(VoidUnion*, ArgT...);
+ // Helper for calling the `void_ptr` case of VoidUnion.
+ template <typename F>
+ static RetT CallVoidPtr(VoidUnion* vu, ArgT... args) {
+ return (*static_cast<F*>(vu->void_ptr))(std::forward<ArgT>(args)...);
+ }
+ // Helper for calling the `fun_ptr` case of VoidUnion.
+ static RetT CallFunPtr(VoidUnion* vu, ArgT... args) {
+ return (reinterpret_cast<RetT (*)(ArgT...)>(vu->fun_ptr))(
+ std::forward<ArgT>(args)...);
+ }
+ // Helper for calling the `inline_storage` case of VoidUnion.
+ template <typename F>
+ static RetT CallInlineStorage(VoidUnion* vu, ArgT... args) {
+ return (*reinterpret_cast<F*>(&vu->inline_storage))(
+ std::forward<ArgT>(args)...);
+ }
+};
+
+} // namespace webrtc_function_impl
+
+// A class that holds (and owns) any callable. The same function call signature
+// must be provided when constructing and calling the object.
+//
+// The point of not having the call signature as a class template parameter is
+// to have one single concrete type for all signatures; this reduces binary
+// size.
+class UntypedFunction final {
+ public:
+ // Callables of at most this size can be stored inline, if they are trivial.
+ // (Useful in tests and benchmarks; avoid using this in production code.)
+ enum : size_t {
+ kInlineStorageSize = sizeof(webrtc_function_impl::VoidUnion::inline_storage)
+ };
+ static_assert(kInlineStorageSize ==
+ webrtc_function_impl::kInlineStorageWords *
+ sizeof(uintptr_t),
+ "");
+
+ // The *UntypedFunctionArgs structs are used to transfer arguments from
+ // PrepareArgs() to Create(). They are trivial, but may own heap allocations,
+ // so make sure to pass them to Create() exactly once!
+ //
+ // The point of doing Create(PrepareArgs(foo)) instead of just Create(foo) is
+ // to separate the code that has to be inlined (PrepareArgs) from the code
+ // that can be noninlined (Create); the *UntypedFunctionArgs types are
+ // designed to efficiently carry the required information from one to the
+ // other.
+ template <size_t N>
+ struct TrivialUntypedFunctionArgs {
+ static_assert(N >= 1, "");
+ static_assert(N <= webrtc_function_impl::kInlineStorageWords, "");
+ // We use an uintptr_t array here instead of std::aligned_storage, because
+ // the former can be efficiently passed in registers when using
+ // TrivialUntypedFunctionArgs as a function argument. (We can't do the same
+ // in VoidUnion, because std::aligned_storage but not uintptr_t can be
+ // legally reinterpret_casted to arbitrary types.
+ // TrivialUntypedFunctionArgs, on the other hand, only needs to handle
+ // placement new and memcpy.)
+ alignas(std::max_align_t) uintptr_t inline_storage[N];
+ webrtc_function_impl::FunVoid* call;
+ };
+ struct NontrivialUntypedFunctionArgs {
+ void* void_ptr;
+ webrtc_function_impl::FunVoid* call;
+ void (*del)(webrtc_function_impl::VoidUnion*);
+ };
+ struct FunctionPointerUntypedFunctionArgs {
+ webrtc_function_impl::FunVoid* fun_ptr;
+ webrtc_function_impl::FunVoid* call;
+ };
+
+ // Create function for lambdas and other callables that are trivial and small;
+ // it accepts every type of argument except those noted in its enable_if call.
+ template <
+ typename Signature,
+ typename F,
+ typename F_deref = typename std::remove_reference<F>::type,
+ typename std::enable_if<
+ // Not for function pointers; we have another overload for that below.
+ !std::is_function<
+ typename std::remove_pointer<F_deref>::type>::value &&
+
+ // Not for nullptr; we have a constructor for that below.
+ !std::is_same<std::nullptr_t,
+ typename std::remove_cv<F>::type>::value &&
+
+ // Not for UntypedFunction objects; use move construction or
+ // assignment.
+ !std::is_same<UntypedFunction,
+ typename std::remove_cv<F_deref>::type>::value &&
+
+ // Only for trivial callables that will fit in inline storage.
+ std::is_trivially_move_constructible<F_deref>::value &&
+ std::is_trivially_destructible<F_deref>::value &&
+ sizeof(F_deref) <= kInlineStorageSize>::type* = nullptr,
+ size_t InlineSize = webrtc_function_impl::InlineStorageSize<F_deref>()>
+ static TrivialUntypedFunctionArgs<InlineSize> PrepareArgs(F&& f) {
+ // The callable is trivial and small enough, so we just store its bytes
+ // in the inline storage.
+ TrivialUntypedFunctionArgs<InlineSize> args;
+ new (&args.inline_storage) F_deref(std::forward<F>(f));
+ args.call = reinterpret_cast<webrtc_function_impl::FunVoid*>(
+ webrtc_function_impl::CallHelpers<
+ Signature>::template CallInlineStorage<F_deref>);
+ return args;
+ }
+ template <size_t InlineSize>
+ static UntypedFunction Create(TrivialUntypedFunctionArgs<InlineSize> args) {
+ webrtc_function_impl::VoidUnion vu;
+ std::memcpy(&vu.inline_storage, args.inline_storage,
+ sizeof(args.inline_storage));
+ return UntypedFunction(vu, args.call, nullptr);
+ }
+
+ // Create function for lambdas and other callables that are nontrivial or
+ // large; it accepts every type of argument except those noted in its
+ // enable_if call.
+ template <typename Signature,
+ typename F,
+ typename F_deref = typename std::remove_reference<F>::type,
+ typename std::enable_if<
+ // Not for function pointers; we have another overload for that
+ // below.
+ !std::is_function<
+ typename std::remove_pointer<F_deref>::type>::value &&
+
+ // Not for nullptr; we have a constructor for that below.
+ !std::is_same<std::nullptr_t,
+ typename std::remove_cv<F>::type>::value &&
+
+ // Not for UntypedFunction objects; use move construction or
+ // assignment.
+ !std::is_same<UntypedFunction,
+ typename std::remove_cv<F_deref>::type>::value &&
+
+ // Only for nontrivial callables, or callables that won't fit in
+ // inline storage.
+ !(std::is_trivially_move_constructible<F_deref>::value &&
+ std::is_trivially_destructible<F_deref>::value &&
+ sizeof(F_deref) <= kInlineStorageSize)>::type* = nullptr>
+ static NontrivialUntypedFunctionArgs PrepareArgs(F&& f) {
+ // The callable is either nontrivial or too large, so we can't keep it
+ // in the inline storage; use the heap instead.
+ NontrivialUntypedFunctionArgs args;
+ args.void_ptr = new F_deref(std::forward<F>(f));
+ args.call = reinterpret_cast<webrtc_function_impl::FunVoid*>(
+ webrtc_function_impl::CallHelpers<Signature>::template CallVoidPtr<
+ F_deref>);
+ args.del = static_cast<void (*)(webrtc_function_impl::VoidUnion*)>(
+ [](webrtc_function_impl::VoidUnion* vu) {
+ // Assuming that this pointer isn't null allows the
+ // compiler to eliminate a null check in the (inlined)
+ // delete operation.
+ RTC_ASSUME(vu->void_ptr != nullptr);
+ delete reinterpret_cast<F_deref*>(vu->void_ptr);
+ });
+ return args;
+ }
+ static UntypedFunction Create(NontrivialUntypedFunctionArgs args) {
+ webrtc_function_impl::VoidUnion vu;
+ vu.void_ptr = args.void_ptr;
+ return UntypedFunction(vu, args.call, args.del);
+ }
+
+ // Create function that accepts function pointers. If the argument is null,
+ // the result is an empty UntypedFunction.
+ template <typename Signature>
+ static FunctionPointerUntypedFunctionArgs PrepareArgs(Signature* f) {
+ FunctionPointerUntypedFunctionArgs args;
+ args.fun_ptr = reinterpret_cast<webrtc_function_impl::FunVoid*>(f);
+ args.call = reinterpret_cast<webrtc_function_impl::FunVoid*>(
+ webrtc_function_impl::CallHelpers<Signature>::CallFunPtr);
+ return args;
+ }
+ static UntypedFunction Create(FunctionPointerUntypedFunctionArgs args) {
+ webrtc_function_impl::VoidUnion vu;
+ vu.fun_ptr = args.fun_ptr;
+ return UntypedFunction(vu, args.fun_ptr == nullptr ? nullptr : args.call,
+ nullptr);
+ }
+
+ // Prepares arguments and creates an UntypedFunction in one go.
+ template <typename Signature, typename F>
+ static UntypedFunction Create(F&& f) {
+ return Create(PrepareArgs<Signature>(std::forward<F>(f)));
+ }
+
+ // Default constructor. Creates an empty UntypedFunction.
+ UntypedFunction() : call_(nullptr), delete_(nullptr) {}
+
+ // Nullptr constructor and assignment. Creates an empty UntypedFunction.
+ UntypedFunction(std::nullptr_t) // NOLINT(runtime/explicit)
+ : call_(nullptr), delete_(nullptr) {}
+ UntypedFunction& operator=(std::nullptr_t) {
+ call_ = nullptr;
+ if (delete_) {
+ delete_(&f_);
+ delete_ = nullptr;
+ }
+ return *this;
+ }
+
+ // Not copyable.
+ UntypedFunction(const UntypedFunction&) = delete;
+ UntypedFunction& operator=(const UntypedFunction&) = delete;
+
+ // Move construction and assignment.
+ UntypedFunction(UntypedFunction&& other)
+ : f_(other.f_), call_(other.call_), delete_(other.delete_) {
+ other.delete_ = nullptr;
+ }
+ UntypedFunction& operator=(UntypedFunction&& other) {
+ if (delete_) {
+ delete_(&f_);
+ }
+ f_ = other.f_;
+ call_ = other.call_;
+ delete_ = other.delete_;
+ other.delete_ = nullptr;
+ return *this;
+ }
+
+ ~UntypedFunction() {
+ if (delete_) {
+ delete_(&f_);
+ }
+ }
+
+ friend void swap(UntypedFunction& a, UntypedFunction& b) {
+ using std::swap;
+ swap(a.f_, b.f_);
+ swap(a.call_, b.call_);
+ swap(a.delete_, b.delete_);
+ }
+
+ // Returns true if we have a function, false if we don't (i.e., we're null).
+ explicit operator bool() const { return call_ != nullptr; }
+
+ template <typename Signature, typename... ArgT>
+ typename webrtc_function_impl::CallHelpers<Signature>::return_type Call(
+ ArgT&&... args) {
+ return reinterpret_cast<
+ typename webrtc_function_impl::CallHelpers<Signature>::function_type*>(
+ call_)(&f_, std::forward<ArgT>(args)...);
+ }
+
+ // Returns true iff we don't need to call a destructor. This is guaranteed
+ // to hold for a moved-from object.
+ bool IsTriviallyDestructible() { return delete_ == nullptr; }
+
+ private:
+ UntypedFunction(webrtc_function_impl::VoidUnion f,
+ webrtc_function_impl::FunVoid* call,
+ void (*del)(webrtc_function_impl::VoidUnion*))
+ : f_(f), call_(call), delete_(del) {}
+
+ // The callable thing, or a pointer to it.
+ webrtc_function_impl::VoidUnion f_;
+
+ // Pointer to a dispatch function that knows the type of the callable thing
+ // that's stored in f_, and how to call it. An UntypedFunction object is empty
+ // (null) iff call_ is null.
+ webrtc_function_impl::FunVoid* call_;
+
+ // Pointer to a function that knows how to delete the callable thing that's
+ // stored in f_. Null if `f_` is trivially deletable.
+ void (*delete_)(webrtc_function_impl::VoidUnion*);
+};
+
+} // namespace webrtc
+
+#endif // RTC_BASE_UNTYPED_FUNCTION_H_