summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.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/bounded_inline_vector_impl.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/bounded_inline_vector_impl.h')
-rw-r--r--third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h225
1 files changed, 225 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h b/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h
new file mode 100644
index 0000000000..3539ace5bc
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/bounded_inline_vector_impl.h
@@ -0,0 +1,225 @@
+/*
+ * 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_BOUNDED_INLINE_VECTOR_IMPL_H_
+#define RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_
+
+#include <stdint.h>
+
+#include <cstring>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace webrtc {
+namespace bounded_inline_vector_impl {
+
+template <bool...>
+struct BoolPack;
+
+// Tests if all its parameters (x0, x1, ..., xn) are true. The implementation
+// checks whether (x0, x1, ..., xn, true) == (true, x0, x1, ..., xn), which is
+// true iff true == x0 && x0 == x1 && x1 == x2 ... && xn-1 == xn && xn == true.
+template <bool... Bs>
+using AllTrue = std::is_same<BoolPack<Bs..., true>, BoolPack<true, Bs...>>;
+
+template <typename To, typename... Froms>
+using AllConvertible = AllTrue<std::is_convertible<Froms, To>::value...>;
+
+// Initializes part of an uninitialized array. Unlike normal array
+// initialization, does not zero the remaining array elements. Caller is
+// responsible for ensuring that there is enough space in `data`.
+template <typename T>
+void InitializeElements(T* data) {}
+template <typename T, typename U, typename... Us>
+void InitializeElements(T* data, U&& element, Us&&... elements) {
+ // Placement new, because we construct a new object in uninitialized memory.
+ ::new (data) T(std::forward<U>(element));
+ InitializeElements(data + 1, std::forward<Us>(elements)...);
+}
+
+// Default initializes uninitialized array elements.
+// TODO(kwiberg): Replace with std::uninitialized_default_construct_n() (C++17).
+template <typename T>
+void DefaultInitializeElements(T* data, int size) {
+ for (int i = 0; i < size; ++i) {
+ // Placement new, because we construct a new object in uninitialized memory.
+ ::new (&data[i]) T;
+ }
+}
+
+// Copies from source to uninitialized destination. Caller is responsible for
+// ensuring that there is enough space in `dst_data`.
+template <typename T>
+void CopyElements(const T* src_data, int src_size, T* dst_data, int* dst_size) {
+ if /*constexpr*/ (std::is_trivially_copy_constructible<T>::value) {
+ std::memcpy(dst_data, src_data, src_size * sizeof(T));
+ } else {
+ std::uninitialized_copy_n(src_data, src_size, dst_data);
+ }
+ *dst_size = src_size;
+}
+
+// Moves from source to uninitialized destination. Caller is responsible for
+// ensuring that there is enough space in `dst_data`.
+template <typename T>
+void MoveElements(T* src_data, int src_size, T* dst_data, int* dst_size) {
+ if /*constexpr*/ (std::is_trivially_move_constructible<T>::value) {
+ std::memcpy(dst_data, src_data, src_size * sizeof(T));
+ } else {
+ // TODO(kwiberg): Use std::uninitialized_move_n() instead (C++17).
+ for (int i = 0; i < src_size; ++i) {
+ // Placement new, because we create a new object in uninitialized
+ // memory.
+ ::new (&dst_data[i]) T(std::move(src_data[i]));
+ }
+ }
+ *dst_size = src_size;
+}
+
+// Destroys elements, leaving them uninitialized.
+template <typename T>
+void DestroyElements(T* data, int size) {
+ if /*constexpr*/ (!std::is_trivially_destructible<T>::value) {
+ for (int i = 0; i < size; ++i) {
+ data[i].~T();
+ }
+ }
+}
+
+// If elements are trivial and the total capacity is at most this many bytes,
+// copy everything instead of just the elements that are in use; this is more
+// efficient, and makes BoundedInlineVector trivially copyable.
+static constexpr int kSmallSize = 64;
+
+// Storage implementations.
+//
+// There are diferent Storage structs for diferent kinds of element types. The
+// common contract is the following:
+//
+// * They have public `size` variables and `data` array members.
+//
+// * Their owner is responsible for enforcing the invariant that the first
+// `size` elements in `data` are initialized, and the remaining elements are
+// not initialized.
+//
+// * They implement default construction, construction with one or more
+// elements, copy/move construction, copy/move assignment, and destruction;
+// the owner must ensure that the invariant holds whenever these operations
+// occur.
+
+// Storage implementation for nontrivial element types.
+template <typename T,
+ int fixed_capacity,
+ bool is_trivial = std::is_trivial<T>::value,
+ bool is_small = (sizeof(T) * fixed_capacity <= kSmallSize)>
+struct Storage {
+ static_assert(!std::is_trivial<T>::value, "");
+
+ template <
+ typename... Ts,
+ typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr>
+ explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) {
+ InitializeElements(data, std::forward<Ts>(elements)...);
+ }
+
+ Storage(const Storage& other) {
+ CopyElements(other.data, other.size, data, &size);
+ }
+
+ Storage(Storage&& other) {
+ MoveElements(other.data, other.size, data, &size);
+ }
+
+ Storage& operator=(const Storage& other) {
+ if (this != &other) {
+ DestroyElements(data, size);
+ CopyElements(other.data, other.size, data, &size);
+ }
+ return *this;
+ }
+
+ Storage& operator=(Storage&& other) {
+ DestroyElements(data, size);
+ size = 0; // Needed in case of self assignment.
+ MoveElements(other.data, other.size, data, &size);
+ return *this;
+ }
+
+ ~Storage() { DestroyElements(data, size); }
+
+ int size;
+ union {
+ // Since this array is in a union, we get to construct and destroy it
+ // manually.
+ T data[fixed_capacity]; // NOLINT(runtime/arrays)
+ };
+};
+
+// Storage implementation for trivial element types when the capacity is small
+// enough that we can cheaply copy everything.
+template <typename T, int fixed_capacity>
+struct Storage<T, fixed_capacity, /*is_trivial=*/true, /*is_small=*/true> {
+ static_assert(std::is_trivial<T>::value, "");
+ static_assert(sizeof(T) * fixed_capacity <= kSmallSize, "");
+
+ template <
+ typename... Ts,
+ typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr>
+ explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) {
+ InitializeElements(data, std::forward<Ts>(elements)...);
+ }
+
+ Storage(const Storage&) = default;
+ Storage& operator=(const Storage&) = default;
+ ~Storage() = default;
+
+ int size;
+ T data[fixed_capacity]; // NOLINT(runtime/arrays)
+};
+
+// Storage implementation for trivial element types when the capacity is large
+// enough that we want to avoid copying uninitialized elements.
+template <typename T, int fixed_capacity>
+struct Storage<T, fixed_capacity, /*is_trivial=*/true, /*is_small=*/false> {
+ static_assert(std::is_trivial<T>::value, "");
+ static_assert(sizeof(T) * fixed_capacity > kSmallSize, "");
+
+ template <
+ typename... Ts,
+ typename std::enable_if_t<AllConvertible<T, Ts...>::value>* = nullptr>
+ explicit Storage(Ts&&... elements) : size(sizeof...(Ts)) {
+ InitializeElements(data, std::forward<Ts>(elements)...);
+ }
+
+ Storage(const Storage& other) : size(other.size) {
+ std::memcpy(data, other.data, other.size * sizeof(T));
+ }
+
+ Storage& operator=(const Storage& other) {
+ if (this != &other) {
+ size = other.size;
+ std::memcpy(data, other.data, other.size * sizeof(T));
+ }
+ return *this;
+ }
+
+ ~Storage() = default;
+
+ int size;
+ union {
+ T data[fixed_capacity]; // NOLINT(runtime/arrays)
+ };
+};
+
+} // namespace bounded_inline_vector_impl
+} // namespace webrtc
+
+#endif // RTC_BASE_BOUNDED_INLINE_VECTOR_IMPL_H_