1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BASE_SPAN_H_ 6 #define THIRD_PARTY_BASE_SPAN_H_ 7 8 #include <stddef.h> 9 10 #include <algorithm> 11 #include <array> 12 #include <iterator> 13 #include <type_traits> 14 #include <utility> 15 16 #include "core/fxcrt/unowned_ptr.h" 17 #include "third_party/base/logging.h" 18 19 namespace pdfium { 20 21 template <typename T> 22 class span; 23 24 namespace internal { 25 26 template <typename T> 27 struct IsSpanImpl : std::false_type {}; 28 29 template <typename T> 30 struct IsSpanImpl<span<T>> : std::true_type {}; 31 32 template <typename T> 33 using IsSpan = IsSpanImpl<typename std::decay<T>::type>; 34 35 template <typename T> 36 struct IsStdArrayImpl : std::false_type {}; 37 38 template <typename T, size_t N> 39 struct IsStdArrayImpl<std::array<T, N>> : std::true_type {}; 40 41 template <typename T> 42 using IsStdArray = IsStdArrayImpl<typename std::decay<T>::type>; 43 44 template <typename From, typename To> 45 using IsLegalSpanConversion = std::is_convertible<From*, To*>; 46 47 template <typename Container, typename T> 48 using ContainerHasConvertibleData = 49 IsLegalSpanConversion<typename std::remove_pointer<decltype( 50 std::declval<Container>().data())>::type, 51 T>; 52 template <typename Container> 53 using ContainerHasIntegralSize = 54 std::is_integral<decltype(std::declval<Container>().size())>; 55 56 template <typename From, typename To> 57 using EnableIfLegalSpanConversion = 58 typename std::enable_if<IsLegalSpanConversion<From, To>::value>::type; 59 60 // SFINAE check if Container can be converted to a span<T>. Note that the 61 // implementation details of this check differ slightly from the requirements in 62 // the working group proposal: in particular, the proposal also requires that 63 // the container conversion constructor participate in overload resolution only 64 // if two additional conditions are true: 65 // 66 // 1. Container implements operator[]. 67 // 2. Container::value_type matches remove_const_t<element_type>. 68 // 69 // The requirements are relaxed slightly here: in particular, not requiring (2) 70 // means that an immutable span can be easily constructed from a mutable 71 // container. 72 template <typename Container, typename T> 73 using EnableIfSpanCompatibleContainer = 74 typename std::enable_if<!internal::IsSpan<Container>::value && 75 !internal::IsStdArray<Container>::value && 76 ContainerHasConvertibleData<Container, T>::value && 77 ContainerHasIntegralSize<Container>::value>::type; 78 79 template <typename Container, typename T> 80 using EnableIfConstSpanCompatibleContainer = 81 typename std::enable_if<std::is_const<T>::value && 82 !internal::IsSpan<Container>::value && 83 !internal::IsStdArray<Container>::value && 84 ContainerHasConvertibleData<Container, T>::value && 85 ContainerHasIntegralSize<Container>::value>::type; 86 87 } // namespace internal 88 89 // A span is a value type that represents an array of elements of type T. Since 90 // it only consists of a pointer to memory with an associated size, it is very 91 // light-weight. It is cheap to construct, copy, move and use spans, so that 92 // users are encouraged to use it as a pass-by-value parameter. A span does not 93 // own the underlying memory, so care must be taken to ensure that a span does 94 // not outlive the backing store. 95 // 96 // span is somewhat analogous to StringPiece, but with arbitrary element types, 97 // allowing mutation if T is non-const. 98 // 99 // span is implicitly convertible from C++ arrays, as well as most [1] 100 // container-like types that provide a data() and size() method (such as 101 // std::vector<T>). A mutable span<T> can also be implicitly converted to an 102 // immutable span<const T>. 103 // 104 // Consider using a span for functions that take a data pointer and size 105 // parameter: it allows the function to still act on an array-like type, while 106 // allowing the caller code to be a bit more concise. 107 // 108 // For read-only data access pass a span<const T>: the caller can supply either 109 // a span<const T> or a span<T>, while the callee will have a read-only view. 110 // For read-write access a mutable span<T> is required. 111 // 112 // Without span: 113 // Read-Only: 114 // // std::string HexEncode(const uint8_t* data, size_t size); 115 // std::vector<uint8_t> data_buffer = GenerateData(); 116 // std::string r = HexEncode(data_buffer.data(), data_buffer.size()); 117 // 118 // Mutable: 119 // // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...); 120 // char str_buffer[100]; 121 // SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14); 122 // 123 // With span: 124 // Read-Only: 125 // // std::string HexEncode(base::span<const uint8_t> data); 126 // std::vector<uint8_t> data_buffer = GenerateData(); 127 // std::string r = HexEncode(data_buffer); 128 // 129 // Mutable: 130 // // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...); 131 // char str_buffer[100]; 132 // SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14); 133 // 134 // Spans with "const" and pointers 135 // ------------------------------- 136 // 137 // Const and pointers can get confusing. Here are vectors of pointers and their 138 // corresponding spans (you can always make the span "more const" too): 139 // 140 // const std::vector<int*> => base::span<int* const> 141 // std::vector<const int*> => base::span<const int*> 142 // const std::vector<const int*> => base::span<const int* const> 143 // 144 // Differences from the working group proposal 145 // ------------------------------------------- 146 // 147 // https://wg21.link/P0122 is the latest working group proposal, Chromium 148 // currently implements R6. The biggest difference is span does not support a 149 // static extent template parameter. Other differences are documented in 150 // subsections below. 151 // 152 // Differences from [views.constants]: 153 // - no dynamic_extent constant 154 // 155 // Differences in constants and types: 156 // - no element_type type alias 157 // - no index_type type alias 158 // - no different_type type alias 159 // - no extent constant 160 // 161 // Differences from [span.cons]: 162 // - no constructor from a pointer range 163 // - no constructor from std::array 164 // 165 // Differences from [span.sub]: 166 // - no templated first() 167 // - no templated last() 168 // - no templated subspan() 169 // - using size_t instead of ptrdiff_t for indexing 170 // 171 // Differences from [span.obs]: 172 // - using size_t instead of ptrdiff_t to represent size() 173 // 174 // Differences from [span.elem]: 175 // - no operator ()() 176 // - using size_t instead of ptrdiff_t for indexing 177 178 // [span], class template span 179 template <typename T> 180 class span { 181 public: 182 using value_type = typename std::remove_cv<T>::type; 183 using pointer = T*; 184 using reference = T&; 185 using iterator = T*; 186 using const_iterator = const T*; 187 using reverse_iterator = std::reverse_iterator<iterator>; 188 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 189 190 // [span.cons], span constructors, copy, assignment, and destructor 191 constexpr span() noexcept : data_(nullptr), size_(0) {} 192 constexpr span(T* data, size_t size) noexcept : data_(data), size_(size) {} 193 194 // TODO(dcheng): Implement construction from a |begin| and |end| pointer. 195 template <size_t N> 196 constexpr span(T (&array)[N]) noexcept : span(array, N) {} 197 // TODO(dcheng): Implement construction from std::array. 198 // Conversion from a container that provides |T* data()| and |integral_type 199 // size()|. 200 template <typename Container, 201 typename = internal::EnableIfSpanCompatibleContainer<Container, T>> 202 constexpr span(Container& container) 203 : span(container.data(), container.size()) {} 204 template < 205 typename Container, 206 typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>> 207 span(const Container& container) : span(container.data(), container.size()) {} 208 constexpr span(const span& other) noexcept = default; 209 // Conversions from spans of compatible types: this allows a span<T> to be 210 // seamlessly used as a span<const T>, but not the other way around. 211 template <typename U, typename = internal::EnableIfLegalSpanConversion<U, T>> 212 constexpr span(const span<U>& other) : span(other.data(), other.size()) {} 213 span& operator=(const span& other) noexcept = default; 214 ~span() noexcept { 215 if (!size_) { 216 // Empty spans might point to byte N+1 of a N-byte object, legal for 217 // C pointers but not UnownedPtrs. 218 data_.ReleaseBadPointer(); 219 } 220 } 221 222 // [span.sub], span subviews 223 const span first(size_t count) const { 224 CHECK(count <= size_); 225 return span(data_.Get(), count); 226 } 227 228 const span last(size_t count) const { 229 CHECK(count <= size_); 230 return span(data_.Get() + (size_ - count), count); 231 } 232 233 const span subspan(size_t pos, size_t count = -1) const { 234 const auto npos = static_cast<size_t>(-1); 235 CHECK(pos <= size_); 236 CHECK(count == npos || count <= size_ - pos); 237 return span(data_.Get() + pos, count == npos ? size_ - pos : count); 238 } 239 240 // [span.obs], span observers 241 constexpr size_t size() const noexcept { return size_; } 242 constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); } 243 constexpr bool empty() const noexcept { return size_ == 0; } 244 245 // [span.elem], span element access 246 T& operator[](size_t index) const noexcept { 247 CHECK(index < size_); 248 return data_.Get()[index]; 249 } 250 constexpr T* data() const noexcept { return data_.Get(); } 251 252 // [span.iter], span iterator support 253 constexpr iterator begin() const noexcept { return data_.Get(); } 254 constexpr iterator end() const noexcept { return data_.Get() + size_; } 255 256 constexpr const_iterator cbegin() const noexcept { return begin(); } 257 constexpr const_iterator cend() const noexcept { return end(); } 258 259 constexpr reverse_iterator rbegin() const noexcept { 260 return reverse_iterator(end()); 261 } 262 constexpr reverse_iterator rend() const noexcept { 263 return reverse_iterator(begin()); 264 } 265 266 constexpr const_reverse_iterator crbegin() const noexcept { 267 return const_reverse_iterator(cend()); 268 } 269 constexpr const_reverse_iterator crend() const noexcept { 270 return const_reverse_iterator(cbegin()); 271 } 272 273 private: 274 UnownedPtr<T> data_; 275 size_t size_; 276 }; 277 278 // [span.comparison], span comparison operators 279 // Relational operators. Equality is a element-wise comparison. 280 template <typename T> 281 constexpr bool operator==(span<T> lhs, span<T> rhs) noexcept { 282 return lhs.size() == rhs.size() && 283 std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); 284 } 285 286 template <typename T> 287 constexpr bool operator!=(span<T> lhs, span<T> rhs) noexcept { 288 return !(lhs == rhs); 289 } 290 291 template <typename T> 292 constexpr bool operator<(span<T> lhs, span<T> rhs) noexcept { 293 return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), 294 rhs.cend()); 295 } 296 297 template <typename T> 298 constexpr bool operator<=(span<T> lhs, span<T> rhs) noexcept { 299 return !(rhs < lhs); 300 } 301 302 template <typename T> 303 constexpr bool operator>(span<T> lhs, span<T> rhs) noexcept { 304 return rhs < lhs; 305 } 306 307 template <typename T> 308 constexpr bool operator>=(span<T> lhs, span<T> rhs) noexcept { 309 return !(lhs < rhs); 310 } 311 312 // [span.objectrep], views of object representation 313 template <typename T> 314 span<const uint8_t> as_bytes(span<T> s) noexcept { 315 return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()}; 316 } 317 318 template <typename T, 319 typename U = typename std::enable_if<!std::is_const<T>::value>::type> 320 span<uint8_t> as_writable_bytes(span<T> s) noexcept { 321 return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()}; 322 } 323 324 // Type-deducing helpers for constructing a span. 325 template <typename T> 326 constexpr span<T> make_span(T* data, size_t size) noexcept { 327 return span<T>(data, size); 328 } 329 330 template <typename T, size_t N> 331 constexpr span<T> make_span(T (&array)[N]) noexcept { 332 return span<T>(array); 333 } 334 335 template <typename Container, 336 typename T = typename Container::value_type, 337 typename = internal::EnableIfSpanCompatibleContainer<Container, T>> 338 constexpr span<T> make_span(Container& container) { 339 return span<T>(container); 340 } 341 342 template < 343 typename Container, 344 typename T = typename std::add_const<typename Container::value_type>::type, 345 typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>> 346 constexpr span<T> make_span(const Container& container) { 347 return span<T>(container); 348 } 349 350 } // namespace pdfium 351 352 #endif // THIRD_PARTY_BASE_SPAN_H_ 353