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(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() const74     ConstIterator begin() const
75     {
76         return data_;
77     }
78     // NOLINTNEXTLINE(readability-identifier-naming)
cbegin() const79     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() const89     ConstIterator end() const
90     {
91         return data_ + size_;  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
92     }
93     // NOLINTNEXTLINE(readability-identifier-naming)
cend() const94     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() const104     ConstReverseIterator rbegin() const
105     {
106         return ConstReverseIterator(end());
107     }
108     // NOLINTNEXTLINE(readability-identifier-naming)
crbegin() const109     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() const119     ConstReverseIterator rend() const
120     {
121         return ConstReverseIterator(begin());
122     }
123     // NOLINTNEXTLINE(readability-identifier-naming)
crend() const124     ConstReverseIterator crend() const
125     {
126         return ConstReverseIterator(cbegin());
127     }
128 
129     // NOLINT(readability-identifier-naming)
operator [](size_t index)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 
143     constexpr size_t Size() const
144     {
145         return size_;
146     }
147     constexpr size_t SizeBytes() const
148     {
149         return size_ * sizeof(ElementType);
150     }
151     constexpr bool Empty() const
152     {
153         return size_ == 0U;
154     }
155 
156     Iterator Data()
157     {
158         return data_;
159     }
160     ConstIterator Data() const
161     {
162         return data_;
163     }
164 
165     Span First(size_t length) const
166     {
167         ASSERT(length <= size_);
168         return SubSpan(0, length);
169     }
170 
171     Span Last(size_t length) const
172     {
173         ASSERT(length <= size_);
174         return SubSpan(size_ - length, length);
175     }
176 
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 
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>
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 
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)
206     size_t size() const
207     {
208         return size_;
209     }
210     // NOLINTNEXTLINE(readability-identifier-naming)
211     bool empty() const
212     {
213         return size() == 0;
214     }
215     // NOLINTNEXTLINE(readability-identifier-naming)
216     Iterator data()
217     {
218         return data_;
219     }
220     // NOLINTNEXTLINE(readability-identifier-naming)
221     ConstIterator data() const
222     {
223         return data_;
224     }
225     static constexpr uint32_t GetDataOffset()
226     {
227         return MEMBER_OFFSET(Span<T>, data_);
228     }
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>
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>>>
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