xxxxxxxxxx
1
844
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 "assert"   // for Expects
21
#include "byte"     // for byte
22
#include "span_ext" // for span specialization of gsl::at and other span-related extensions
23
#include "util"     // for narrow_cast
24

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 <memory>      // for pointer_traits
29
#include <type_traits> // for enable_if_t, declval, is_convertible, inte...
30

31
#if defined(__has_include) && __has_include(<version>)
32
#include <version>
33
#endif
34

35
#if defined(_MSC_VER) && !defined(__clang__)
36
#pragma warning(push)
37

38
// turn off some warnings that are noisy about our Expects statements
39
#pragma warning(disable : 4127) // conditional expression is constant
40
#pragma warning(                                                                                   \
41
    disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
42
#pragma warning(disable : 4702) // unreachable code
43

44
// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
45
#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
46
#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
47

48
#endif // _MSC_VER
49

50
// See if we have enough C++17 power to use a static constexpr data member
51
// without needing an out-of-line definition
52
#if !(defined(__cplusplus) && (__cplusplus >= 201703L))
53
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
54
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
55

56
// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
57
// While there is a conversion from signed to unsigned, it happens at
58
// compiletime, so the compiler wouldn't have to warn indiscriminately, but
59
// could check if the source value actually doesn't fit into the target type
60
// and only warn in those cases.
61
#if defined(__GNUC__) && __GNUC__ > 6
62
#pragma GCC diagnostic push
63
#pragma GCC diagnostic ignored "-Wsign-conversion"
64
#endif
65

66
namespace gsl
67
{
68

69
// implementation details
70
namespace details
71
{
72
    template <class T>
73
    struct is_span_oracle : std::false_type
74
    {
75
    };
76

77
    template <class ElementType, std::size_t Extent>
78
    struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
79
    {
80
    };
81

82
    template <class T>
83
    struct is_span : public is_span_oracle<std::remove_cv_t<T>>
84
    {
85
    };
86

87
    template <class T>
88
    struct is_std_array_oracle : std::false_type
89
    {
90
    };
91

92
    template <class ElementType, std::size_t Extent>
93
    struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
94
    {
95
    };
96

97
    template <class T>
98
    struct is_std_array : is_std_array_oracle<std::remove_cv_t<T>>
99
    {
100
    };
101

102
    template <std::size_t From, std::size_t To>
103
    struct is_allowed_extent_conversion
104
        : std::integral_constant<bool, From == To || To == dynamic_extent>
105
    {
106
    };
107

108
    template <class From, class To>
109
    struct is_allowed_element_type_conversion
110
        : std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
111
    {
112
    };
113

114
    template <class Type>
115
    class span_iterator
116
    {
117
    public:
118
#if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts))
119
        using iterator_concept = std::contiguous_iterator_tag;
120
#endif // __cpp_lib_ranges
121
        using iterator_category = std::random_access_iterator_tag;
122
        using value_type = std::remove_cv_t<Type>;
123
        using difference_type = std::ptrdiff_t;
124
        using pointer = Type*;
125
        using reference = Type&;
126

127
#ifdef _MSC_VER
128
        using _Unchecked_type = pointer;
129
#endif // _MSC_VER
130
        constexpr span_iterator() = default;
131

132
        constexpr span_iterator(pointer begin, pointer end, pointer current)
133
            : begin_(begin), end_(end), current_(current)
134
        {}
135

136
        constexpr operator span_iterator<const Type>() const noexcept
137
        {
138
            return {begin_, end_, current_};
139
        }
140

141
        constexpr reference operator*() const noexcept
142
        {
143
            Expects(begin_ && end_);
144
            Expects(begin_ <= current_ && current_ < end_);
145
            return *current_;
146
        }
147

148
        constexpr pointer operator->() const noexcept
149
        {
150
            Expects(begin_ && end_);
151
            Expects(begin_ <= current_ && current_ < end_);
152
            return current_;
153
        }
154
        constexpr span_iterator& operator++() noexcept
155
        {
156
            Expects(begin_ && current_ && end_);
157
            Expects(current_ < end_);
158
            // clang-format off
159
            GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
160
            // clang-format on
161
            ++current_;
162
            return *this;
163
        }
164

165
        constexpr span_iterator operator++(int) noexcept
166
        {
167
            span_iterator ret = *this;
168
            ++*this;
169
            return ret;
170
        }
171

172
        constexpr span_iterator& operator--() noexcept
173
        {
174
            Expects(begin_ && end_);
175
            Expects(begin_ < current_);
176
            --current_;
177
            return *this;
178
        }
179

180
        constexpr span_iterator operator--(int) noexcept
181
        {
182
            span_iterator ret = *this;
183
            --*this;
184
            return ret;
185
        }
186

187
        constexpr span_iterator& operator+=(const difference_type n) noexcept
188
        {
189
            if (n != 0) Expects(begin_ && current_ && end_);
190
            if (n > 0) Expects(end_ - current_ >= n);
191
            if (n < 0) Expects(current_ - begin_ >= -n);
192
            // clang-format off
193
            GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
194
            // clang-format on
195
            current_ += n;
196
            return *this;
197
        }
198

199
        constexpr span_iterator operator+(const difference_type n) const noexcept
200
        {
201
            span_iterator ret = *this;
202
            ret += n;
203
            return ret;
204
        }
205

206
        friend constexpr span_iterator operator+(const difference_type n,
207
                                                 const span_iterator& rhs) noexcept
208
        {
209
            return rhs + n;
210
        }
211

212
        constexpr span_iterator& operator-=(const difference_type n) noexcept
213
        {
214
            if (n != 0) Expects(begin_ && current_ && end_);
215
            if (n > 0) Expects(current_ - begin_ >= n);
216
            if (n < 0) Expects(end_ - current_ >= -n);
217
            current_ -= n;
218
            return *this;
219
        }
220

221
        constexpr span_iterator operator-(const difference_type n) const noexcept
222
        {
223
            span_iterator ret = *this;
224
            ret -= n;
225
            return ret;
226
        }
227

228
        template <
229
            class Type2,
230
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
231
        constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept
232
        {
233
            Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
234
            return current_ - rhs.current_;
235
        }
236

237
        constexpr reference operator[](const difference_type n) const noexcept
238
        {
239
            return *(*this + n);
240
        }
241

242
        template <
243
            class Type2,
244
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
245
        constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept
246
        {
247
            Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
248
            return current_ == rhs.current_;
249
        }
250

251
        template <
252
            class Type2,
253
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
254
        constexpr bool operator!=(const span_iterator<Type2>& rhs) const noexcept
255
        {
256
            return !(*this == rhs);
257
        }
258

259
        template <
260
            class Type2,
261
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
262
        constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept
263
        {
264
            Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
265
            return current_ < rhs.current_;
266
        }
267

268
        template <
269
            class Type2,
270
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
271
        constexpr bool operator>(const span_iterator<Type2>& rhs) const noexcept
272
        {
273
            return rhs < *this;
274
        }
275

276
        template <
277
            class Type2,
278
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
279
        constexpr bool operator<=(const span_iterator<Type2>& rhs) const noexcept
280
        {
281
            return !(rhs < *this);
282
        }
283

284
        template <
285
            class Type2,
286
            std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
287
        constexpr bool operator>=(const span_iterator<Type2>& rhs) const noexcept
288
        {
289
            return !(*this < rhs);
290
        }
291

292
#ifdef _MSC_VER
293
        // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
294
        // to unwrap span_iterator to a pointer type after a range check in STL
295
        // algorithm calls
296
        friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
297
        { // test that [lhs, rhs) forms a valid range inside an STL algorithm
298
            Expects(lhs.begin_ == rhs.begin_ // range spans have to match
299
                    && lhs.end_ == rhs.end_ &&
300
                    lhs.current_ <= rhs.current_); // range must not be transposed
301
        }
302

303
        constexpr void _Verify_offset(const difference_type n) const noexcept
304
        { // test that *this + n is within the range of this call
305
            if (n != 0) Expects(begin_ && current_ && end_);
306
            if (n > 0) Expects(end_ - current_ >= n);
307
            if (n < 0) Expects(current_ - begin_ >= -n);
308
        }
309

310
        // clang-format off
311
        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
312
        // clang-format on
313
        constexpr pointer _Unwrapped() const noexcept
314
        { // after seeking *this to a high water mark, or using one of the
315
            // _Verify_xxx functions above, unwrap this span_iterator to a raw
316
            // pointer
317
            return current_;
318
        }
319

320
        // Tell the STL that span_iterator should not be unwrapped if it can't
321
        // validate in advance, even in release / optimized builds:
322
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
323
        static constexpr const bool _Unwrap_when_unverified = false;
324
#else
325
        static constexpr bool _Unwrap_when_unverified = false;
326
#endif
327
        // clang-format off
328
        GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
329
        // clang-format on
330
        constexpr void _Seek_to(const pointer p) noexcept
331
        { // adjust the position of *this to previously verified location p
332
            // after _Unwrapped
333
            current_ = p;
334
        }
335
#endif
336

337
        pointer begin_ = nullptr;
338
        pointer end_ = nullptr;
339
        pointer current_ = nullptr;
340

341
        template <typename Ptr>
342
        friend struct std::pointer_traits;
343
    };
344
}} // namespace gsl::details
345

346
namespace std
347
{
348
template <class Type>
349
struct pointer_traits<::gsl::details::span_iterator<Type>>
350
{
351
    using pointer = ::gsl::details::span_iterator<Type>;
352
    using element_type = Type;
353
    using difference_type = ptrdiff_t;
354

355
    static constexpr element_type* to_address(const pointer i) noexcept { return i.current_; }
356
};
357
} // namespace std
358

359
namespace gsl { namespace details {
360
    template <std::size_t Ext>
361
    class extent_type
362
    {
363
    public:
364
        using size_type = std::size_t;
365

366
        constexpr extent_type() noexcept = default;
367

368
        constexpr explicit extent_type(extent_type<dynamic_extent>);
369

370
        constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
371

372
        constexpr size_type size() const noexcept { return Ext; }
373

374
    private:
375
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
376
        static constexpr const size_type size_ = Ext; // static size equal to Ext
377
#else
378
        static constexpr size_type size_ = Ext; // static size equal to Ext
379
#endif
380
    };
381

382
    template <>
383
    class extent_type<dynamic_extent>
384
    {
385
    public:
386
        using size_type = std::size_t;
387

388
        template <size_type Other>
389
        constexpr explicit extent_type(extent_type<Other> ext) : size_(ext.size())
390
        {}
391

392
        constexpr explicit extent_type(size_type size) : size_(size)
393
        {
394
            Expects(size != dynamic_extent);
395
        }
396

397
        constexpr size_type size() const noexcept { return size_; }
398

399
    private:
400
        size_type size_;
401
    };
402

403
    template <std::size_t Ext>
404
    constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
405
    {
406
        Expects(ext.size() == Ext);
407
    }
408

409
    template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
410
    struct calculate_subspan_type
411
    {
412
        using type = span<ElementType, Count != dynamic_extent
413
                                           ? Count
414
                                           : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
415
    };
416
} // namespace details
417

418
// [span], class template span
419
template <class ElementType, std::size_t Extent>
420
class span
421
{
422
public:
423
    // constants and types
424
    using element_type = ElementType;
425
    using value_type = std::remove_cv_t<ElementType>;
426
    using size_type = std::size_t;
427
    using pointer = element_type*;
428
    using const_pointer = const element_type*;
429
    using reference = element_type&;
430
    using const_reference = const element_type&;
431
    using difference_type = std::ptrdiff_t;
432

433
    using iterator = details::span_iterator<ElementType>;
434
    using reverse_iterator = std::reverse_iterator<iterator>;
435

436
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
437
    static constexpr const size_type extent{Extent};
438
#else
439
    static constexpr size_type extent{Extent};
440
#endif
441

442
    // [span.cons], span constructors, copy, assignment, and destructor
443
    template <bool Dependent = false,
444
              // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent == 0 || Extent
445
              // == dynamic_extent>" SFINAE, since "std::enable_if_t<Extent == 0 || Extent ==
446
              // dynamic_extent>" is ill-formed when Extent is greater than 0.
447
              class = std::enable_if_t<(Dependent ||
448
                                        details::is_allowed_extent_conversion<0, Extent>::value)>>
449
    constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
450
    {}
451

452
    template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
453
    constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
454
    {
455
        Expects(count == Extent);
456
    }
457

458
    template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
459
    constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
460
    {}
461

462
    template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
463
    constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
464
        : storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
465
    {
466
        Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
467
    }
468

469
    template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
470
    constexpr span(pointer firstElem, pointer lastElem) noexcept
471
        : storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
472
    {}
473

474
    template <std::size_t N,
475
              std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
476
    constexpr span(element_type (&arr)[N]) noexcept
477
        : storage_(KnownNotNull{arr}, details::extent_type<N>())
478
    {}
479

480
    template <
481
        class T, std::size_t N,
482
        std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
483
                          details::is_allowed_element_type_conversion<T, element_type>::value),
484
                         int> = 0>
485
    constexpr span(std::array<T, N>& arr) noexcept
486
        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
487
    {}
488

489
    template <class T, std::size_t N,
490
              std::enable_if_t<
491
                  (details::is_allowed_extent_conversion<N, Extent>::value &&
492
                   details::is_allowed_element_type_conversion<const T, element_type>::value),
493
                  int> = 0>
494
    constexpr span(const std::array<T, N>& arr) noexcept
495
        : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
496
    {}
497

498
    // NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
499
    // requirement on Container to be a contiguous sequence container.
500
    template <std::size_t MyExtent = Extent, class Container,
501
              std::enable_if_t<
502
                  MyExtent != dynamic_extent && !details::is_span<Container>::value &&
503
                      !details::is_std_array<Container>::value &&
504
                      std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
505
                      std::is_convertible<
506
                          std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
507
                          element_type (*)[]>::value,
508
                  int> = 0>
509
    constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
510
    {}
511

512
    template <std::size_t MyExtent = Extent, class Container,
513
              std::enable_if_t<
514
                  MyExtent == dynamic_extent && !details::is_span<Container>::value &&
515
                      !details::is_std_array<Container>::value &&
516
                      std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
517
                      std::is_convertible<
518
                          std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
519
                          element_type (*)[]>::value,
520
                  int> = 0>
521
    constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
522
    {}
523

524
    template <
525
        std::size_t MyExtent = Extent, class Container,
526
        std::enable_if_t<
527
            MyExtent != dynamic_extent && std::is_const<element_type>::value &&
528
                !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
529
                std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
530
                std::is_convertible<
531
                    std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
532
                    element_type (*)[]>::value,
533
            int> = 0>
534
    constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size())
535
    {}
536

537
    template <
538
        std::size_t MyExtent = Extent, class Container,
539
        std::enable_if_t<
540
            MyExtent == dynamic_extent && std::is_const<element_type>::value &&
541
                !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
542
                std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
543
                std::is_convertible<
544
                    std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
545
                    element_type (*)[]>::value,
546
            int> = 0>
547
    constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
548
    {}
549

550
    constexpr span(const span& other) noexcept = default;
551

552
    template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
553
              std::enable_if_t<(MyExtent == dynamic_extent || MyExtent == OtherExtent) &&
554
                                   details::is_allowed_element_type_conversion<OtherElementType,
555
                                                                               element_type>::value,
556
                               int> = 0>
557
    constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
558
        : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
559
    {}
560

561
    template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
562
              std::enable_if_t<MyExtent != dynamic_extent && OtherExtent == dynamic_extent &&
563
                                   details::is_allowed_element_type_conversion<OtherElementType,
564
                                                                               element_type>::value,
565
                               int> = 0>
566
    constexpr explicit span(const span<OtherElementType, OtherExtent>& other) noexcept
567
        : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
568
    {}
569

570
    ~span() noexcept = default;
571
    constexpr span& operator=(const span& other) noexcept = default;
572

573
    // [span.sub], span subviews
574
    template <std::size_t Count>
575
    constexpr span<element_type, Count> first() const noexcept
576
    {
577
        Expects(Count <= size());
578
        return span<element_type, Count>{data(), Count};
579
    }
580

581
    template <std::size_t Count>
582
    // clang-format off
583
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
584
        // clang-format on
585
        constexpr span<element_type, Count> last() const noexcept
586
    {
587
        Expects(Count <= size());
588
        return span<element_type, Count>{data() + (size() - Count), Count};
589
    }
590

591
    template <std::size_t Offset, std::size_t Count = dynamic_extent>
592
    // clang-format off
593
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
594
        // clang-format on
595
        constexpr auto subspan() const noexcept ->
596
        typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
597
    {
598
        Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
599
        using type =
600
            typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
601
        return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
602
    }
603

604
    constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
605
    {
606
        Expects(count <= size());
607
        return {data(), count};
608
    }
609

610
    constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept
611
    {
612
        Expects(count <= size());
613
        return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
614
    }
615

616
    constexpr span<element_type, dynamic_extent>
617
    subspan(size_type offset, size_type count = dynamic_extent) const noexcept
618
    {
619
        return make_subspan(offset, count, subspan_selector<Extent>{});
620
    }
621

622
    // [span.obs], span observers
623
    constexpr size_type size() const noexcept { return storage_.size(); }
624

625
    constexpr size_type size_bytes() const noexcept
626
    {
627
        Expects(size() < dynamic_extent / sizeof(element_type));
628
        return size() * sizeof(element_type);
629
    }
630

631
    constexpr bool empty() const noexcept { return size() == 0; }
632

633
    // [span.elem], span element access
634
    // clang-format off
635
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
636
    // clang-format on
637
    constexpr reference operator[](size_type idx) const noexcept
638
    {
639
        Expects(idx < size());
640
        return data()[idx];
641
    }
642

643
    constexpr reference front() const noexcept
644
    {
645
        Expects(size() > 0);
646
        return data()[0];
647
    }
648

649
    constexpr reference back() const noexcept
650
    {
651
        Expects(size() > 0);
652
        return data()[size() - 1];
653
    }
654

655
    constexpr pointer data() const noexcept { return storage_.data(); }
656

657
    // [span.iter], span iterator support
658
    constexpr iterator begin() const noexcept
659
    {
660
        const auto data = storage_.data();
661
        // clang-format off
662
        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
663
        // clang-format on
664
        return {data, data + size(), data};
665
    }
666

667
    constexpr iterator end() const noexcept
668
    {
669
        const auto data = storage_.data();
670
        // clang-format off
671
        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
672
        // clang-format on
673
        const auto endData = data + storage_.size();
674
        return {data, endData, endData};
675
    }
676

677
    constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
678
    constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
679

680
#ifdef _MSC_VER
681
    // Tell MSVC how to unwrap spans in range-based-for
682
    constexpr pointer _Unchecked_begin() const noexcept { return data(); }
683
    constexpr pointer _Unchecked_end() const noexcept
684
    {
685
        // clang-format off
686
        GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
687
        // clang-format on
688
        return data() + size();
689
    }
690
#endif // _MSC_VER
691

692
private:
693
    // Needed to remove unnecessary null check in subspans
694
    struct KnownNotNull
695
    {
696
        pointer p;
697
    };
698

699
    // this implementation detail class lets us take advantage of the
700
    // empty base class optimization to pay for only storage of a single
701
    // pointer in the case of fixed-size spans
702
    template <class ExtentType>
703
    class storage_type : public ExtentType
704
    {
705
    public:
706
        // KnownNotNull parameter is needed to remove unnecessary null check
707
        // in subspans and constructors from arrays
708
        template <class OtherExtentType>
709
        constexpr storage_type(KnownNotNull data, OtherExtentType ext)
710
            : ExtentType(ext), data_(data.p)
711
        {}
712

713
        template <class OtherExtentType>
714
        constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
715
        {
716
            Expects(data || ExtentType::size() == 0);
717
        }
718

719
        constexpr pointer data() const noexcept { return data_; }
720

721
    private:
722
        pointer data_;
723
    };
724

725
    storage_type<details::extent_type<Extent>> storage_;
726

727
    // The rest is needed to remove unnecessary null check
728
    // in subspans and constructors from arrays
729
    constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {}
730

731
    template <std::size_t CallerExtent>
732
    class subspan_selector
733
    {
734
    };
735

736
    template <std::size_t CallerExtent>
737
    constexpr span<element_type, dynamic_extent>
738
    make_subspan(size_type offset, size_type count, subspan_selector<CallerExtent>) const noexcept
739
    {
740
        const span<element_type, dynamic_extent> tmp(*this);
741
        return tmp.subspan(offset, count);
742
    }
743

744
    // clang-format off
745
    GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
746
    // clang-format on
747
    constexpr span<element_type, dynamic_extent>
748
    make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
749
    {
750
        Expects(size() >= offset);
751

752
        if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
753

754
        Expects(size() - offset >= count);
755
        return {KnownNotNull{data() + offset}, count};
756
    }
757
};
758

759
#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
760

761
// Deduction Guides
762
template <class Type, std::size_t Extent>
763
span(Type (&)[Extent]) -> span<Type, Extent>;
764

765
template <class Type, std::size_t Size>
766
span(std::array<Type, Size>&) -> span<Type, Size>;
767

768
template <class Type, std::size_t Size>
769
span(const std::array<Type, Size>&) -> span<const Type, Size>;
770

771
template <class Container,
772
          class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
773
span(Container&) -> span<Element>;
774

775
template <class Container,
776
          class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
777
span(const Container&) -> span<Element>;
778

779
#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
780

781
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
782
template <class ElementType, std::size_t Extent>
783
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
784
#endif
785

786
namespace details
787
{
788
    // if we only supported compilers with good constexpr support then
789
    // this pair of classes could collapse down to a constexpr function
790

791
    // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
792
    // constexpr
793
    // and so will fail compilation of the template
794
    template <class ElementType, std::size_t Extent>
795
    struct calculate_byte_size : std::integral_constant<std::size_t, sizeof(ElementType) * Extent>
796
    {
797
        static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big.");
798
    };
799

800
    template <class ElementType>
801
    struct calculate_byte_size<ElementType, dynamic_extent>
802
        : std::integral_constant<std::size_t, dynamic_extent>
803
    {
804
    };
805
} // namespace details
806

807
// [span.objectrep], views of object representation
808
template <class ElementType, std::size_t Extent>
809
span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
810
as_bytes(span<ElementType, Extent> s) noexcept
811
{
812
    using type = span<const byte, details::calculate_byte_size<ElementType, Extent>::value>;
813

814
    // clang-format off
815
    GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
816
    // clang-format on
817
    return type{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
818
}
819

820
template <class ElementType, std::size_t Extent,
821
          std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
822
span<byte, details::calculate_byte_size<ElementType, Extent>::value>
823
as_writable_bytes(span<ElementType, Extent> s) noexcept
824
{
825
    using type = span<byte, details::calculate_byte_size<ElementType, Extent>::value>;
826

827
    // clang-format off
828
    GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
829
    // clang-format on
830
    return type{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
831
}
832

833
} // namespace gsl
834

835
#if defined(_MSC_VER) && !defined(__clang__)
836

837
#pragma warning(pop)
838
#endif // _MSC_VER
839

840
#if defined(__GNUC__) && __GNUC__ > 6
841
#pragma GCC diagnostic pop
842
#endif // __GNUC__ > 6
843

844
#endif // GSL_SPAN_H