• 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#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
59namespace gsl
60{
61
62// [views.constants], constants
63constexpr const std::ptrdiff_t dynamic_extent = -1;
64
65template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
66class span;
67
68// implementation details
69namespace 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
316template <class ElementType, std::ptrdiff_t Extent>
317class span
318{
319public:
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
512private:
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
536template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
537inline 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
543template <class ElementType, std::ptrdiff_t Extent>
544inline constexpr bool operator!=(const span<ElementType, Extent>& l,
545                                 const span<ElementType, Extent>& r)
546{
547    return !(l == r);
548}
549
550template <class ElementType, std::ptrdiff_t Extent>
551inline 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
557template <class ElementType, std::ptrdiff_t Extent>
558inline constexpr bool operator<=(const span<ElementType, Extent>& l,
559                                 const span<ElementType, Extent>& r)
560{
561    return !(l > r);
562}
563
564template <class ElementType, std::ptrdiff_t Extent>
565inline constexpr bool operator>(const span<ElementType, Extent>& l,
566                                const span<ElementType, Extent>& r)
567{
568    return r < l;
569}
570
571template <class ElementType, std::ptrdiff_t Extent>
572inline constexpr bool operator>=(const span<ElementType, Extent>& l,
573                                 const span<ElementType, Extent>& r)
574{
575    return !(l < r);
576}
577
578namespace 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
602template <class ElementType, std::ptrdiff_t Extent>
603span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
604as_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT
605{
606    return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
607}
608
609template <class ElementType, std::ptrdiff_t Extent,
610          class = std::enable_if_t<!std::is_const<ElementType>::value>>
611span<byte, details::calculate_byte_size<ElementType, Extent>::value>
612as_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//
620template <class ElementType>
621span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::index_type count)
622{
623    return span<ElementType>(ptr, count);
624}
625
626template <class ElementType>
627span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem)
628{
629    return span<ElementType>(firstElem, lastElem);
630}
631
632template <class ElementType, std::size_t N>
633span<ElementType, N> make_span(ElementType (&arr)[N])
634{
635    return span<ElementType, N>(arr);
636}
637
638template <class Container>
639span<typename Container::value_type> make_span(Container& cont)
640{
641    return span<typename Container::value_type>(cont);
642}
643
644template <class Container>
645span<const typename Container::value_type> make_span(const Container& cont)
646{
647    return span<const typename Container::value_type>(cont);
648}
649
650template <class Ptr>
651span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count)
652{
653    return span<typename Ptr::element_type>(cont, count);
654}
655
656template <class Ptr>
657span<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
663template <class ElementType, std::ptrdiff_t Extent>
664inline 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