1 /**
2 * Copyright (c) 2021-2022 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 LIBPANDABASE_UTILS_SPAN_H
17 #define 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 // NOLINTNEXTLINE(readability-identifier-naming)
begin()70 Iterator begin()
71 {
72 return data_;
73 }
74 // NOLINTNEXTLINE(readability-identifier-naming)
begin()75 ConstIterator begin() const
76 {
77 return data_;
78 }
79 // NOLINTNEXTLINE(readability-identifier-naming)
cbegin()80 ConstIterator cbegin() const
81 {
82 return data_;
83 }
84 // NOLINTNEXTLINE(readability-identifier-naming)
end()85 Iterator end()
86 {
87 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
88 }
89 // NOLINTNEXTLINE(readability-identifier-naming)
end()90 ConstIterator end() const
91 {
92 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
93 }
94 // NOLINTNEXTLINE(readability-identifier-naming)
cend()95 ConstIterator cend() const
96 {
97 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
98 }
99 // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()100 ReverseIterator rbegin()
101 {
102 return ReverseIterator(end());
103 }
104 // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()105 ConstReverseIterator rbegin() const
106 {
107 return ConstReverseIterator(end());
108 }
109 // NOLINTNEXTLINE(readability-identifier-naming)
crbegin()110 ConstReverseIterator crbegin() const
111 {
112 return ConstReverseIterator(cend());
113 }
114 // NOLINTNEXTLINE(readability-identifier-naming)
rend()115 ReverseIterator rend()
116 {
117 return ReverseIterator(begin());
118 }
119 // NOLINTNEXTLINE(readability-identifier-naming)
rend()120 ConstReverseIterator rend() const
121 {
122 return ConstReverseIterator(begin());
123 }
124 // NOLINTNEXTLINE(readability-identifier-naming)
crend()125 ConstReverseIterator crend() const
126 {
127 return ConstReverseIterator(cbegin());
128 }
129
130 // NOLINT(readability-identifier-naming)
131 Reference operator[](size_t index)
132 {
133 ASSERT(index < size_);
134 return data_[index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
135 }
136
137 // NOLINT(readability-identifier-naming)
138 ConstReference operator[](size_t index) const
139 {
140 ASSERT(index < size_);
141 return data_[index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
142 }
143
Size()144 constexpr size_t Size() const
145 {
146 return size_;
147 }
SizeBytes()148 constexpr size_t SizeBytes() const
149 {
150 return size_ * sizeof(ElementType);
151 }
Empty()152 constexpr bool Empty() const
153 {
154 return size_ == 0U;
155 }
156
Data()157 Iterator Data()
158 {
159 return data_;
160 }
Data()161 ConstIterator Data() const
162 {
163 return data_;
164 }
165
First(size_t length)166 Span First(size_t length) const
167 {
168 ASSERT(length <= size_);
169 return SubSpan(0, length);
170 }
171
Last(size_t length)172 Span Last(size_t length) const
173 {
174 ASSERT(length <= size_);
175 return SubSpan(size_ - length, length);
176 }
177
SubSpan(size_t position,size_t length)178 Span SubSpan(size_t position, size_t length) const
179 {
180 ASSERT((position + length) <= size_);
181 return Span(data_ + position, length); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
182 }
183
SubSpan(size_t position)184 Span SubSpan(size_t position) const
185 {
186 ASSERT(position <= size_);
187 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
188 return Span(data_ + position, size_ - position);
189 }
190
191 template <typename SubT>
SubSpan(size_t position,size_t length)192 Span<SubT> SubSpan(size_t position, size_t length) const
193 {
194 ASSERT((position * sizeof(T) + length * sizeof(SubT)) <= (size_ * sizeof(T)));
195 ASSERT(((reinterpret_cast<uintptr_t>(data_ + position)) % alignof(SubT)) == 0);
196 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
197 return Span<SubT>(reinterpret_cast<SubT *>(data_ + position), length);
198 }
199
ToConst()200 auto ToConst() const
201 {
202 return Span<const std::remove_const_t<T>>(data_, size_);
203 }
204
205 // Methods for compatibility with std containers
206 // NOLINTNEXTLINE(readability-identifier-naming)
size()207 size_t size() const
208 {
209 return size_;
210 }
211 // NOLINTNEXTLINE(readability-identifier-naming)
empty()212 bool empty() const
213 {
214 return size() == 0;
215 }
216 // NOLINTNEXTLINE(readability-identifier-naming)
data()217 Iterator data()
218 {
219 return data_;
220 }
221 // NOLINTNEXTLINE(readability-identifier-naming)
data()222 ConstIterator data() const
223 {
224 return data_;
225 }
GetDataOffset()226 static constexpr uint32_t GetDataOffset()
227 {
228 return MEMBER_OFFSET(Span<T>, data_);
229 }
GetSizeOffset()230 static constexpr uint32_t GetSizeOffset()
231 {
232 return MEMBER_OFFSET(Span<T>, size_);
233 }
234
235 private:
236 Iterator data_ {nullptr};
237 size_t size_ {0};
238 };
239
240 // Deduction guides
241 template <class U, size_t N>
242 Span(U (&)[N])->Span<U>; // NOLINT(modernize-avoid-c-arrays)
243
244 template <class Vector>
245 Span(Vector &)->Span<typename Vector::value_type>;
246
247 template <class Vector>
248 Span(const Vector &)->Span<const typename Vector::value_type>;
249
250 // Non-member functions
251 template <class T>
AsBytes(Span<T> s)252 Span<const std::byte> AsBytes(Span<T> s) noexcept
253 {
254 return {reinterpret_cast<const std::byte *>(s.Data()), s.SizeBytes()};
255 }
256 template <class T, typename = std::enable_if_t<!std::is_const_v<T>>>
AsWritableBytes(Span<T> s)257 Span<std::byte> AsWritableBytes(Span<T> s) noexcept
258 {
259 return {reinterpret_cast<std::byte *>(s.Data()), s.SizeBytes()};
260 }
261
262 } // namespace panda
263
264 #endif // LIBPANDABASE_UTILS_SPAN_H
265