| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #ifndef WEBRTC_BASE_ARRAY_VIEW_H_ | 11 #ifndef WEBRTC_BASE_ARRAY_VIEW_H_ |
| 12 #define WEBRTC_BASE_ARRAY_VIEW_H_ | 12 #define WEBRTC_BASE_ARRAY_VIEW_H_ |
| 13 | 13 |
| 14 #include "webrtc/base/checks.h" | |
| 15 #include "webrtc/base/type_traits.h" | |
| 16 | 14 |
| 17 namespace rtc { | 15 // This header is deprecated and is just left here temporarily during |
| 18 | 16 // refactoring. See https://bugs.webrtc.org/7634 for more details. |
| 19 // Many functions read from or write to arrays. The obvious way to do this is | 17 #include "webrtc/rtc_base/array_view.h" |
| 20 // to use two arguments, a pointer to the first element and an element count: | |
| 21 // | |
| 22 // bool Contains17(const int* arr, size_t size) { | |
| 23 // for (size_t i = 0; i < size; ++i) { | |
| 24 // if (arr[i] == 17) | |
| 25 // return true; | |
| 26 // } | |
| 27 // return false; | |
| 28 // } | |
| 29 // | |
| 30 // This is flexible, since it doesn't matter how the array is stored (C array, | |
| 31 // std::vector, rtc::Buffer, ...), but it's error-prone because the caller has | |
| 32 // to correctly specify the array length: | |
| 33 // | |
| 34 // Contains17(arr, arraysize(arr)); // C array | |
| 35 // Contains17(arr.data(), arr.size()); // std::vector | |
| 36 // Contains17(arr, size); // pointer + size | |
| 37 // ... | |
| 38 // | |
| 39 // It's also kind of messy to have two separate arguments for what is | |
| 40 // conceptually a single thing. | |
| 41 // | |
| 42 // Enter rtc::ArrayView<T>. It contains a T pointer (to an array it doesn't | |
| 43 // own) and a count, and supports the basic things you'd expect, such as | |
| 44 // indexing and iteration. It allows us to write our function like this: | |
| 45 // | |
| 46 // bool Contains17(rtc::ArrayView<const int> arr) { | |
| 47 // for (auto e : arr) { | |
| 48 // if (e == 17) | |
| 49 // return true; | |
| 50 // } | |
| 51 // return false; | |
| 52 // } | |
| 53 // | |
| 54 // And even better, because a bunch of things will implicitly convert to | |
| 55 // ArrayView, we can call it like this: | |
| 56 // | |
| 57 // Contains17(arr); // C array | |
| 58 // Contains17(arr); // std::vector | |
| 59 // Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size | |
| 60 // Contains17(nullptr); // nullptr -> empty ArrayView | |
| 61 // ... | |
| 62 // | |
| 63 // ArrayView<T> stores both a pointer and a size, but you may also use | |
| 64 // ArrayView<T, N>, which has a size that's fixed at compile time (which means | |
| 65 // it only has to store the pointer). | |
| 66 // | |
| 67 // One important point is that ArrayView<T> and ArrayView<const T> are | |
| 68 // different types, which allow and don't allow mutation of the array elements, | |
| 69 // respectively. The implicit conversions work just like you'd hope, so that | |
| 70 // e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const | |
| 71 // int>, but const vector<int> will convert only to ArrayView<const int>. | |
| 72 // (ArrayView itself can be the source type in such conversions, so | |
| 73 // ArrayView<int> will convert to ArrayView<const int>.) | |
| 74 // | |
| 75 // Note: ArrayView is tiny (just a pointer and a count if variable-sized, just | |
| 76 // a pointer if fix-sized) and trivially copyable, so it's probably cheaper to | |
| 77 // pass it by value than by const reference. | |
| 78 | |
| 79 namespace impl { | |
| 80 | |
| 81 // Magic constant for indicating that the size of an ArrayView is variable | |
| 82 // instead of fixed. | |
| 83 enum : std::ptrdiff_t { kArrayViewVarSize = -4711 }; | |
| 84 | |
| 85 // Base class for ArrayViews of fixed nonzero size. | |
| 86 template <typename T, std::ptrdiff_t Size> | |
| 87 class ArrayViewBase { | |
| 88 static_assert(Size > 0, "ArrayView size must be variable or non-negative"); | |
| 89 | |
| 90 public: | |
| 91 ArrayViewBase(T* data, size_t size) : data_(data) {} | |
| 92 | |
| 93 static constexpr size_t size() { return Size; } | |
| 94 static constexpr bool empty() { return false; } | |
| 95 T* data() const { return data_; } | |
| 96 | |
| 97 protected: | |
| 98 static constexpr bool fixed_size() { return true; } | |
| 99 | |
| 100 private: | |
| 101 T* data_; | |
| 102 }; | |
| 103 | |
| 104 // Specialized base class for ArrayViews of fixed zero size. | |
| 105 template <typename T> | |
| 106 class ArrayViewBase<T, 0> { | |
| 107 public: | |
| 108 explicit ArrayViewBase(T* data, size_t size) {} | |
| 109 | |
| 110 static constexpr size_t size() { return 0; } | |
| 111 static constexpr bool empty() { return true; } | |
| 112 T* data() const { return nullptr; } | |
| 113 | |
| 114 protected: | |
| 115 static constexpr bool fixed_size() { return true; } | |
| 116 }; | |
| 117 | |
| 118 // Specialized base class for ArrayViews of variable size. | |
| 119 template <typename T> | |
| 120 class ArrayViewBase<T, impl::kArrayViewVarSize> { | |
| 121 public: | |
| 122 ArrayViewBase(T* data, size_t size) | |
| 123 : data_(size == 0 ? nullptr : data), size_(size) {} | |
| 124 | |
| 125 size_t size() const { return size_; } | |
| 126 bool empty() const { return size_ == 0; } | |
| 127 T* data() const { return data_; } | |
| 128 | |
| 129 protected: | |
| 130 static constexpr bool fixed_size() { return false; } | |
| 131 | |
| 132 private: | |
| 133 T* data_; | |
| 134 size_t size_; | |
| 135 }; | |
| 136 | |
| 137 } // namespace impl | |
| 138 | |
| 139 template <typename T, std::ptrdiff_t Size = impl::kArrayViewVarSize> | |
| 140 class ArrayView final : public impl::ArrayViewBase<T, Size> { | |
| 141 public: | |
| 142 using value_type = T; | |
| 143 using const_iterator = const T*; | |
| 144 | |
| 145 // Construct an ArrayView from a pointer and a length. | |
| 146 template <typename U> | |
| 147 ArrayView(U* data, size_t size) | |
| 148 : impl::ArrayViewBase<T, Size>::ArrayViewBase(data, size) { | |
| 149 RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data()); | |
| 150 RTC_DCHECK_EQ(size, this->size()); | |
| 151 RTC_DCHECK_EQ(!this->data(), | |
| 152 this->size() == 0); // data is null iff size == 0. | |
| 153 } | |
| 154 | |
| 155 // Construct an empty ArrayView. Note that fixed-size ArrayViews of size > 0 | |
| 156 // cannot be empty. | |
| 157 ArrayView() : ArrayView(nullptr, 0) {} | |
| 158 ArrayView(std::nullptr_t) : ArrayView() {} | |
| 159 ArrayView(std::nullptr_t, size_t size) | |
| 160 : ArrayView(static_cast<T*>(nullptr), size) { | |
| 161 static_assert(Size == 0 || Size == impl::kArrayViewVarSize, ""); | |
| 162 RTC_DCHECK_EQ(0, size); | |
| 163 } | |
| 164 | |
| 165 // Construct an ArrayView from an array. | |
| 166 template <typename U, size_t N> | |
| 167 ArrayView(U (&array)[N]) : ArrayView(array, N) { | |
| 168 static_assert(Size == N || Size == impl::kArrayViewVarSize, | |
| 169 "Array size must match ArrayView size"); | |
| 170 } | |
| 171 | |
| 172 // (Only if size is fixed.) Construct an ArrayView from any type U that has a | |
| 173 // static constexpr size() method whose return value is equal to Size, and a | |
| 174 // data() method whose return value converts implicitly to T*. In particular, | |
| 175 // this means we allow conversion from ArrayView<T, N> to ArrayView<const T, | |
| 176 // N>, but not the other way around. We also don't allow conversion from | |
| 177 // ArrayView<T> to ArrayView<T, N>, or from ArrayView<T, M> to ArrayView<T, | |
| 178 // N> when M != N. | |
| 179 template <typename U, | |
| 180 typename std::enable_if< | |
| 181 Size != impl::kArrayViewVarSize && | |
| 182 HasDataAndSize<U, T>::value>::type* = nullptr> | |
| 183 ArrayView(U& u) : ArrayView(u.data(), u.size()) { | |
| 184 static_assert(U::size() == Size, "Sizes must match exactly"); | |
| 185 } | |
| 186 | |
| 187 // (Only if size is variable.) Construct an ArrayView from any type U that | |
| 188 // has a size() method whose return value converts implicitly to size_t, and | |
| 189 // a data() method whose return value converts implicitly to T*. In | |
| 190 // particular, this means we allow conversion from ArrayView<T> to | |
| 191 // ArrayView<const T>, but not the other way around. Other allowed | |
| 192 // conversions include | |
| 193 // ArrayView<T, N> to ArrayView<T> or ArrayView<const T>, | |
| 194 // std::vector<T> to ArrayView<T> or ArrayView<const T>, | |
| 195 // const std::vector<T> to ArrayView<const T>, | |
| 196 // rtc::Buffer to ArrayView<uint8_t> or ArrayView<const uint8_t>, and | |
| 197 // const rtc::Buffer to ArrayView<const uint8_t>. | |
| 198 template < | |
| 199 typename U, | |
| 200 typename std::enable_if<Size == impl::kArrayViewVarSize && | |
| 201 HasDataAndSize<U, T>::value>::type* = nullptr> | |
| 202 ArrayView(U& u) : ArrayView(u.data(), u.size()) {} | |
| 203 | |
| 204 // Indexing and iteration. These allow mutation even if the ArrayView is | |
| 205 // const, because the ArrayView doesn't own the array. (To prevent mutation, | |
| 206 // use a const element type.) | |
| 207 T& operator[](size_t idx) const { | |
| 208 RTC_DCHECK_LT(idx, this->size()); | |
| 209 RTC_DCHECK(this->data()); | |
| 210 return this->data()[idx]; | |
| 211 } | |
| 212 T* begin() const { return this->data(); } | |
| 213 T* end() const { return this->data() + this->size(); } | |
| 214 const T* cbegin() const { return this->data(); } | |
| 215 const T* cend() const { return this->data() + this->size(); } | |
| 216 | |
| 217 ArrayView<T> subview(size_t offset, size_t size) const { | |
| 218 return offset < this->size() | |
| 219 ? ArrayView<T>(this->data() + offset, | |
| 220 std::min(size, this->size() - offset)) | |
| 221 : ArrayView<T>(); | |
| 222 } | |
| 223 ArrayView<T> subview(size_t offset) const { | |
| 224 return subview(offset, this->size()); | |
| 225 } | |
| 226 }; | |
| 227 | |
| 228 // Comparing two ArrayViews compares their (pointer,size) pairs; it does *not* | |
| 229 // dereference the pointers. | |
| 230 template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2> | |
| 231 bool operator==(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) { | |
| 232 return a.data() == b.data() && a.size() == b.size(); | |
| 233 } | |
| 234 template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2> | |
| 235 bool operator!=(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) { | |
| 236 return !(a == b); | |
| 237 } | |
| 238 | |
| 239 // Variable-size ArrayViews are the size of two pointers; fixed-size ArrayViews | |
| 240 // are the size of one pointer. (And as a special case, fixed-size ArrayViews | |
| 241 // of size 0 require no storage.) | |
| 242 static_assert(sizeof(ArrayView<int>) == 2 * sizeof(int*), ""); | |
| 243 static_assert(sizeof(ArrayView<int, 17>) == sizeof(int*), ""); | |
| 244 static_assert(std::is_empty<ArrayView<int, 0>>::value, ""); | |
| 245 | |
| 246 template <typename T> | |
| 247 inline ArrayView<T> MakeArrayView(T* data, size_t size) { | |
| 248 return ArrayView<T>(data, size); | |
| 249 } | |
| 250 | |
| 251 } // namespace rtc | |
| 252 | 18 |
| 253 #endif // WEBRTC_BASE_ARRAY_VIEW_H_ | 19 #endif // WEBRTC_BASE_ARRAY_VIEW_H_ |
| OLD | NEW |