]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/std/ranges/access/end.cc
libstdc++: Implement ranges::safe_range for C++20 (P1870R1)
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / std / ranges / access / end.cc
1 // Copyright (C) 2019 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 #include <testsuite_iterators.h>
24
25 using std::same_as;
26
27 void
28 test01()
29 {
30 int a[2] = {};
31
32 static_assert(same_as<decltype(std::ranges::end(a)), decltype(a + 2)>);
33 static_assert(noexcept(std::ranges::end(a)));
34 VERIFY( std::ranges::end(a) == (a + 2) );
35 }
36
37 void
38 test02()
39 {
40 using __gnu_test::test_range;
41 using __gnu_test::random_access_iterator_wrapper;
42 using __gnu_test::input_iterator_wrapper;
43 using __gnu_test::output_iterator_wrapper;
44
45 int a[] = { 0, 1 };
46
47 test_range<int, random_access_iterator_wrapper> r(a);
48 static_assert(same_as<decltype(std::ranges::end(r)), decltype(r.end())>);
49 VERIFY( std::ranges::end(r) == r.end() );
50
51 test_range<int, input_iterator_wrapper> i(a);
52 static_assert(same_as<decltype(std::ranges::end(i)), decltype(i.end())>);
53 VERIFY( std::ranges::end(i) == i.end() );
54
55 test_range<int, output_iterator_wrapper> o(a);
56 static_assert(same_as<decltype(std::ranges::end(o)), decltype(o.end())>);
57 VERIFY( std::ranges::end(o) == std::ranges::next(o.begin(), 2) );
58 }
59
60 struct R
61 {
62 int a[4] = { 0, 1, 2, 3 };
63
64 const int* begin() const;
65 friend int* begin(R&&) noexcept;
66 friend const int* begin(const R&&) noexcept;
67
68 // Should be ignored because it doesn't return a sentinel for int*
69 const long* end() const;
70
71 friend int* end(R& r) { return r.a + 0; }
72 friend int* end(R&& r) { return r.a + 1; }
73 friend const int* end(const R& r) noexcept { return r.a + 2; }
74 friend const int* end(const R&& r) noexcept { return r.a + 3; }
75 };
76
77 struct RV // view on an R
78 {
79 R& r;
80
81 const int* begin() const;
82
83 friend int* end(RV& v) noexcept { return end(v.r); }
84 friend const int* end(const RV& v) { return end(std::as_const(v.r)); }
85 };
86
87 // Allow ranges::begin to work with RV&&
88 template<> constexpr bool std::ranges::enable_safe_range<RV> = true;
89
90 void
91 test03()
92 {
93 R r;
94 const R& c = r;
95
96 static_assert(same_as<decltype(std::ranges::end(r)), decltype(end(r))>);
97 static_assert(!noexcept(std::ranges::end(r)));
98 VERIFY( std::ranges::end(r) == end(r) );
99
100 static_assert(same_as<decltype(std::ranges::end(c)), decltype(end(c))>);
101 static_assert(noexcept(std::ranges::end(c)));
102 VERIFY( std::ranges::end(c) == end(c) );
103
104 RV v{r};
105 static_assert(same_as<decltype(std::ranges::end(std::move(v))),
106 decltype(end(r))>);
107 static_assert(noexcept(std::ranges::end(std::move(v))));
108 VERIFY( std::ranges::end(std::move(v)) == end(r) );
109
110 const RV cv{r};
111 static_assert(same_as<decltype(std::ranges::end(std::move(cv))),
112 decltype(end(c))>);
113 static_assert(!noexcept(std::ranges::end(std::move(cv))));
114 VERIFY( std::ranges::end(std::move(cv)) == end(c) );
115 }
116
117 struct RR
118 {
119 short s = 0;
120 long l = 0;
121 int a[4] = { 0, 1, 2, 3 };
122
123 const void* begin() const; // return type not an iterator
124
125 friend const short* begin(RR&) noexcept;
126 short* end() noexcept { return &s; }
127
128 friend const long* begin(const RR&) noexcept;
129 const long* end() const { return &l; }
130
131 friend const int* begin(RR&&) noexcept;
132 friend int* end(RR&) { throw 1; } // not valid for rvalues
133 friend int* end(RR&& r) { return r.a + 1; }
134
135 friend const int* begin(const RR&&) noexcept;
136 friend const int* end(const RR&) { throw 1; } // not valid for rvalues
137 friend const int* end(const RR&& r) noexcept { return r.a + 3; }
138 };
139
140 // N.B. this is a lie, end on an RR rvalue will return a dangling pointer.
141 template<> constexpr bool std::ranges::enable_safe_range<RR> = true;
142
143 void
144 test04()
145 {
146 RR r;
147 const RR& c = r;
148 VERIFY( std::ranges::end(r) == &r.s );
149 static_assert(noexcept(std::ranges::end(r)));
150
151 VERIFY( std::ranges::end(std::move(r)) == &r.s );
152 static_assert(noexcept(std::ranges::end(std::move(r))));
153
154 VERIFY( std::ranges::end(c) == &r.l );
155 static_assert(!noexcept(std::ranges::end(c)));
156
157 VERIFY( std::ranges::end(std::move(c)) == &r.l );
158 static_assert(!noexcept(std::ranges::end(std::move(c))));
159 }
160
161 int
162 main()
163 {
164 test01();
165 test02();
166 test03();
167 test04();
168 }