// -*- C++ -*- //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef _LIBCPP___RANGES_ADJACENT_VIEW_H #define _LIBCPP___RANGES_ADJACENT_VIEW_H #include <__config> #include <__algorithm/min.h> #include <__compare/three_way_comparable.h> #include <__concepts/constructible.h> #include <__concepts/convertible_to.h> #include <__concepts/equality_comparable.h> #include <__cstddef/size_t.h> #include <__functional/invoke.h> #include <__functional/operations.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iter_move.h> #include <__iterator/iter_swap.h> #include <__iterator/iterator_traits.h> #include <__iterator/next.h> #include <__iterator/prev.h> #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> #include <__ranges/empty_view.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/range_adaptor.h> #include <__ranges/size.h> #include <__ranges/view_interface.h> #include <__tuple/tuple_transform.h> #include <__type_traits/common_type.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/make_unsigned.h> #include <__type_traits/maybe_const.h> #include <__utility/declval.h> #include <__utility/forward.h> #include <__utility/integer_sequence.h> #include <__utility/move.h> #include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif _LIBCPP_PUSH_MACROS #include <__undef_macros> _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 23 namespace ranges { template requires view<_View> && (_Np > 0) class adjacent_view : public view_interface> { private: _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); template class __iterator; template class __sentinel; struct __as_sentinel {}; public: _LIBCPP_HIDE_FROM_ABI adjacent_view() requires default_initializable<_View> = default; _LIBCPP_HIDE_FROM_ABI constexpr explicit adjacent_view(_View __base) : __base_(std::move(__base)) {} _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires(!__simple_view<_View>) { return __iterator(ranges::begin(__base_), ranges::end(__base_)); } _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range // LWG4482 This is under-constrained. { return __iterator(ranges::begin(__base_), ranges::end(__base_)); } _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires(!__simple_view<_View>) { if constexpr (common_range<_View>) { return __iterator(__as_sentinel{}, ranges::begin(__base_), ranges::end(__base_)); } else { return __sentinel(ranges::end(__base_)); } } _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range // LWG4482 This is under-constrained. { if constexpr (common_range) { return __iterator(__as_sentinel{}, ranges::begin(__base_), ranges::end(__base_)); } else { return __sentinel(ranges::end(__base_)); } } _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { using _ST = decltype(ranges::size(__base_)); using _CT = common_type_t<_ST, size_t>; auto __sz = static_cast<_CT>(ranges::size(__base_)); __sz -= std::min<_CT>(__sz, _Np - 1); return static_cast<_ST>(__sz); } _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range { using _ST = decltype(ranges::size(__base_)); using _CT = common_type_t<_ST, size_t>; auto __sz = static_cast<_CT>(ranges::size(__base_)); __sz -= std::min<_CT>(__sz, _Np - 1); return static_cast<_ST>(__sz); } }; struct __adjacent_view_iter_access { template _LIBCPP_HIDE_FROM_ABI constexpr static auto& __get_current(_Iter& __it) noexcept { return __it.__current_; } }; template requires view<_View> && (_Np > 0) template class adjacent_view<_View, _Np>::__iterator { friend __adjacent_view_iter_access; friend adjacent_view; using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; array, _Np> __current_ = array, _Np>(); _LIBCPP_HIDE_FROM_ABI constexpr __iterator(iterator_t<_Base> __first, sentinel_t<_Base> __last) { __current_[0] = __first; for (size_t __i = 1; __i < _Np; ++__i) { __current_[__i] = ranges::next(__current_[__i - 1], 1, __last); } } _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__as_sentinel, iterator_t<_Base> __first, iterator_t<_Base> __last) { if constexpr (!bidirectional_range<_Base>) { __current_.fill(__last); } else { __current_[_Np - 1] = __last; for (int __i = static_cast(_Np) - 2; __i >= 0; --__i) { __current_[__i] = ranges::prev(__current_[__i + 1], 1, __first); } } } template _LIBCPP_HIDE_FROM_ABI explicit constexpr __iterator(_Iter&& __i, index_sequence<_Is...>) : __current_{std::move(__i.__current_[_Is])...} {} static consteval auto __get_iterator_concept() { if constexpr (random_access_range<_Base>) return random_access_iterator_tag{}; else if constexpr (bidirectional_range<_Base>) return bidirectional_iterator_tag{}; else return forward_iterator_tag{}; } template using __always _LIBCPP_NODEBUG = _Tp; template static auto __repeat_tuple_helper(index_sequence<_Is...>) -> tuple<__always<_Tp, _Is>...>; public: using iterator_category = input_iterator_tag; using iterator_concept = decltype(__get_iterator_concept()); using value_type = decltype(__repeat_tuple_helper>(make_index_sequence<_Np>{})); using difference_type = range_difference_t<_Base>; _LIBCPP_HIDE_FROM_ABI __iterator() = default; _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator __i) requires _Const && convertible_to, iterator_t> : __iterator(std::move(__i), make_index_sequence<_Np>{}) {} _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return std::__tuple_transform([](auto& __i) -> decltype(auto) { return *__i; }, __current_); } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { for (auto& __i : __current_) { ++__i; } return *this; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() requires bidirectional_range<_Base> { for (auto& __i : __current_) { --__i; } return *this; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) requires bidirectional_range<_Base> { auto __tmp = *this; --*this; return __tmp; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __x) requires random_access_range<_Base> { for (auto& __i : __current_) { __i += __x; } return *this; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x) requires random_access_range<_Base> { for (auto& __i : __current_) { __i -= __x; } return *this; } _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const requires random_access_range<_Base> { return std::__tuple_transform([&](auto& __i) -> decltype(auto) { return __i[__n]; }, __current_); } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) { return __x.__current_.back() == __y.__current_.back(); } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y) requires random_access_range<_Base> { return __x.__current_.back() < __y.__current_.back(); } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y) requires random_access_range<_Base> { return __y < __x; } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y) requires random_access_range<_Base> { return !(__y < __x); } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y) requires random_access_range<_Base> { return !(__x < __y); } _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) requires random_access_range<_Base> && three_way_comparable> { return __x.__current_.back() <=> __y.__current_.back(); } _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n) requires random_access_range<_Base> { auto __r = __i; __r += __n; return __r; } _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i) requires random_access_range<_Base> { return __i + __n; } _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n) requires random_access_range<_Base> { auto __r = __i; __r -= __n; return __r; } _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) requires sized_sentinel_for, iterator_t<_Base>> { return __x.__current_.back() - __y.__current_.back(); } _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept( noexcept(ranges::iter_move(std::declval&>())) && is_nothrow_move_constructible_v>) { return std::__tuple_transform(ranges::iter_move, __i.__current_); } _LIBCPP_HIDE_FROM_ABI friend constexpr void iter_swap(const __iterator& __l, const __iterator& __r) noexcept( noexcept(ranges::iter_swap(std::declval>(), std::declval>()))) requires indirectly_swappable> { for (size_t __i = 0; __i < _Np; ++__i) { ranges::iter_swap(__l.__current_[__i], __r.__current_[__i]); } } }; template requires view<_View> && (_Np > 0) template class adjacent_view<_View, _Np>::__sentinel { friend adjacent_view; using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; sentinel_t<_Base> __end_ = sentinel_t<_Base>(); _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) { __end_ = std::move(__end); } public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel __i) requires _Const && convertible_to, sentinel_t<_Base>> : __end_(std::move(__i.__end_)) {} template requires sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { return __x.__current_.back() == __y.__end_; } template requires sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) { return __x.__current_.back() - __y.__end_; } template requires sized_sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> operator-(const __sentinel& __y, const __iterator<_OtherConst>& __x) { return __y.__end_ - __x.__current_.back(); } }; template constexpr bool enable_borrowed_range> = enable_borrowed_range<_View>; namespace views { namespace __adjacent { template struct __fn : __range_adaptor_closure<__fn<_Np>> { template requires(_Np == 0 && forward_range<_Range &&>) _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&&) noexcept { return empty_view>{}; } template _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ranges&& __range) noexcept( noexcept(adjacent_view, _Np>(std::forward<_Ranges>(__range)))) -> decltype(adjacent_view, _Np>(std::forward<_Ranges>(__range))) { return adjacent_view, _Np>(std::forward<_Ranges>(__range)); } }; } // namespace __adjacent inline namespace __cpo { template inline constexpr auto adjacent = __adjacent::__fn<_Np>{}; inline constexpr auto pairwise = adjacent<2>; } // namespace __cpo } // namespace views } // namespace ranges #endif // _LIBCPP_STD_VER >= 23 _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS #endif // _LIBCPP___RANGES_ADJACENT_VIEW_H