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