Line data Source code
1 : /*
2 : * Copyright 2015 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 WEBRTC_BASE_ARRAY_VIEW_H_
12 : #define WEBRTC_BASE_ARRAY_VIEW_H_
13 :
14 : #include "webrtc/base/checks.h"
15 : #include "webrtc/base/type_traits.h"
16 :
17 : namespace rtc {
18 :
19 : // Many functions read from or write to arrays. The obvious way to do this is
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[0], 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 : // 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,
65 : // 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
67 : // int>, but const vector<int> will convert only to ArrayView<const int>.
68 : // (ArrayView itself can be the source type in such conversions, so
69 : // ArrayView<int> will convert to ArrayView<const int>.)
70 : //
71 : // Note: ArrayView is tiny (just a pointer and a count) and trivially copyable,
72 : // so it's probably cheaper to pass it by value than by const reference.
73 : template <typename T>
74 : class ArrayView final {
75 : public:
76 : using value_type = T;
77 : using const_iterator = const T*;
78 :
79 : // Construct an empty ArrayView.
80 0 : ArrayView() : ArrayView(static_cast<T*>(nullptr), 0) {}
81 0 : ArrayView(std::nullptr_t) : ArrayView() {}
82 :
83 : // Construct an ArrayView for a (pointer,size) pair.
84 : template <typename U>
85 0 : ArrayView(U* data, size_t size)
86 0 : : data_(size == 0 ? nullptr : data), size_(size) {
87 0 : CheckInvariant();
88 0 : }
89 :
90 : // Construct an ArrayView for an array.
91 : template <typename U, size_t N>
92 0 : ArrayView(U (&array)[N]) : ArrayView(&array[0], N) {}
93 :
94 : // Construct an ArrayView for any type U that has a size() method whose
95 : // return value converts implicitly to size_t, and a data() method whose
96 : // return value converts implicitly to T*. In particular, this means we allow
97 : // conversion from ArrayView<T> to ArrayView<const T>, but not the other way
98 : // around. Other allowed conversions include std::vector<T> to ArrayView<T>
99 : // or ArrayView<const T>, const std::vector<T> to ArrayView<const T>, and
100 : // rtc::Buffer to ArrayView<uint8_t> (with the same const behavior as
101 : // std::vector).
102 : template <
103 : typename U,
104 : typename std::enable_if<HasDataAndSize<U, T>::value>::type* = nullptr>
105 0 : ArrayView(U& u) : ArrayView(u.data(), u.size()) {}
106 :
107 : // Indexing, size, and iteration. These allow mutation even if the ArrayView
108 : // is const, because the ArrayView doesn't own the array. (To prevent
109 : // mutation, use ArrayView<const T>.)
110 0 : size_t size() const { return size_; }
111 0 : bool empty() const { return size_ == 0; }
112 0 : T* data() const { return data_; }
113 0 : T& operator[](size_t idx) const {
114 0 : RTC_DCHECK_LT(idx, size_);
115 0 : RTC_DCHECK(data_); // Follows from size_ > idx and the class invariant.
116 0 : return data_[idx];
117 : }
118 0 : T* begin() const { return data_; }
119 0 : T* end() const { return data_ + size_; }
120 0 : const T* cbegin() const { return data_; }
121 0 : const T* cend() const { return data_ + size_; }
122 :
123 : ArrayView subview(size_t offset, size_t size) const {
124 : if (offset >= size_)
125 : return ArrayView();
126 : return ArrayView(data_ + offset, std::min(size, size_ - offset));
127 : }
128 : ArrayView subview(size_t offset) const { return subview(offset, size_); }
129 :
130 : // Comparing two ArrayViews compares their (pointer,size) pairs; it does
131 : // *not* dereference the pointers.
132 : friend bool operator==(const ArrayView& a, const ArrayView& b) {
133 : return a.data_ == b.data_ && a.size_ == b.size_;
134 : }
135 : friend bool operator!=(const ArrayView& a, const ArrayView& b) {
136 : return !(a == b);
137 : }
138 :
139 : private:
140 : // Invariant: !data_ iff size_ == 0.
141 0 : void CheckInvariant() const { RTC_DCHECK_EQ(!data_, size_ == 0); }
142 : T* data_;
143 : size_t size_;
144 : };
145 :
146 : template <typename T>
147 0 : inline ArrayView<T> MakeArrayView(T* data, size_t size) {
148 0 : return ArrayView<T>(data, size);
149 : }
150 :
151 : } // namespace rtc
152 :
153 : #endif // WEBRTC_BASE_ARRAY_VIEW_H_
|