1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef PANDA_LIBPANDABASE_UTILS_SPAN_H_
17 #define PANDA_LIBPANDABASE_UTILS_SPAN_H_
18
19 #include "macros.h"
20
21 #include <cstddef>
22 #include <iterator>
23
24 namespace panda {
25
26 /**
27 * Similar to std::span that will come in C++20.
28 */
29 template <class T>
30 class Span {
31 public:
32 using ElementType = T;
33 using value_type = std::remove_cv_t<T>;
34 using ValueType = value_type;
35 using Reference = T &;
36 using ConstReference = const T &;
37 using Iterator = T *;
38 using ConstIterator = const T *;
39 using ReverseIterator = std::reverse_iterator<Iterator>;
40 using ConstReverseIterator = std::reverse_iterator<ConstIterator>;
41
42 Span() = default;
Span(Iterator data,size_t size)43 Span(Iterator data, size_t size) : data_(data), size_(size) {}
44 constexpr Span(const Span &other) noexcept = default;
45 Span(Span &&other) noexcept = default;
46 ~Span() = default;
47
48 // The following constructor is non-explicit to be aligned with std::span
49 template <class U, size_t N>
50 // NOLINTNEXTLINE(google-explicit-constructor,modernize-avoid-c-arrays)
Span(U (& array)[N])51 constexpr Span(U (&array)[N]) : Span(array, N)
52 {
53 }
54
Span(Iterator begin,Iterator end)55 Span(Iterator begin, Iterator end) : Span(begin, end - begin) {}
56
57 template <class Vector>
Span(Vector & v)58 explicit Span(Vector &v) : Span(v.data(), v.size())
59 {
60 }
61
62 template <class Vector>
Span(const Vector & v)63 explicit Span(const Vector &v) : Span(v.data(), v.size())
64 {
65 }
66
67 constexpr Span &operator=(const Span &other) noexcept = default;
68 Span &operator=(Span &&other) noexcept = default;
69
70 // NOLINTNEXTLINE(readability-identifier-naming)
begin()71 Iterator begin()
72 {
73 return data_;
74 }
75
76 // NOLINTNEXTLINE(readability-identifier-naming)
begin()77 ConstIterator begin() const
78 {
79 return data_;
80 }
81
82 // NOLINTNEXTLINE(readability-identifier-naming)
cbegin()83 ConstIterator cbegin() const
84 {
85 return data_;
86 }
87
88 // NOLINTNEXTLINE(readability-identifier-naming)
end()89 Iterator end()
90 {
91 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
92 }
93
94 // NOLINTNEXTLINE(readability-identifier-naming)
end()95 ConstIterator end() const
96 {
97 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
98 }
99
100 // NOLINTNEXTLINE(readability-identifier-naming)
cend()101 ConstIterator cend() const
102 {
103 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
104 }
105
106 // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()107 ReverseIterator rbegin()
108 {
109 return ReverseIterator(end());
110 }
111
112 // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()113 ConstReverseIterator rbegin() const
114 {
115 return ConstReverseIterator(end());
116 }
117
118 // NOLINTNEXTLINE(readability-identifier-naming)
crbegin()119 ConstReverseIterator crbegin() const
120 {
121 return ConstReverseIterator(cend());
122 }
123
124 // NOLINTNEXTLINE(readability-identifier-naming)
rend()125 ReverseIterator rend()
126 {
127 return ReverseIterator(begin());
128 }
129
130 // NOLINTNEXTLINE(readability-identifier-naming)
rend()131 ConstReverseIterator rend() const
132 {
133 return ConstReverseIterator(begin());
134 }
135
136 // NOLINTNEXTLINE(readability-identifier-naming)
crend()137 ConstReverseIterator crend() const
138 {
139 return ConstReverseIterator(cbegin());
140 }
141
142 // NOLINT(readability-identifier-naming)
143 Reference operator[](size_t index)
144 {
145 ASSERT(index < size_);
146 return data_[index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
147 }
148
149 // NOLINT(readability-identifier-naming)
150 ConstReference operator[](size_t index) const
151 {
152 ASSERT(index < size_);
153 return data_[index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
154 }
155
Size()156 constexpr size_t Size() const
157 {
158 return size_;
159 }
160
SizeBytes()161 constexpr size_t SizeBytes() const
162 {
163 return size_ * sizeof(ElementType);
164 }
165
Empty()166 constexpr bool Empty() const
167 {
168 return size_ == 0U;
169 }
170
Data()171 Iterator Data()
172 {
173 return data_;
174 }
175
Data()176 ConstIterator Data() const
177 {
178 return data_;
179 }
180
First(size_t length)181 Span First(size_t length) const
182 {
183 ASSERT(length <= size_);
184 return SubSpan(0, length);
185 }
186
Last(size_t length)187 Span Last(size_t length) const
188 {
189 ASSERT(length <= size_);
190 return SubSpan(size_ - length, length);
191 }
192
SubSpan(size_t position,size_t length)193 Span SubSpan(size_t position, size_t length) const
194 {
195 ASSERT((position + length) <= size_);
196 return Span(data_ + position, length); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
197 }
198
SubSpan(size_t position)199 Span SubSpan(size_t position) const
200 {
201 ASSERT(position <= size_);
202 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
203 return Span(data_ + position, size_ - position);
204 }
205
206 template <typename SubT>
SubSpan(size_t position,size_t length)207 Span<SubT> SubSpan(size_t position, size_t length) const
208 {
209 ASSERT((position * sizeof(T) + length * sizeof(SubT)) <= (size_ * sizeof(T)));
210 ASSERT(((reinterpret_cast<uintptr_t>(data_ + position)) % alignof(SubT)) == 0);
211 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
212 return Span<SubT>(reinterpret_cast<SubT *>(data_ + position), length);
213 }
214
ToConst()215 auto ToConst() const
216 {
217 return Span<const std::remove_const_t<T>>(data_, size_);
218 }
219
220 // Methods for compatibility with std containers
221 // NOLINTNEXTLINE(readability-identifier-naming)
size()222 size_t size() const
223 {
224 return size_;
225 }
226
227 // NOLINTNEXTLINE(readability-identifier-naming)
empty()228 size_t empty() const
229 {
230 return size() == 0;
231 }
232
233 // NOLINTNEXTLINE(readability-identifier-naming)
data()234 Iterator data()
235 {
236 return data_;
237 }
238
239 // NOLINTNEXTLINE(readability-identifier-naming)
data()240 ConstIterator data() const
241 {
242 return data_;
243 }
244
245 private:
246 Iterator data_ {nullptr};
247 size_t size_ {0};
248 };
249
250 // Deduction guides
251 template <class U, size_t N>
252 Span(U (&)[N])->Span<U>; // NOLINT(modernize-avoid-c-arrays)
253
254 template <class Vector>
255 Span(Vector &)->Span<typename Vector::value_type>;
256
257 template <class Vector>
258 Span(const Vector &)->Span<const typename Vector::value_type>;
259
260 // Non-member functions
261 template <class T>
AsBytes(Span<T> s)262 Span<const std::byte> AsBytes(Span<T> s) noexcept
263 {
264 return {reinterpret_cast<const std::byte *>(s.Data()), s.SizeBytes()};
265 }
266
267 template <class T, typename = std::enable_if_t<!std::is_const_v<T>>>
AsWritableBytes(Span<T> s)268 Span<std::byte> AsWritableBytes(Span<T> s) noexcept
269 {
270 return {reinterpret_cast<std::byte *>(s.Data()), s.SizeBytes()};
271 }
272
273 } // namespace panda
274
275 #endif // PANDA_LIBPANDABASE_UTILS_SPAN_H_
276