Karl Wiberg | c126937 | 2020-03-02 20:23:41 +0100 | [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: |
| 37 | using value_type = T; |
| 38 | using const_iterator = const T*; |
| 39 | |
| 40 | BoundedInlineVector() = default; |
| 41 | BoundedInlineVector(const BoundedInlineVector&) = default; |
| 42 | BoundedInlineVector(BoundedInlineVector&&) = default; |
| 43 | BoundedInlineVector& operator=(const BoundedInlineVector&) = default; |
| 44 | BoundedInlineVector& operator=(BoundedInlineVector&&) = default; |
| 45 | ~BoundedInlineVector() = default; |
| 46 | |
| 47 | // This constructor is implicit, to make it possible to write e.g. |
| 48 | // |
| 49 | // BoundedInlineVector<double, 7> x = {2.72, 3.14}; |
| 50 | // |
| 51 | // and |
| 52 | // |
| 53 | // BoundedInlineVector<double, 7> GetConstants() { |
| 54 | // return {2.72, 3.14}; |
| 55 | // } |
| 56 | template <typename... Ts, |
| 57 | typename std::enable_if_t< |
| 58 | bounded_inline_vector_impl::AllConvertible<T, Ts...>::value>* = |
| 59 | nullptr> |
| 60 | BoundedInlineVector(Ts&&... elements) // NOLINT(runtime/explicit) |
| 61 | : storage_(std::forward<Ts>(elements)...) { |
| 62 | static_assert(sizeof...(Ts) <= fixed_capacity, ""); |
| 63 | } |
| 64 | |
| 65 | template < |
| 66 | int other_capacity, |
| 67 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 68 | BoundedInlineVector(const BoundedInlineVector<T, other_capacity>& other) { |
| 69 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 70 | bounded_inline_vector_impl::CopyElements(other.data(), other.size(), |
| 71 | storage_.data, &storage_.size); |
| 72 | } |
| 73 | |
| 74 | template < |
| 75 | int other_capacity, |
| 76 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 77 | BoundedInlineVector(BoundedInlineVector<T, other_capacity>&& other) { |
| 78 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 79 | bounded_inline_vector_impl::MoveElements(other.data(), other.size(), |
| 80 | storage_.data, &storage_.size); |
| 81 | } |
| 82 | |
| 83 | template < |
| 84 | int other_capacity, |
| 85 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 86 | BoundedInlineVector& operator=( |
| 87 | const BoundedInlineVector<T, other_capacity>& other) { |
| 88 | bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size); |
| 89 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 90 | bounded_inline_vector_impl::CopyElements(other.data(), other.size(), |
| 91 | storage_.data, &storage_.size); |
| 92 | return *this; |
| 93 | } |
| 94 | |
| 95 | template < |
| 96 | int other_capacity, |
| 97 | typename std::enable_if_t<other_capacity != fixed_capacity>* = nullptr> |
| 98 | BoundedInlineVector& operator=( |
| 99 | BoundedInlineVector<T, other_capacity>&& other) { |
| 100 | bounded_inline_vector_impl::DestroyElements(storage_.data, storage_.size); |
| 101 | RTC_DCHECK_LE(other.size(), fixed_capacity); |
| 102 | bounded_inline_vector_impl::MoveElements(other.data(), other.size(), |
| 103 | storage_.data, &storage_.size); |
| 104 | return *this; |
| 105 | } |
| 106 | |
| 107 | bool empty() const { return storage_.size == 0; } |
| 108 | int size() const { return storage_.size; } |
| 109 | constexpr int capacity() const { return fixed_capacity; } |
| 110 | |
| 111 | const T* data() const { return storage_.data; } |
| 112 | T* data() { return storage_.data; } |
| 113 | |
| 114 | const T& operator[](int index) const { |
| 115 | RTC_DCHECK_GE(index, 0); |
| 116 | RTC_DCHECK_LT(index, storage_.size); |
| 117 | return storage_.data[index]; |
| 118 | } |
| 119 | T& operator[](int index) { |
| 120 | RTC_DCHECK_GE(index, 0); |
| 121 | RTC_DCHECK_LT(index, storage_.size); |
| 122 | return storage_.data[index]; |
| 123 | } |
| 124 | |
| 125 | T* begin() { return storage_.data; } |
| 126 | T* end() { return storage_.data + storage_.size; } |
| 127 | const T* begin() const { return storage_.data; } |
| 128 | const T* end() const { return storage_.data + storage_.size; } |
| 129 | const T* cbegin() const { return storage_.data; } |
| 130 | const T* cend() const { return storage_.data + storage_.size; } |
| 131 | |
| 132 | private: |
| 133 | bounded_inline_vector_impl::Storage<T, fixed_capacity> storage_; |
| 134 | }; |
| 135 | |
| 136 | } // namespace webrtc |
| 137 | |
| 138 | #endif // RTC_BASE_BOUNDED_INLINE_VECTOR_H_ |