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 |