Span.h (35919B)
1 /////////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 // 5 // This code is licensed under the MIT License (MIT). 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 // THE SOFTWARE. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 17 // Adapted from 18 // https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/span 19 // and 20 // https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/include/gsl/gsl_util 21 22 #ifndef mozilla_Span_h 23 #define mozilla_Span_h 24 25 #include <algorithm> 26 #include <array> 27 #include <cstddef> 28 #include <cstdint> 29 #include <iterator> 30 #include <limits> 31 #include <string> 32 #include <type_traits> 33 #include <utility> 34 35 #include "mozilla/Assertions.h" 36 #include "mozilla/Attributes.h" 37 #include "mozilla/Casting.h" 38 #include "mozilla/UniquePtr.h" 39 40 namespace mozilla { 41 42 template <typename T, size_t Length> 43 class Array; 44 45 template <typename Enum, typename T, size_t Length> 46 class EnumeratedArray; 47 48 // Stuff from gsl_util 49 50 // narrow_cast(): a searchable way to do narrowing casts of values 51 template <class T, class U> 52 inline constexpr T narrow_cast(U&& u) { 53 return static_cast<T>(std::forward<U>(u)); 54 } 55 56 // end gsl_util 57 58 // [views.constants], constants 59 // This was -1 in gsl::span, but using size_t for sizes instead of ptrdiff_t 60 // and reserving a magic value that realistically doesn't occur in 61 // compile-time-constant Span sizes makes things a lot less messy in terms of 62 // comparison between signed and unsigned. 63 constexpr const size_t dynamic_extent = std::numeric_limits<size_t>::max(); 64 65 template <class ElementType, size_t Extent = dynamic_extent> 66 class Span; 67 68 // implementation details 69 namespace span_details { 70 71 template <class T> 72 struct is_span_oracle : std::false_type {}; 73 74 template <class ElementType, size_t Extent> 75 struct is_span_oracle<mozilla::Span<ElementType, Extent>> : std::true_type {}; 76 77 template <class T> 78 struct is_span : public is_span_oracle<std::remove_cv_t<T>> {}; 79 80 template <class T> 81 struct is_std_array_oracle : std::false_type {}; 82 83 template <class ElementType, size_t Extent> 84 struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type {}; 85 86 template <class T> 87 struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>> {}; 88 89 template <size_t From, size_t To> 90 struct is_allowed_extent_conversion 91 : public std::integral_constant<bool, From == To || 92 From == mozilla::dynamic_extent || 93 To == mozilla::dynamic_extent> {}; 94 95 template <class From, class To> 96 struct is_allowed_element_type_conversion 97 : public std::integral_constant< 98 bool, std::is_convertible_v<From (*)[], To (*)[]>> {}; 99 100 struct SpanKnownBounds {}; 101 102 template <class SpanT, bool IsConst> 103 class span_iterator { 104 using element_type_ = typename SpanT::element_type; 105 106 template <class ElementType, size_t Extent> 107 friend class ::mozilla::Span; 108 109 public: 110 using iterator_category = std::random_access_iterator_tag; 111 using value_type = std::remove_const_t<element_type_>; 112 using difference_type = ptrdiff_t; 113 114 using reference = 115 std::conditional_t<IsConst, const element_type_, element_type_>&; 116 using pointer = std::add_pointer_t<reference>; 117 118 constexpr span_iterator() : span_iterator(nullptr, 0, SpanKnownBounds{}) {} 119 120 constexpr span_iterator(const SpanT* span, typename SpanT::index_type index) 121 : span_(span), index_(index) { 122 MOZ_RELEASE_ASSERT(span == nullptr || 123 (index_ >= 0 && index <= span_->Length())); 124 } 125 126 private: 127 // For whatever reason, the compiler doesn't like optimizing away the above 128 // MOZ_RELEASE_ASSERT when `span_iterator` is constructed for 129 // obviously-correct cases like `span.begin()` or `span.end()`. We provide 130 // this private constructor for such cases. 131 constexpr span_iterator(const SpanT* span, typename SpanT::index_type index, 132 SpanKnownBounds) 133 : span_(span), index_(index) {} 134 135 public: 136 // `other` is already correct by construction; we do not need to go through 137 // the release assert above. Put differently, this constructor is effectively 138 // a copy constructor and therefore needs no assertions. 139 friend class span_iterator<SpanT, true>; 140 constexpr MOZ_IMPLICIT span_iterator(const span_iterator<SpanT, false>& other) 141 : span_(other.span_), index_(other.index_) {} 142 143 constexpr span_iterator<SpanT, IsConst>& operator=( 144 const span_iterator<SpanT, IsConst>&) = default; 145 146 constexpr reference operator*() const { 147 MOZ_RELEASE_ASSERT(span_); 148 return (*span_)[index_]; 149 } 150 151 constexpr pointer operator->() const { 152 MOZ_RELEASE_ASSERT(span_); 153 return &((*span_)[index_]); 154 } 155 156 constexpr span_iterator& operator++() { 157 ++index_; 158 return *this; 159 } 160 161 constexpr span_iterator operator++(int) { 162 auto ret = *this; 163 ++(*this); 164 return ret; 165 } 166 167 constexpr span_iterator& operator--() { 168 --index_; 169 return *this; 170 } 171 172 constexpr span_iterator operator--(int) { 173 auto ret = *this; 174 --(*this); 175 return ret; 176 } 177 178 constexpr span_iterator operator+(difference_type n) const { 179 auto ret = *this; 180 return ret += n; 181 } 182 183 constexpr span_iterator& operator+=(difference_type n) { 184 MOZ_RELEASE_ASSERT(span_ && (index_ + n) >= 0 && 185 (index_ + n) <= span_->Length()); 186 index_ += n; 187 return *this; 188 } 189 190 constexpr span_iterator operator-(difference_type n) const { 191 auto ret = *this; 192 return ret -= n; 193 } 194 195 constexpr span_iterator& operator-=(difference_type n) { return *this += -n; } 196 197 constexpr difference_type operator-(const span_iterator& rhs) const { 198 MOZ_RELEASE_ASSERT(span_ == rhs.span_); 199 return index_ - rhs.index_; 200 } 201 202 constexpr reference operator[](difference_type n) const { 203 return *(*this + n); 204 } 205 206 constexpr friend bool operator==(const span_iterator& lhs, 207 const span_iterator& rhs) { 208 // Iterators from different spans are uncomparable. A diagnostic assertion 209 // should be enough to check this, though. To ensure that no iterators from 210 // different spans are ever considered equal, still compare them in release 211 // builds. 212 MOZ_DIAGNOSTIC_ASSERT(lhs.span_ == rhs.span_); 213 return lhs.index_ == rhs.index_ && lhs.span_ == rhs.span_; 214 } 215 216 constexpr friend bool operator!=(const span_iterator& lhs, 217 const span_iterator& rhs) { 218 return !(lhs == rhs); 219 } 220 221 constexpr friend bool operator<(const span_iterator& lhs, 222 const span_iterator& rhs) { 223 MOZ_DIAGNOSTIC_ASSERT(lhs.span_ == rhs.span_); 224 return lhs.index_ < rhs.index_; 225 } 226 227 constexpr friend bool operator<=(const span_iterator& lhs, 228 const span_iterator& rhs) { 229 return !(rhs < lhs); 230 } 231 232 constexpr friend bool operator>(const span_iterator& lhs, 233 const span_iterator& rhs) { 234 return rhs < lhs; 235 } 236 237 constexpr friend bool operator>=(const span_iterator& lhs, 238 const span_iterator& rhs) { 239 return !(rhs > lhs); 240 } 241 242 void swap(span_iterator& rhs) { 243 std::swap(index_, rhs.index_); 244 std::swap(span_, rhs.span_); 245 } 246 247 protected: 248 const SpanT* span_; 249 size_t index_; 250 }; 251 252 template <class Span, bool IsConst> 253 inline constexpr span_iterator<Span, IsConst> operator+( 254 typename span_iterator<Span, IsConst>::difference_type n, 255 const span_iterator<Span, IsConst>& rhs) { 256 return rhs + n; 257 } 258 259 template <size_t Ext> 260 class extent_type { 261 public: 262 using index_type = size_t; 263 264 static_assert(Ext >= 0, "A fixed-size Span must be >= 0 in size."); 265 266 constexpr extent_type() = default; 267 268 template <index_type Other> 269 constexpr MOZ_IMPLICIT extent_type(extent_type<Other> ext) { 270 static_assert( 271 Other == Ext || Other == dynamic_extent, 272 "Mismatch between fixed-size extent and size of initializing data."); 273 MOZ_RELEASE_ASSERT(ext.size() == Ext); 274 } 275 276 constexpr MOZ_IMPLICIT extent_type(index_type length) { 277 MOZ_RELEASE_ASSERT(length == Ext); 278 } 279 280 constexpr index_type size() const { return Ext; } 281 }; 282 283 template <> 284 class extent_type<dynamic_extent> { 285 public: 286 using index_type = size_t; 287 288 template <index_type Other> 289 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size()) {} 290 291 explicit constexpr extent_type(index_type length) : size_(length) {} 292 293 constexpr index_type size() const { return size_; } 294 295 private: 296 index_type size_; 297 }; 298 } // namespace span_details 299 300 /** 301 * Span - slices for C++ 302 * 303 * Span implements Rust's slice concept for C++. It's called "Span" instead of 304 * "Slice" to follow the naming used in C++ Core Guidelines. 305 * 306 * A Span wraps a pointer and a length that identify a non-owning view to a 307 * contiguous block of memory of objects of the same type. Various types, 308 * including (pre-decay) C arrays, XPCOM strings, nsTArray, mozilla::Array, 309 * mozilla::Range and contiguous standard-library containers, auto-convert 310 * into Spans when attempting to pass them as arguments to methods that take 311 * Spans. (Span itself autoconverts into mozilla::Range.) 312 * 313 * Like Rust's slices, Span provides safety against out-of-bounds access by 314 * performing run-time bound checks. However, unlike Rust's slices, Span 315 * cannot provide safety against use-after-free. 316 * 317 * (Note: Span is like Rust's slice only conceptually. Due to the lack of 318 * ABI guarantees, you should still decompose spans/slices to raw pointer 319 * and length parts when crossing the FFI. The Elements() and data() methods 320 * are guaranteed to return a non-null pointer even for zero-length spans, 321 * so the pointer can be used as a raw part of a Rust slice without further 322 * checks.) 323 * 324 * In addition to having constructors (with the support of deduction guides) 325 * that take various well-known types, a Span for an arbitrary type can be 326 * constructed from a pointer and a length or a pointer and another pointer 327 * pointing just past the last element. 328 * 329 * A Span<const char> or Span<const char16_t> can be obtained for const char* 330 * or const char16_t pointing to a zero-terminated string using the 331 * MakeStringSpan() function (which treats a nullptr argument equivalently 332 * to the empty string). Corresponding implicit constructor does not exist 333 * in order to avoid accidental construction in cases where const char* or 334 * const char16_t* do not point to a zero-terminated string. 335 * 336 * Span has methods that follow the Mozilla naming style and methods that 337 * don't. The methods that follow the Mozilla naming style are meant to be 338 * used directly from Mozilla code. The methods that don't are meant for 339 * integration with C++11 range-based loops and with meta-programming that 340 * expects the same methods that are found on the standard-library 341 * containers. For example, to decompose a Span into its parts in Mozilla 342 * code, use Elements() and Length() (as with nsTArray) instead of data() 343 * and size() (as with std::vector). 344 * 345 * The pointer and length wrapped by a Span cannot be changed after a Span has 346 * been created. When new values are required, simply create a new Span. Span 347 * has a method called Subspan() that works analogously to the Substring() 348 * method of XPCOM strings taking a start index and an optional length. As a 349 * Mozilla extension (relative to Microsoft's gsl::span that mozilla::Span is 350 * based on), Span has methods From(start), To(end) and FromTo(start, end) 351 * that correspond to Rust's &slice[start..], &slice[..end] and 352 * &slice[start..end], respectively. (That is, the end index is the index of 353 * the first element not to be included in the new subspan.) 354 * 355 * When indicating a Span that's only read from, const goes inside the type 356 * parameter. Don't put const in front of Span. That is: 357 * size_t ReadsFromOneSpanAndWritesToAnother(Span<const uint8_t> aReadFrom, 358 * Span<uint8_t> aWrittenTo); 359 * 360 * Any Span<const T> can be viewed as Span<const uint8_t> using the function 361 * AsBytes(). Any Span<T> can be viewed as Span<uint8_t> using the function 362 * AsWritableBytes(). 363 * 364 * Note that iterators from different Span instances are uncomparable, even if 365 * they refer to the same memory. This also applies to any spans derived via 366 * Subspan etc. 367 */ 368 template <class ElementType, size_t Extent /* = dynamic_extent */> 369 class MOZ_GSL_POINTER Span { 370 public: 371 // constants and types 372 using element_type = ElementType; 373 using value_type = std::remove_cv_t<element_type>; 374 using index_type = size_t; 375 using pointer = element_type*; 376 using reference = element_type&; 377 378 using iterator = 379 span_details::span_iterator<Span<ElementType, Extent>, false>; 380 using const_iterator = 381 span_details::span_iterator<Span<ElementType, Extent>, true>; 382 using reverse_iterator = std::reverse_iterator<iterator>; 383 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 384 385 constexpr static const index_type extent = Extent; 386 constexpr static const index_type npos = index_type(-1); 387 388 // [Span.cons], Span constructors, copy, assignment, and destructor 389 // "Dependent" is needed to make "std::enable_if_t<(Dependent || 390 // Extent == 0 || Extent == dynamic_extent)>" SFINAE, 391 // since 392 // "std::enable_if_t<(Extent == 0 || Extent == dynamic_extent)>" is 393 // ill-formed when Extent is neither of the extreme values. 394 /** 395 * Constructor with no args. 396 */ 397 template <bool Dependent = false, 398 class = std::enable_if_t<(Dependent || Extent == 0 || 399 Extent == dynamic_extent)>> 400 constexpr Span() : storage_(nullptr, span_details::extent_type<0>()) {} 401 402 /** 403 * Constructor for nullptr. 404 */ 405 constexpr MOZ_IMPLICIT Span(std::nullptr_t) : Span() {} 406 407 /** 408 * Constructor for pointer and length. 409 */ 410 constexpr Span(pointer aPtr MOZ_LIFETIME_BOUND, index_type aLength) 411 : storage_(aPtr, aLength) {} 412 413 /** 414 * Constructor for start pointer and pointer past end. 415 */ 416 constexpr Span(pointer aStartPtr MOZ_LIFETIME_BOUND, 417 pointer aEndPtr MOZ_LIFETIME_BOUND) 418 : storage_(aStartPtr, std::distance(aStartPtr, aEndPtr)) {} 419 420 /** 421 * Constructor for pair of Span iterators. 422 */ 423 template <typename OtherElementType, size_t OtherExtent, bool IsConst> 424 constexpr Span( 425 span_details::span_iterator<Span<OtherElementType, OtherExtent>, IsConst> 426 aBegin, 427 span_details::span_iterator<Span<OtherElementType, OtherExtent>, IsConst> 428 aEnd) 429 : storage_(aBegin == aEnd ? nullptr : &*aBegin, aEnd - aBegin) {} 430 431 /** 432 * Constructor for {iterator,size_t} 433 */ 434 template <typename OtherElementType, size_t OtherExtent, bool IsConst> 435 constexpr Span( 436 span_details::span_iterator<Span<OtherElementType, OtherExtent>, IsConst> 437 aBegin, 438 index_type aLength) 439 : storage_(!aLength ? nullptr : &*aBegin, aLength) {} 440 441 /** 442 * Constructor for C array. 443 */ 444 template <size_t N> 445 constexpr MOZ_IMPLICIT Span(element_type (&aArr MOZ_LIFETIME_BOUND)[N]) 446 : storage_(&aArr[0], span_details::extent_type<N>()) {} 447 448 // Implicit constructors for char* and char16_t* pointers are deleted in order 449 // to avoid accidental construction in cases where a pointer does not point to 450 // a zero-terminated string. A Span<const char> or Span<const char16_t> can be 451 // obtained for const char* or const char16_t pointing to a zero-terminated 452 // string using the MakeStringSpan() function. 453 // (This must be a template because otherwise it will prevent the previous 454 // array constructor to match because an array decays to a pointer. This only 455 // exists to point to the above explanation, since there's no other 456 // constructor that would match.) 457 template < 458 typename T, 459 typename = std::enable_if_t< 460 std::is_pointer_v<T> && 461 (std::is_same_v<std::remove_const_t<std::decay_t<T>>, char> || 462 std::is_same_v<std::remove_const_t<std::decay_t<T>>, char16_t>)>> 463 Span(T& aStr) = delete; 464 465 /** 466 * Constructor for std::array. 467 */ 468 template <size_t N, 469 class ArrayElementType = std::remove_const_t<element_type>> 470 constexpr MOZ_IMPLICIT Span( 471 std::array<ArrayElementType, N>& aArr MOZ_LIFETIME_BOUND) 472 : storage_(&aArr[0], span_details::extent_type<N>()) {} 473 474 /** 475 * Constructor for const std::array. 476 */ 477 template <size_t N> 478 constexpr MOZ_IMPLICIT Span( 479 const std::array<std::remove_const_t<element_type>, N>& aArr 480 MOZ_LIFETIME_BOUND) 481 : storage_(&aArr[0], span_details::extent_type<N>()) {} 482 483 /** 484 * Constructor for mozilla::Array. 485 */ 486 template <size_t N, 487 class ArrayElementType = std::remove_const_t<element_type>> 488 constexpr MOZ_IMPLICIT Span( 489 mozilla::Array<ArrayElementType, N>& aArr MOZ_LIFETIME_BOUND) 490 : storage_(&aArr[0], span_details::extent_type<N>()) {} 491 492 /** 493 * Constructor for const mozilla::Array. 494 */ 495 template <size_t N> 496 constexpr MOZ_IMPLICIT Span( 497 const mozilla::Array<std::remove_const_t<element_type>, N>& aArr 498 MOZ_LIFETIME_BOUND) 499 : storage_(&aArr[0], span_details::extent_type<N>()) {} 500 501 /** 502 * Constructor for mozilla::EnumeratedArray. 503 */ 504 template <size_t N, class Enum, 505 class ArrayElementType = std::remove_const_t<element_type>> 506 constexpr MOZ_IMPLICIT Span( 507 mozilla::EnumeratedArray<Enum, ArrayElementType, N>& aArr 508 MOZ_LIFETIME_BOUND) 509 : storage_(&aArr[Enum(0)], span_details::extent_type<N>()) {} 510 511 /** 512 * Constructor for const mozilla::EnumeratedArray. 513 */ 514 template <size_t N, class Enum> 515 constexpr MOZ_IMPLICIT Span( 516 const mozilla::EnumeratedArray<Enum, std::remove_const_t<element_type>, 517 N>& aArr MOZ_LIFETIME_BOUND) 518 : storage_(&aArr[Enum(0)], span_details::extent_type<N>()) {} 519 520 /** 521 * Constructor for mozilla::UniquePtr holding an array and length. 522 */ 523 template <class ArrayElementType = std::add_pointer<element_type>, 524 class DeleterType> 525 constexpr Span(const mozilla::UniquePtr<ArrayElementType, DeleterType>& aPtr 526 MOZ_LIFETIME_BOUND, 527 index_type aLength) 528 : storage_(aPtr.get(), aLength) {} 529 530 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the 531 // requirement on Container to be a contiguous sequence container. 532 /** 533 * Constructor for standard-library containers. 534 */ 535 template < 536 class Container, 537 class Dummy = std::enable_if_t< 538 !std::is_const_v<Container> && 539 !span_details::is_span<Container>::value && 540 !span_details::is_std_array<Container>::value && 541 std::is_convertible_v<typename Container::pointer, pointer> && 542 std::is_convertible_v<typename Container::pointer, 543 decltype(std::declval<Container>().data())>, 544 Container>> 545 constexpr MOZ_IMPLICIT Span(Container& cont, Dummy* = nullptr) 546 : Span(cont.data(), ReleaseAssertedCast<index_type>(cont.size())) {} 547 548 /** 549 * Constructor for standard-library containers (const version). 550 */ 551 template < 552 class Container, 553 class = std::enable_if_t< 554 std::is_const_v<element_type> && 555 !span_details::is_span<Container>::value && 556 std::is_convertible_v<typename Container::pointer, pointer> && 557 std::is_convertible_v<typename Container::pointer, 558 decltype(std::declval<Container>().data())>>> 559 constexpr MOZ_IMPLICIT Span(const Container& cont) 560 : Span(cont.data(), ReleaseAssertedCast<index_type>(cont.size())) {} 561 562 // NB: the SFINAE here uses .Elements() as a incomplete/imperfect proxy for 563 // the requirement on Container to be a contiguous sequence container. 564 /** 565 * Constructor for contiguous Mozilla containers. 566 */ 567 template < 568 class Container, 569 class = std::enable_if_t< 570 !std::is_const_v<Container> && 571 !span_details::is_span<Container>::value && 572 !span_details::is_std_array<Container>::value && 573 std::is_convertible_v<typename Container::value_type*, pointer> && 574 std::is_convertible_v< 575 typename Container::value_type*, 576 decltype(std::declval<Container>().Elements())>>> 577 constexpr MOZ_IMPLICIT Span(Container& cont, void* = nullptr) 578 : Span(cont.Elements(), ReleaseAssertedCast<index_type>(cont.Length())) {} 579 580 /** 581 * Constructor for contiguous Mozilla containers (const version). 582 */ 583 template < 584 class Container, 585 class = std::enable_if_t< 586 std::is_const_v<element_type> && 587 !span_details::is_span<Container>::value && 588 std::is_convertible_v<typename Container::value_type*, pointer> && 589 std::is_convertible_v< 590 typename Container::value_type*, 591 decltype(std::declval<Container>().Elements())>>> 592 constexpr MOZ_IMPLICIT Span(const Container& cont, void* = nullptr) 593 : Span(cont.Elements(), ReleaseAssertedCast<index_type>(cont.Length())) {} 594 595 /** 596 * Constructor from other Span. 597 */ 598 constexpr Span(const Span& other) = default; 599 600 /** 601 * Constructor from other Span. 602 */ 603 constexpr Span(Span&& other) = default; 604 605 /** 606 * Constructor from other Span with conversion of element type. 607 */ 608 template < 609 class OtherElementType, size_t OtherExtent, 610 class = std::enable_if_t<span_details::is_allowed_extent_conversion< 611 OtherExtent, Extent>::value && 612 span_details::is_allowed_element_type_conversion< 613 OtherElementType, element_type>::value>> 614 constexpr MOZ_IMPLICIT Span(const Span<OtherElementType, OtherExtent>& other) 615 : storage_(other.data(), 616 span_details::extent_type<OtherExtent>(other.size())) {} 617 618 /** 619 * Constructor from other Span with conversion of element type. 620 */ 621 template < 622 class OtherElementType, size_t OtherExtent, 623 class = std::enable_if_t<span_details::is_allowed_extent_conversion< 624 OtherExtent, Extent>::value && 625 span_details::is_allowed_element_type_conversion< 626 OtherElementType, element_type>::value>> 627 constexpr MOZ_IMPLICIT Span(Span<OtherElementType, OtherExtent>&& other) 628 : storage_(other.data(), 629 span_details::extent_type<OtherExtent>(other.size())) {} 630 631 ~Span() = default; 632 constexpr Span& operator=(const Span& other) = default; 633 634 constexpr Span& operator=(Span&& other) = default; 635 636 // [Span.sub], Span subviews 637 /** 638 * Subspan with first N elements with compile-time N. 639 */ 640 template <size_t Count> 641 constexpr Span<element_type, Count> First() const { 642 MOZ_RELEASE_ASSERT(Count <= size()); 643 return {data(), Count}; 644 } 645 646 /** 647 * Subspan with last N elements with compile-time N. 648 */ 649 template <size_t Count> 650 constexpr Span<element_type, Count> Last() const { 651 const size_t len = size(); 652 MOZ_RELEASE_ASSERT(Count <= len); 653 return {data() + (len - Count), Count}; 654 } 655 656 /** 657 * Subspan with compile-time start index and length. 658 */ 659 template <size_t Offset, size_t Count = dynamic_extent> 660 constexpr Span<element_type, Count> Subspan() const { 661 const size_t len = size(); 662 MOZ_RELEASE_ASSERT(Offset <= len && 663 (Count == dynamic_extent || (Offset + Count <= len))); 664 return {data() + Offset, Count == dynamic_extent ? len - Offset : Count}; 665 } 666 667 /** 668 * Subspan with first N elements with run-time N. 669 */ 670 constexpr Span<element_type, dynamic_extent> First(index_type aCount) const { 671 MOZ_RELEASE_ASSERT(aCount <= size()); 672 return {data(), aCount}; 673 } 674 675 /** 676 * Subspan with last N elements with run-time N. 677 */ 678 constexpr Span<element_type, dynamic_extent> Last(index_type aCount) const { 679 const size_t len = size(); 680 MOZ_RELEASE_ASSERT(aCount <= len); 681 return {data() + (len - aCount), aCount}; 682 } 683 684 /** 685 * Subspan with run-time start index and length. 686 */ 687 constexpr Span<element_type, dynamic_extent> Subspan( 688 index_type aStart, index_type aLength = dynamic_extent) const { 689 const size_t len = size(); 690 MOZ_RELEASE_ASSERT(aStart <= len && (aLength == dynamic_extent || 691 (aStart + aLength <= len))); 692 return {data() + aStart, 693 aLength == dynamic_extent ? len - aStart : aLength}; 694 } 695 696 /** 697 * Subspan with run-time start index. (Rust's &foo[start..]) 698 */ 699 constexpr Span<element_type, dynamic_extent> From(index_type aStart) const { 700 return Subspan(aStart); 701 } 702 703 /** 704 * Subspan with run-time exclusive end index. (Rust's &foo[..end]) 705 */ 706 constexpr Span<element_type, dynamic_extent> To(index_type aEnd) const { 707 return Subspan(0, aEnd); 708 } 709 710 /// std::span-compatible method name 711 constexpr auto subspan(index_type aStart, 712 index_type aLength = dynamic_extent) const { 713 return Subspan(aStart, aLength); 714 } 715 /// std::span-compatible method name 716 constexpr auto from(index_type aStart) const { return From(aStart); } 717 /// std::span-compatible method name 718 constexpr auto to(index_type aEnd) const { return To(aEnd); } 719 720 /** 721 * Subspan with run-time start index and exclusive end index. 722 * (Rust's &foo[start..end]) 723 */ 724 constexpr Span<element_type, dynamic_extent> FromTo(index_type aStart, 725 index_type aEnd) const { 726 MOZ_RELEASE_ASSERT(aStart <= aEnd); 727 return Subspan(aStart, aEnd - aStart); 728 } 729 730 // [Span.obs], Span observers 731 /** 732 * Number of elements in the span. 733 */ 734 constexpr index_type Length() const { return size(); } 735 736 /** 737 * Number of elements in the span (standard-libray duck typing version). 738 */ 739 constexpr index_type size() const { return storage_.size(); } 740 741 /** 742 * Size of the span in bytes. 743 */ 744 constexpr index_type LengthBytes() const { return size_bytes(); } 745 746 /** 747 * Size of the span in bytes (standard-library naming style version). 748 */ 749 constexpr index_type size_bytes() const { 750 return size() * narrow_cast<index_type>(sizeof(element_type)); 751 } 752 753 /** 754 * Checks if the the length of the span is zero. 755 */ 756 constexpr bool IsEmpty() const { return empty(); } 757 758 /** 759 * Checks if the the length of the span is zero (standard-libray duck 760 * typing version). 761 */ 762 constexpr bool empty() const { return size() == 0; } 763 764 // [Span.elem], Span element access 765 constexpr reference operator[](index_type idx) const { 766 MOZ_RELEASE_ASSERT(idx < storage_.size()); 767 return data()[idx]; 768 } 769 770 /** 771 * Access element of span by index (standard-library duck typing version). 772 */ 773 constexpr reference at(index_type idx) const { return this->operator[](idx); } 774 775 constexpr reference operator()(index_type idx) const { 776 return this->operator[](idx); 777 } 778 779 /** 780 * Pointer to the first element of the span. The return value is never 781 * nullptr, not ever for zero-length spans, so it can be passed as-is 782 * to std::slice::from_raw_parts() in Rust. 783 */ 784 constexpr pointer Elements() const { return data(); } 785 786 /** 787 * Pointer to the first element of the span (standard-libray duck typing 788 * version). The return value is never nullptr, not ever for zero-length 789 * spans, so it can be passed as-is to std::slice::from_raw_parts() in Rust. 790 */ 791 constexpr pointer data() const { return storage_.data(); } 792 793 // [Span.iter], Span iterator support 794 iterator begin() const { return {this, 0, span_details::SpanKnownBounds{}}; } 795 iterator end() const { 796 return {this, Length(), span_details::SpanKnownBounds{}}; 797 } 798 799 const_iterator cbegin() const { 800 return {this, 0, span_details::SpanKnownBounds{}}; 801 } 802 const_iterator cend() const { 803 return {this, Length(), span_details::SpanKnownBounds{}}; 804 } 805 806 reverse_iterator rbegin() const { return reverse_iterator{end()}; } 807 reverse_iterator rend() const { return reverse_iterator{begin()}; } 808 809 const_reverse_iterator crbegin() const { 810 return const_reverse_iterator{cend()}; 811 } 812 const_reverse_iterator crend() const { 813 return const_reverse_iterator{cbegin()}; 814 } 815 816 template <size_t SplitPoint> 817 constexpr std::pair<Span<ElementType, SplitPoint>, 818 Span<ElementType, Extent - SplitPoint>> 819 SplitAt() const { 820 static_assert(Extent != dynamic_extent); 821 static_assert(SplitPoint <= Extent); 822 return {First<SplitPoint>(), Last<Extent - SplitPoint>()}; 823 } 824 825 constexpr std::pair<Span<ElementType, dynamic_extent>, 826 Span<ElementType, dynamic_extent>> 827 SplitAt(const index_type aSplitPoint) const { 828 MOZ_RELEASE_ASSERT(aSplitPoint <= Length()); 829 return {First(aSplitPoint), Last(Length() - aSplitPoint)}; 830 } 831 832 constexpr Span<std::add_const_t<ElementType>, Extent> AsConst() const { 833 return {Elements(), Length()}; 834 } 835 836 // Returns the index of the given element in the span, or `npos` otherwise. 837 template <typename Item> 838 index_type IndexOf(const Item& aItem) const { 839 auto begin = this->begin(); 840 auto end = this->end(); 841 auto it = std::find(begin, end, aItem); 842 if (it == end) { 843 return npos; 844 } 845 return index_type(it - begin); 846 } 847 848 private: 849 // this implementation detail class lets us take advantage of the 850 // empty base class optimization to pay for only storage of a single 851 // pointer in the case of fixed-size Spans 852 template <class ExtentType> 853 class storage_type : public ExtentType { 854 public: 855 template <class OtherExtentType> 856 constexpr storage_type(pointer elements, OtherExtentType ext) 857 : ExtentType(ext) 858 // Replace nullptr with aligned bogus pointer for Rust slice 859 // compatibility. See 860 // https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html 861 , 862 data_(elements ? elements 863 : reinterpret_cast<pointer>(alignof(element_type))) { 864 MOZ_ASSERT((!elements && ExtentType::size() == 0) || 865 (elements && ExtentType::size() != dynamic_extent)); 866 } 867 868 constexpr pointer data() const { return data_; } 869 870 private: 871 pointer data_; 872 }; 873 874 storage_type<span_details::extent_type<Extent>> storage_; 875 }; 876 877 template <typename T, size_t OtherExtent, bool IsConst> 878 Span(span_details::span_iterator<Span<T, OtherExtent>, IsConst> aBegin, 879 span_details::span_iterator<Span<T, OtherExtent>, IsConst> aEnd) 880 -> Span<std::conditional_t<IsConst, std::add_const_t<T>, T>>; 881 882 template <typename T, size_t Extent> 883 Span(T (&)[Extent]) -> Span<T, Extent>; 884 885 template <class Container> 886 Span(Container&) -> Span<typename Container::value_type>; 887 888 template <class Container> 889 Span(const Container&) -> Span<const typename Container::value_type>; 890 891 template <typename T, size_t Extent> 892 Span(mozilla::Array<T, Extent>&) -> Span<T, Extent>; 893 894 template <typename T, size_t Extent> 895 Span(const mozilla::Array<T, Extent>&) -> Span<const T, Extent>; 896 897 template <typename Enum, typename T, size_t Extent> 898 Span(mozilla::EnumeratedArray<Enum, T, Extent>&) -> Span<T, Extent>; 899 900 template <typename Enum, typename T, size_t Extent> 901 Span(const mozilla::EnumeratedArray<Enum, T, Extent>&) -> Span<const T, Extent>; 902 903 // [Span.comparison], Span comparison operators 904 template <class ElementType, size_t FirstExtent, size_t SecondExtent> 905 inline constexpr bool operator==(const Span<ElementType, FirstExtent>& l, 906 const Span<ElementType, SecondExtent>& r) { 907 return (l.size() == r.size()) && 908 std::equal(l.data(), l.data() + l.size(), r.data()); 909 } 910 911 template <class ElementType, size_t Extent> 912 inline constexpr bool operator!=(const Span<ElementType, Extent>& l, 913 const Span<ElementType, Extent>& r) { 914 return !(l == r); 915 } 916 917 template <class ElementType, size_t Extent> 918 inline constexpr bool operator<(const Span<ElementType, Extent>& l, 919 const Span<ElementType, Extent>& r) { 920 return std::lexicographical_compare(l.data(), l.data() + l.size(), r.data(), 921 r.data() + r.size()); 922 } 923 924 template <class ElementType, size_t Extent> 925 inline constexpr bool operator<=(const Span<ElementType, Extent>& l, 926 const Span<ElementType, Extent>& r) { 927 return !(l > r); 928 } 929 930 template <class ElementType, size_t Extent> 931 inline constexpr bool operator>(const Span<ElementType, Extent>& l, 932 const Span<ElementType, Extent>& r) { 933 return r < l; 934 } 935 936 template <class ElementType, size_t Extent> 937 inline constexpr bool operator>=(const Span<ElementType, Extent>& l, 938 const Span<ElementType, Extent>& r) { 939 return !(l < r); 940 } 941 942 namespace span_details { 943 // if we only supported compilers with good constexpr support then 944 // this pair of classes could collapse down to a constexpr function 945 946 // we should use a narrow_cast<> to go to size_t, but older compilers may not 947 // see it as constexpr and so will fail compilation of the template 948 template <class ElementType, size_t Extent> 949 struct calculate_byte_size 950 : std::integral_constant<size_t, 951 static_cast<size_t>(sizeof(ElementType) * 952 static_cast<size_t>(Extent))> { 953 }; 954 955 template <class ElementType> 956 struct calculate_byte_size<ElementType, dynamic_extent> 957 : std::integral_constant<size_t, dynamic_extent> {}; 958 } // namespace span_details 959 960 // [Span.objectrep], views of object representation 961 /** 962 * View span as Span<const uint8_t>. 963 */ 964 template <class ElementType, size_t Extent> 965 Span<const uint8_t, 966 span_details::calculate_byte_size<ElementType, Extent>::value> 967 AsBytes(Span<ElementType, Extent> s) { 968 return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()}; 969 } 970 971 /** 972 * View span as Span<uint8_t>. 973 */ 974 template <class ElementType, size_t Extent, 975 class = std::enable_if_t<!std::is_const_v<ElementType>>> 976 Span<uint8_t, span_details::calculate_byte_size<ElementType, Extent>::value> 977 AsWritableBytes(Span<ElementType, Extent> s) { 978 return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()}; 979 } 980 981 /** 982 * View a span of uint8_t as a span of char. 983 */ 984 inline Span<const char> AsChars(Span<const uint8_t> s) { 985 return {reinterpret_cast<const char*>(s.data()), s.size()}; 986 } 987 988 /** 989 * View a writable span of uint8_t as a span of char. 990 */ 991 inline Span<char> AsWritableChars(Span<uint8_t> s) { 992 return {reinterpret_cast<char*>(s.data()), s.size()}; 993 } 994 995 /** 996 * Create span from a zero-terminated C string. nullptr is 997 * treated as the empty string. 998 */ 999 constexpr Span<const char> MakeStringSpan(const char* aZeroTerminated) { 1000 if (!aZeroTerminated) { 1001 return Span<const char>(); 1002 } 1003 return Span<const char>(aZeroTerminated, 1004 std::char_traits<char>::length(aZeroTerminated)); 1005 } 1006 1007 /** 1008 * Create span from a zero-terminated UTF-16 C string. nullptr is 1009 * treated as the empty string. 1010 */ 1011 constexpr Span<const char16_t> MakeStringSpan(const char16_t* aZeroTerminated) { 1012 if (!aZeroTerminated) { 1013 return Span<const char16_t>(); 1014 } 1015 return Span<const char16_t>( 1016 aZeroTerminated, std::char_traits<char16_t>::length(aZeroTerminated)); 1017 } 1018 1019 } // namespace mozilla 1020 1021 #endif // mozilla_Span_h