Karl Wiberg | c126937 | 2020-03-02 19:23:41 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2020 The WebRTC Project Authors. All rights reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | #ifndef RTC_BASE_BOUNDED_INLINE_VECTOR_H_ |
| 12 | #define RTC_BASE_BOUNDED_INLINE_VECTOR_H_ |
| 13 | |
| 14 | #include <stdint.h> |
| 15 | |
| 16 | #include <memory> |
| 17 | #include <type_traits> |
| 18 | #include <utility> |
| 19 | |
| 20 | #include "rtc_base/bounded_inline_vector_impl.h" |
| 21 | #include "rtc_base/checks.h" |
| 22 | |
| 23 | namespace webrtc { |
| 24 | |
| 25 | // A small std::vector-like type whose capacity is a compile-time constant. It |
| 26 | // stores all data inline and never heap allocates (beyond what its element type |
| 27 | // requires). Trying to grow it beyond its constant capacity is an error. |
| 28 | // |
| 29 | // TODO(bugs.webrtc.org/11391): Comparison operators. |
| 30 | // TODO(bugs.webrtc.org/11391): Methods for adding and deleting elements. |
| 31 | template <typename T, int fixed_capacity> |
| 32 | class BoundedInlineVector { |
| 33 | static_assert(!std::is_const<T>::value, "T may not be const"); |
| 34 | static_assert(fixed_capacity > 0, "Capacity must be strictly positive"); |
| 35 | |
| 36 | public: |
Karl Wiberg | d084ea9 | 2020-03-02 20:49:20 | [diff] [blame] | 37 | using size_type = int; |
Karl Wiberg | c126937 | 2020-03-02 19:23:41 | [diff] [blame] | 38 | using value_type = T; |
| 39 | using const_iterator = const T*; |
| 40 | |
| 41 | BoundedInlineVector() = default; |
| 42 | BoundedInlineVector(const BoundedInlineVector&) = default; |
| 43 | BoundedInlineVector(BoundedInlineVector&&) = default; |
| 44 | BoundedInlineVector& operator=(const BoundedInlineVector&) = default; |
| 45 | BoundedInlineVector& operator=(BoundedInlineVector&&) = default; |
| 46 | ~BoundedInlineVector() = default; |
| 47 | |
| 48 | // This constructor is implicit, to make it possible to write e.g. |
| 49 | // |
| 50 | // BoundedInlineVector<double, 7> x = {2.72, 3.14}; |
| 51 | // |
| 52 | // and |
| 53 | // |
| 54 | // BoundedInlineVector<double, 7> GetConstants() { |
| 55 | // return {2.72, 3.14}; |
| 56 | // } |
| 57 | template <typename... Ts, |
| 58 | typename std::enable_if_t< |
| 59 | bounded_inline_vector_impl::AllConvertible<T, Ts...>::value>* = |
| 60 | nullptr> |
| 61 | BoundedInlineVector(Ts&&... elements) // NOLINT(runtime/explicit) |
| 62 | : storage_(std::forward<Ts>(elements)...) { |
| 63 | static_assert(sizeof...(Ts) <= fixed_capacity, ""); |
| 64 | } |
| 65 | |
| 66 | template < |
| 67 | int other_capacity, |
| 68 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 69 | BoundedInlineVector(const BoundedInlineVector<T, other_capacity>& other) { |
| 70 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 71 | bounded_inline_vector_impl::CopyElements(other.data(), other.size(), |
| 72 | storage_.data, &storage_.size); |
| 73 | } |
| 74 | |
| 75 | template < |
| 76 | int other_capacity, |
| 77 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 78 | BoundedInlineVector(BoundedInlineVector<T, other_capacity>&& other) { |
| 79 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 80 | bounded_inline_vector_impl::MoveElements(other.data(), other.size(), |
| 81 | storage_.data, &storage_.size); |
| 82 | } |
| 83 | |
| 84 | template < |
| 85 | int other_capacity, |
| 86 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 87 | BoundedInlineVector& operator=( |
| 88 | const BoundedInlineVector<T, other_capacity>& other) { |
| 89 | bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size); |
| 90 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 91 | bounded_inline_vector_impl::CopyElements(other.data(), other.size(), |
| 92 | storage_.data, &storage_.size); |
| 93 | return *this; |
| 94 | } |
| 95 | |
| 96 | template < |
| 97 | int other_capacity, |
| 98 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 99 | BoundedInlineVector& operator=( |
| 100 | BoundedInlineVector<T, other_capacity>&& other) { |
| 101 | bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size); |
| 102 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 103 | bounded_inline_vector_impl::MoveElements(other.data(), other.size(), |
| 104 | storage_.data, &storage_.size); |
| 105 | return *this; |
| 106 | } |
| 107 | |
| 108 | bool empty() const { return storage_.size == 0; } |
| 109 | int size() const { return storage_.size; } |
| 110 | constexpr int capacity() const { return fixed_capacity; } |
| 111 | |
Karl Wiberg | d084ea9 | 2020-03-02 20:49:20 | [diff] [blame] | 112 | // Resizes the BoundedInlineVector to the given size, which must not exceed |
| 113 | // its constant capacity. If the size is increased, the added elements are |
| 114 | // default constructed. |
| 115 | void resize(int new_size) { |
| 116 | RTC_DCHECK_GE(new_size, 0); |
| 117 | RTC_DCHECK_LE(new_size, fixed_capacity); |
| 118 | if (new_size > storage_.size) { |
| 119 | bounded_inline_vector_impl::DefaultInitializeElements( |
| 120 | storage_.data + storage_.size, new_size - storage_.size); |
| 121 | } else if (new_size < storage_.size) { |
| 122 | bounded_inline_vector_impl::DestroyElements(storage_.data + new_size, |
| 123 | storage_.size - new_size); |
| 124 | } |
| 125 | storage_.size = new_size; |
| 126 | } |
| 127 | |
Karl Wiberg | c126937 | 2020-03-02 19:23:41 | [diff] [blame] | 128 | const T* data() const { return storage_.data; } |
| 129 | T* data() { return storage_.data; } |
| 130 | |
| 131 | const T& operator[](int index) const { |
| 132 | RTC_DCHECK_GE(index, 0); |
| 133 | RTC_DCHECK_LT(index, storage_.size); |
| 134 | return storage_.data[index]; |
| 135 | } |
| 136 | T& operator[](int index) { |
| 137 | RTC_DCHECK_GE(index, 0); |
| 138 | RTC_DCHECK_LT(index, storage_.size); |
| 139 | return storage_.data[index]; |
| 140 | } |
| 141 | |
| 142 | T* begin() { return storage_.data; } |
| 143 | T* end() { return storage_.data + storage_.size; } |
| 144 | const T* begin() const { return storage_.data; } |
| 145 | const T* end() const { return storage_.data + storage_.size; } |
| 146 | const T* cbegin() const { return storage_.data; } |
| 147 | const T* cend() const { return storage_.data + storage_.size; } |
| 148 | |
| 149 | private: |
| 150 | bounded_inline_vector_impl::Storage<T, fixed_capacity> storage_; |
| 151 | }; |
| 152 | |
| 153 | } // namespace webrtc |
| 154 | |
| 155 | #endif // RTC_BASE_BOUNDED_INLINE_VECTOR_H_ |