/// \file // Range v3 library // // Copyright Casey Carter 2016-2017 // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_VIEW_SPAN_HPP #define RANGES_V3_VIEW_SPAN_HPP #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { using span_index_t = std::ptrdiff_t; } // namespace detail /// \endcond constexpr detail::span_index_t dynamic_extent = -1; /// \cond namespace detail { template constexpr auto narrow_cast(From from) noexcept -> CPP_ret(To)( // requires integral && integral) { using C = common_type_t; return RANGES_EXPECT((from > 0) == (static_cast(from) > 0)), RANGES_EXPECT(static_cast(from) == static_cast(static_cast(from))), static_cast(from); } template constexpr span_index_t byte_size(span_index_t n) noexcept { return n == dynamic_extent ? dynamic_extent : (RANGES_EXPECT(n >= 0), RANGES_EXPECT(narrow_cast(n) <= PTRDIFF_MAX / sizeof(T)), n * narrow_cast(sizeof(T))); } template struct span_extent { CPP_assert(N >= 0); constexpr span_extent() noexcept = default; constexpr span_extent(span_index_t size) noexcept // this constructor does nothing, the delegation exists only // to provide a place for the contract check expression. : span_extent{(RANGES_EXPECT(size == N), tag{})} {} constexpr span_index_t size() const noexcept { return N; } private: struct tag {}; constexpr span_extent(tag) noexcept {} }; template<> struct span_extent { span_extent() = default; constexpr span_extent(span_index_t size) noexcept : size_{((void)RANGES_EXPECT(size >= 0), size)} {} constexpr span_index_t size() const noexcept { return size_; } private: span_index_t size_ = 0; }; constexpr span_index_t subspan_extent(span_index_t Extent, span_index_t Offset, span_index_t Count) noexcept { return Count == dynamic_extent && Extent != dynamic_extent ? Extent - Offset : Count; } } // namespace detail // clang-format off CPP_def ( template(typename Rng, typename T) concept span_compatible_range, sized_range && contiguous_range && detail::is_convertible< detail::element_t(*)[], T(*)[]>::value ); CPP_def ( template(typename Rng, detail::span_index_t N) (concept span_dynamic_conversion)(Rng, N), N == dynamic_extent || range_cardinality::value < cardinality() ); CPP_def ( template(typename Rng, detail::span_index_t N) (concept span_static_conversion)(Rng, N), N != dynamic_extent && range_cardinality::value == N ); // clang-format on /// \endcond template struct RANGES_EMPTY_BASES span : public view_interface< span, (N == dynamic_extent ? finite : static_cast(N))> , public detail::span_extent { CPP_assert(std::is_object::value); using element_type = T; using value_type = meta::_t>; using index_type = detail::span_index_t; using difference_type = index_type; using pointer = T *; using reference = T &; using iterator = T *; using reverse_iterator = ranges::reverse_iterator; static constexpr index_type extent = N; constexpr span() noexcept = default; constexpr span(pointer ptr, index_type cnt) noexcept : detail::span_extent{(RANGES_EXPECT(cnt >= 0), cnt)} , data_{(RANGES_EXPECT(0 == cnt || ptr != nullptr), ptr)} {} template // Artificially templatize so that the other // constructor is preferred for {ptr, 0} constexpr span(pointer first, pointer last) noexcept : span{first, last - first} {} CPP_template(typename Rng)( // requires(!defer::same_as>) && defer::span_compatible_range && defer::span_dynamic_conversion) // constexpr span(Rng && rng) noexcept(noexcept(ranges::data(rng), ranges::size(rng))) : span{ranges::data(rng), detail::narrow_cast(ranges::size(rng))} {} CPP_template(typename Rng)( // requires(!defer::same_as>) && defer::span_compatible_range && defer::span_static_conversion) // constexpr span(Rng && rng) noexcept(noexcept(ranges::data(rng))) : span{ranges::data(rng), N} {} template constexpr span first() const noexcept { static_assert(Count >= 0, "Count of elements to extract cannot be negative."); static_assert( N == dynamic_extent || Count <= N, "Count of elements to extract must be less than the static span extent."); return RANGES_EXPECT(Count <= size()), RANGES_EXPECT(Count == 0 || data_ != nullptr), span{data_, Count}; } constexpr span first(index_type cnt) const noexcept { return RANGES_EXPECT(cnt >= 0 && cnt <= size()), RANGES_EXPECT(cnt == 0 || data_ != nullptr), span{data_, cnt}; } template constexpr span last() const noexcept { static_assert(Count >= 0, "Count of elements to extract cannot be negative."); static_assert( N == dynamic_extent || Count <= N, "Count of elements to extract must be less than the static span extent."); return RANGES_EXPECT(Count <= size()), RANGES_EXPECT((Count == 0 && size() == 0) || data_ != nullptr), span{data_ + size() - Count, Count}; } constexpr span last(index_type cnt) const noexcept { return RANGES_EXPECT(cnt >= 0 && cnt <= size()), RANGES_EXPECT((cnt == 0 && size() == 0) || data_ != nullptr), span{data_ + size() - cnt, cnt}; } template constexpr span subspan() const noexcept { static_assert(Offset >= 0, "Offset of first element to extract cannot be negative."); static_assert(Count >= dynamic_extent, "Count of elements to extract cannot be negative."); static_assert( N == dynamic_extent || N >= Offset + (Count == dynamic_extent ? 0 : Count), "Sequence of elements to extract must be within the static span extent."); return RANGES_EXPECT(size() >= Offset + (Count == dynamic_extent ? 0 : Count)), RANGES_EXPECT((Offset == 0 && Count <= 0) || data_ != nullptr), span{ data_ + Offset, Count == dynamic_extent ? size() - Offset : Count}; } template constexpr span= Offset ? N - Offset : dynamic_extent)> subspan() const noexcept { static_assert(Offset >= 0, "Offset of first element to extract cannot be negative."); static_assert(N == dynamic_extent || N >= Offset, "Offset of first element to extract must be within the static " "span extent."); return RANGES_EXPECT(size() >= Offset), RANGES_EXPECT((Offset == 0 && size() == 0) || data_ != nullptr), span < T, N >= Offset ? N - Offset : dynamic_extent > {data_ + Offset, size() - Offset}; } constexpr span subspan(index_type offset) const noexcept { return RANGES_EXPECT(offset >= 0), RANGES_EXPECT(size() >= offset), RANGES_EXPECT((offset == 0 && size() == 0) || data_ != nullptr), span{data_ + offset, size() - offset}; } constexpr span subspan(index_type offset, index_type cnt) const noexcept { return RANGES_EXPECT(offset >= 0), RANGES_EXPECT(cnt >= 0), RANGES_EXPECT(size() >= offset + cnt), RANGES_EXPECT((offset == 0 && cnt == 0) || data_ != nullptr), span{data_ + offset, cnt}; } constexpr pointer data() const noexcept { return data_; } using detail::span_extent::size; constexpr index_type size_bytes() const noexcept { return detail::byte_size(size()); } constexpr bool empty() const noexcept { return size() == 0; } constexpr reference operator[](index_type idx) const noexcept { return RANGES_EXPECT(idx >= 0), RANGES_EXPECT(idx < size()), RANGES_EXPECT(data_), data_[idx]; } constexpr iterator begin() const noexcept { return RANGES_EXPECT(!size() || data_), data_; } constexpr iterator end() const noexcept { return RANGES_EXPECT(!size() || data_), data_ + size(); } constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } template auto operator==(span const & that) const -> CPP_ret(bool)( // requires equality_comparable_with) { RANGES_EXPECT(!size() || data()); RANGES_EXPECT(!that.size() || that.data()); return ranges::equal(*this, that); } template auto operator!=(span const & that) const -> CPP_ret(bool)( // requires equality_comparable_with) { return !(*this == that); } template auto operator<(span const & that) const -> CPP_ret(bool)( // requires totally_ordered_with) { RANGES_EXPECT(!size() || data()); RANGES_EXPECT(!that.size() || that.data()); return ranges::lexicographical_compare(*this, that); } template auto operator>(span const & that) const -> CPP_ret(bool)( // requires totally_ordered_with) { return that < *this; } template auto operator<=(span const & that) const -> CPP_ret(bool)( // requires totally_ordered_with) { return !(that < *this); } template auto operator>=(span const & that) const -> CPP_ret(bool)( // requires totally_ordered_with) { return !(*this < that); } private: T * data_ = nullptr; }; template constexpr detail::span_index_t span::extent; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 CPP_template(typename Rng)( // requires contiguous_range) // span(Rng && rng) ->span, (range_cardinality::value < cardinality() ? dynamic_extent : static_cast( range_cardinality::value))>; #endif template span(N)> as_bytes(span s) noexcept { return {reinterpret_cast(s.data()), s.size_bytes()}; } template span(N)> as_writeable_bytes(span s) noexcept { return {reinterpret_cast(s.data()), s.size_bytes()}; } template constexpr span make_span(ElementType * ptr, detail::span_index_t cnt) noexcept { return span{ptr, cnt}; } template constexpr span make_span(ElementType * first, ElementType * last) noexcept { return span{first, last}; } CPP_template(typename Rng)( // requires contiguous_range && (range_cardinality::value < cardinality())) // constexpr span> make_span(Rng && rng) noexcept( noexcept(ranges::data(rng), ranges::size(rng))) { return {ranges::data(rng), detail::narrow_cast(ranges::size(rng))}; } CPP_template(typename Rng)( // requires contiguous_range && (range_cardinality::value >= cardinality())) // constexpr span< detail::element_t, static_cast( range_cardinality:: value)> make_span(Rng && rng) noexcept(noexcept(ranges::data(rng))) { return {ranges::data(rng), range_cardinality::value}; } } // namespace ranges #endif // RANGES_V3_VIEW_SPAN_HPP