1 /**
2 * Copyright (c) 2021-2025 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(data_ != nullptr);
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 ark
263 #endif // LIBPANDABASE_UTILS_SPAN_H_
264