libstdc++: Implement ranges::repeat_view from P2474R2

libstdc++-v3/ChangeLog:

	* include/std/ranges (repeat_view): Define.
	(repeat_view::_Iterator): Define.
	(views::__detail::__can_repeat_view): Define.
	(views::__detail::__can_bounded_repeat_view): Define.
	(views::_Repeat, views::repeat): Define.
	* testsuite/std/ranges/repeat/1.cc: New test.
This commit is contained in:
Patrick Palka
2022-10-12 11:14:11 -04:00
parent fbf423309e
commit bfcd9f8453
2 changed files with 303 additions and 0 deletions

View File

@@ -7356,6 +7356,216 @@ namespace views::__adaptor
inline constexpr _JoinWith join_with;
} // namespace views
template<copy_constructible _Tp, semiregular _Bound = unreachable_sentinel_t>
requires (is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
&& (__detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>))
class repeat_view : public view_interface<repeat_view<_Tp, _Bound>>
{
__detail::__box<_Tp> _M_value = _Tp();
[[no_unique_address]] _Bound _M_bound = _Bound();
struct _Iterator;
public:
repeat_view() requires default_initializable<_Tp> = default;
constexpr explicit
repeat_view(const _Tp& __value, _Bound __bound = _Bound())
: _M_value(__value), _M_bound(__bound)
{
if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
__glibcxx_assert(__bound >= 0);
}
constexpr explicit
repeat_view(_Tp&& __value, _Bound __bound = _Bound())
: _M_value(std::move(__value)), _M_bound(__bound)
{ }
template<typename... _Args, typename... _BoundArgs>
requires constructible_from<_Tp, _Args...>
&& constructible_from<_Bound, _BoundArgs...>
constexpr explicit
repeat_view(piecewise_construct_t,
tuple<_Args...> __args,
tuple<_BoundArgs...> __bound_args = tuple<>{})
: _M_value(std::make_from_tuple<_Tp>(std::move(__args))),
_M_bound(std::make_from_tuple<_Bound>(std::move(__bound_args)))
{ }
constexpr _Iterator
begin() const
{ return _Iterator(std::__addressof(*_M_value)); }
constexpr _Iterator
end() const requires (!same_as<_Bound, unreachable_sentinel_t>)
{ return _Iterator(std::__addressof(*_M_value), _M_bound); }
constexpr unreachable_sentinel_t
end() const noexcept
{ return unreachable_sentinel; }
constexpr auto
size() const requires (!same_as<_Bound, unreachable_sentinel_t>)
{ return __detail::__to_unsigned_like(_M_bound); }
};
template<typename _Tp, typename _Bound>
repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
template<copy_constructible _Tp, semiregular _Bound>
requires __detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t>
class repeat_view<_Tp, _Bound>::_Iterator
{
using __index_type
= __conditional_t<same_as<_Bound, unreachable_sentinel_t>, ptrdiff_t, _Bound>;
const _Tp* _M_value = nullptr;
__index_type _M_current = __index_type();
constexpr explicit
_Iterator(const _Tp* __value, __index_type __bound = __index_type())
: _M_value(__value), _M_current(__bound)
{
if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
__glibcxx_assert(__bound >= 0);
}
friend repeat_view;
public:
using iterator_concept = random_access_iterator_tag;
using iterator_category = random_access_iterator_tag;
using value_type = _Tp;
using difference_type = __conditional_t<__detail::__is_signed_integer_like<__index_type>,
__index_type,
__detail::__iota_diff_t<__index_type>>;
_Iterator() = default;
constexpr const _Tp&
operator*() const noexcept
{ return *_M_value; }
constexpr _Iterator&
operator++()
{
++_M_current;
return *this;
}
constexpr _Iterator
operator++(int)
{
auto __tmp = *this;
++*this;
return __tmp;
}
constexpr _Iterator&
operator--()
{
if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
__glibcxx_assert(_M_current > 0);
--_M_current;
return *this;
}
constexpr _Iterator
operator--(int)
{
auto __tmp = *this;
--*this;
return __tmp;
}
constexpr _Iterator&
operator+=(difference_type __n)
{
if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
__glibcxx_assert(_M_current + __n >= 0);
_M_current += __n;
return *this;
}
constexpr _Iterator&
operator-=(difference_type __n)
{
if constexpr (!same_as<_Bound, unreachable_sentinel_t>)
__glibcxx_assert(_M_current - __n >= 0);
_M_current -= __n;
return *this;
}
constexpr const _Tp&
operator[](difference_type __n) const noexcept
{ return *(*this + __n); }
friend constexpr bool
operator==(const _Iterator& __x, const _Iterator& __y)
{ return __x._M_current == __y._M_current; }
friend constexpr auto
operator<=>(const _Iterator& __x, const _Iterator& __y)
{ return __x._M_current <=> __y._M_current; }
friend constexpr _Iterator
operator+(_Iterator __i, difference_type __n)
{
__i += __n;
return __i;
}
friend constexpr _Iterator
operator+(difference_type __n, _Iterator __i)
{ return __i + __n; }
friend constexpr _Iterator
operator-(_Iterator __i, difference_type __n)
{
__i -= __n;
return __i;
}
friend constexpr difference_type
operator-(const _Iterator& __x, const _Iterator& __y)
{
return (static_cast<difference_type>(__x._M_current)
- static_cast<difference_type>(__y._M_current));
}
};
namespace views
{
namespace __detail
{
template<typename _Tp>
concept __can_repeat_view
= requires { repeat_view(std::declval<_Tp>()); };
template<typename _Tp, typename _Bound>
concept __can_bounded_repeat_view
= requires { repeat_view(std::declval<_Tp>(), std::declval<_Bound>()); };
}
struct _Repeat
{
template<typename _Tp>
requires __detail::__can_repeat_view<_Tp>
constexpr auto
operator() [[nodiscard]] (_Tp&& __value) const
{ return repeat_view(std::forward<_Tp>(__value)); }
template<typename _Tp, typename _Bound>
requires __detail::__can_bounded_repeat_view<_Tp, _Bound>
constexpr auto
operator() [[nodiscard]] (_Tp&& __value, _Bound __bound) const
{ return repeat_view(std::forward<_Tp>(__value), __bound); }
};
inline constexpr _Repeat repeat;
}
#endif // C++23
} // namespace ranges

View File

@@ -0,0 +1,93 @@
// { dg-options "-std=gnu++23" }
// { dg-do run { target c++23 } }
#include <ranges>
#include <algorithm>
#include <testsuite_hooks.h>
namespace ranges = std::ranges;
namespace views = std::views;
constexpr bool
test01()
{
auto v = views::repeat(42);
static_assert(ranges::random_access_range<decltype(v)>
&& !ranges::sized_range<decltype(v)>);
auto i = ranges::begin(v);
auto s = ranges::end(v);
VERIFY( *i == 42 );
VERIFY( i[0] == 42 );
VERIFY( &i[0] == &i[1] );
VERIFY( &*i == &*(i+1) );
VERIFY( i != s );
auto j = i + 5, k = i + 12;
VERIFY( k - i == 12 );
VERIFY( k - j == 7 );
VERIFY( i - j == -5 );
VERIFY( k > j );
VERIFY( j < k );
VERIFY( i + 5 == j );
VERIFY( i != j );
VERIFY( i + 5 <= j );
VERIFY( j - 5 >= i );
return true;
}
constexpr bool
test02()
{
constexpr int bound = 20;
auto v = views::repeat(42, bound);
static_assert(ranges::random_access_range<decltype(v)>
&& ranges::sized_range<decltype(v)>);
VERIFY( ranges::equal(v, views::repeat(42) | views::take(bound)) );
auto i = ranges::begin(v);
auto s = ranges::end(v);
VERIFY( *i == 42 );
VERIFY( i[0] == 42 );
VERIFY( &i[0] == &i[1] );
VERIFY( &*i == &*(i+1) );
VERIFY( i != s );
auto j = i + 5, k = i + 12;
VERIFY( k - i == 12 );
VERIFY( k - j == 7 );
VERIFY( i - j == -5 );
VERIFY( k > j );
VERIFY( j < k );
VERIFY( i + 5 == j );
VERIFY( i != j );
VERIFY( i + 5 <= j );
VERIFY( j - 5 >= i );
VERIFY( ranges::size(v) == bound );
VERIFY( s - i == bound );
VERIFY( s - j == bound - (j - i) );
VERIFY( i + bound == s );
VERIFY( bound + i == s );
return true;
}
constexpr bool
test03()
{
struct A { int n, m; };
auto v = ranges::repeat_view<A, unsigned>(std::piecewise_construct,
std::tuple{1, 2},
std::tuple{3});
VERIFY( v[0].n == 1 );
VERIFY( v[0].m == 2 );
VERIFY( ranges::size(v) == 3 );
return true;
}
int
main()
{
static_assert(test01());
static_assert(test02());
static_assert(test03());
}