1 /**
2 * Copyright (c) 2021-2024 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 ark {
25
26 /// Similar to std::span that will come in C++20.
27 template <class T>
28 class Span {
29 public:
30 using ElementType = T;
31 // NOLINTNEXTLINE(readability-identifier-naming)
32 using value_type = std::remove_cv_t<T>;
33 using ValueType = value_type;
34 using Reference = T &;
35 using ConstReference = const T &;
36 using Iterator = T *;
37 using ConstIterator = const T *;
38 using ReverseIterator = std::reverse_iterator<Iterator>;
39 using ConstReverseIterator = std::reverse_iterator<ConstIterator>;
40
41 Span() = default;
Span(Iterator data,size_t size)42 Span(Iterator data, size_t size) : data_(data), size_(size) {}
43 constexpr Span(const Span &other) noexcept = default;
44 Span(Span &&other) noexcept = default;
45 ~Span() = default;
46
47 // The following constructor is non-explicit to be aligned with std::span
48 template <class U, size_t N>
49 // NOLINTNEXTLINE(google-explicit-constructor,modernize-avoid-c-arrays)
Span(U (& array)[N])50 constexpr Span(U (&array)[N]) : Span(array, N)
51 {
52 }
53
Span(Iterator begin,Iterator end)54 Span(Iterator begin, Iterator end) : Span(begin, end - begin) {}
55
56 template <class Vector>
Span(Vector & v)57 explicit Span(Vector &v) : Span(v.data(), v.size())
58 {
59 }
60
61 template <class Vector>
Span(const Vector & v)62 explicit Span(const Vector &v) : Span(v.data(), v.size())
63 {
64 }
65
66 constexpr Span &operator=(const Span &other) noexcept = default;
67 Span &operator=(Span &&other) noexcept = default;
68 // NOLINTNEXTLINE(readability-identifier-naming)
begin()69 Iterator begin()
70 {
71 return data_;
72 }
73 // NOLINTNEXTLINE(readability-identifier-naming)
begin()74 ConstIterator begin() const
75 {
76 return data_;
77 }
78 // NOLINTNEXTLINE(readability-identifier-naming)
cbegin()79 ConstIterator cbegin() const
80 {
81 return data_;
82 }
83 // NOLINTNEXTLINE(readability-identifier-naming)
end()84 Iterator end()
85 {
86 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
87 }
88 // NOLINTNEXTLINE(readability-identifier-naming)
end()89 ConstIterator end() const
90 {
91 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
92 }
93 // NOLINTNEXTLINE(readability-identifier-naming)
cend()94 ConstIterator cend() const
95 {
96 return data_ + size_; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
97 }
98 // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()99 ReverseIterator rbegin()
100 {
101 return ReverseIterator(end());
102 }
103 // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()104 ConstReverseIterator rbegin() const
105 {
106 return ConstReverseIterator(end());
107 }
108 // NOLINTNEXTLINE(readability-identifier-naming)
crbegin()109 ConstReverseIterator crbegin() const
110 {
111 return ConstReverseIterator(cend());
112 }
113 // NOLINTNEXTLINE(readability-identifier-naming)
rend()114 ReverseIterator rend()
115 {
116 return ReverseIterator(begin());
117 }
118 // NOLINTNEXTLINE(readability-identifier-naming)
rend()119 ConstReverseIterator rend() const
120 {
121 return ConstReverseIterator(begin());
122 }
123 // NOLINTNEXTLINE(readability-identifier-naming)
crend()124 ConstReverseIterator crend() const
125 {
126 return ConstReverseIterator(cbegin());
127 }
128
129 // NOLINT(readability-identifier-naming)
130 Reference operator[](size_t index)
131 {
132 ASSERT(index < size_);
133 return data_[index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
134 }
135
136 // NOLINT(readability-identifier-naming)
137 ConstReference operator[](size_t index) const
138 {
139 ASSERT(index < size_);
140 return data_[index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
141 }
142
Size()143 constexpr size_t Size() const
144 {
145 return size_;
146 }
SizeBytes()147 constexpr size_t SizeBytes() const
148 {
149 return size_ * sizeof(ElementType);
150 }
Empty()151 constexpr bool Empty() const
152 {
153 return size_ == 0U;
154 }
155
Data()156 Iterator Data()
157 {
158 return data_;
159 }
Data()160 ConstIterator Data() const
161 {
162 return data_;
163 }
164
First(size_t length)165 Span First(size_t length) const
166 {
167 ASSERT(length <= size_);
168 return SubSpan(0, length);
169 }
170
Last(size_t length)171 Span Last(size_t length) const
172 {
173 ASSERT(length <= size_);
174 return SubSpan(size_ - length, length);
175 }
176
SubSpan(size_t position,size_t length)177 Span SubSpan(size_t position, size_t length) const
178 {
179 ASSERT((position + length) <= size_);
180 return Span(data_ + position, length); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
181 }
182
SubSpan(size_t position)183 Span SubSpan(size_t position) const
184 {
185 ASSERT(position <= size_);
186 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
187 return Span(data_ + position, size_ - position);
188 }
189
190 template <typename SubT>
SubSpan(size_t position,size_t length)191 Span<SubT> SubSpan(size_t position, size_t length) const
192 {
193 ASSERT((position * sizeof(T) + length * sizeof(SubT)) <= (size_ * sizeof(T)));
194 ASSERT(((reinterpret_cast<uintptr_t>(data_ + position)) % alignof(SubT)) == 0);
195 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
196 return Span<SubT>(reinterpret_cast<SubT *>(data_ + position), length);
197 }
198
ToConst()199 auto ToConst() const
200 {
201 return Span<const std::remove_const_t<T>>(data_, size_);
202 }
203
204 // Methods for compatibility with std containers
205 // NOLINTNEXTLINE(readability-identifier-naming)
size()206 size_t size() const
207 {
208 return size_;
209 }
210 // NOLINTNEXTLINE(readability-identifier-naming)
empty()211 bool empty() const
212 {
213 return size() == 0;
214 }
215 // NOLINTNEXTLINE(readability-identifier-naming)
data()216 Iterator data()
217 {
218 return data_;
219 }
220 // NOLINTNEXTLINE(readability-identifier-naming)
data()221 ConstIterator data() const
222 {
223 return data_;
224 }
GetDataOffset()225 static constexpr uint32_t GetDataOffset()
226 {
227 return MEMBER_OFFSET(Span<T>, data_);
228 }
GetSizeOffset()229 static constexpr uint32_t GetSizeOffset()
230 {
231 return MEMBER_OFFSET(Span<T>, size_);
232 }
233
234 private:
235 Iterator data_ {nullptr};
236 size_t size_ {0};
237 };
238
239 // Deduction guides
240 template <class U, size_t N>
241 Span(U (&)[N]) -> Span<U>; // NOLINT(modernize-avoid-c-arrays)
242
243 template <class Vector>
244 Span(Vector &) -> Span<typename Vector::value_type>;
245
246 template <class Vector>
247 Span(const Vector &) -> Span<const typename Vector::value_type>;
248
249 // Non-member functions
250 template <class T>
AsBytes(Span<T> s)251 Span<const std::byte> AsBytes(Span<T> s) noexcept
252 {
253 return {reinterpret_cast<const std::byte *>(s.Data()), s.SizeBytes()};
254 }
255 template <class T, typename = std::enable_if_t<!std::is_const_v<T>>>
AsWritableBytes(Span<T> s)256 Span<std::byte> AsWritableBytes(Span<T> s) noexcept
257 {
258 return {reinterpret_cast<std::byte *>(s.Data()), s.SizeBytes()};
259 }
260
261 } // namespace ark
262 #endif // LIBPANDABASE_UTILS_SPAN_H_
263