• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
69namespace gsl
70{
71
72// [views.constants], constants
73constexpr const std::ptrdiff_t dynamic_extent = -1;
74
75template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
76class span;
77
78// implementation details
79namespace 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
354template <class ElementType, std::ptrdiff_t Extent>
355class span
356{
357public:
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
546private:
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)
641template <class ElementType, std::ptrdiff_t Extent>
642constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent;
643#endif
644
645// [span.comparison], span comparison operators
646template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
647constexpr 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
652template <class ElementType, std::ptrdiff_t Extent>
653constexpr bool operator!=(span<ElementType, Extent> l, span<ElementType, Extent> r)
654{
655    return !(l == r);
656}
657
658template <class ElementType, std::ptrdiff_t Extent>
659constexpr 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
664template <class ElementType, std::ptrdiff_t Extent>
665constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r)
666{
667    return !(l > r);
668}
669
670template <class ElementType, std::ptrdiff_t Extent>
671constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r)
672{
673    return r < l;
674}
675
676template <class ElementType, std::ptrdiff_t Extent>
677constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r)
678{
679    return !(l < r);
680}
681
682namespace 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
706template <class ElementType, std::ptrdiff_t Extent>
707span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
708as_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
714template <class ElementType, std::ptrdiff_t Extent,
715          class = std::enable_if_t<!std::is_const<ElementType>::value>>
716span<byte, details::calculate_byte_size<ElementType, Extent>::value>
717as_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//
726template <class ElementType>
727constexpr span<ElementType> make_span(ElementType* ptr,
728                                      typename span<ElementType>::index_type count)
729{
730    return span<ElementType>(ptr, count);
731}
732
733template <class ElementType>
734constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
735{
736    return span<ElementType>(firstElem, lastElem);
737}
738
739template <class ElementType, std::size_t N>
740constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept
741{
742    return span<ElementType, N>(arr);
743}
744
745template <class Container>
746constexpr span<typename Container::value_type> make_span(Container& cont)
747{
748    return span<typename Container::value_type>(cont);
749}
750
751template <class Container>
752constexpr span<const typename Container::value_type> make_span(const Container& cont)
753{
754    return span<const typename Container::value_type>(cont);
755}
756
757template <class Ptr>
758constexpr 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
763template <class Ptr>
764constexpr 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
770template <class ElementType, std::ptrdiff_t Extent>
771constexpr 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