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
24namespace panda {
25
26/**
27 * Similar to std::span that will come in C++20.
28 */
29template <class T>
30class Span {
31public:
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;
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)
51    constexpr Span(U (&array)[N]) : Span(array, N)
52    {
53    }
54
55    Span(Iterator begin, Iterator end) : Span(begin, end - begin) {}
56
57    template <class Vector>
58    explicit Span(Vector &v) : Span(v.data(), v.size())
59    {
60    }
61
62    template <class Vector>
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)
70    Iterator begin()
71    {
72        return data_;
73    }
74    // NOLINTNEXTLINE(readability-identifier-naming)
75    ConstIterator begin() const
76    {
77        return data_;
78    }
79    // NOLINTNEXTLINE(readability-identifier-naming)
80    ConstIterator cbegin() const
81    {
82        return data_;
83    }
84    // NOLINTNEXTLINE(readability-identifier-naming)
85    Iterator end()
86    {
87        return data_ + size_;  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
88    }
89    // NOLINTNEXTLINE(readability-identifier-naming)
90    ConstIterator end() const
91    {
92        return data_ + size_;  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
93    }
94    // NOLINTNEXTLINE(readability-identifier-naming)
95    ConstIterator cend() const
96    {
97        return data_ + size_;  // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
98    }
99    // NOLINTNEXTLINE(readability-identifier-naming)
100    ReverseIterator rbegin()
101    {
102        return ReverseIterator(end());
103    }
104    // NOLINTNEXTLINE(readability-identifier-naming)
105    ConstReverseIterator rbegin() const
106    {
107        return ConstReverseIterator(end());
108    }
109    // NOLINTNEXTLINE(readability-identifier-naming)
110    ConstReverseIterator crbegin() const
111    {
112        return ConstReverseIterator(cend());
113    }
114    // NOLINTNEXTLINE(readability-identifier-naming)
115    ReverseIterator rend()
116    {
117        return ReverseIterator(begin());
118    }
119    // NOLINTNEXTLINE(readability-identifier-naming)
120    ConstReverseIterator rend() const
121    {
122        return ConstReverseIterator(begin());
123    }
124    // NOLINTNEXTLINE(readability-identifier-naming)
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
144    constexpr size_t Size() const
145    {
146        return size_;
147    }
148    constexpr size_t SizeBytes() const
149    {
150        return size_ * sizeof(ElementType);
151    }
152    constexpr bool Empty() const
153    {
154        return size_ == 0U;
155    }
156
157    Iterator Data()
158    {
159        return data_;
160    }
161    ConstIterator Data() const
162    {
163        return data_;
164    }
165
166    Span First(size_t length) const
167    {
168        ASSERT(length <= size_);
169        return SubSpan(0, length);
170    }
171
172    Span Last(size_t length) const
173    {
174        ASSERT(length <= size_);
175        return SubSpan(size_ - length, length);
176    }
177
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
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>
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
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)
207    size_t size() const
208    {
209        return size_;
210    }
211    // NOLINTNEXTLINE(readability-identifier-naming)
212    bool empty() const
213    {
214        return size() == 0;
215    }
216    // NOLINTNEXTLINE(readability-identifier-naming)
217    Iterator data()
218    {
219        return data_;
220    }
221    // NOLINTNEXTLINE(readability-identifier-naming)
222    ConstIterator data() const
223    {
224        return data_;
225    }
226    static constexpr uint32_t GetDataOffset()
227    {
228        return MEMBER_OFFSET(Span<T>, data_);
229    }
230    static constexpr uint32_t GetSizeOffset()
231    {
232        return MEMBER_OFFSET(Span<T>, size_);
233    }
234
235private:
236    Iterator data_ {nullptr};
237    size_t size_ {0};
238};
239
240// Deduction guides
241template <class U, size_t N>
242Span(U (&)[N])->Span<U>;  // NOLINT(modernize-avoid-c-arrays)
243
244template <class Vector>
245Span(Vector &)->Span<typename Vector::value_type>;
246
247template <class Vector>
248Span(const Vector &)->Span<const typename Vector::value_type>;
249
250// Non-member functions
251template <class T>
252Span<const std::byte> AsBytes(Span<T> s) noexcept
253{
254    return {reinterpret_cast<const std::byte *>(s.Data()), s.SizeBytes()};
255}
256template <class T, typename = std::enable_if_t<!std::is_const_v<T>>>
257Span<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