diff options
author | Patrick Palka <ppalka@redhat.com> | 2022-10-12 11:14:11 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2022-10-12 11:14:11 -0400 |
commit | bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360 (patch) | |
tree | 46a78efd572379901fefd61f470d5d908be435b1 | |
parent | fbf423309e103b54f7c9d39b2f7870b9bedfe9d2 (diff) | |
download | gcc-bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360.zip gcc-bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360.tar.gz gcc-bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360.tar.bz2 |
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.
-rw-r--r-- | libstdc++-v3/include/std/ranges | 210 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 93 |
2 files changed, 303 insertions, 0 deletions
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 1f82112..5857d42 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -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 diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc new file mode 100644 index 0000000..3698ed1 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc @@ -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()); +} |