1 // Copyright (C) 2019-2021 Free Software Foundation, Inc.
2 //
3 // This file is part of the GNU ISO C++ Library. This library is free
4 // software; you can redistribute it and/or modify it under the
5 // terms of the GNU General Public License as published by the
6 // Free Software Foundation; either version 3, or (at your option)
7 // any later version.
8
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13
14 // You should have received a copy of the GNU General Public License along
15 // with this library; see the file COPYING3. If not see
16 // <http://www.gnu.org/licenses/>.
17
18 // { dg-options "-std=gnu++2a" }
19 // { dg-do run { target c++2a } }
20
21 #include <ranges>
22 #include <testsuite_hooks.h>
23 using std::same_as;
24
25 void
test01()26 test01()
27 {
28 int a[2] = {};
29
30 static_assert(same_as<decltype(std::ranges::cbegin(a)), const int*>);
31 static_assert(noexcept(std::ranges::cbegin(a)));
32 VERIFY( std::ranges::cbegin(a) == (a + 0) );
33
34 constexpr long b[2] = {};
35 static_assert( std::ranges::cbegin(b) == (b + 0) );
36 }
37
38 struct R
39 {
40 int a[4] = { 0, 1, 2, 3 };
41
begin(R & r)42 friend int* begin(R& r) { return r.a + 0; }
43 friend int* begin(R&&); // this function is not defined
begin(const R & r)44 friend const int* begin(const R& r) noexcept { return r.a + 2; }
45 friend const int* begin(const R&&); // this function is not defined
46 };
47
48 struct RV // view on an R
49 {
50 R& r;
51
52 friend int* begin(RV&); // this function is not defined
begin(const RV & rv)53 friend const int* begin(const RV& rv) noexcept { return begin(std::as_const(rv.r)); }
54 };
55
56 // Allow ranges::begin to work with RV&&
57 template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
58
59 void
test03()60 test03()
61 {
62 R r;
63 const R& c = r;
64 VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c));
65 VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c));
66
67 RV v{r};
68 VERIFY(std::ranges::cbegin(std::move(v)) == std::ranges::begin(c));
69 const RV cv{r};
70 VERIFY(std::ranges::cbegin(std::move(cv)) == std::ranges::begin(c));
71 }
72
73 struct RR
74 {
75 short s = 0;
76 long l = 0;
77 int a[4] = { 0, 1, 2, 3 };
78
beginRR79 short* begin() noexcept { return &s; }
beginRR80 const long* begin() const { return &l; }
81
begin(RR & r)82 friend int* begin(RR& r) { return r.a + 0; }
begin(RR && r)83 friend int* begin(RR&& r) { return r.a + 1; }
begin(const RR & r)84 friend const int* begin(const RR& r) { return r.a + 2; }
begin(const RR && r)85 friend const int* begin(const RR&& r) noexcept { return r.a + 3; }
86 };
87
88 // N.B. this is a lie, cbegin on an RR rvalue will return a dangling pointer.
89 template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
90
91 void
test04()92 test04()
93 {
94 RR r;
95 const RR& c = r;
96 VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c));
97 VERIFY(std::ranges::cbegin(std::move(r)) == std::ranges::begin(c));
98 VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c));
99 VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(c));
100 }
101
102 int
main()103 main()
104 {
105 test01();
106 test03();
107 test04();
108 }
109