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 |
(...skipping 13 matching lines...) Expand all Loading... |
24 // if (arr[i] == 17) | 24 // if (arr[i] == 17) |
25 // return true; | 25 // return true; |
26 // } | 26 // } |
27 // return false; | 27 // return false; |
28 // } | 28 // } |
29 // | 29 // |
30 // This is flexible, since it doesn't matter how the array is stored (C array, | 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 | 31 // std::vector, rtc::Buffer, ...), but it's error-prone because the caller has |
32 // to correctly specify the array length: | 32 // to correctly specify the array length: |
33 // | 33 // |
34 // Contains17(arr, arraysize(arr)); // C array | 34 // Contains17(arr, arraysize(arr)); // C array |
35 // Contains17(&arr[0], arr.size()); // std::vector | 35 // Contains17(arr.data(), arr.size()); // std::vector |
36 // Contains17(arr, size); // pointer + size | 36 // Contains17(arr, size); // pointer + size |
37 // ... | 37 // ... |
38 // | 38 // |
39 // It's also kind of messy to have two separate arguments for what is | 39 // It's also kind of messy to have two separate arguments for what is |
40 // conceptually a single thing. | 40 // conceptually a single thing. |
41 // | 41 // |
42 // Enter rtc::ArrayView<T>. It contains a T pointer (to an array it doesn't | 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 | 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: | 44 // indexing and iteration. It allows us to write our function like this: |
45 // | 45 // |
46 // bool Contains17(rtc::ArrayView<const int> arr) { | 46 // bool Contains17(rtc::ArrayView<const int> arr) { |
47 // for (auto e : arr) { | 47 // for (auto e : arr) { |
48 // if (e == 17) | 48 // if (e == 17) |
49 // return true; | 49 // return true; |
50 // } | 50 // } |
51 // return false; | 51 // return false; |
52 // } | 52 // } |
53 // | 53 // |
54 // And even better, because a bunch of things will implicitly convert to | 54 // And even better, because a bunch of things will implicitly convert to |
55 // ArrayView, we can call it like this: | 55 // ArrayView, we can call it like this: |
56 // | 56 // |
57 // Contains17(arr); // C array | 57 // Contains17(arr); // C array |
58 // Contains17(arr); // std::vector | 58 // Contains17(arr); // std::vector |
59 // Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size | 59 // Contains17(rtc::ArrayView<int>(arr, size)); // pointer + size |
60 // Contains17(nullptr); // nullptr -> empty ArrayView | 60 // Contains17(nullptr); // nullptr -> empty ArrayView |
61 // ... | 61 // ... |
62 // | 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 // |
63 // One important point is that ArrayView<T> and ArrayView<const T> are | 67 // One important point is that ArrayView<T> and ArrayView<const T> are |
64 // different types, which allow and don't allow mutation of the array elements, | 68 // different types, which allow and don't allow mutation of the array elements, |
65 // respectively. The implicit conversions work just like you'd hope, so that | 69 // respectively. The implicit conversions work just like you'd hope, so that |
66 // e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const | 70 // e.g. vector<int> will convert to either ArrayView<int> or ArrayView<const |
67 // int>, but const vector<int> will convert only to ArrayView<const int>. | 71 // int>, but const vector<int> will convert only to ArrayView<const int>. |
68 // (ArrayView itself can be the source type in such conversions, so | 72 // (ArrayView itself can be the source type in such conversions, so |
69 // ArrayView<int> will convert to ArrayView<const int>.) | 73 // ArrayView<int> will convert to ArrayView<const int>.) |
70 // | 74 // |
71 // Note: ArrayView is tiny (just a pointer and a count) and trivially copyable, | 75 // Note: ArrayView is tiny (just a pointer and a count if variable-sized, just |
72 // so it's probably cheaper to pass it by value than by const reference. | 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. |
73 template <typename T> | 105 template <typename T> |
74 class ArrayView final { | 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> { |
75 public: | 141 public: |
76 using value_type = T; | 142 using value_type = T; |
77 using const_iterator = const T*; | 143 using const_iterator = const T*; |
78 | 144 |
79 // Construct an empty ArrayView. | 145 // Construct an ArrayView from a pointer and a length. |
80 ArrayView() : ArrayView(static_cast<T*>(nullptr), 0) {} | |
81 ArrayView(std::nullptr_t) : ArrayView() {} | |
82 | |
83 // Construct an ArrayView for a (pointer,size) pair. | |
84 template <typename U> | 146 template <typename U> |
85 ArrayView(U* data, size_t size) | 147 ArrayView(U* data, size_t size) |
86 : data_(size == 0 ? nullptr : data), size_(size) { | 148 : impl::ArrayViewBase<T, Size>::ArrayViewBase(data, size) { |
87 CheckInvariant(); | 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. |
88 } | 153 } |
89 | 154 |
90 // Construct an ArrayView for an array. | 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. |
91 template <typename U, size_t N> | 166 template <typename U, size_t N> |
92 ArrayView(U (&array)[N]) : ArrayView(&array[0], 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 } |
93 | 171 |
94 // Construct an ArrayView for any type U that has a size() method whose | 172 // (Only if size is fixed.) Construct an ArrayView from any type U that has a |
95 // return value converts implicitly to size_t, and a data() method whose | 173 // static constexpr size() method whose return value is equal to Size, and a |
96 // return value converts implicitly to T*. In particular, this means we allow | 174 // data() method whose return value converts implicitly to T*. In particular, |
97 // conversion from ArrayView<T> to ArrayView<const T>, but not the other way | 175 // this means we allow conversion from ArrayView<T, N> to ArrayView<const T, |
98 // around. Other allowed conversions include std::vector<T> to ArrayView<T> | 176 // N>, but not the other way around. We also don't allow conversion from |
99 // or ArrayView<const T>, const std::vector<T> to ArrayView<const T>, and | 177 // ArrayView<T> to ArrayView<T, N>, or from ArrayView<T, M> to ArrayView<T, |
100 // rtc::Buffer to ArrayView<uint8_t> (with the same const behavior as | 178 // N> when M != N. |
101 // std::vector). | 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>. |
102 template < | 198 template < |
103 typename U, | 199 typename U, |
104 typename std::enable_if<HasDataAndSize<U, T>::value>::type* = nullptr> | 200 typename std::enable_if<Size == impl::kArrayViewVarSize && |
| 201 HasDataAndSize<U, T>::value>::type* = nullptr> |
105 ArrayView(U& u) : ArrayView(u.data(), u.size()) {} | 202 ArrayView(U& u) : ArrayView(u.data(), u.size()) {} |
106 | 203 |
107 // Indexing, size, and iteration. These allow mutation even if the ArrayView | 204 // Indexing and iteration. These allow mutation even if the ArrayView is |
108 // is const, because the ArrayView doesn't own the array. (To prevent | 205 // const, because the ArrayView doesn't own the array. (To prevent mutation, |
109 // mutation, use ArrayView<const T>.) | 206 // use a const element type.) |
110 size_t size() const { return size_; } | |
111 bool empty() const { return size_ == 0; } | |
112 T* data() const { return data_; } | |
113 T& operator[](size_t idx) const { | 207 T& operator[](size_t idx) const { |
114 RTC_DCHECK_LT(idx, size_); | 208 RTC_DCHECK_LT(idx, this->size()); |
115 RTC_DCHECK(data_); // Follows from size_ > idx and the class invariant. | 209 RTC_DCHECK(this->data()); |
116 return data_[idx]; | 210 return this->data()[idx]; |
117 } | 211 } |
118 T* begin() const { return data_; } | 212 T* begin() const { return this->data(); } |
119 T* end() const { return data_ + size_; } | 213 T* end() const { return this->data() + this->size(); } |
120 const T* cbegin() const { return data_; } | 214 const T* cbegin() const { return this->data(); } |
121 const T* cend() const { return data_ + size_; } | 215 const T* cend() const { return this->data() + this->size(); } |
122 | 216 |
123 ArrayView subview(size_t offset, size_t size) const { | 217 ArrayView<T> subview(size_t offset, size_t size) const { |
124 if (offset >= size_) | 218 return offset < this->size() |
125 return ArrayView(); | 219 ? ArrayView<T>(this->data() + offset, |
126 return ArrayView(data_ + offset, std::min(size, size_ - offset)); | 220 std::min(size, this->size() - offset)) |
| 221 : ArrayView<T>(); |
127 } | 222 } |
128 ArrayView subview(size_t offset) const { return subview(offset, size_); } | 223 ArrayView<T> subview(size_t offset) const { |
| 224 return subview(offset, this->size()); |
| 225 } |
| 226 }; |
129 | 227 |
130 // Comparing two ArrayViews compares their (pointer,size) pairs; it does | 228 // Comparing two ArrayViews compares their (pointer,size) pairs; it does *not* |
131 // *not* dereference the pointers. | 229 // dereference the pointers. |
132 friend bool operator==(const ArrayView& a, const ArrayView& b) { | 230 template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2> |
133 return a.data_ == b.data_ && a.size_ == b.size_; | 231 bool operator==(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) { |
134 } | 232 return a.data() == b.data() && a.size() == b.size(); |
135 friend bool operator!=(const ArrayView& a, const ArrayView& b) { | 233 } |
136 return !(a == b); | 234 template <typename T, std::ptrdiff_t Size1, std::ptrdiff_t Size2> |
137 } | 235 bool operator!=(const ArrayView<T, Size1>& a, const ArrayView<T, Size2>& b) { |
| 236 return !(a == b); |
| 237 } |
138 | 238 |
139 private: | 239 // Variable-size ArrayViews are the size of two pointers; fixed-size ArrayViews |
140 // Invariant: !data_ iff size_ == 0. | 240 // are the size of one pointer. (And as a special case, fixed-size ArrayViews |
141 void CheckInvariant() const { RTC_DCHECK_EQ(!data_, size_ == 0); } | 241 // of size 0 require no storage.) |
142 T* data_; | 242 static_assert(sizeof(ArrayView<int>) == 2 * sizeof(int*), ""); |
143 size_t size_; | 243 static_assert(sizeof(ArrayView<int, 17>) == sizeof(int*), ""); |
144 }; | 244 static_assert(std::is_empty<ArrayView<int, 0>>::value, ""); |
145 | 245 |
146 template <typename T> | 246 template <typename T> |
147 inline ArrayView<T> MakeArrayView(T* data, size_t size) { | 247 inline ArrayView<T> MakeArrayView(T* data, size_t size) { |
148 return ArrayView<T>(data, size); | 248 return ArrayView<T>(data, size); |
149 } | 249 } |
150 | 250 |
151 } // namespace rtc | 251 } // namespace rtc |
152 | 252 |
153 #endif // WEBRTC_BASE_ARRAY_VIEW_H_ | 253 #endif // WEBRTC_BASE_ARRAY_VIEW_H_ |
OLD | NEW |