Home | History | Annotate | Download | only in gsl
      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 #ifndef GSL_SPAN_H
     18 #define GSL_SPAN_H
     19 
     20 #include <gsl/gsl_assert> // for Expects
     21 #include <gsl/gsl_byte>   // for byte
     22 #include <gsl/gsl_util>   // for narrow_cast, narrow
     23 
     24 #include <algorithm> // for lexicographical_compare
     25 #include <array>     // for array
     26 #include <cstddef>   // for ptrdiff_t, size_t, nullptr_t
     27 #include <iterator>  // for reverse_iterator, distance, random_access_...
     28 #include <limits>
     29 #include <stdexcept>
     30 #include <type_traits> // for enable_if_t, declval, is_convertible, inte...
     31 #include <utility>
     32 #include <memory> // for std::addressof
     33 
     34 #if defined(_MSC_VER) && !defined(__clang__)
     35 #pragma warning(push)
     36 
     37 // turn off some warnings that are noisy about our Expects statements
     38 #pragma warning(disable : 4127) // conditional expression is constant
     39 #pragma warning(disable : 4702) // unreachable code
     40 
     41 // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
     42 #pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
     43 #pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
     44 
     45 #if _MSC_VER < 1910
     46 #pragma push_macro("constexpr")
     47 #define constexpr /*constexpr*/
     48 #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
     49 
     50 #endif // _MSC_VER < 1910
     51 #endif // _MSC_VER
     52 
     53 // See if we have enough C++17 power to use a static constexpr data member
     54 // without needing an out-of-line definition
     55 #if !(defined(__cplusplus) && (__cplusplus >= 201703L))
     56 #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
     57 #endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
     58 
     59 // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
     60 // While there is a conversion from signed to unsigned, it happens at
     61 // compiletime, so the compiler wouldn't have to warn indiscriminently, but
     62 // could check if the source value actually doesn't fit into the target type
     63 // and only warn in those cases.
     64 #if defined(__GNUC__) && __GNUC__ > 6
     65 #pragma GCC diagnostic push
     66 #pragma GCC diagnostic ignored "-Wsign-conversion"
     67 #endif
     68 
     69 namespace gsl
     70 {
     71 
     72 // [views.constants], constants
     73 constexpr const std::ptrdiff_t dynamic_extent = -1;
     74 
     75 template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
     76 class span;
     77 
     78 // implementation details
     79 namespace details
     80 {
     81     template <class T>
     82     struct is_span_oracle : std::false_type
     83     {
     84     };
     85 
     86     template <class ElementType, std::ptrdiff_t Extent>
     87     struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
     88     {
     89     };
     90 
     91     template <class T>
     92     struct is_span : public is_span_oracle<std::remove_cv_t<T>>
     93     {
     94     };
     95 
     96     template <class T>
     97     struct is_std_array_oracle : std::false_type
     98     {
     99     };
    100 
    101     template <class ElementType, std::size_t Extent>
    102     struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
    103     {
    104     };
    105 
    106     template <class T>
    107     struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>>
    108     {
    109     };
    110 
    111     template <std::ptrdiff_t From, std::ptrdiff_t To>
    112     struct is_allowed_extent_conversion
    113         : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
    114                                                   To == gsl::dynamic_extent>
    115     {
    116     };
    117 
    118     template <class From, class To>
    119     struct is_allowed_element_type_conversion
    120         : public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
    121     {
    122     };
    123 
    124     template <class Span, bool IsConst>
    125     class span_iterator
    126     {
    127         using element_type_ = typename Span::element_type;
    128 
    129     public:
    130 #ifdef _MSC_VER
    131         // Tell Microsoft standard library that span_iterators are checked.
    132         using _Unchecked_type = typename Span::pointer;
    133 #endif
    134 
    135         using iterator_category = std::random_access_iterator_tag;
    136         using value_type = std::remove_cv_t<element_type_>;
    137         using difference_type = typename Span::index_type;
    138 
    139         using reference = std::conditional_t<IsConst, const element_type_, element_type_>&;
    140         using pointer = std::add_pointer_t<reference>;
    141 
    142         span_iterator() = default;
    143 
    144         constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept
    145             : span_(span), index_(idx)
    146         {}
    147 
    148         friend span_iterator<Span, true>;
    149         template <bool B, std::enable_if_t<!B && IsConst>* = nullptr>
    150         constexpr span_iterator(const span_iterator<Span, B>& other) noexcept
    151             : span_iterator(other.span_, other.index_)
    152         {}
    153 
    154         GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    155         constexpr reference operator*() const
    156         {
    157             Expects(index_ != span_->size());
    158             return *(span_->data() + index_);
    159         }
    160 
    161         constexpr pointer operator->() const
    162         {
    163             Expects(index_ != span_->size());
    164             return span_->data() + index_;
    165         }
    166 
    167         constexpr span_iterator& operator++()
    168         {
    169             Expects(0 <= index_ && index_ != span_->size());
    170             ++index_;
    171             return *this;
    172         }
    173 
    174         constexpr span_iterator operator++(int)
    175         {
    176             auto ret = *this;
    177             ++(*this);
    178             return ret;
    179         }
    180 
    181         constexpr span_iterator& operator--()
    182         {
    183             Expects(index_ != 0 && index_ <= span_->size());
    184             --index_;
    185             return *this;
    186         }
    187 
    188         constexpr span_iterator operator--(int)
    189         {
    190             auto ret = *this;
    191             --(*this);
    192             return ret;
    193         }
    194 
    195         constexpr span_iterator operator+(difference_type n) const
    196         {
    197             auto ret = *this;
    198             return ret += n;
    199         }
    200 
    201         friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs)
    202         {
    203             return rhs + n;
    204         }
    205 
    206         constexpr span_iterator& operator+=(difference_type n)
    207         {
    208             Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
    209             index_ += n;
    210             return *this;
    211         }
    212 
    213         constexpr span_iterator operator-(difference_type n) const
    214         {
    215             auto ret = *this;
    216             return ret -= n;
    217         }
    218 
    219         constexpr span_iterator& operator-=(difference_type n) { return *this += -n; }
    220 
    221         constexpr difference_type operator-(span_iterator rhs) const
    222         {
    223             Expects(span_ == rhs.span_);
    224             return index_ - rhs.index_;
    225         }
    226 
    227         constexpr reference operator[](difference_type n) const { return *(*this + n); }
    228 
    229         constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept
    230         {
    231             return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
    232         }
    233 
    234         constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept
    235         {
    236             return !(lhs == rhs);
    237         }
    238 
    239         constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept
    240         {
    241             return lhs.index_ < rhs.index_;
    242         }
    243 
    244         constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept
    245         {
    246             return !(rhs < lhs);
    247         }
    248 
    249         constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept
    250         {
    251             return rhs < lhs;
    252         }
    253 
    254         constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept
    255         {
    256             return !(rhs > lhs);
    257         }
    258 
    259 #ifdef _MSC_VER
    260         // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
    261         // to unwrap span_iterator to a pointer type after a range check in STL
    262         // algorithm calls
    263         friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
    264         { // test that [lhs, rhs) forms a valid range inside an STL algorithm
    265             Expects(lhs.span_ == rhs.span_        // range spans have to match
    266                     && lhs.index_ <= rhs.index_); // range must not be transposed
    267         }
    268 
    269         constexpr void _Verify_offset(const difference_type n) const noexcept
    270         { // test that the iterator *this + n is a valid range in an STL
    271             // algorithm call
    272             Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
    273         }
    274 
    275         GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    276         constexpr pointer _Unwrapped() const noexcept
    277         { // after seeking *this to a high water mark, or using one of the
    278             // _Verify_xxx functions above, unwrap this span_iterator to a raw
    279             // pointer
    280             return span_->data() + index_;
    281         }
    282 
    283         // Tell the STL that span_iterator should not be unwrapped if it can't
    284         // validate in advance, even in release / optimized builds:
    285 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
    286         static constexpr const bool _Unwrap_when_unverified = false;
    287 #else
    288         static constexpr bool _Unwrap_when_unverified = false;
    289 #endif
    290         GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
    291         constexpr void _Seek_to(const pointer p) noexcept
    292         { // adjust the position of *this to previously verified location p
    293             // after _Unwrapped
    294             index_ = p - span_->data();
    295         }
    296 #endif
    297 
    298     protected:
    299         const Span* span_ = nullptr;
    300         std::ptrdiff_t index_ = 0;
    301     };
    302 
    303     template <std::ptrdiff_t Ext>
    304     class extent_type
    305     {
    306     public:
    307         using index_type = std::ptrdiff_t;
    308 
    309         static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
    310 
    311         constexpr extent_type() noexcept {}
    312 
    313         template <index_type Other>
    314         constexpr extent_type(extent_type<Other> ext)
    315         {
    316             static_assert(Other == Ext || Other == dynamic_extent,
    317                           "Mismatch between fixed-size extent and size of initializing data.");
    318             Expects(ext.size() == Ext);
    319         }
    320 
    321         constexpr extent_type(index_type size) { Expects(size == Ext); }
    322 
    323         constexpr index_type size() const noexcept { return Ext; }
    324     };
    325 
    326     template <>
    327     class extent_type<dynamic_extent>
    328     {
    329     public:
    330         using index_type = std::ptrdiff_t;
    331 
    332         template <index_type Other>
    333         explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
    334         {}
    335 
    336         explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
    337 
    338         constexpr index_type size() const noexcept { return size_; }
    339 
    340     private:
    341         index_type size_;
    342     };
    343 
    344     template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset, std::ptrdiff_t Count>
    345     struct calculate_subspan_type
    346     {
    347         using type = span<ElementType, Count != dynamic_extent
    348                                            ? Count
    349                                            : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
    350     };
    351 } // namespace details
    352 
    353 // [span], class template span
    354 template <class ElementType, std::ptrdiff_t Extent>
    355 class span
    356 {
    357 public:
    358     // constants and types
    359     using element_type = ElementType;
    360     using value_type = std::remove_cv_t<ElementType>;
    361     using index_type = std::ptrdiff_t;
    362     using pointer = element_type*;
    363     using reference = element_type&;
    364 
    365     using iterator = details::span_iterator<span<ElementType, Extent>, false>;
    366     using const_iterator = details::span_iterator<span<ElementType, Extent>, true>;
    367     using reverse_iterator = std::reverse_iterator<iterator>;
    368     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    369 
    370     using size_type = index_type;
    371 
    372 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
    373     static constexpr const index_type extent{Extent};
    374 #else
    375     static constexpr index_type extent{Extent};
    376 #endif
    377 
    378     // [span.cons], span constructors, copy, assignment, and destructor
    379     template <bool Dependent = false,
    380               // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE,
    381               // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
    382               class = std::enable_if_t<(Dependent || Extent <= 0)>>
    383     constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
    384     {}
    385 
    386     constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
    387 
    388     constexpr span(pointer firstElem, pointer lastElem)
    389         : storage_(firstElem, std::distance(firstElem, lastElem))
    390     {}
    391 
    392     template <std::size_t N>
    393     constexpr span(element_type (&arr)[N]) noexcept
    394         : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>())
    395     {}
    396 
    397     template <std::size_t N, class = std::enable_if_t<(N > 0)>>
    398     constexpr span(std::array<std::remove_const_t<element_type>, N>& arr) noexcept
    399         : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
    400     {
    401     }
    402 
    403     constexpr span(std::array<std::remove_const_t<element_type>, 0>&) noexcept
    404         : storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
    405     {
    406     }
    407 
    408     template <std::size_t N, class = std::enable_if_t<(N > 0)>>
    409     constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept
    410         : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
    411     {
    412     }
    413 
    414     constexpr span(const std::array<std::remove_const_t<element_type>, 0>&) noexcept
    415         : storage_(static_cast<pointer>(nullptr), details::extent_type<0>())
    416     {
    417     }
    418 
    419     // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
    420     // on Container to be a contiguous sequence container.
    421     template <class Container,
    422               class = std::enable_if_t<
    423                   !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
    424                   std::is_convertible<typename Container::pointer, pointer>::value &&
    425                   std::is_convertible<typename Container::pointer,
    426                                       decltype(std::declval<Container>().data())>::value>>
    427     constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
    428     {}
    429 
    430     template <class Container,
    431               class = std::enable_if_t<
    432                   std::is_const<element_type>::value && !details::is_span<Container>::value &&
    433                   std::is_convertible<typename Container::pointer, pointer>::value &&
    434                   std::is_convertible<typename Container::pointer,
    435                                       decltype(std::declval<Container>().data())>::value>>
    436     constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
    437     {}
    438 
    439     constexpr span(const span& other) noexcept = default;
    440 
    441     template <
    442         class OtherElementType, std::ptrdiff_t OtherExtent,
    443         class = std::enable_if_t<
    444             details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
    445             details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
    446     constexpr span(const span<OtherElementType, OtherExtent>& other)
    447         : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
    448     {}
    449 
    450     ~span() noexcept = default;
    451     constexpr span& operator=(const span& other) noexcept = default;
    452 
    453     // [span.sub], span subviews
    454     template <std::ptrdiff_t Count>
    455     constexpr span<element_type, Count> first() const
    456     {
    457         Expects(Count >= 0 && Count <= size());
    458         return {data(), Count};
    459     }
    460 
    461     template <std::ptrdiff_t Count>
    462     GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    463     constexpr span<element_type, Count> last() const
    464     {
    465         Expects(Count >= 0 && size() - Count >= 0);
    466         return {data() + (size() - Count), Count};
    467     }
    468 
    469     template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
    470     GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    471     constexpr auto subspan() const ->
    472         typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
    473     {
    474         Expects((Offset >= 0 && size() - Offset >= 0) &&
    475                 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
    476 
    477         return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
    478     }
    479 
    480     constexpr span<element_type, dynamic_extent> first(index_type count) const
    481     {
    482         Expects(count >= 0 && count <= size());
    483         return {data(), count};
    484     }
    485 
    486     constexpr span<element_type, dynamic_extent> last(index_type count) const
    487     {
    488         return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
    489     }
    490 
    491     constexpr span<element_type, dynamic_extent> subspan(index_type offset,
    492                                                          index_type count = dynamic_extent) const
    493     {
    494         return make_subspan(offset, count, subspan_selector<Extent>{});
    495     }
    496 
    497     // [span.obs], span observers
    498     constexpr index_type size() const noexcept { return storage_.size(); }
    499     constexpr index_type size_bytes() const noexcept
    500     {
    501         return size() * narrow_cast<index_type>(sizeof(element_type));
    502     }
    503     constexpr bool empty() const noexcept { return size() == 0; }
    504 
    505     // [span.elem], span element access
    506     GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    507     constexpr reference operator[](index_type idx) const
    508     {
    509         Expects(CheckRange(idx, storage_.size()));
    510         return data()[idx];
    511     }
    512 
    513     constexpr reference at(index_type idx) const { return this->operator[](idx); }
    514     constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
    515     constexpr pointer data() const noexcept { return storage_.data(); }
    516 
    517     // [span.iter], span iterator support
    518     constexpr iterator begin() const noexcept { return {this, 0}; }
    519     constexpr iterator end() const noexcept { return {this, size()}; }
    520 
    521     constexpr const_iterator cbegin() const noexcept { return {this, 0}; }
    522     constexpr const_iterator cend() const noexcept { return {this, size()}; }
    523 
    524     constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
    525     constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
    526 
    527     constexpr const_reverse_iterator crbegin() const noexcept
    528     {
    529         return const_reverse_iterator{cend()};
    530     }
    531     constexpr const_reverse_iterator crend() const noexcept
    532     {
    533         return const_reverse_iterator{cbegin()};
    534     }
    535 
    536 #ifdef _MSC_VER
    537     // Tell MSVC how to unwrap spans in range-based-for
    538     constexpr pointer _Unchecked_begin() const noexcept { return data(); }
    539     constexpr pointer _Unchecked_end() const noexcept
    540     {
    541         GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    542         return data() + size();
    543     }
    544 #endif // _MSC_VER
    545 
    546 private:
    547     static constexpr bool CheckRange(index_type idx, index_type size) noexcept
    548     {
    549         // Optimization:
    550         //
    551         // idx >= 0 && idx < size
    552         // =>
    553         // static_cast<size_t>(idx) < static_cast<size_t>(size)
    554         //
    555         // because size >=0 by span construction, and negative idx will
    556         // wrap around to a value always greater than size when casted.
    557 
    558         // check if we have enough space to wrap around
    559 #if defined(__cpp_if_constexpr)
    560         if constexpr (sizeof(index_type) <= sizeof(size_t))
    561 #else
    562         if (sizeof(index_type) <= sizeof(size_t))
    563 #endif
    564         {
    565             return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size);
    566         }
    567         else
    568         {
    569             return idx >= 0 && idx < size;
    570         }
    571     }
    572 
    573     // Needed to remove unnecessary null check in subspans
    574     struct KnownNotNull
    575     {
    576         pointer p;
    577     };
    578 
    579     // this implementation detail class lets us take advantage of the
    580     // empty base class optimization to pay for only storage of a single
    581     // pointer in the case of fixed-size spans
    582     template <class ExtentType>
    583     class storage_type : public ExtentType
    584     {
    585     public:
    586         // KnownNotNull parameter is needed to remove unnecessary null check
    587         // in subspans and constructors from arrays
    588         template <class OtherExtentType>
    589         constexpr storage_type(KnownNotNull data, OtherExtentType ext)
    590             : ExtentType(ext), data_(data.p)
    591         {
    592             Expects(ExtentType::size() >= 0);
    593         }
    594 
    595         template <class OtherExtentType>
    596         constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
    597         {
    598             Expects(ExtentType::size() >= 0);
    599             Expects(data || ExtentType::size() == 0);
    600         }
    601 
    602         constexpr pointer data() const noexcept { return data_; }
    603 
    604     private:
    605         pointer data_;
    606     };
    607 
    608     storage_type<details::extent_type<Extent>> storage_;
    609 
    610     // The rest is needed to remove unnecessary null check
    611     // in subspans and constructors from arrays
    612     constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}
    613 
    614     template <std::ptrdiff_t CallerExtent>
    615     class subspan_selector
    616     {
    617     };
    618 
    619     template <std::ptrdiff_t CallerExtent>
    620     span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count,
    621                                                     subspan_selector<CallerExtent>) const
    622     {
    623         const span<element_type, dynamic_extent> tmp(*this);
    624         return tmp.subspan(offset, count);
    625     }
    626 
    627     GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
    628     span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count,
    629                                                     subspan_selector<dynamic_extent>) const
    630     {
    631         Expects(offset >= 0 && size() - offset >= 0);
    632 
    633         if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
    634 
    635         Expects(count >= 0 && size() - offset >= count);
    636         return {KnownNotNull{data() + offset}, count};
    637     }
    638 };
    639 
    640 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
    641 template <class ElementType, std::ptrdiff_t Extent>
    642 constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent;
    643 #endif
    644 
    645 // [span.comparison], span comparison operators
    646 template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
    647 constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r)
    648 {
    649     return std::equal(l.begin(), l.end(), r.begin(), r.end());
    650 }
    651 
    652 template <class ElementType, std::ptrdiff_t Extent>
    653 constexpr bool operator!=(span<ElementType, Extent> l, span<ElementType, Extent> r)
    654 {
    655     return !(l == r);
    656 }
    657 
    658 template <class ElementType, std::ptrdiff_t Extent>
    659 constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r)
    660 {
    661     return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
    662 }
    663 
    664 template <class ElementType, std::ptrdiff_t Extent>
    665 constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r)
    666 {
    667     return !(l > r);
    668 }
    669 
    670 template <class ElementType, std::ptrdiff_t Extent>
    671 constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r)
    672 {
    673     return r < l;
    674 }
    675 
    676 template <class ElementType, std::ptrdiff_t Extent>
    677 constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r)
    678 {
    679     return !(l < r);
    680 }
    681 
    682 namespace details
    683 {
    684     // if we only supported compilers with good constexpr support then
    685     // this pair of classes could collapse down to a constexpr function
    686 
    687     // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
    688     // constexpr
    689     // and so will fail compilation of the template
    690     template <class ElementType, std::ptrdiff_t Extent>
    691     struct calculate_byte_size
    692         : std::integral_constant<std::ptrdiff_t,
    693                                  static_cast<std::ptrdiff_t>(sizeof(ElementType) *
    694                                                              static_cast<std::size_t>(Extent))>
    695     {
    696     };
    697 
    698     template <class ElementType>
    699     struct calculate_byte_size<ElementType, dynamic_extent>
    700         : std::integral_constant<std::ptrdiff_t, dynamic_extent>
    701     {
    702     };
    703 } // namespace details
    704 
    705 // [span.objectrep], views of object representation
    706 template <class ElementType, std::ptrdiff_t Extent>
    707 span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
    708 as_bytes(span<ElementType, Extent> s) noexcept
    709 {
    710     GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
    711     return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
    712 }
    713 
    714 template <class ElementType, std::ptrdiff_t Extent,
    715           class = std::enable_if_t<!std::is_const<ElementType>::value>>
    716 span<byte, details::calculate_byte_size<ElementType, Extent>::value>
    717 as_writeable_bytes(span<ElementType, Extent> s) noexcept
    718 {
    719     GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
    720     return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
    721 }
    722 
    723 //
    724 // make_span() - Utility functions for creating spans
    725 //
    726 template <class ElementType>
    727 constexpr span<ElementType> make_span(ElementType* ptr,
    728                                       typename span<ElementType>::index_type count)
    729 {
    730     return span<ElementType>(ptr, count);
    731 }
    732 
    733 template <class ElementType>
    734 constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
    735 {
    736     return span<ElementType>(firstElem, lastElem);
    737 }
    738 
    739 template <class ElementType, std::size_t N>
    740 constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
    741 {
    742     return span<ElementType, N>(arr);
    743 }
    744 
    745 template <class Container>
    746 constexpr span<typename Container::value_type> make_span(Container& cont)
    747 {
    748     return span<typename Container::value_type>(cont);
    749 }
    750 
    751 template <class Container>
    752 constexpr span<const typename Container::value_type> make_span(const Container& cont)
    753 {
    754     return span<const typename Container::value_type>(cont);
    755 }
    756 
    757 template <class Ptr>
    758 constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count)
    759 {
    760     return span<typename Ptr::element_type>(cont, count);
    761 }
    762 
    763 template <class Ptr>
    764 constexpr span<typename Ptr::element_type> make_span(Ptr& cont)
    765 {
    766     return span<typename Ptr::element_type>(cont);
    767 }
    768 
    769 // Specialization of gsl::at for span
    770 template <class ElementType, std::ptrdiff_t Extent>
    771 constexpr ElementType& at(span<ElementType, Extent> s, index i)
    772 {
    773     // No bounds checking here because it is done in span::operator[] called below
    774     return s[i];
    775 }
    776 
    777 } // namespace gsl
    778 
    779 #if defined(_MSC_VER) && !defined(__clang__)
    780 #if _MSC_VER < 1910
    781 #undef constexpr
    782 #pragma pop_macro("constexpr")
    783 
    784 #endif // _MSC_VER < 1910
    785 
    786 #pragma warning(pop)
    787 #endif // _MSC_VER
    788 
    789 #if defined(__GNUC__) && __GNUC__ > 6
    790 #pragma GCC diagnostic pop
    791 #endif // __GNUC__ > 6
    792 
    793 #endif // GSL_SPAN_H
    794