diff --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h --- a/libcxx/include/__algorithm/copy.h +++ b/libcxx/include/__algorithm/copy.h @@ -47,7 +47,7 @@ template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) const { - using _Traits = __segmented_iterator_traits<_InIter>; + using _Traits = __segmented_iterator_traits_t<_InIter>; auto __sfirst = _Traits::__segment(__first); auto __slast = _Traits::__segment(__last); if (__sfirst == __slast) { @@ -74,7 +74,7 @@ int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _InIter __last, _OutIter __result) { - using _Traits = __segmented_iterator_traits<_OutIter>; + using _Traits = __segmented_iterator_traits_t<_OutIter>; using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; if (__first == __last) @@ -89,7 +89,7 @@ __first = std::move(__iters.first); if (__first == __last) - return std::make_pair(std::move(__first), _Traits::__compose(__segment_iterator, std::move(__iters.second))); + return std::make_pair(std::move(__first), _Traits::template __compose<_OutIter>(__segment_iterator, std::move(__iters.second))); __local_first = _Traits::__begin(++__segment_iterator); } diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h --- a/libcxx/include/__algorithm/copy_backward.h +++ b/libcxx/include/__algorithm/copy_backward.h @@ -99,7 +99,7 @@ __last -= __size; if (__first == __last) - return std::make_pair(std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iter))); + return std::make_pair(std::move(__orig_last), _Traits::template __compose<_OutIter>(__segment_iterator, std::move(__iter))); --__segment_iterator; __local_last = _Traits::__end(__segment_iterator); } diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -90,7 +90,7 @@ __first = std::move(__iters.first); if (__first == __last) - return std::make_pair(std::move(__first), _Traits::__compose(__segment_iterator, std::move(__iters.second))); + return std::make_pair(std::move(__first), _Traits::template __compose<_OutIter>(__segment_iterator, std::move(__iters.second))); __local_first = _Traits::__begin(++__segment_iterator); } diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -99,7 +99,7 @@ __last -= __size; if (__first == __last) - return std::make_pair(std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iter))); + return std::make_pair(std::move(__orig_last), _Traits::template __compose<_OutIter>(__segment_iterator, std::move(__iter))); __local_last = _Traits::__end(--__segment_iterator); } diff --git a/libcxx/include/__iterator/segmented_iterator.h b/libcxx/include/__iterator/segmented_iterator.h --- a/libcxx/include/__iterator/segmented_iterator.h +++ b/libcxx/include/__iterator/segmented_iterator.h @@ -16,17 +16,12 @@ // allows algorithms to operate over these multi-level iterators natively, opening the // door to various optimizations. See http://lafstern.org/matt/segmented.pdf for details. // -// If __segmented_iterator_traits can be instantiated, the following functions and associated types must be provided: -// - Traits::__local_iterator -// The type of iterators used to iterate inside a segment. -// -// - Traits::__segment_iterator -// The type of iterators used to iterate over segments. -// Segment iterators can be forward iterators or bidirectional iterators, depending on the -// underlying data structure. +// If __segmented_iterator_traits can be instantiated, the following functions must be provided: // // - static __segment_iterator Traits::__segment(It __it) // Returns an iterator to the segment that the provided iterator is in. +// Segment iterators can be forward iterators or bidirectional iterators, depending on the +// underlying data structure. // // - static __local_iterator Traits::__local(It __it) // Returns the local iterator pointing to the element that the provided iterator points to. @@ -37,7 +32,8 @@ // - static __local_iterator Traits::__end(__segment_iterator __it) // Returns the one-past-the-end local iterator to the segment that the provided iterator is pointing into. // -// - static It Traits::__compose(__segment_iterator, __local_iterator) +// - template +// static It Traits::__compose(__segment_iterator, __local_iterator) // Returns the iterator composed of the segment iterator and local iterator. #include <__config> @@ -50,17 +46,31 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template +template +struct __segmented_iter_tag_of { + using __tag = T; +}; + +template +using __segmented_iter_tag_of_t = typename __segmented_iter_tag_of::__tag; + +template struct __segmented_iterator_traits; /* exposition-only: { - using __segment_iterator = ...; - using __local_iterator = ...; - + template static __segment_iterator __segment(_Iterator); + + template static __local_iterator __local(_Iterator); + + template static __local_iterator __begin(__segment_iterator); + + template static __local_iterator __end(__segment_iterator); + + template static _Iterator __compose(__segment_iterator, __local_iterator); }; */ @@ -72,7 +82,10 @@ struct __has_specialization<_Tp, sizeof(_Tp) * 0> : true_type {}; template -using __is_segmented_iterator = __has_specialization<__segmented_iterator_traits<_Iterator> >; +using __is_segmented_iterator = __has_specialization<__segmented_iterator_traits<__segmented_iter_tag_of_t<_Iterator> > >; + +template +using __segmented_iterator_traits_t = __segmented_iterator_traits<__segmented_iter_tag_of_t<_Iterator> >; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -66,14 +66,6 @@ >; }; - template - requires view<_View> && input_range> - struct __join_view_iterator; - - template - requires view<_View> && input_range> - struct __join_view_sentinel; - template requires view<_View> && input_range> class join_view @@ -81,19 +73,9 @@ private: using _InnerRange = range_reference_t<_View>; - template - using __iterator = __join_view_iterator<_View, _Const>; - - template - using __sentinel = __join_view_sentinel<_View, _Const>; + template struct __iterator; - template - requires view<_View2> && input_range> - friend struct __join_view_iterator; - - template - requires view<_View2> && input_range> - friend struct __join_view_sentinel; + template struct __sentinel; template friend struct std::__segmented_iterator_traits; @@ -164,12 +146,12 @@ } }; - template + template requires view<_View> && input_range> - struct __join_view_sentinel { - template - requires view<_View2> && input_range> - friend struct __join_view_sentinel; + template + struct join_view<_View>::__sentinel { + template + friend struct __sentinel; private: using _Parent = __maybe_const<_Const, join_view<_View>>; @@ -178,37 +160,53 @@ public: _LIBCPP_HIDE_FROM_ABI - __join_view_sentinel() = default; + __sentinel() = default; _LIBCPP_HIDE_FROM_ABI - constexpr explicit __join_view_sentinel(_Parent& __parent) + constexpr explicit __sentinel(_Parent& __parent) : __end_(ranges::end(__parent.__base_)) {} _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_sentinel(__join_view_sentinel<_View, !_Const> __s) + constexpr __sentinel(__sentinel __s) requires _Const && convertible_to, sentinel_t<_Base>> : __end_(std::move(__s.__end_)) {} template requires sentinel_for, iterator_t<__maybe_const<_OtherConst, _View>>> _LIBCPP_HIDE_FROM_ABI - friend constexpr bool operator==(const __join_view_iterator<_View, _OtherConst>& __x, const __join_view_sentinel& __y) { + friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { return __x.__outer_ == __y.__end_; } }; - template + // This complicated thing is to make sure __is_join_view_iterator_fun is not coming from a derived class of __iterator + template + struct __is_join_view_iterator_checker{ + static false_type __check(); + static true_type __check() requires (std::is_same_v); + }; + + template + struct __is_join_view_iterator : decltype(__is_join_view_iterator_checker::__check()) {}; + + template requires view<_View> && input_range> - struct __join_view_iterator + template + struct join_view<_View>::__iterator : public __join_view_iterator_category<__maybe_const<_Const, _View>> { - template - requires view<_View2> && input_range> - friend struct __join_view_iterator; + template + friend struct __iterator; template friend struct std::__segmented_iterator_traits; + template + friend struct std::__segmented_iter_tag_of; + + template + friend struct __is_join_view_iterator_checker; + private: using _Parent = __maybe_const<_Const, join_view<_View>>; using _Base = __maybe_const<_Const, _View>; @@ -216,6 +214,7 @@ using _Inner = iterator_t>; using _InnerRange = range_reference_t<_View>; + void __is_join_view_iterator_fun(); static constexpr bool __ref_is_glvalue = is_reference_v>; public: @@ -243,7 +242,7 @@ __inner_.reset(); } - _LIBCPP_HIDE_FROM_ABI constexpr __join_view_iterator(_Parent* __parent, _Outer __outer, _Inner __inner) + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner) : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {} public: @@ -264,17 +263,17 @@ range_difference_t<_Base>, range_difference_t>>; _LIBCPP_HIDE_FROM_ABI - __join_view_iterator() requires default_initializable<_Outer> = default; + __iterator() requires default_initializable<_Outer> = default; _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_iterator(_Parent& __parent, _Outer __outer) + constexpr __iterator(_Parent& __parent, _Outer __outer) : __outer_(std::move(__outer)) , __parent_(std::addressof(__parent)) { __satisfy(); } _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_iterator(__join_view_iterator<_View, !_Const> __i) + constexpr __iterator(__iterator __i) requires _Const && convertible_to, _Outer> && convertible_to, _Inner> @@ -295,7 +294,7 @@ } _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_iterator& operator++() { + constexpr __iterator& operator++() { auto&& __inner = [&]() -> auto&& { if constexpr (__ref_is_glvalue) return *__outer_; @@ -315,7 +314,7 @@ } _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_iterator operator++(int) + constexpr __iterator operator++(int) requires __ref_is_glvalue && forward_range<_Base> && forward_range> @@ -326,7 +325,7 @@ } _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_iterator& operator--() + constexpr __iterator& operator--() requires __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range> && @@ -345,7 +344,7 @@ } _LIBCPP_HIDE_FROM_ABI - constexpr __join_view_iterator operator--(int) + constexpr __iterator operator--(int) requires __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range> && @@ -357,7 +356,7 @@ } _LIBCPP_HIDE_FROM_ABI - friend constexpr bool operator==(const __join_view_iterator& __x, const __join_view_iterator& __y) + friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) requires __ref_is_glvalue && equality_comparable> && equality_comparable>> @@ -366,14 +365,14 @@ } _LIBCPP_HIDE_FROM_ABI - friend constexpr decltype(auto) iter_move(const __join_view_iterator& __i) + 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 __join_view_iterator& __x, const __join_view_iterator& __y) + friend constexpr void iter_swap(const __iterator& __x, const __iterator& __y) noexcept(noexcept(ranges::iter_swap(*__x.__inner_, *__y.__inner_))) requires indirectly_swappable<_Inner> { @@ -401,28 +400,38 @@ } // namespace views } // namespace ranges -template - requires(ranges::common_range::_Parent> && - __is_cpp17_random_access_iterator::_Outer>::value && - __is_cpp17_random_access_iterator::_Inner>::value) -struct __segmented_iterator_traits> { - using _JoinViewIterator = ranges::__join_view_iterator<_View, _Const>; +struct __join_view_iterator_segmented_tag {}; +template + requires (ranges::__is_join_view_iterator::value && + ranges::common_range && + __is_cpp17_random_access_iterator::value && + __is_cpp17_random_access_iterator::value) +struct __segmented_iter_tag_of { + using __tag = __join_view_iterator_segmented_tag; +}; + +template <> +struct __segmented_iterator_traits<__join_view_iterator_segmented_tag> { + + template using __segment_iterator = _LIBCPP_NODEBUG __iterator_with_data; - using __local_iterator = typename _JoinViewIterator::_Inner; - // TODO: Would it make sense to enable the optimization for other iterator types? + template + using __local_iterator = typename _JoinViewIterator::_Inner; - static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_JoinViewIterator __iter) { + template + static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator<_JoinViewIterator> __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_); + return __segment_iterator<_JoinViewIterator>(--__iter.__outer_, __iter.__parent_); + return __segment_iterator<_JoinViewIterator>(__iter.__outer_, __iter.__parent_); } - static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_JoinViewIterator __iter) { + template + static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator<_JoinViewIterator> __local(_JoinViewIterator __iter) { if (ranges::empty(__iter.__parent_->__base_)) return {}; if (!__iter.__inner_.has_value()) @@ -430,16 +439,19 @@ return *__iter.__inner_; } - static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) { + template + static constexpr _LIBCPP_HIDE_FROM_ABI auto __begin(__segment_iterator __iter) { return ranges::begin(*__iter.__get_iter()); } - static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) { + template + static constexpr _LIBCPP_HIDE_FROM_ABI auto __end(__segment_iterator __iter) { return ranges::end(*__iter.__get_iter()); } + template static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator - __compose(__segment_iterator __seg_iter, __local_iterator __local_iter) { + __compose(__segment_iterator<_JoinViewIterator> __seg_iter, __local_iterator<_JoinViewIterator> __local_iter) { return _JoinViewIterator( std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter)); } diff --git a/libcxx/include/deque b/libcxx/include/deque --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -398,7 +398,6 @@ using _Iterator = __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize>; public: - using __is_segmented_iterator = true_type; using __segment_iterator = _MapPointer; using __local_iterator = _Pointer; @@ -410,6 +409,7 @@ return *__iter + _Iterator::__block_size; } + template static _LIBCPP_HIDE_FROM_ABI _Iterator __compose(__segment_iterator __segment, __local_iterator __local) { if (__local == __end(__segment)) { ++__segment; diff --git a/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/deque/segmented_iterator.compile.pass.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include + + +using DequeIterator = typename std::deque::iterator; +static_assert(std::__is_segmented_iterator::value); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include +#include + +#include "test_iterators.h" + +using JoinView = decltype(std::views::join(std::declval>&>())); +using JoinIter = std::ranges::iterator_t; +static_assert(std::__is_segmented_iterator::value); + +struct DerivedIter : JoinIter{}; + +static_assert(!std::__is_segmented_iterator::value);