123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- // -*- 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_JOIN_VIEW_H
- #define _LIBCPP___RANGES_JOIN_VIEW_H
- #include <__concepts/constructible.h>
- #include <__concepts/convertible_to.h>
- #include <__concepts/copyable.h>
- #include <__concepts/derived_from.h>
- #include <__concepts/equality_comparable.h>
- #include <__config>
- #include <__iterator/concepts.h>
- #include <__iterator/iter_move.h>
- #include <__iterator/iter_swap.h>
- #include <__iterator/iterator_traits.h>
- #include <__iterator/iterator_with_data.h>
- #include <__iterator/segmented_iterator.h>
- #include <__ranges/access.h>
- #include <__ranges/all.h>
- #include <__ranges/concepts.h>
- #include <__ranges/empty.h>
- #include <__ranges/non_propagating_cache.h>
- #include <__ranges/range_adaptor.h>
- #include <__ranges/view_interface.h>
- #include <__type_traits/maybe_const.h>
- #include <__utility/forward.h>
- #include <optional>
- #include <type_traits>
- #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
- # pragma GCC system_header
- #endif
- _LIBCPP_BEGIN_NAMESPACE_STD
- // Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in
- // the pipeline (https://isocpp.org/files/papers/D2770R0.html).
- // TODO: make `join_view` non-experimental once D2770 is implemented.
- #if _LIBCPP_STD_VER > 17
- namespace ranges {
- template<class>
- struct __join_view_iterator_category {};
- template<class _View>
- requires is_reference_v<range_reference_t<_View>> &&
- forward_range<_View> &&
- forward_range<range_reference_t<_View>>
- struct __join_view_iterator_category<_View> {
- using _OuterC = typename iterator_traits<iterator_t<_View>>::iterator_category;
- using _InnerC = typename iterator_traits<iterator_t<range_reference_t<_View>>>::iterator_category;
- using iterator_category = _If<
- derived_from<_OuterC, bidirectional_iterator_tag> && derived_from<_InnerC, bidirectional_iterator_tag> &&
- common_range<range_reference_t<_View>>,
- bidirectional_iterator_tag,
- _If<
- derived_from<_OuterC, forward_iterator_tag> && derived_from<_InnerC, forward_iterator_tag>,
- forward_iterator_tag,
- input_iterator_tag
- >
- >;
- };
- template<input_range _View>
- requires view<_View> && input_range<range_reference_t<_View>>
- class join_view
- : public view_interface<join_view<_View>> {
- private:
- using _InnerRange = range_reference_t<_View>;
- template<bool> struct __iterator;
- template<bool> struct __sentinel;
- template <class>
- friend struct std::__segmented_iterator_traits;
- static constexpr bool _UseCache = !is_reference_v<_InnerRange>;
- using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
- _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_;
- _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
- public:
- _LIBCPP_HIDE_FROM_ABI
- join_view() requires default_initializable<_View> = default;
- _LIBCPP_HIDE_FROM_ABI
- constexpr explicit join_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() {
- constexpr bool __use_const = __simple_view<_View> &&
- is_reference_v<range_reference_t<_View>>;
- return __iterator<__use_const>{*this, ranges::begin(__base_)};
- }
- template<class _V2 = _View>
- _LIBCPP_HIDE_FROM_ABI
- constexpr auto begin() const
- requires input_range<const _V2> &&
- is_reference_v<range_reference_t<const _V2>>
- {
- return __iterator<true>{*this, ranges::begin(__base_)};
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr auto end() {
- if constexpr (forward_range<_View> &&
- is_reference_v<_InnerRange> &&
- forward_range<_InnerRange> &&
- common_range<_View> &&
- common_range<_InnerRange>)
- return __iterator<__simple_view<_View>>{*this, ranges::end(__base_)};
- else
- return __sentinel<__simple_view<_View>>{*this};
- }
- template<class _V2 = _View>
- _LIBCPP_HIDE_FROM_ABI
- constexpr auto end() const
- requires input_range<const _V2> &&
- is_reference_v<range_reference_t<const _V2>>
- {
- using _ConstInnerRange = range_reference_t<const _View>;
- if constexpr (forward_range<const _View> &&
- is_reference_v<_ConstInnerRange> &&
- forward_range<_ConstInnerRange> &&
- common_range<const _View> &&
- common_range<_ConstInnerRange>) {
- return __iterator<true>{*this, ranges::end(__base_)};
- } else {
- return __sentinel<true>{*this};
- }
- }
- };
- template<input_range _View>
- requires view<_View> && input_range<range_reference_t<_View>>
- template<bool _Const>
- struct join_view<_View>::__sentinel {
- template<bool>
- friend struct __sentinel;
- private:
- using _Parent = __maybe_const<_Const, join_view<_View>>;
- using _Base = __maybe_const<_Const, _View>;
- sentinel_t<_Base> __end_ = sentinel_t<_Base>();
- public:
- _LIBCPP_HIDE_FROM_ABI
- __sentinel() = default;
- _LIBCPP_HIDE_FROM_ABI
- constexpr explicit __sentinel(_Parent& __parent)
- : __end_(ranges::end(__parent.__base_)) {}
- _LIBCPP_HIDE_FROM_ABI
- constexpr __sentinel(__sentinel<!_Const> __s)
- requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
- : __end_(std::move(__s.__end_)) {}
- template<bool _OtherConst>
- requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
- _LIBCPP_HIDE_FROM_ABI
- friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
- return __x.__outer_ == __y.__end_;
- }
- };
- // https://reviews.llvm.org/D142811#inline-1383022
- // To simplify the segmented iterator traits specialization,
- // make the iterator `final`
- template<input_range _View>
- requires view<_View> && input_range<range_reference_t<_View>>
- template<bool _Const>
- struct join_view<_View>::__iterator final
- : public __join_view_iterator_category<__maybe_const<_Const, _View>> {
- template<bool>
- friend struct __iterator;
- template <class>
- friend struct std::__segmented_iterator_traits;
- static constexpr bool __is_join_view_iterator = true;
- private:
- using _Parent = __maybe_const<_Const, join_view<_View>>;
- using _Base = __maybe_const<_Const, _View>;
- using _Outer = iterator_t<_Base>;
- using _Inner = iterator_t<range_reference_t<_Base>>;
- using _InnerRange = range_reference_t<_View>;
- static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
- public:
- _Outer __outer_ = _Outer();
- private:
- optional<_Inner> __inner_;
- _Parent *__parent_ = nullptr;
- _LIBCPP_HIDE_FROM_ABI
- constexpr void __satisfy() {
- for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) {
- auto&& __inner = [&]() -> auto&& {
- if constexpr (__ref_is_glvalue)
- return *__outer_;
- else
- return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; });
- }();
- __inner_ = ranges::begin(__inner);
- if (*__inner_ != ranges::end(__inner))
- return;
- }
- if constexpr (__ref_is_glvalue)
- __inner_.reset();
- }
- _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
- : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
- public:
- using iterator_concept = _If<
- __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> &&
- common_range<range_reference_t<_Base>>,
- bidirectional_iterator_tag,
- _If<
- __ref_is_glvalue && forward_range<_Base> && forward_range<range_reference_t<_Base>>,
- forward_iterator_tag,
- input_iterator_tag
- >
- >;
- using value_type = range_value_t<range_reference_t<_Base>>;
- using difference_type = common_type_t<
- range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
- _LIBCPP_HIDE_FROM_ABI
- __iterator() requires default_initializable<_Outer> = default;
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator(_Parent& __parent, _Outer __outer)
- : __outer_(std::move(__outer))
- , __parent_(std::addressof(__parent)) {
- __satisfy();
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator(__iterator<!_Const> __i)
- requires _Const &&
- convertible_to<iterator_t<_View>, _Outer> &&
- convertible_to<iterator_t<_InnerRange>, _Inner>
- : __outer_(std::move(__i.__outer_))
- , __inner_(std::move(__i.__inner_))
- , __parent_(__i.__parent_) {}
- _LIBCPP_HIDE_FROM_ABI
- constexpr decltype(auto) operator*() const {
- return **__inner_;
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr _Inner operator->() const
- requires __has_arrow<_Inner> && copyable<_Inner>
- {
- return *__inner_;
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator& operator++() {
- auto&& __inner = [&]() -> auto&& {
- if constexpr (__ref_is_glvalue)
- return *__outer_;
- else
- return *__parent_->__cache_;
- }();
- if (++*__inner_ == ranges::end(__inner)) {
- ++__outer_;
- __satisfy();
- }
- return *this;
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr void operator++(int) {
- ++*this;
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator operator++(int)
- requires __ref_is_glvalue &&
- forward_range<_Base> &&
- forward_range<range_reference_t<_Base>>
- {
- auto __tmp = *this;
- ++*this;
- return __tmp;
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator& operator--()
- requires __ref_is_glvalue &&
- bidirectional_range<_Base> &&
- bidirectional_range<range_reference_t<_Base>> &&
- common_range<range_reference_t<_Base>>
- {
- if (__outer_ == ranges::end(__parent_->__base_))
- __inner_ = ranges::end(*--__outer_);
- // Skip empty inner ranges when going backwards.
- while (*__inner_ == ranges::begin(*__outer_)) {
- __inner_ = ranges::end(*--__outer_);
- }
- --*__inner_;
- return *this;
- }
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator operator--(int)
- requires __ref_is_glvalue &&
- bidirectional_range<_Base> &&
- bidirectional_range<range_reference_t<_Base>> &&
- common_range<range_reference_t<_Base>>
- {
- auto __tmp = *this;
- --*this;
- return __tmp;
- }
- _LIBCPP_HIDE_FROM_ABI
- friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
- requires __ref_is_glvalue &&
- equality_comparable<iterator_t<_Base>> &&
- equality_comparable<iterator_t<range_reference_t<_Base>>>
- {
- return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
- }
- _LIBCPP_HIDE_FROM_ABI
- friend constexpr decltype(auto) iter_move(const __iterator& __i)
- noexcept(noexcept(ranges::iter_move(*__i.__inner_)))
- {
- return ranges::iter_move(*__i.__inner_);
- }
- _LIBCPP_HIDE_FROM_ABI
- friend constexpr void iter_swap(const __iterator& __x, const __iterator& __y)
- noexcept(noexcept(ranges::iter_swap(*__x.__inner_, *__y.__inner_)))
- requires indirectly_swappable<_Inner>
- {
- return ranges::iter_swap(*__x.__inner_, *__y.__inner_);
- }
- };
- template<class _Range>
- explicit join_view(_Range&&) -> join_view<views::all_t<_Range>>;
- namespace views {
- namespace __join_view {
- struct __fn : __range_adaptor_closure<__fn> {
- template<class _Range>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
- constexpr auto operator()(_Range&& __range) const
- noexcept(noexcept(join_view<all_t<_Range&&>>(std::forward<_Range>(__range))))
- -> decltype( join_view<all_t<_Range&&>>(std::forward<_Range>(__range)))
- { return join_view<all_t<_Range&&>>(std::forward<_Range>(__range)); }
- };
- } // namespace __join_view
- inline namespace __cpo {
- inline constexpr auto join = __join_view::__fn{};
- } // namespace __cpo
- } // namespace views
- } // namespace ranges
- template <class _JoinViewIterator>
- requires(_JoinViewIterator::__is_join_view_iterator &&
- ranges::common_range<typename _JoinViewIterator::_Parent> &&
- __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Outer>::value &&
- __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Inner>::value)
- struct __segmented_iterator_traits<_JoinViewIterator> {
- using __segment_iterator =
- _LIBCPP_NODEBUG __iterator_with_data<typename _JoinViewIterator::_Outer, typename _JoinViewIterator::_Parent*>;
- using __local_iterator = typename _JoinViewIterator::_Inner;
- // TODO: Would it make sense to enable the optimization for other iterator types?
- static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_JoinViewIterator __iter) {
- if (ranges::empty(__iter.__parent_->__base_))
- return {};
- if (!__iter.__inner_.has_value())
- return __segment_iterator(--__iter.__outer_, __iter.__parent_);
- return __segment_iterator(__iter.__outer_, __iter.__parent_);
- }
- static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_JoinViewIterator __iter) {
- if (ranges::empty(__iter.__parent_->__base_))
- return {};
- if (!__iter.__inner_.has_value())
- return ranges::end(*--__iter.__outer_);
- return *__iter.__inner_;
- }
- static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) {
- return ranges::begin(*__iter.__get_iter());
- }
- static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) {
- return ranges::end(*__iter.__get_iter());
- }
- static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator
- __compose(__segment_iterator __seg_iter, __local_iterator __local_iter) {
- return _JoinViewIterator(
- std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter));
- }
- };
- #endif // #if _LIBCPP_STD_VER > 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
- _LIBCPP_END_NAMESPACE_STD
- #endif // _LIBCPP___RANGES_JOIN_VIEW_H
|