LCOV - code coverage report
Current view: top level - mfbt - Span.h (source / functions) Hit Total Coverage
Test: output.info Lines: 46 89 51.7 %
Date: 2017-07-14 16:53:18 Functions: 54 128 42.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13