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