From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 7595B3851ABA; Wed, 12 Oct 2022 15:14:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7595B3851ABA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1665587696; bh=d0CQ/PzdFzQbg8bNsrgt4aj8alRgwPvHotPfoxlBxHg=; h=From:To:Subject:Date:From; b=OoPs1p5SYOZXf+WpFD+JJttMjln2LmDWn74a5PPhUrlpaVOU5VVUMeWow1RenBTyS Jh6gEHpvnC1494raBFcC+Qy1Fhw04UQ+9g4nsAKkf4anUEv/ahoONP1aPkH9B2jsID IdW2pTIaO8A7ykhaS7H8seacdzDdhIaVocNnpqBU= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-3255] libstdc++: Implement ranges::repeat_view from P2474R2 X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: fbf423309e103b54f7c9d39b2f7870b9bedfe9d2 X-Git-Newrev: bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360 Message-Id: <20221012151456.7595B3851ABA@sourceware.org> Date: Wed, 12 Oct 2022 15:14:56 +0000 (GMT) List-Id: https://gcc.gnu.org/g:bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360 commit r13-3255-gbfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360 Author: Patrick Palka Date: Wed Oct 12 11:14:11 2022 -0400 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. Diff: --- libstdc++-v3/include/std/ranges | 210 ++++++++++++++++++++++++++ libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 93 ++++++++++++ 2 files changed, 303 insertions(+) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 1f821128d2d..5857d426a66 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 + 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> + { + __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 + 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 + repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>; + + template + requires __detail::__is_integer_like<_Bound> || same_as<_Bound, unreachable_sentinel_t> + class repeat_view<_Tp, _Bound>::_Iterator + { + using __index_type + = __conditional_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(__x._M_current) + - static_cast(__y._M_current)); + } + }; + + namespace views + { + namespace __detail + { + template + concept __can_repeat_view + = requires { repeat_view(std::declval<_Tp>()); }; + + template + concept __can_bounded_repeat_view + = requires { repeat_view(std::declval<_Tp>(), std::declval<_Bound>()); }; + } + + struct _Repeat + { + template + requires __detail::__can_repeat_view<_Tp> + constexpr auto + operator() [[nodiscard]] (_Tp&& __value) const + { return repeat_view(std::forward<_Tp>(__value)); } + + template + 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 00000000000..3698ed12c14 --- /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 +#include +#include + +namespace ranges = std::ranges; +namespace views = std::views; + +constexpr bool +test01() +{ + auto v = views::repeat(42); + static_assert(ranges::random_access_range + && !ranges::sized_range); + 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 + && ranges::sized_range); + 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(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()); +}