tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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