123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
- //
- // This code is licensed under the MIT License (MIT).
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- ///////////////////////////////////////////////////////////////////////////////
- #ifndef GSL_SPAN_H
- #define GSL_SPAN_H
- #include <gsl/gsl_assert> // for Expects
- #include <gsl/gsl_byte> // for byte
- #include <array> // for array
- #include <cstddef> // for ptrdiff_t, size_t, nullptr_t
- #include <iterator> // for reverse_iterator, distance, random_access_...
- #include <type_traits> // for enable_if_t, declval, is_convertible, inte...
- #if defined(_MSC_VER) && !defined(__clang__)
- #pragma warning(push)
- // turn off some warnings that are noisy about our Expects statements
- #pragma warning(disable : 4127) // conditional expression is constant
- #pragma warning( \
- disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
- #pragma warning(disable : 4702) // unreachable code
- // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
- #pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
- #pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
- #endif // _MSC_VER
- // See if we have enough C++17 power to use a static constexpr data member
- // without needing an out-of-line definition
- #if !(defined(__cplusplus) && (__cplusplus >= 201703L))
- #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
- #endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
- // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
- // While there is a conversion from signed to unsigned, it happens at
- // compiletime, so the compiler wouldn't have to warn indiscriminately, but
- // could check if the source value actually doesn't fit into the target type
- // and only warn in those cases.
- #if defined(__GNUC__) && __GNUC__ > 6
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wsign-conversion"
- #endif
- namespace gsl
- {
- // [views.constants], constants
- constexpr const std::size_t dynamic_extent = static_cast<std::size_t>(-1);
- template <class ElementType, std::size_t Extent = dynamic_extent>
- class span;
- // implementation details
- namespace details
- {
- template <class T>
- struct is_span_oracle : std::false_type
- {
- };
- template <class ElementType, std::size_t Extent>
- struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
- {
- };
- template <class T>
- struct is_span : public is_span_oracle<std::remove_cv_t<T>>
- {
- };
- template <class T>
- struct is_std_array_oracle : std::false_type
- {
- };
- template <class ElementType, std::size_t Extent>
- struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
- {
- };
- template <class T>
- struct is_std_array : is_std_array_oracle<std::remove_cv_t<T>>
- {
- };
- template <std::size_t From, std::size_t To>
- struct is_allowed_extent_conversion
- : std::integral_constant<bool, From == To || To == gsl::dynamic_extent>
- {
- };
- template <class From, class To>
- struct is_allowed_element_type_conversion
- : std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
- {
- };
- template <class Type>
- class span_iterator
- {
- public:
- using iterator_category = std::random_access_iterator_tag;
- using value_type = std::remove_cv_t<Type>;
- using difference_type = std::ptrdiff_t;
- using pointer = Type*;
- using reference = Type&;
- #ifdef _MSC_VER
- using _Unchecked_type = pointer;
- #endif // _MSC_VER
- constexpr span_iterator() = default;
- constexpr span_iterator(pointer begin, pointer end, pointer current)
- : begin_(begin), end_(end), current_(current)
- {}
- constexpr operator span_iterator<const Type>() const noexcept
- {
- return {begin_, end_, current_};
- }
- constexpr reference operator*() const noexcept
- {
- Expects(begin_ && end_);
- Expects(begin_ <= current_ && current_ < end_);
- return *current_;
- }
- constexpr pointer operator->() const noexcept
- {
- Expects(begin_ && end_);
- Expects(begin_ <= current_ && current_ < end_);
- return current_;
- }
- constexpr span_iterator& operator++() noexcept
- {
- Expects(begin_ && current_ && end_);
- Expects(current_ < end_);
- ++current_;
- return *this;
- }
- constexpr span_iterator operator++(int) noexcept
- {
- span_iterator ret = *this;
- ++*this;
- return ret;
- }
- constexpr span_iterator& operator--() noexcept
- {
- Expects(begin_ && end_);
- Expects(begin_ < current_);
- --current_;
- return *this;
- }
- constexpr span_iterator operator--(int) noexcept
- {
- span_iterator ret = *this;
- --*this;
- return ret;
- }
- constexpr span_iterator& operator+=(const difference_type n) noexcept
- {
- if (n != 0) Expects(begin_ && current_ && end_);
- if (n > 0) Expects(end_ - current_ >= n);
- if (n < 0) Expects(current_ - begin_ >= -n);
- current_ += n;
- return *this;
- }
- constexpr span_iterator operator+(const difference_type n) const noexcept
- {
- span_iterator ret = *this;
- ret += n;
- return ret;
- }
- friend constexpr span_iterator operator+(const difference_type n,
- const span_iterator& rhs) noexcept
- {
- return rhs + n;
- }
- constexpr span_iterator& operator-=(const difference_type n) noexcept
- {
- if (n != 0) Expects(begin_ && current_ && end_);
- if (n > 0) Expects(current_ - begin_ >= n);
- if (n < 0) Expects(end_ - current_ >= -n);
- current_ -= n;
- return *this;
- }
- constexpr span_iterator operator-(const difference_type n) const noexcept
- {
- span_iterator ret = *this;
- ret -= n;
- return ret;
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept
- {
- Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
- return current_ - rhs.current_;
- }
- constexpr reference operator[](const difference_type n) const noexcept
- {
- return *(*this + n);
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept
- {
- Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
- return current_ == rhs.current_;
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr bool operator!=(const span_iterator<Type2>& rhs) const noexcept
- {
- return !(*this == rhs);
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept
- {
- Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
- return current_ < rhs.current_;
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr bool operator>(const span_iterator<Type2>& rhs) const noexcept
- {
- return rhs < *this;
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr bool operator<=(const span_iterator<Type2>& rhs) const noexcept
- {
- return !(rhs < *this);
- }
- template <
- class Type2,
- std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
- constexpr bool operator>=(const span_iterator<Type2>& rhs) const noexcept
- {
- return !(*this < rhs);
- }
- #ifdef _MSC_VER
- // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
- // to unwrap span_iterator to a pointer type after a range check in STL
- // algorithm calls
- friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
- { // test that [lhs, rhs) forms a valid range inside an STL algorithm
- Expects(lhs.begin_ == rhs.begin_ // range spans have to match
- && lhs.end_ == rhs.end_ &&
- lhs.current_ <= rhs.current_); // range must not be transposed
- }
- constexpr void _Verify_offset(const difference_type n) const noexcept
- { // test that *this + n is within the range of this call
- if (n != 0) Expects(begin_ && current_ && end_);
- if (n > 0) Expects(end_ - current_ >= n);
- if (n < 0) Expects(current_ - begin_ >= -n);
- }
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- constexpr pointer _Unwrapped() const noexcept
- { // after seeking *this to a high water mark, or using one of the
- // _Verify_xxx functions above, unwrap this span_iterator to a raw
- // pointer
- return current_;
- }
- // Tell the STL that span_iterator should not be unwrapped if it can't
- // validate in advance, even in release / optimized builds:
- #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
- static constexpr const bool _Unwrap_when_unverified = false;
- #else
- static constexpr bool _Unwrap_when_unverified = false;
- #endif
- // clang-format off
- GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
- // clang-format on
- constexpr void _Seek_to(const pointer p) noexcept
- { // adjust the position of *this to previously verified location p
- // after _Unwrapped
- current_ = p;
- }
- #endif
- pointer begin_ = nullptr;
- pointer end_ = nullptr;
- pointer current_ = nullptr;
- };
- template <std::size_t Ext>
- class extent_type
- {
- public:
- using size_type = std::size_t;
- constexpr extent_type() noexcept = default;
- constexpr explicit extent_type(extent_type<dynamic_extent>);
- constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
- constexpr size_type size() const noexcept { return Ext; }
- private:
- #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
- static constexpr const size_type size_ = Ext; // static size equal to Ext
- #else
- static constexpr size_type size_ = Ext; // static size equal to Ext
- #endif
- };
- template <>
- class extent_type<dynamic_extent>
- {
- public:
- using size_type = std::size_t;
- template <size_type Other>
- constexpr explicit extent_type(extent_type<Other> ext) : size_(ext.size())
- {}
- constexpr explicit extent_type(size_type size) : size_(size)
- {
- Expects(size != dynamic_extent);
- }
- constexpr size_type size() const noexcept { return size_; }
- private:
- size_type size_;
- };
- template <std::size_t Ext>
- constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
- {
- Expects(ext.size() == Ext);
- }
- template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
- struct calculate_subspan_type
- {
- using type = span<ElementType, Count != dynamic_extent
- ? Count
- : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
- };
- } // namespace details
- // [span], class template span
- template <class ElementType, std::size_t Extent>
- class span
- {
- public:
- // constants and types
- using element_type = ElementType;
- using value_type = std::remove_cv_t<ElementType>;
- using size_type = std::size_t;
- using pointer = element_type*;
- using const_pointer = const element_type*;
- using reference = element_type&;
- using const_reference = const element_type&;
- using difference_type = std::ptrdiff_t;
- using iterator = details::span_iterator<ElementType>;
- using reverse_iterator = std::reverse_iterator<iterator>;
- #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
- static constexpr const size_type extent{Extent};
- #else
- static constexpr size_type extent{Extent};
- #endif
- // [span.cons], span constructors, copy, assignment, and destructor
- template <bool Dependent = false,
- // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent == 0 || Extent
- // == dynamic_extent>" SFINAE, since "std::enable_if_t<Extent == 0 || Extent ==
- // dynamic_extent>" is ill-formed when Extent is greater than 0.
- class = std::enable_if_t<(Dependent ||
- details::is_allowed_extent_conversion<0, Extent>::value)>>
- constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
- {}
- template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != gsl::dynamic_extent, int> = 0>
- constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
- {
- Expects(count == Extent);
- }
- template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == gsl::dynamic_extent, int> = 0>
- constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
- {}
- template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != gsl::dynamic_extent, int> = 0>
- constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
- : storage_(firstElem, static_cast<std::size_t>(lastElem - firstElem))
- {
- Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
- }
- template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == gsl::dynamic_extent, int> = 0>
- constexpr span(pointer firstElem, pointer lastElem) noexcept
- : storage_(firstElem, static_cast<std::size_t>(lastElem - firstElem))
- {}
- template <std::size_t N,
- std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
- constexpr span(element_type (&arr)[N]) noexcept
- : storage_(KnownNotNull{arr + 0}, details::extent_type<N>())
- {}
- template <
- class T, std::size_t N,
- std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
- details::is_allowed_element_type_conversion<T, element_type>::value),
- int> = 0>
- constexpr span(std::array<T, N>& arr) noexcept
- : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
- {}
- template <class T, std::size_t N,
- std::enable_if_t<
- (details::is_allowed_extent_conversion<N, Extent>::value &&
- details::is_allowed_element_type_conversion<const T, element_type>::value),
- int> = 0>
- constexpr span(const std::array<T, N>& arr) noexcept
- : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
- {}
- // NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
- // requirement on Container to be a contiguous sequence container.
- template <std::size_t MyExtent = Extent, class Container,
- std::enable_if_t<
- MyExtent != dynamic_extent &&
- !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
- std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
- std::is_convertible<
- std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
- element_type (*)[]>::value, int> = 0>
- constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
- {}
- template <std::size_t MyExtent = Extent, class Container,
- std::enable_if_t<
- MyExtent == dynamic_extent &&
- !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
- std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
- std::is_convertible<
- std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
- element_type (*)[]>::value, int> = 0>
- constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
- {}
- template <std::size_t MyExtent = Extent, class Container,
- std::enable_if_t<
- MyExtent != dynamic_extent &&
- std::is_const<element_type>::value && !details::is_span<Container>::value &&
- !details::is_std_array<Container>::value &&
- std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
- std::is_convertible<std::remove_pointer_t<
- decltype(std::declval<const Container&>().data())> (*)[],
- element_type (*)[]>::value, int> = 0>
- constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size())
- {}
- template <std::size_t MyExtent = Extent, class Container,
- std::enable_if_t<
- MyExtent == dynamic_extent &&
- std::is_const<element_type>::value && !details::is_span<Container>::value &&
- !details::is_std_array<Container>::value &&
- std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
- std::is_convertible<std::remove_pointer_t<
- decltype(std::declval<const Container&>().data())> (*)[],
- element_type (*)[]>::value, int> = 0>
- constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
- {}
- constexpr span(const span& other) noexcept = default;
- template <
- class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
- std::enable_if_t<
- (MyExtent == dynamic_extent || MyExtent == OtherExtent) &&
- details::is_allowed_element_type_conversion<OtherElementType, element_type>::value, int> = 0>
- constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
- : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
- {}
- template <
- class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
- std::enable_if_t<
- MyExtent != dynamic_extent && OtherExtent == dynamic_extent &&
- details::is_allowed_element_type_conversion<OtherElementType, element_type>::value, int> = 0>
- constexpr explicit span(const span<OtherElementType, OtherExtent>& other) noexcept
- : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
- {}
- ~span() noexcept = default;
- constexpr span& operator=(const span& other) noexcept = default;
- // [span.sub], span subviews
- template <std::size_t Count>
- constexpr span<element_type, Count> first() const noexcept
- {
- Expects(Count <= size());
- return span<element_type, Count>{data(), Count};
- }
- template <std::size_t Count>
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- constexpr span<element_type, Count> last() const noexcept
- {
- Expects(Count <= size());
- return span<element_type, Count>{data() + (size() - Count), Count};
- }
- template <std::size_t Offset, std::size_t Count = dynamic_extent>
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- constexpr auto subspan() const noexcept ->
- typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
- {
- Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
- using type = typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
- return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
- }
- constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
- {
- Expects(count <= size());
- return {data(), count};
- }
- constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept
- {
- Expects(count <= size());
- return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
- }
- constexpr span<element_type, dynamic_extent> subspan(size_type offset,
- size_type count = dynamic_extent) const
- noexcept
- {
- return make_subspan(offset, count, subspan_selector<Extent>{});
- }
- // [span.obs], span observers
- constexpr size_type size() const noexcept { return storage_.size(); }
- constexpr size_type size_bytes() const noexcept
- {
- Expects(size() < dynamic_extent / sizeof(element_type));
- return size() * sizeof(element_type);
- }
- constexpr bool empty() const noexcept { return size() == 0; }
- // [span.elem], span element access
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- constexpr reference operator[](size_type idx) const noexcept
- {
- Expects(idx < size());
- return data()[idx];
- }
- constexpr reference front() const noexcept
- {
- Expects(size() > 0);
- return data()[0];
- }
- constexpr reference back() const noexcept
- {
- Expects(size() > 0);
- return data()[size() - 1];
- }
- constexpr pointer data() const noexcept { return storage_.data(); }
- // [span.iter], span iterator support
- constexpr iterator begin() const noexcept
- {
- const auto data = storage_.data();
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- return {data, data + size(), data};
- }
- constexpr iterator end() const noexcept
- {
- const auto data = storage_.data();
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- const auto endData = data + storage_.size();
- return {data, endData, endData};
- }
- constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
- constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
- #ifdef _MSC_VER
- // Tell MSVC how to unwrap spans in range-based-for
- constexpr pointer _Unchecked_begin() const noexcept { return data(); }
- constexpr pointer _Unchecked_end() const noexcept
- {
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- return data() + size();
- }
- #endif // _MSC_VER
- private:
- // Needed to remove unnecessary null check in subspans
- struct KnownNotNull
- {
- pointer p;
- };
- // this implementation detail class lets us take advantage of the
- // empty base class optimization to pay for only storage of a single
- // pointer in the case of fixed-size spans
- template <class ExtentType>
- class storage_type : public ExtentType
- {
- public:
- // KnownNotNull parameter is needed to remove unnecessary null check
- // in subspans and constructors from arrays
- template <class OtherExtentType>
- constexpr storage_type(KnownNotNull data, OtherExtentType ext)
- : ExtentType(ext), data_(data.p)
- {
- Expects(ExtentType::size() != dynamic_extent);
- }
- template <class OtherExtentType>
- constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
- {
- Expects(ExtentType::size() != dynamic_extent);
- Expects(data || ExtentType::size() == 0);
- }
- constexpr pointer data() const noexcept { return data_; }
- private:
- pointer data_;
- };
- storage_type<details::extent_type<Extent>> storage_;
- // The rest is needed to remove unnecessary null check
- // in subspans and constructors from arrays
- constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {}
- template <std::size_t CallerExtent>
- class subspan_selector
- {
- };
- template <std::size_t CallerExtent>
- constexpr span<element_type, dynamic_extent> make_subspan(size_type offset, size_type count,
- subspan_selector<CallerExtent>) const
- noexcept
- {
- const span<element_type, dynamic_extent> tmp(*this);
- return tmp.subspan(offset, count);
- }
- // clang-format off
- GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
- // clang-format on
- constexpr span<element_type, dynamic_extent>
- make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
- {
- Expects(size() >= offset);
- if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
- Expects(size() - offset >= count);
- return {KnownNotNull{data() + offset}, count};
- }
- };
- #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
- // Deduction Guides
- template <class Type, std::size_t Extent>
- span(Type (&)[Extent])->span<Type, Extent>;
- template <class Type, std::size_t Size>
- span(std::array<Type, Size>&)->span<Type, Size>;
- template <class Type, std::size_t Size>
- span(const std::array<Type, Size>&)->span<const Type, Size>;
- template <class Container,
- class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
- span(Container&)->span<Element>;
- template <class Container,
- class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
- span(const Container&)->span<Element>;
- #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
- #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
- template <class ElementType, std::size_t Extent>
- constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
- #endif
- namespace details
- {
- // if we only supported compilers with good constexpr support then
- // this pair of classes could collapse down to a constexpr function
- // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
- // constexpr
- // and so will fail compilation of the template
- template <class ElementType, std::size_t Extent>
- struct calculate_byte_size : std::integral_constant<std::size_t, sizeof(ElementType) * Extent>
- {
- static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big.");
- };
- template <class ElementType>
- struct calculate_byte_size<ElementType, dynamic_extent>
- : std::integral_constant<std::size_t, dynamic_extent>
- {
- };
- } // namespace details
- // [span.objectrep], views of object representation
- template <class ElementType, std::size_t Extent>
- span<const byte, details::calculate_byte_size<ElementType, Extent>::value>
- as_bytes(span<ElementType, Extent> s) noexcept
- {
- using type = span<const byte, details::calculate_byte_size<ElementType, Extent>::value>;
- // clang-format off
- GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
- // clang-format on
- return type{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
- }
- template <class ElementType, std::size_t Extent,
- std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
- span<byte, details::calculate_byte_size<ElementType, Extent>::value>
- as_writable_bytes(span<ElementType, Extent> s) noexcept
- {
- using type = span<byte, details::calculate_byte_size<ElementType, Extent>::value>;
- // clang-format off
- GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
- // clang-format on
- return type{reinterpret_cast<byte*>(s.data()), s.size_bytes()};
- }
- } // namespace gsl
- #if defined(_MSC_VER) && !defined(__clang__)
- #pragma warning(pop)
- #endif // _MSC_VER
- #if defined(__GNUC__) && __GNUC__ > 6
- #pragma GCC diagnostic pop
- #endif // __GNUC__ > 6
- #endif // GSL_SPAN_H
|