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