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 
24 using std::same_as;
25 
26 void
test01()27 test01()
28 {
29   int a[2] = {};
30 
31   static_assert(same_as<decltype(std::ranges::cend(a)), const int*>);
32   static_assert(noexcept(std::ranges::cend(a)));
33   VERIFY( std::ranges::cend(a) == (a + 2) );
34 }
35 
36 struct R
37 {
38   int a[4] = { 0, 1, 2, 3 };
39 
beginR40   const int* begin() const { return nullptr; }
begin(const R && r)41   friend const int* begin(const R&& r) noexcept { return nullptr; }
42 
43   // Should be ignored because it doesn't return a sentinel for int*
endR44   const long* end() const { return nullptr; }
45 
end(R & r)46   friend int* end(R& r) { return r.a + 0; }
end(R && r)47   friend int* end(R&& r) { return r.a + 1; }
end(const R & r)48   friend const int* end(const R& r) noexcept { return r.a + 2; }
end(const R && r)49   friend const int* end(const R&& r) noexcept { return r.a + 3; }
50 };
51 
52 struct RV // view on an R
53 {
54   R& r;
55 
begin(RV & rv)56   friend const int* begin(RV& rv) { return rv.r.begin(); }
end(RV & rv)57   friend int* end(RV& rv) { return end(rv.r); }
begin(const RV & rv)58   friend const int* begin(const RV& rv) noexcept { return rv.r.begin(); }
end(const RV & rv)59   friend const int* end(const RV& rv) noexcept { return end(std::as_const(rv.r)); }
60 };
61 
62 // Allow ranges::end to work with RV&&
63 template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
64 
65 void
test03()66 test03()
67 {
68   R r;
69   const R& c = r;
70   VERIFY( std::ranges::cend(r) == std::ranges::end(c) );
71   VERIFY( std::ranges::cend(c) == std::ranges::end(c) );
72 
73   RV v{r};
74   const RV cv{r};
75   VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(c) );
76   VERIFY( std::ranges::cend(std::move(cv)) == std::ranges::end(c) );
77 }
78 
79 struct RR
80 {
81   short s = 0;
82   long l = 0;
83   int a[4] = { 0, 1, 2, 3 };
84 
85   const void* begin() const; // return type not an iterator
86 
end(RR &)87   friend int* end(RR&) { throw 1; }
endRR88   short* end() noexcept { return &s; }
89 
90   friend const long* begin(const RR&) noexcept;
endRR91   const long* end() const { return &l; }
92 
93   friend int* begin(RR&&) noexcept;
end(RR && r)94   friend int* end(RR&& r) { return r.a + 1; }
95 
96   friend const int* begin(const RR&&) noexcept;
end(const RR && r)97   friend const int* end(const RR&& r) noexcept { return r.a + 3; }
98 };
99 
100 // N.B. this is a lie, begin/end on an RR rvalue will return a dangling pointer.
101 template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
102 
103 void
test04()104 test04()
105 {
106   RR r;
107   const RR& c = r;
108   VERIFY( std::ranges::cend(r) == std::ranges::end(c) );
109   VERIFY( std::ranges::cend(c) == std::ranges::end(c) );
110 
111   VERIFY( std::ranges::cend(std::move(r)) == std::ranges::end(c) );
112   VERIFY( std::ranges::cend(std::move(c)) == std::ranges::end(c) );
113 }
114 
115 int
main()116 main()
117 {
118   test01();
119   test03();
120   test04();
121 }
122