mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 23:25:24 +02:00
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:
@@ -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
|
||||
|
||||
|
||||
93
libstdc++-v3/testsuite/std/ranges/repeat/1.cc
Normal file
93
libstdc++-v3/testsuite/std/ranges/repeat/1.cc
Normal 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());
|
||||
}
|
||||
Reference in New Issue
Block a user