};
#endif // C++20
+ namespace __detail
+ {
+#if __cplusplus > 201703L && __cpp_lib_concepts
+ template<typename _Iterator>
+ struct __move_iter_cat
+ { };
+
+ template<typename _Iterator>
+ requires requires { typename iterator_traits<_Iterator>::iterator_category; }
+ struct __move_iter_cat<_Iterator>
+ {
+ using iterator_category
+ = __clamp_iter_cat<typename iterator_traits<_Iterator>::iterator_category,
+ random_access_iterator_tag>;
+ };
+#endif
+ }
+
// 24.4.3 Move iterators
/**
* Class template move_iterator is an iterator adapter with the same
*/
template<typename _Iterator>
class move_iterator
+#if __cplusplus > 201703L && __cpp_lib_concepts
+ : public __detail::__move_iter_cat<_Iterator>
+#endif
{
_Iterator _M_current;
using __traits_type = iterator_traits<_Iterator>;
-#if __cplusplus > 201703L && __cpp_lib_concepts
- using __base_cat = typename __traits_type::iterator_category;
-#else
+#if ! (__cplusplus > 201703L && __cpp_lib_concepts)
using __base_ref = typename __traits_type::reference;
#endif
#if __cplusplus > 201703L && __cpp_lib_concepts
using iterator_concept = input_iterator_tag;
- using iterator_category
- = __detail::__clamp_iter_cat<__base_cat, random_access_iterator_tag>;
+ // iterator_category defined in __move_iter_cat
using value_type = iter_value_t<_Iterator>;
using difference_type = iter_difference_t<_Iterator>;
using pointer = _Iterator;
|| is_reference_v<iter_reference_t<_It>>
|| constructible_from<iter_value_t<_It>, iter_reference_t<_It>>);
+ template<typename _It>
+ concept __common_iter_use_postfix_proxy
+ = (!requires (_It& __i) { { *__i++ } -> __can_reference; })
+ && constructible_from<iter_value_t<_It>, iter_reference_t<_It>>;
} // namespace __detail
/// An iterator/sentinel adaptor for representing a non-common range.
_S_noexcept()
{ return _S_noexcept1<_It, _It2>() && _S_noexcept1<_Sent, _Sent2>(); }
- class _Proxy
+ class __arrow_proxy
{
iter_value_t<_It> _M_keep;
- _Proxy(iter_reference_t<_It>&& __x)
+ __arrow_proxy(iter_reference_t<_It>&& __x)
: _M_keep(std::move(__x)) { }
friend class common_iterator;
{ return std::__addressof(_M_keep); }
};
+ class __postfix_proxy
+ {
+ iter_value_t<_It> _M_keep;
+
+ __postfix_proxy(iter_reference_t<_It>&& __x)
+ : _M_keep(std::move(__x)) { }
+
+ friend class common_iterator;
+
+ public:
+ const iter_value_t<_It>&
+ operator*() const
+ { return _M_keep; }
+ };
+
public:
constexpr
common_iterator()
return std::__addressof(__tmp);
}
else
- return _Proxy{*_M_it};
+ return __arrow_proxy{*_M_it};
}
common_iterator&
++*this;
return __tmp;
}
- else
+ else if constexpr (!__detail::__common_iter_use_postfix_proxy<_It>)
return _M_it++;
+ else
+ {
+ __postfix_proxy __p(**this);
+ ++*this;
+ return __p;
+ }
}
template<typename _It2, sentinel_for<_It> _Sent2>
using type = decltype(std::declval<const _CIter&>().operator->());
};
+ static auto
+ _S_iter_cat()
+ {
+ using _Traits = iterator_traits<_It>;
+ if constexpr (requires { requires derived_from<typename _Traits::iterator_category,
+ forward_iterator_tag>; })
+ return forward_iterator_tag{};
+ else
+ return input_iterator_tag{};
+ }
+
public:
using iterator_concept = conditional_t<forward_iterator<_It>,
forward_iterator_tag, input_iterator_tag>;
- using iterator_category = __detail::__clamp_iter_cat<
- typename iterator_traits<_It>::iterator_category,
- forward_iterator_tag, input_iterator_tag>;
+ using iterator_category = decltype(_S_iter_cat());
using value_type = iter_value_t<_It>;
using difference_type = iter_difference_t<_It>;
using pointer = typename __ptr<_It>::type;
// [iterators.counted] Counted iterators
+ namespace __detail
+ {
+ template<typename _It>
+ struct __counted_iter_value_type
+ { };
+
+ template<indirectly_readable _It>
+ struct __counted_iter_value_type<_It>
+ { using value_type = iter_value_t<_It>; };
+
+ template<typename _It>
+ struct __counted_iter_concept
+ { };
+
+ template<typename _It>
+ requires requires { typename _It::iterator_concept; }
+ struct __counted_iter_concept<_It>
+ { using iterator_concept = typename _It::iterator_concept; };
+
+ template<typename _It>
+ struct __counted_iter_cat
+ { };
+
+ template<typename _It>
+ requires requires { typename _It::iterator_category; }
+ struct __counted_iter_cat<_It>
+ { using iterator_category = typename _It::iterator_category; };
+ }
+
/// An iterator adaptor that keeps track of the distance to the end.
template<input_or_output_iterator _It>
class counted_iterator
+ : public __detail::__counted_iter_value_type<_It>,
+ public __detail::__counted_iter_concept<_It>,
+ public __detail::__counted_iter_cat<_It>
{
public:
using iterator_type = _It;
+ // value_type defined in __counted_iter_value_type
+ using difference_type = iter_difference_t<_It>;
+ // iterator_concept defined in __counted_iter_concept
+ // iterator_category defined in __counted_iter_cat
constexpr counted_iterator() = default;
return *_M_current;
}
+ constexpr auto
+ operator->() const noexcept
+ requires contiguous_iterator<_It>
+ { return std::to_address(_M_current); }
+
constexpr counted_iterator&
operator++()
{
iter_difference_t<_It> _M_length = 0;
};
- template<typename _It>
- struct incrementable_traits<counted_iterator<_It>>
- {
- using difference_type = iter_difference_t<_It>;
- };
-
template<input_iterator _It>
+ requires same_as<__detail::__iter_traits<_It>, iterator_traits<_It>>
struct iterator_traits<counted_iterator<_It>> : iterator_traits<_It>
{
- using pointer = void;
+ using pointer = conditional_t<contiguous_iterator<_It>,
+ add_pointer_t<iter_reference_t<_It>>,
+ void>;
};
#endif // C++20
{ __j - __j } -> convertible_to<__iota_diff_t<_It>>;
};
+ template<typename _Winc>
+ struct __iota_view_iter_cat
+ { };
+
+ template<incrementable _Winc>
+ struct __iota_view_iter_cat<_Winc>
+ { using iterator_category = input_iterator_tag; };
} // namespace __detail
template<weakly_incrementable _Winc,
private:
struct _Sentinel;
- struct _Iterator
+ struct _Iterator : __detail::__iota_view_iter_cat<_Winc>
{
private:
static auto
- _S_iter_cat()
+ _S_iter_concept()
{
using namespace __detail;
if constexpr (__advanceable<_Winc>)
}
public:
- using iterator_category = decltype(_S_iter_cat());
+ using iterator_concept = decltype(_S_iter_concept());
+ // iterator_category defined in __iota_view_iter_cat
using value_type = _Winc;
using difference_type = __detail::__iota_diff_t<_Winc>;
_M_offset = __it - ranges::begin(__r);
}
};
+ } // namespace __detail
+
+ namespace __detail
+ {
+ template<typename _Base>
+ struct __filter_view_iter_cat
+ { };
+ template<forward_range _Base>
+ struct __filter_view_iter_cat<_Base>
+ {
+ private:
+ static auto
+ _S_iter_cat()
+ {
+ using _Cat = typename iterator_traits<iterator_t<_Base>>::iterator_category;
+ if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
+ return bidirectional_iterator_tag{};
+ else if constexpr (derived_from<_Cat, forward_iterator_tag>)
+ return forward_iterator_tag{};
+ else
+ return _Cat{};
+ }
+ public:
+ using iterator_category = decltype(_S_iter_cat());
+ };
} // namespace __detail
template<input_range _Vp,
private:
struct _Sentinel;
- struct _Iterator
+ struct _Iterator : __detail::__filter_view_iter_cat<_Vp>
{
private:
static constexpr auto
return input_iterator_tag{};
}
- static constexpr auto
- _S_iter_cat()
- {
- using _Cat = typename iterator_traits<_Vp_iter>::iterator_category;
- if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
- return bidirectional_iterator_tag{};
- else if constexpr (derived_from<_Cat, forward_iterator_tag>)
- return forward_iterator_tag{};
- else
- return _Cat{};
- }
-
friend filter_view;
using _Vp_iter = iterator_t<_Vp>;
public:
using iterator_concept = decltype(_S_iter_concept());
- using iterator_category = decltype(_S_iter_cat());
+ // iterator_category defined in __filter_view_iter_cat
using value_type = range_value_t<_Vp>;
using difference_type = range_difference_t<_Vp>;
{
private:
template<bool _Const>
- struct _Sentinel;
+ using _Base = __detail::__maybe_const_t<_Const, _Vp>;
template<bool _Const>
- struct _Iterator
+ struct __iter_cat
+ { };
+
+ template<bool _Const>
+ requires forward_range<_Base<_Const>>
+ struct __iter_cat<_Const>
{
private:
- using _Parent = __detail::__maybe_const_t<_Const, transform_view>;
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
-
- static constexpr auto
- _S_iter_concept()
- {
- if constexpr (random_access_range<_Vp>)
- return random_access_iterator_tag{};
- else if constexpr (bidirectional_range<_Vp>)
- return bidirectional_iterator_tag{};
- else if constexpr (forward_range<_Vp>)
- return forward_iterator_tag{};
- else
- return input_iterator_tag{};
- }
-
- static constexpr auto
+ static auto
_S_iter_cat()
{
+ using _Base = transform_view::_Base<_Const>;
using _Res = invoke_result_t<_Fp&, range_reference_t<_Base>>;
if constexpr (is_lvalue_reference_v<_Res>)
{
using _Cat
- = typename iterator_traits<_Base_iter>::iterator_category;
+ = typename iterator_traits<iterator_t<_Base>>::iterator_category;
if constexpr (derived_from<_Cat, contiguous_iterator_tag>)
return random_access_iterator_tag{};
else
else
return input_iterator_tag{};
}
+ public:
+ using iterator_category = decltype(_S_iter_cat());
+ };
+
+ template<bool _Const>
+ struct _Sentinel;
+
+ template<bool _Const>
+ struct _Iterator : __iter_cat<_Const>
+ {
+ private:
+ using _Parent = __detail::__maybe_const_t<_Const, transform_view>;
+ using _Base = transform_view::_Base<_Const>;
+
+ static auto
+ _S_iter_concept()
+ {
+ if constexpr (random_access_range<_Vp>)
+ return random_access_iterator_tag{};
+ else if constexpr (bidirectional_range<_Vp>)
+ return bidirectional_iterator_tag{};
+ else if constexpr (forward_range<_Vp>)
+ return forward_iterator_tag{};
+ else
+ return input_iterator_tag{};
+ }
using _Base_iter = iterator_t<_Base>;
public:
using iterator_concept = decltype(_S_iter_concept());
- using iterator_category = decltype(_S_iter_cat());
+ // iterator_category defined in __transform_view_iter_cat
using value_type
= remove_cvref_t<invoke_result_t<_Fp&, range_reference_t<_Base>>>;
using difference_type = range_difference_t<_Base>;
{
private:
using _Parent = __detail::__maybe_const_t<_Const, transform_view>;
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = transform_view::_Base<_Const>;
template<bool _Const2>
constexpr auto
using _InnerRange = range_reference_t<_Vp>;
template<bool _Const>
+ using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+
+ template<bool _Const>
+ using _Outer_iter = iterator_t<_Base<_Const>>;
+
+ template<bool _Const>
+ using _Inner_iter = iterator_t<range_reference_t<_Base<_Const>>>;
+
+ template<bool _Const>
+ static constexpr bool _S_ref_is_glvalue
+ = is_reference_v<range_reference_t<_Base<_Const>>>;
+
+ template<bool _Const>
+ struct __iter_cat
+ { };
+
+ template<bool _Const>
+ requires _S_ref_is_glvalue<_Const>
+ && forward_range<_Base<_Const>>
+ && forward_range<range_reference_t<_Base<_Const>>>
+ struct __iter_cat<_Const>
+ {
+ private:
+ static constexpr auto
+ _S_iter_cat()
+ {
+ using _Outer_iter = join_view::_Outer_iter<_Const>;
+ using _Inner_iter = join_view::_Inner_iter<_Const>;
+ using _OuterCat = typename iterator_traits<_Outer_iter>::iterator_category;
+ using _InnerCat = typename iterator_traits<_Inner_iter>::iterator_category;
+ if constexpr (derived_from<_OuterCat, bidirectional_iterator_tag>
+ && derived_from<_InnerCat, bidirectional_iterator_tag>)
+ return bidirectional_iterator_tag{};
+ else if constexpr (derived_from<_OuterCat, forward_iterator_tag>
+ && derived_from<_InnerCat, forward_iterator_tag>)
+ return forward_iterator_tag{};
+ else
+ return input_iterator_tag{};
+ }
+ public:
+ using iterator_category = decltype(_S_iter_cat());
+ };
+
+ template<bool _Const>
struct _Sentinel;
template<bool _Const>
- struct _Iterator
+ struct _Iterator : __iter_cat<_Const>
{
private:
using _Parent = __detail::__maybe_const_t<_Const, join_view>;
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = join_view::_Base<_Const>;
static constexpr bool _S_ref_is_glvalue
- = is_reference_v<range_reference_t<_Base>>;
+ = join_view::_S_ref_is_glvalue<_Const>;
constexpr void
_M_satisfy()
return input_iterator_tag{};
}
- static constexpr auto
- _S_iter_cat()
- {
- using _OuterCat
- = typename iterator_traits<_Outer_iter>::iterator_category;
- using _InnerCat
- = typename iterator_traits<_Inner_iter>::iterator_category;
- if constexpr (_S_ref_is_glvalue
- && derived_from<_OuterCat, bidirectional_iterator_tag>
- && derived_from<_InnerCat, bidirectional_iterator_tag>)
- return bidirectional_iterator_tag{};
- else if constexpr (_S_ref_is_glvalue
- && derived_from<_OuterCat, forward_iterator_tag>
- && derived_from<_InnerCat, forward_iterator_tag>)
- return forward_iterator_tag{};
- else if constexpr (derived_from<_OuterCat, input_iterator_tag>
- && derived_from<_InnerCat, input_iterator_tag>)
- return input_iterator_tag{};
- else
- return output_iterator_tag{};
- }
-
- using _Outer_iter = iterator_t<_Base>;
- using _Inner_iter = iterator_t<range_reference_t<_Base>>;
+ using _Outer_iter = join_view::_Outer_iter<_Const>;
+ using _Inner_iter = join_view::_Inner_iter<_Const>;
_Outer_iter _M_outer = _Outer_iter();
_Inner_iter _M_inner = _Inner_iter();
public:
using iterator_concept = decltype(_S_iter_concept());
- using iterator_category = decltype(_S_iter_cat());
+ // iterator_category defined in __join_view_iter_cat
using value_type = range_value_t<range_reference_t<_Base>>;
using difference_type
= common_type_t<range_difference_t<_Base>,
{
private:
using _Parent = __detail::__maybe_const_t<_Const, join_view>;
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = join_view::_Base<_Const>;
template<bool _Const2>
constexpr bool
&& requires
{ typename __require_constant<remove_reference_t<_Range>::size()>; }
&& (remove_reference_t<_Range>::size() <= 1);
+
+ template<typename _Base>
+ struct __split_view_outer_iter_cat
+ { };
+
+ template<forward_range _Base>
+ struct __split_view_outer_iter_cat<_Base>
+ { using iterator_category = input_iterator_tag; };
+
+ template<typename _Base>
+ struct __split_view_inner_iter_cat
+ { };
+
+ template<forward_range _Base>
+ struct __split_view_inner_iter_cat<_Base>
+ {
+ private:
+ static constexpr auto
+ _S_iter_cat()
+ {
+ using _Cat = typename iterator_traits<iterator_t<_Base>>::iterator_category;
+ if constexpr (derived_from<_Cat, forward_iterator_tag>)
+ return forward_iterator_tag{};
+ else
+ return _Cat{};
+ }
+ public:
+ using iterator_category = decltype(_S_iter_cat());
+ };
}
template<input_range _Vp, forward_range _Pattern>
{
private:
template<bool _Const>
+ using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+
+ template<bool _Const>
struct _InnerIter;
template<bool _Const>
struct _OuterIter
+ : __detail::__split_view_outer_iter_cat<_Base<_Const>>
{
private:
using _Parent = __detail::__maybe_const_t<_Const, split_view>;
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = split_view::_Base<_Const>;
constexpr bool
__at_end() const
using iterator_concept = conditional_t<forward_range<_Base>,
forward_iterator_tag,
input_iterator_tag>;
- using iterator_category = input_iterator_tag;
+ // iterator_category defined in __split_view_outer_iter_cat
using difference_type = range_difference_t<_Base>;
struct value_type : view_interface<value_type>
template<bool _Const>
struct _InnerIter
+ : __detail::__split_view_inner_iter_cat<_Base<_Const>>
{
private:
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = split_view::_Base<_Const>;
constexpr bool
__at_end() const
}
}
- static constexpr auto
- _S_iter_cat()
- {
- using _Cat
- = typename iterator_traits<iterator_t<_Base>>::iterator_category;
- if constexpr (derived_from<_Cat, forward_iterator_tag>)
- return forward_iterator_tag{};
- else
- return _Cat{};
- }
-
constexpr auto&
_M_i_current() noexcept
{ return _M_i.__current(); }
public:
using iterator_concept
= typename _OuterIter<_Const>::iterator_concept;
- using iterator_category = decltype(_S_iter_cat());
+ // iterator_category defined in __split_view_inner_iter_cat
using value_type = range_value_t<_Base>;
using difference_type = range_difference_t<_Base>;
private:
template<bool _Const>
+ using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+
+ template<bool _Const>
+ struct __iter_cat
+ { };
+
+ template<bool _Const>
+ requires forward_range<_Base<_Const>>
+ struct __iter_cat<_Const>
+ {
+ private:
+ static auto _S_iter_cat()
+ {
+ using _Base = elements_view::_Base<_Const>;
+ using _Cat = iterator_traits<iterator_t<_Base>>::iterator_category;
+ using _Res = decltype((std::get<_Nm>(*std::declval<iterator_t<_Base>>())));
+ if constexpr (!is_lvalue_reference_v<_Res>)
+ return input_iterator_tag{};
+ else if constexpr (derived_from<_Cat, random_access_iterator_tag>)
+ return random_access_iterator_tag{};
+ else
+ return _Cat{};
+ }
+ public:
+ using iterator_category = decltype(_S_iter_cat());
+ };
+
+ template<bool _Const>
struct _Sentinel;
template<bool _Const>
- struct _Iterator
+ struct _Iterator : __iter_cat<_Const>
{
private:
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = elements_view::_Base<_Const>;
iterator_t<_Base> _M_current = iterator_t<_Base>();
}
}
+ static auto
+ _S_iter_concept()
+ {
+ if constexpr (random_access_range<_Vp>)
+ return random_access_iterator_tag{};
+ else if constexpr (bidirectional_range<_Vp>)
+ return bidirectional_iterator_tag{};
+ else if constexpr (forward_range<_Vp>)
+ return forward_iterator_tag{};
+ else
+ return input_iterator_tag{};
+ }
+
friend _Iterator<!_Const>;
public:
- using iterator_category
- = typename iterator_traits<iterator_t<_Base>>::iterator_category;
+ using iterator_concept = decltype(_S_iter_concept());
+ // iterator_category defined in elements_view::__iter_cat
using value_type
= remove_cvref_t<tuple_element_t<_Nm, range_value_t<_Base>>>;
using difference_type = range_difference_t<_Base>;
_M_equal(const _Iterator<_Const>& __x) const
{ return __x._M_current == _M_end; }
- using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+ using _Base = elements_view::_Base<_Const>;
sentinel_t<_Base> _M_end = sentinel_t<_Base>();
public:
--- /dev/null
+// Copyright (C) 2021 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Verify P2259 changes.
+
+#include <ranges>
+#include <tuple>
+#include <vector>
+
+namespace ranges = std::ranges;
+namespace views = std::views;
+
+using std::__detail::__iter_without_category;
+
+template<typename _Range>
+concept only_cxx20_input_range = ranges::input_range<_Range>
+ && !ranges::forward_range<_Range>
+ && __iter_without_category<ranges::iterator_t<_Range>>;
+
+void
+test01()
+{
+ extern std::vector<int> vec;
+ only_cxx20_input_range auto v0
+ = vec
+ | views::transform([](int c) { return views::single(c); })
+ | views::join;
+
+ // Verify the changes to filter_view.
+ only_cxx20_input_range auto v1 = v0 | views::filter([](int c) { return c > 0; });
+
+ // Verify the changes to transform_view.
+ only_cxx20_input_range auto v2 = v0 | views::transform([](int& c) -> auto& { return c; });
+
+ // Verify the changes to split_view.
+ only_cxx20_input_range auto v3 = v0 | views::split(12);
+ static_assert(only_cxx20_input_range<decltype(*v3.begin())>);
+
+ // Verify the changes to join_view.
+ only_cxx20_input_range auto v4 = v0 | views::split(12) | views::join;
+
+ // Verify the changes to elements_view.
+ only_cxx20_input_range auto v5
+ = v0
+ | views::transform([](int c) { return std::make_tuple(c, c); })
+ | views::elements<0>;
+
+ // Verify the changes to common_iterator.
+ only_cxx20_input_range auto v6 = v0 | views::common;
+ *(v6.begin()++);
+
+ // Verify the changes to iota_view.
+ only_cxx20_input_range auto v8 = ranges::iota_view{v0.begin()};
+
+ // Verify the changes to move_iterator.
+ __iter_without_category auto i9 = std::make_move_iterator(v0.begin());
+
+ // Verify the changes to counted_iterator.
+ extern std::counted_iterator<int*> i10;
+ static_assert(std::contiguous_iterator<decltype(i10)>);
+ static_assert(std::same_as<std::iterator_traits<decltype(i10)>::iterator_category,
+ std::random_access_iterator_tag>);
+ i10.operator->();
+ __iter_without_category auto i11 = std::counted_iterator{v0.begin(), 5};
+}
+
+void
+test02()
+{
+ // Verify LWG 3291 example.
+ auto v = views::iota(0);
+ auto i = std::counted_iterator{v.begin(), 5};
+ static_assert(std::random_access_iterator<decltype(i)>);
+}