libstdc++/ranges: Implement various small LWG issues
This implements the following small LWG issues: 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap 3947. Unexpected constraints on adjacent_transform_view::base() 4001. iota_view should provide empty 4012. common_view::begin/end are missing the simple-view check 4013. lazy_split_view::outer-iterator::value_type should not provide default constructor 4035. single_view should provide empty 4053. Unary call to std::views::repeat does not decay the argument 4054. Repeating a repeat_view should repeat the view libstdc++-v3/ChangeLog: * include/std/ranges (single_view::empty): Define as per LWG 4035. (iota_view::empty): Define as per LWG 4001. (lazy_split_view::_OuterIter::value_type): Remove default constructor and make other constructor private as per LWG 4013. (common_view::begin): Disable non-const overload for simple views as per LWG 4012. (common_view::end): Likewise. (adjacent_view::base): Define as per LWG 3848. (adjacent_transform_view::base): Likewise. (chunk_view::_InnerIter::iter_move): Define as per LWG 3851. (chunk_view::_InnerIter::itep_swap): Likewise. (slide_view::base): Define as per LWG 3848. (repeat_view): Adjust deduction guide as per LWG 4053. (_Repeat::operator()): Adjust single-parameter overload as per LWG 4054. * testsuite/std/ranges/adaptors/adjacent/1.cc: Verify existence of base member function. * testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise. * testsuite/std/ranges/adaptors/chunk/1.cc: Test LWG 3851 example. * testsuite/std/ranges/adaptors/slide/1.cc: Verify existence of base member function. * testsuite/std/ranges/iota/iota_view.cc: Test LWG 4001 example. * testsuite/std/ranges/repeat/1.cc: Test LWG 4053/4054 examples. Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
This commit is contained in:
parent
c679cafb0d
commit
20165d0107
7 changed files with 135 additions and 8 deletions
|
@ -335,6 +335,12 @@ namespace ranges
|
|||
end() const noexcept
|
||||
{ return data() + 1; }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4035. single_view should provide empty
|
||||
static constexpr bool
|
||||
empty() noexcept
|
||||
{ return false; }
|
||||
|
||||
static constexpr size_t
|
||||
size() noexcept
|
||||
{ return 1; }
|
||||
|
@ -695,6 +701,12 @@ namespace ranges
|
|||
end() const requires same_as<_Winc, _Bound>
|
||||
{ return _Iterator{_M_bound}; }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4001. iota_view should provide empty
|
||||
constexpr bool
|
||||
empty() const
|
||||
{ return _M_value == _M_bound; }
|
||||
|
||||
constexpr auto
|
||||
size() const
|
||||
requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>)
|
||||
|
@ -3349,14 +3361,17 @@ namespace views::__adaptor
|
|||
private:
|
||||
_OuterIter _M_i = _OuterIter();
|
||||
|
||||
public:
|
||||
value_type() = default;
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4013. lazy_split_view::outer-iterator::value_type should not
|
||||
// provide default constructor
|
||||
constexpr explicit
|
||||
value_type(_OuterIter __i)
|
||||
: _M_i(std::move(__i))
|
||||
{ }
|
||||
|
||||
friend _OuterIter;
|
||||
|
||||
public:
|
||||
constexpr _InnerIter<_Const>
|
||||
begin() const
|
||||
{ return _InnerIter<_Const>{_M_i}; }
|
||||
|
@ -3948,8 +3963,10 @@ namespace views::__adaptor
|
|||
base() &&
|
||||
{ return std::move(_M_base); }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4012. common_view::begin/end are missing the simple-view check
|
||||
constexpr auto
|
||||
begin()
|
||||
begin() requires (!__detail::__simple_view<_Vp>)
|
||||
{
|
||||
if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
|
||||
return ranges::begin(_M_base);
|
||||
|
@ -3969,7 +3986,7 @@ namespace views::__adaptor
|
|||
}
|
||||
|
||||
constexpr auto
|
||||
end()
|
||||
end() requires (!__detail::__simple_view<_Vp>)
|
||||
{
|
||||
if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
|
||||
return ranges::begin(_M_base) + ranges::size(_M_base);
|
||||
|
@ -5316,6 +5333,16 @@ namespace views::__adaptor
|
|||
: _M_base(std::move(__base))
|
||||
{ }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
|
||||
constexpr _Vp
|
||||
base() const & requires copy_constructible<_Vp>
|
||||
{ return _M_base; }
|
||||
|
||||
constexpr _Vp
|
||||
base() &&
|
||||
{ return std::move(_M_base); }
|
||||
|
||||
constexpr auto
|
||||
begin() requires (!__detail::__simple_view<_Vp>)
|
||||
{ return _Iterator<false>(ranges::begin(_M_base), ranges::end(_M_base)); }
|
||||
|
@ -5709,6 +5736,17 @@ namespace views::__adaptor
|
|||
: _M_fun(std::move(__fun)), _M_inner(std::move(__base))
|
||||
{ }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
|
||||
// 3947. Unexpected constraints on adjacent_transform_view::base()
|
||||
constexpr _Vp
|
||||
base() const & requires copy_constructible<_Vp>
|
||||
{ return _M_inner.base(); }
|
||||
|
||||
constexpr _Vp
|
||||
base() &&
|
||||
{ return std::move(_M_inner.base()); }
|
||||
|
||||
constexpr auto
|
||||
begin()
|
||||
{ return _Iterator<false>(*this, _M_inner.begin()); }
|
||||
|
@ -6236,6 +6274,20 @@ namespace views::__adaptor
|
|||
operator-(const _InnerIter& __x, default_sentinel_t __y)
|
||||
requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>>
|
||||
{ return -(__y - __x); }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
|
||||
friend constexpr range_rvalue_reference_t<_Vp>
|
||||
iter_move(const _InnerIter& __i)
|
||||
noexcept(noexcept(ranges::iter_move(*__i._M_parent->_M_current)))
|
||||
{ return ranges::iter_move(*__i._M_parent->_M_current); }
|
||||
|
||||
friend constexpr void
|
||||
iter_swap(const _InnerIter& __x, const _InnerIter& __y)
|
||||
noexcept(noexcept(ranges::iter_swap(*__x._M_parent->_M_current,
|
||||
*__x._M_parent->_M_current)))
|
||||
requires indirectly_swappable<iterator_t<_Vp>>
|
||||
{ return ranges::iter_swap(*__x._M_parent->_M_current, *__y._M_parent->_M_current); }
|
||||
};
|
||||
|
||||
template<view _Vp>
|
||||
|
@ -6577,6 +6629,16 @@ namespace views::__adaptor
|
|||
: _M_base(std::move(__base)), _M_n(__n)
|
||||
{ __glibcxx_assert(__n > 0); }
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
|
||||
constexpr _Vp
|
||||
base() const & requires copy_constructible<_Vp>
|
||||
{ return _M_base; }
|
||||
|
||||
constexpr _Vp
|
||||
base() &&
|
||||
{ return std::move(_M_base); }
|
||||
|
||||
constexpr auto
|
||||
begin() requires (!(__detail::__simple_view<_Vp>
|
||||
&& __detail::__slide_caches_nothing<const _Vp>))
|
||||
|
@ -7692,8 +7754,10 @@ namespace views::__adaptor
|
|||
{ return __detail::__to_unsigned_like(_M_bound); }
|
||||
};
|
||||
|
||||
template<typename _Tp, typename _Bound>
|
||||
repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4053. Unary call to std::views::repeat does not decay the argument
|
||||
template<typename _Tp, typename _Bound = unreachable_sentinel_t>
|
||||
repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>;
|
||||
|
||||
template<move_constructible _Tp, semiregular _Bound>
|
||||
requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
|
||||
|
@ -7840,7 +7904,11 @@ namespace views::__adaptor
|
|||
requires __detail::__can_repeat_view<_Tp>
|
||||
constexpr auto
|
||||
operator() [[nodiscard]] (_Tp&& __value) const
|
||||
{ return repeat_view(std::forward<_Tp>(__value)); }
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4054. Repeating a repeat_view should repeat the view
|
||||
return repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value));
|
||||
}
|
||||
|
||||
template<typename _Tp, typename _Bound>
|
||||
requires __detail::__can_bounded_repeat_view<_Tp, _Bound>
|
||||
|
|
|
@ -47,6 +47,9 @@ test01()
|
|||
VERIFY( &std::get<2>(v3[i]) == &y[i] + 2 );
|
||||
}
|
||||
|
||||
// LWG 3848 - adjacent_view etc missing base accessor
|
||||
v3.base();
|
||||
|
||||
const auto v5 = y | views::adjacent<5>;
|
||||
VERIFY( ranges::equal(v5, views::single(std::make_tuple(1, 2, 3, 4, 5))) );
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ test01()
|
|||
VERIFY( ranges::size(v3) == 4 );
|
||||
VERIFY( ranges::equal(v3, (int[]){3, 4, 5, 6}) );
|
||||
|
||||
// LWG 3848 - adjacent_transform_view etc missing base accessor
|
||||
v3.base();
|
||||
|
||||
const auto v6 = y | views::adjacent_transform<6>([](auto...) { return 0; });
|
||||
VERIFY( ranges::equal(v6, (int[]){0}) );
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_iterators.h>
|
||||
|
@ -76,10 +77,24 @@ test02()
|
|||
VERIFY( ranges::equal(wrapper(x) | views::chunk(i) | views::join, x) );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
// LWG 3851 - chunk_view::inner-iterator missing custom iter_move and iter_swap
|
||||
auto ints = std::istringstream{"0 1 2 3 4"};
|
||||
std::vector<std::string> vs{"the", "quick", "brown", "fox"};
|
||||
auto r = views::zip(vs, views::istream<int>(ints)) | views::chunk(2) | views::join;
|
||||
std::vector<std::tuple<std::string, int>> res;
|
||||
ranges::copy(std::move_iterator(r.begin()), std::move_sentinel(r.end()),
|
||||
std::back_inserter(res));
|
||||
VERIFY( vs.front().empty() );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert(test01());
|
||||
test02<__gnu_test::test_input_range<int>>();
|
||||
test02<__gnu_test::test_forward_range<int>>();
|
||||
test03();
|
||||
}
|
||||
|
|
|
@ -50,6 +50,9 @@ test01()
|
|||
VERIFY( &v3[i][2] == &y[i] + 2 );
|
||||
}
|
||||
|
||||
// LWG 3848 - slide_view etc missing base accessor
|
||||
v3.base();
|
||||
|
||||
const auto v5 = y | views::slide(5);
|
||||
VERIFY( ranges::size(v5) == 1 );
|
||||
VERIFY( ranges::equal(v5 | views::join, y) );
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
|
@ -118,6 +119,16 @@ test07()
|
|||
static_assert(!requires { iota(nullptr, nullptr); });
|
||||
}
|
||||
|
||||
void
|
||||
test08()
|
||||
{
|
||||
// LWC 4001 - iota_view should provide empty
|
||||
std::vector<int> v;
|
||||
auto it = std::back_inserter(v);
|
||||
auto r = std::views::iota(it);
|
||||
VERIFY( !r.empty() );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
@ -128,4 +139,5 @@ main()
|
|||
test05();
|
||||
test06();
|
||||
test07();
|
||||
test08();
|
||||
}
|
||||
|
|
|
@ -151,6 +151,27 @@ test07()
|
|||
auto d2 = std::views::repeat(std::make_unique<int>(5), 4) | std::views::drop(2);
|
||||
}
|
||||
|
||||
void
|
||||
test08()
|
||||
{
|
||||
// LWG 4053 - Unary call to std::views::repeat does not decay the argument
|
||||
using type = ranges::repeat_view<const char*>;
|
||||
using type = decltype(views::repeat("foo", std::unreachable_sentinel));
|
||||
using type = decltype(views::repeat(+"foo", std::unreachable_sentinel));
|
||||
using type = decltype(views::repeat("foo"));
|
||||
using type = decltype(views::repeat(+"foo"));
|
||||
}
|
||||
|
||||
void
|
||||
test09()
|
||||
{
|
||||
// LWG 4054 - Repeating a repeat_view should repeat the view
|
||||
auto v = views::repeat(views::repeat(5));
|
||||
using type = decltype(v);
|
||||
using type = ranges::repeat_view<ranges::repeat_view<int>>;
|
||||
VERIFY( v[0][0] == 5 );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
@ -161,4 +182,6 @@ main()
|
|||
test05();
|
||||
test06();
|
||||
test07();
|
||||
test08();
|
||||
test09();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue