From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id DA59B3858437 for ; Tue, 11 Oct 2022 02:51:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DA59B3858437 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1665456679; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=rSOsoHms8egAMaL/PcHfkLWGn047tXUo7S8AjFTaqQk=; b=HtMSEUGrXIB+DqxrfO0VpGkYmhi2r/L9CQirYXtA5aQE9wIQcBFIsf2gD0G6yCsYPBf05Q arFZu2vKWCd9FEN1S8zUEEMcftlB0ZHQCJUiHDKzdRzx3Qql1qIEsPav3k91laBO++NakD n9E6He3iTMfdWhBkghnDr9iB4uHMsxU= Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-219-H8avFLGiNwWeVE3x8sIOeA-1; Mon, 10 Oct 2022 22:51:18 -0400 X-MC-Unique: H8avFLGiNwWeVE3x8sIOeA-1 Received: by mail-qk1-f199.google.com with SMTP id ay35-20020a05620a17a300b006cfc01b4436so10678584qkb.13 for ; Mon, 10 Oct 2022 19:51:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=rSOsoHms8egAMaL/PcHfkLWGn047tXUo7S8AjFTaqQk=; b=p++cB0/WhCFTkRC/wAyCSPbQ465bqwzh6kFlHx13ToYVD3eongwqI7yD7aUXQj7l/k 0xkLVbjmWWYOHyBZv4KBAK6HebH5ni1r5GAmO08IEW1QJzDfEh9fBYOjvxRa2DZnMRYG OcvpDZewPSSWcVIIHHctR/WlwKbKp6p/zFWjEFhMjZdUCFKMMpQz1vI1guADEyq+ZqOA Kw3LBbyH3dUkEDBh0hCeIrVZ0mLMgV3bD7eIDHpLbYiimeKObbw+dK7JcnRBXXQXZoDI sdr5rMQjphus3ZWg9Jaf+ZF+Eug+7OMFabqG/nbJcKkRGmFS+AZCxogoYvVWoXSZ+k5D rEvw== X-Gm-Message-State: ACrzQf3CCmVDu5L6LzWjwL8fU2JKS8g+ayEY+rem628JIvrUHQJgvmoE BvTdHZqeX2qWw53UHy4+1l/+WhKt5alg/0qbYtTepUQzs6KgILcwVi43qTe9yyn7/0cw9B2FXng baA+Vi8CICHkg23XwmZ77pQ9BX5Poava4UGHUQgxYPB2ST5R3fFnGFuc6fn/mbolyOIo= X-Received: by 2002:a05:620a:438d:b0:6e2:a30c:25d1 with SMTP id a13-20020a05620a438d00b006e2a30c25d1mr14956822qkp.155.1665456677151; Mon, 10 Oct 2022 19:51:17 -0700 (PDT) X-Google-Smtp-Source: AMsMyM52W7BOEsWQGnyU4pgcnfRNwgjPksYR6u6H80NxIr8hkIXATRqR1JlYEC/XGB8Bh/ALTJjSvg== X-Received: by 2002:a05:620a:438d:b0:6e2:a30c:25d1 with SMTP id a13-20020a05620a438d00b006e2a30c25d1mr14956808qkp.155.1665456676775; Mon, 10 Oct 2022 19:51:16 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b006c73c3d288esm11513195qkb.131.2022.10.10.19.51.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Oct 2022 19:51:16 -0700 (PDT) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, Patrick Palka Subject: [PATCH] libstdc++: Implement ranges::repeat_view from P2474R2 Date: Mon, 10 Oct 2022 22:51:13 -0400 Message-Id: <20221011025113.624107-1-ppalka@redhat.com> X-Mailer: git-send-email 2.38.0.15.gbbe21b64a0 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-14.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_NUMSUBJECT,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Tested on x86_64-pc-linux-gnu, does this look OK for trunk? (The paper also makes changes to views::take and views::drop, which will be implemented separately.) 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. --- libstdc++-v3/include/std/ranges | 210 ++++++++++++++++++ libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 93 ++++++++ 2 files changed, 303 insertions(+) create mode 100644 libstdc++-v3/testsuite/std/ranges/repeat/1.cc 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()); +} -- 2.38.0.15.gbbe21b64a0