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 #pragma once
     18 
     19 #ifndef GSL_SPAN_H
     20 #define GSL_SPAN_H
     21 
     22 #include <gsl/gsl_assert>
     23 #include <gsl/gsl_byte>
     24 #include <gsl/gsl_util>
     25 
     26 #include <array>
     27 #include <iterator>
     28 #include <limits>
     29 #include <memory>
     30 #include <stdexcept>
     31 #include <type_traits>
     32 #include <utility>
     33 
     34 #ifdef _MSC_VER
     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 // blanket turn off warnings from CppCoreCheck for now
     42 // so people aren't annoyed by them when running the tool.
     43 // more targeted suppressions will be added in a future update to the GSL
     44 #pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495)
     45 
     46 #if _MSC_VER < 1910
     47 #pragma push_macro("constexpr")
     48 #define constexpr /*constexpr*/
     49 
     50 #endif                          // _MSC_VER < 1910
     51 #endif                          // _MSC_VER
     52 
     53 #ifdef GSL_THROW_ON_CONTRACT_VIOLATION
     54 #define GSL_NOEXCEPT /*noexcept*/
     55 #else
     56 #define GSL_NOEXCEPT noexcept
     57 #endif // GSL_THROW_ON_CONTRACT_VIOLATION
     58 
     59 namespace gsl
     60 {
     61 
     62 // [views.constants], constants
     63 constexpr const std::ptrdiff_t dynamic_extent = -1;
     64 
     65 template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
     66 class span;
     67 
     68 // implementation details
     69 namespace details
     70 {
     71     template <class T>
     72     struct is_span_oracle : std::false_type
     73     {
     74     };
     75 
     76     template <class ElementType, std::ptrdiff_t Extent>
     77     struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
     78     {
     79     };
     80 
     81     template <class T>
     82     struct is_span : public is_span_oracle<std::remove_cv_t<T>>
     83     {
     84     };
     85 
     86     template <class T>
     87     struct is_std_array_oracle : std::false_type
     88     {
     89     };
     90 
     91     template <class ElementType, std::size_t Extent>
     92     struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
     93     {
     94     };
     95 
     96     template <class T>
     97     struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>>
     98     {
     99     };
    100 
    101     template <std::ptrdiff_t From, std::ptrdiff_t To>
    102     struct is_allowed_extent_conversion
    103         : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent ||
    104                                                   To == gsl::dynamic_extent>
    105     {
    106     };
    107 
    108     template <class From, class To>
    109     struct is_allowed_element_type_conversion
    110         : public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
    111     {
    112     };
    113 
    114     template <class Span, bool IsConst>
    115     class span_iterator
    116     {
    117         using element_type_ = typename Span::element_type;
    118 
    119     public:
    120         using iterator_category = std::random_access_iterator_tag;
    121         using value_type = std::remove_cv_t<element_type_>;
    122         using difference_type = typename Span::index_type;
    123 
    124         using reference = std::conditional_t<IsConst, const element_type_, element_type_>&;
    125         using pointer = std::add_pointer_t<reference>;
    126 
    127         span_iterator() = default;
    128 
    129         constexpr span_iterator(const Span* span, typename Span::index_type index) GSL_NOEXCEPT
    130             : span_(span), index_(index)
    131         {
    132             Expects(span == nullptr || (index_ >= 0 && index <= span_->length()));
    133         }
    134 
    135         friend span_iterator<Span, true>;
    136         template<bool B, std::enable_if_t<!B && IsConst>* = nullptr>
    137         constexpr span_iterator(const span_iterator<Span, B>& other) GSL_NOEXCEPT
    138             : span_iterator(other.span_, other.index_)
    139         {
    140         }
    141 
    142         constexpr reference operator*() const GSL_NOEXCEPT
    143         {
    144             Expects(span_);
    145             return (*span_)[index_];
    146         }
    147 
    148         constexpr pointer operator->() const GSL_NOEXCEPT
    149         {
    150             Expects(span_ && index_ >= 0 && index_ < span_->length());
    151             return span_->data() + index_;
    152         }
    153 
    154         constexpr span_iterator& operator++() GSL_NOEXCEPT
    155         {
    156             Expects(span_ && index_ >= 0 && index_ < span_->length());
    157             ++index_;
    158             return *this;
    159         }
    160 
    161         constexpr span_iterator operator++(int) GSL_NOEXCEPT
    162         {
    163             auto ret = *this;
    164             ++(*this);
    165             return ret;
    166         }
    167 
    168         constexpr span_iterator& operator--() GSL_NOEXCEPT
    169         {
    170             Expects(span_ && index_ > 0 && index_ <= span_->length());
    171             --index_;
    172             return *this;
    173         }
    174 
    175         constexpr span_iterator operator--(int) GSL_NOEXCEPT
    176         {
    177             auto ret = *this;
    178             --(*this);
    179             return ret;
    180         }
    181 
    182         constexpr span_iterator operator+(difference_type n) const GSL_NOEXCEPT
    183         {
    184             auto ret = *this;
    185             return ret += n;
    186         }
    187 
    188         constexpr span_iterator& operator+=(difference_type n) GSL_NOEXCEPT
    189         {
    190             Expects(span_ && (index_ + n) >= 0 && (index_ + n) <= span_->length());
    191             index_ += n;
    192             return *this;
    193         }
    194 
    195         constexpr span_iterator operator-(difference_type n) const GSL_NOEXCEPT
    196         {
    197             auto ret = *this;
    198             return ret -= n;
    199         }
    200 
    201         constexpr span_iterator& operator-=(difference_type n) GSL_NOEXCEPT { return *this += -n; }
    202 
    203         constexpr difference_type operator-(const span_iterator& rhs) const GSL_NOEXCEPT
    204         {
    205             Expects(span_ == rhs.span_);
    206             return index_ - rhs.index_;
    207         }
    208 
    209         constexpr reference operator[](difference_type n) const GSL_NOEXCEPT
    210         {
    211             return *(*this + n);
    212         }
    213 
    214         constexpr friend bool operator==(const span_iterator& lhs,
    215                                          const span_iterator& rhs) GSL_NOEXCEPT
    216         {
    217             return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
    218         }
    219 
    220         constexpr friend bool operator!=(const span_iterator& lhs,
    221                                          const span_iterator& rhs) GSL_NOEXCEPT
    222         {
    223             return !(lhs == rhs);
    224         }
    225 
    226         constexpr friend bool operator<(const span_iterator& lhs,
    227                                         const span_iterator& rhs) GSL_NOEXCEPT
    228         {
    229             Expects(lhs.span_ == rhs.span_);
    230             return lhs.index_ < rhs.index_;
    231         }
    232 
    233         constexpr friend bool operator<=(const span_iterator& lhs,
    234                                          const span_iterator& rhs) GSL_NOEXCEPT
    235         {
    236             return !(rhs < lhs);
    237         }
    238 
    239         constexpr friend bool operator>(const span_iterator& lhs,
    240                                         const span_iterator& rhs) GSL_NOEXCEPT
    241         {
    242             return rhs < lhs;
    243         }
    244 
    245         constexpr friend bool operator>=(const span_iterator& lhs,
    246                                          const span_iterator& rhs) GSL_NOEXCEPT
    247         {
    248             return !(rhs > lhs);
    249         }
    250 
    251     protected:
    252         const Span* span_ = nullptr;
    253         std::ptrdiff_t index_ = 0;
    254     };
    255 
    256     template <class Span, bool IsConst>
    257     inline constexpr span_iterator<Span, IsConst>
    258     operator+(typename span_iterator<Span, IsConst>::difference_type n,
    259               const span_iterator<Span, IsConst>& rhs) GSL_NOEXCEPT
    260     {
    261         return rhs + n;
    262     }
    263 
    264     template <class Span, bool IsConst>
    265     inline constexpr span_iterator<Span, IsConst>
    266     operator-(typename span_iterator<Span, IsConst>::difference_type n,
    267               const span_iterator<Span, IsConst>& rhs) GSL_NOEXCEPT
    268     {
    269         return rhs - n;
    270     }
    271 
    272     template <std::ptrdiff_t Ext>
    273     class extent_type
    274     {
    275     public:
    276         using index_type = std::ptrdiff_t;
    277 
    278         static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
    279 
    280         constexpr extent_type() GSL_NOEXCEPT {}
    281 
    282         template <index_type Other>
    283         constexpr extent_type(extent_type<Other> ext)
    284         {
    285             static_assert(Other == Ext || Other == dynamic_extent,
    286                           "Mismatch between fixed-size extent and size of initializing data.");
    287             Expects(ext.size() == Ext);
    288         }
    289 
    290         constexpr extent_type(index_type size) { Expects(size == Ext); }
    291 
    292         constexpr index_type size() const GSL_NOEXCEPT { return Ext; }
    293     };
    294 
    295     template <>
    296     class extent_type<dynamic_extent>
    297     {
    298     public:
    299         using index_type = std::ptrdiff_t;
    300 
    301         template <index_type Other>
    302         explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
    303         {
    304         }
    305 
    306         explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); }
    307 
    308         constexpr index_type size() const GSL_NOEXCEPT { return size_; }
    309 
    310     private:
    311         index_type size_;
    312     };
    313 } // namespace details
    314 
    315 // [span], class template span
    316 template <class ElementType, std::ptrdiff_t Extent>
    317 class span
    318 {
    319 public:
    320     // constants and types
    321     using element_type = ElementType;
    322     using value_type = std::remove_cv_t<ElementType>;
    323     using index_type = std::ptrdiff_t;
    324     using pointer = element_type*;
    325     using reference = element_type&;
    326 
    327     using iterator = details::span_iterator<span<ElementType, Extent>, false>;
    328     using const_iterator = details::span_iterator<span<ElementType, Extent>, true>;
    329     using reverse_iterator = std::reverse_iterator<iterator>;
    330     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    331 
    332     using size_type = index_type;
    333 
    334     constexpr static const index_type extent = Extent;
    335 
    336     // [span.cons], span constructors, copy, assignment, and destructor
    337     template <bool Dependent = false,
    338               // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE,
    339               // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0.
    340               class = std::enable_if_t<(Dependent || Extent <= 0)>>
    341     constexpr span() GSL_NOEXCEPT : storage_(nullptr, details::extent_type<0>())
    342     {
    343     }
    344 
    345     constexpr span(std::nullptr_t) GSL_NOEXCEPT : span() {}
    346 
    347     constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
    348 
    349     constexpr span(pointer firstElem, pointer lastElem)
    350         : storage_(firstElem, std::distance(firstElem, lastElem))
    351     {
    352     }
    353 
    354     template <std::size_t N>
    355     constexpr span(element_type (&arr)[N]) GSL_NOEXCEPT
    356         : storage_(&arr[0], details::extent_type<N>())
    357     {
    358     }
    359 
    360     template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>>
    361     constexpr span(std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT
    362         : storage_(&arr[0], details::extent_type<N>())
    363     {
    364     }
    365 
    366     template <std::size_t N>
    367     constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) GSL_NOEXCEPT
    368         : storage_(&arr[0], details::extent_type<N>())
    369     {
    370     }
    371 
    372     template <class ArrayElementType = std::add_pointer<element_type>>
    373     constexpr span(const std::unique_ptr<ArrayElementType>& ptr, index_type count)
    374         : storage_(ptr.get(), count)
    375     {
    376     }
    377 
    378     constexpr span(const std::unique_ptr<ElementType>& ptr) : storage_(ptr.get(), ptr.get() ? 1 : 0)
    379     {
    380     }
    381     constexpr span(const std::shared_ptr<ElementType>& ptr) : storage_(ptr.get(), ptr.get() ? 1 : 0)
    382     {
    383     }
    384 
    385     // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement
    386     // on Container to be a contiguous sequence container.
    387     template <class Container,
    388               class = std::enable_if_t<
    389                   !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
    390                   std::is_convertible<typename Container::pointer, pointer>::value &&
    391                   std::is_convertible<typename Container::pointer,
    392                                       decltype(std::declval<Container>().data())>::value>>
    393     constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
    394     {
    395     }
    396 
    397     template <class Container,
    398               class = std::enable_if_t<
    399                   std::is_const<element_type>::value && !details::is_span<Container>::value &&
    400                   std::is_convertible<typename Container::pointer, pointer>::value &&
    401                   std::is_convertible<typename Container::pointer,
    402                                       decltype(std::declval<Container>().data())>::value>>
    403     constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size()))
    404     {
    405     }
    406 
    407     constexpr span(const span& other) GSL_NOEXCEPT = default;
    408     constexpr span(span&& other) GSL_NOEXCEPT = default;
    409 
    410     template <
    411         class OtherElementType, std::ptrdiff_t OtherExtent,
    412         class = std::enable_if_t<
    413             details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
    414             details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
    415     constexpr span(const span<OtherElementType, OtherExtent>& other)
    416         : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
    417     {
    418     }
    419 
    420     template <
    421         class OtherElementType, std::ptrdiff_t OtherExtent,
    422         class = std::enable_if_t<
    423             details::is_allowed_extent_conversion<OtherExtent, Extent>::value &&
    424             details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>>
    425     constexpr span(span<OtherElementType, OtherExtent>&& other)
    426         : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
    427     {
    428     }
    429 
    430     ~span() GSL_NOEXCEPT = default;
    431     constexpr span& operator=(const span& other) GSL_NOEXCEPT = default;
    432 
    433     constexpr span& operator=(span&& other) GSL_NOEXCEPT = default;
    434 
    435     // [span.sub], span subviews
    436     template <std::ptrdiff_t Count>
    437     constexpr span<element_type, Count> first() const
    438     {
    439         Expects(Count >= 0 && Count <= size());
    440         return {data(), Count};
    441     }
    442 
    443     template <std::ptrdiff_t Count>
    444     constexpr span<element_type, Count> last() const
    445     {
    446         Expects(Count >= 0 && Count <= size());
    447         return {data() + (size() - Count), Count};
    448     }
    449 
    450     template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
    451     constexpr span<element_type, Count> subspan() const
    452     {
    453         Expects((Offset == 0 || (Offset > 0 && Offset <= size())) &&
    454                 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
    455         return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
    456     }
    457 
    458     constexpr span<element_type, dynamic_extent> first(index_type count) const
    459     {
    460         Expects(count >= 0 && count <= size());
    461         return {data(), count};
    462     }
    463 
    464     constexpr span<element_type, dynamic_extent> last(index_type count) const
    465     {
    466         Expects(count >= 0 && count <= size());
    467         return {data() + (size() - count), count};
    468     }
    469 
    470     constexpr span<element_type, dynamic_extent> subspan(index_type offset,
    471                                                          index_type count = dynamic_extent) const
    472     {
    473         Expects((offset == 0 || (offset > 0 && offset <= size())) &&
    474                 (count == dynamic_extent || (count >= 0 && offset + count <= size())));
    475         return {data() + offset, count == dynamic_extent ? size() - offset : count};
    476     }
    477 
    478     // [span.obs], span observers
    479     constexpr index_type length() const GSL_NOEXCEPT { return size(); }
    480     constexpr index_type size() const GSL_NOEXCEPT { return storage_.size(); }
    481     constexpr index_type length_bytes() const GSL_NOEXCEPT { return size_bytes(); }
    482     constexpr index_type size_bytes() const GSL_NOEXCEPT
    483     {
    484         return size() * narrow_cast<index_type>(sizeof(element_type));
    485     }
    486     constexpr bool empty() const GSL_NOEXCEPT { return size() == 0; }
    487 
    488     // [span.elem], span element access
    489     constexpr reference operator[](index_type idx) const
    490     {
    491         Expects(idx >= 0 && idx < storage_.size());
    492         return data()[idx];
    493     }
    494 
    495     constexpr reference at(index_type idx) const { return this->operator[](idx); }
    496     constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
    497     constexpr pointer data() const GSL_NOEXCEPT { return storage_.data(); }
    498 
    499     // [span.iter], span iterator support
    500     iterator begin() const GSL_NOEXCEPT { return {this, 0}; }
    501     iterator end() const GSL_NOEXCEPT { return {this, length()}; }
    502 
    503     const_iterator cbegin() const GSL_NOEXCEPT { return {this, 0}; }
    504     const_iterator cend() const GSL_NOEXCEPT { return {this, length()}; }
    505 
    506     reverse_iterator rbegin() const GSL_NOEXCEPT { return reverse_iterator{end()}; }
    507     reverse_iterator rend() const GSL_NOEXCEPT { return reverse_iterator{begin()}; }
    508 
    509     const_reverse_iterator crbegin() const GSL_NOEXCEPT { return const_reverse_iterator{cend()}; }
    510     const_reverse_iterator crend() const GSL_NOEXCEPT { return const_reverse_iterator{cbegin()}; }
    511 
    512 private:
    513     // this implementation detail class lets us take advantage of the
    514     // empty base class optimization to pay for only storage of a single
    515     // pointer in the case of fixed-size spans
    516     template <class ExtentType>
    517     class storage_type : public ExtentType
    518     {
    519     public:
    520         template <class OtherExtentType>
    521         constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
    522         {
    523             Expects((!data && ExtentType::size() == 0) || (data && ExtentType::size() >= 0));
    524         }
    525 
    526         constexpr pointer data() const GSL_NOEXCEPT { return data_; }
    527 
    528     private:
    529         pointer data_;
    530     };
    531 
    532     storage_type<details::extent_type<Extent>> storage_;
    533 };
    534 
    535 // [span.comparison], span comparison operators
    536 template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
    537 inline constexpr bool operator==(const span<ElementType, FirstExtent>& l,
    538                                  const span<ElementType, SecondExtent>& r)
    539 {
    540     return std::equal(l.begin(), l.end(), r.begin(), r.end());
    541 }
    542 
    543 template <class ElementType, std::ptrdiff_t Extent>
    544 inline constexpr bool operator!=(const span<ElementType, Extent>& l,
    545                                  const span<ElementType, Extent>& r)
    546 {
    547     return !(l == r);
    548 }
    549 
    550 template <class ElementType, std::ptrdiff_t Extent>
    551 inline constexpr bool operator<(const span<ElementType, Extent>& l,
    552                                 const span<ElementType, Extent>& r)
    553 {
    554     return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
    555 }
    556 
    557 template <class ElementType, std::ptrdiff_t Extent>
    558 inline constexpr bool operator<=(const span<ElementType, Extent>& l,
    559                                  const span<ElementType, Extent>& r)
    560 {
    561     return !(l > r);
    562 }
    563 
    564 template <class ElementType, std::ptrdiff_t Extent>
    565 inline constexpr bool operator>(const span<ElementType, Extent>& l,
    566                                 const span<ElementType, Extent>& r)
    567 {
    568     return r < l;
    569 }
    570 
    571 template <class ElementType, std::ptrdiff_t Extent>
    572 inline constexpr bool operator>=(const span<ElementType, Extent>& l,
    573                                  const span<ElementType, Extent>& r)
    574 {
    575     return !(l < r);
    576 }
    577 
    578 namespace details
    579 {
    580     // if we only supported compilers with good constexpr support then
    581     // this pair of classes could collapse down to a constexpr function
    582 
    583     // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
    584     // constexpr
    585     // and so will fail compilation of the template
    586     template <class ElementType, std::ptrdiff_t Extent>
    587     struct calculate_byte_size
    588         : std::integral_constant<std::ptrdiff_t,
    589                                  static_cast<std::ptrdiff_t>(sizeof(ElementType) *
    590                                                              static_cast<std::size_t>(Extent))>
    591     {
    592     };
    593 
    594     template <class ElementType>
    595     struct calculate_byte_size<ElementType, dynamic_extent>
    596         : std::integral_constant<std::ptrdiff_t, dynamic_extent>
    597     {
    598     };
    599 }
    600 
    601 // [span.objectrep], views of object representation
    602 template <class ElementType, std::ptrdiff_t Extent>
    603 span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
    604 as_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT
    605 {
    606     return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
    607 }
    608 
    609 template <class ElementType, std::ptrdiff_t Extent,
    610           class = std::enable_if_t<!std::is_const<ElementType>::value>>
    611 span<byte, details::calculate_byte_size<ElementType, Extent>::value>
    612 as_writeable_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT
    613 {
    614     return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
    615 }
    616 
    617 //
    618 // make_span() - Utility functions for creating spans
    619 //
    620 template <class ElementType>
    621 span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::index_type count)
    622 {
    623     return span<ElementType>(ptr, count);
    624 }
    625 
    626 template <class ElementType>
    627 span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
    628 {
    629     return span<ElementType>(firstElem, lastElem);
    630 }
    631 
    632 template <class ElementType, std::size_t N>
    633 span<ElementType, N> make_span(ElementType (&arr)[N])
    634 {
    635     return span<ElementType, N>(arr);
    636 }
    637 
    638 template <class Container>
    639 span<typename Container::value_type> make_span(Container& cont)
    640 {
    641     return span<typename Container::value_type>(cont);
    642 }
    643 
    644 template <class Container>
    645 span<const typename Container::value_type> make_span(const Container& cont)
    646 {
    647     return span<const typename Container::value_type>(cont);
    648 }
    649 
    650 template <class Ptr>
    651 span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count)
    652 {
    653     return span<typename Ptr::element_type>(cont, count);
    654 }
    655 
    656 template <class Ptr>
    657 span<typename Ptr::element_type> make_span(Ptr& cont)
    658 {
    659     return span<typename Ptr::element_type>(cont);
    660 }
    661 
    662 // Specialization of gsl::at for span
    663 template <class ElementType, std::ptrdiff_t Extent>
    664 inline constexpr ElementType& at(const span<ElementType, Extent>& s, std::ptrdiff_t index)
    665 {
    666     // No bounds checking here because it is done in span::operator[] called below
    667     return s[index];
    668 }
    669 
    670 } // namespace gsl
    671 
    672 #undef GSL_NOEXCEPT
    673 
    674 #ifdef _MSC_VER
    675 #if _MSC_VER < 1910
    676 #undef constexpr
    677 #pragma pop_macro("constexpr")
    678 
    679 #endif // _MSC_VER < 1910
    680 
    681 #pragma warning(pop)
    682 #endif // _MSC_VER
    683 
    684 #endif // GSL_SPAN_H
    685