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 <utility> // as_const
23 #include <testsuite_hooks.h>
24 #include <testsuite_iterators.h>
25
26 static_assert(__gnu_test::is_customization_point_object(std::ranges::cbegin));
27
28 using std::same_as;
29
30 void
test01()31 test01()
32 {
33 int a[2] = {};
34
35 static_assert(same_as<decltype(std::ranges::cbegin(a)), const int*>);
36 static_assert(noexcept(std::ranges::cbegin(a)));
37 VERIFY( std::ranges::cbegin(a) == (a + 0) );
38
39 constexpr long b[2] = {};
40 static_assert( std::ranges::cbegin(b) == (b + 0) );
41 }
42
43 struct R
44 {
45 int a[4] = { 0, 1, 2, 3 };
46
begin(R & r)47 friend int* begin(R& r) { return r.a + 0; }
48 friend int* begin(R&&); // this function is not defined
begin(const R & r)49 friend const int* begin(const R& r) noexcept { return r.a + 2; }
50 friend const int* begin(const R&&); // this function is not defined
51 };
52
53 struct RV // view on an R
54 {
55 R& r;
56
57 friend int* begin(RV&); // this function is not defined
begin(const RV & rv)58 friend const int* begin(const RV& rv) noexcept { return begin(std::as_const(rv.r)); }
59 };
60
61 // Allow ranges::begin to work with RV&&
62 template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
63
64 void
test03()65 test03()
66 {
67 R r;
68 const R& c = r;
69 VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c));
70 VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c));
71
72 RV v{r};
73 VERIFY(std::ranges::cbegin(std::move(v)) == std::ranges::begin(c));
74 const RV cv{r};
75 VERIFY(std::ranges::cbegin(std::move(cv)) == std::ranges::begin(c));
76 }
77
78 struct RR
79 {
80 short s = 0;
81 long l = 0;
82 int a[4] = { 0, 1, 2, 3 };
83
beginRR84 short* begin() noexcept { return &s; }
beginRR85 const long* begin() const { return &l; }
86
begin(RR & r)87 friend int* begin(RR& r) { return r.a + 0; }
begin(RR && r)88 friend int* begin(RR&& r) { return r.a + 1; }
begin(const RR & r)89 friend const int* begin(const RR& r) { return r.a + 2; }
begin(const RR && r)90 friend const int* begin(const RR&& r) noexcept { return r.a + 3; }
91 };
92
93 // N.B. this is a lie, cbegin on an RR rvalue will return a dangling pointer.
94 template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
95
96 void
test04()97 test04()
98 {
99 RR r;
100 const RR& c = r;
101 VERIFY(std::ranges::cbegin(r) == std::ranges::begin(c));
102 VERIFY(std::ranges::cbegin(std::move(r)) == std::ranges::begin(c));
103 VERIFY(std::ranges::cbegin(c) == std::ranges::begin(c));
104 VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(c));
105 }
106
107 int
main()108 main()
109 {
110 test01();
111 test03();
112 test04();
113 }
114