1 // Copyright (C) 2020-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 <algorithm>
22 #include <ranges>
23 #include <string>
24 #include <string_view>
25 #include <testsuite_hooks.h>
26 #include <testsuite_iterators.h>
27 
28 using __gnu_test::test_range;
29 using __gnu_test::forward_iterator_wrapper;
30 using __gnu_test::input_iterator_wrapper;
31 
32 namespace ranges = std::ranges;
33 namespace views = std::ranges::views;
34 
35 using namespace std::literals;
36 
37 void
test01()38 test01()
39 {
40   auto x = "the  quick  brown  fox"sv;
41   auto p = std::string{"  "};
42   auto v = x | views::split(views::all(p)); // views::all is needed here after P2281.
43   auto i = v.begin();
44   VERIFY( ranges::equal(*i++, "the"sv) );
45   VERIFY( ranges::equal(*i++, "quick"sv) );
46   VERIFY( ranges::equal(*i++, "brown"sv) );
47   VERIFY( ranges::equal(*i++, "fox"sv) );
48   VERIFY( i == v.end() );
49 }
50 
51 void
test02()52 test02()
53 {
54   auto x = "the quick brown fox"sv;
55   auto v = x | views::split(' ');
56   auto i = v.begin();
57   VERIFY( ranges::equal(*i++, "the"sv) );
58   VERIFY( ranges::equal(*i++, "quick"sv) );
59   VERIFY( ranges::equal(*i++, "brown"sv) );
60   VERIFY( ranges::equal(*i++, "fox"sv) );
61   VERIFY( i == v.end() );
62 }
63 
64 void
test03()65 test03()
66 {
67   char x[] = "the quick brown fox";
68   test_range<char, forward_iterator_wrapper> rx(x, x+sizeof(x)-1);
69   auto v = rx | views::split(' ');
70   auto i = v.begin();
71   VERIFY( ranges::equal(*i++, "the"sv) );
72   VERIFY( ranges::equal(*i++, "quick"sv) );
73   VERIFY( ranges::equal(*i++, "brown"sv) );
74   VERIFY( ranges::equal(*i++, "fox"sv) );
75   VERIFY( i == v.end() );
76 }
77 
78 void
test04()79 test04()
80 {
81   auto x = "the  quick  brown  fox"sv;
82   std::initializer_list<char> p = {' ', ' '};
83   static_assert(!ranges::view<decltype(p)>);
84   static_assert(std::same_as<decltype(p | views::all),
85 			     ranges::ref_view<decltype(p)>>);
86   auto v = x | views::split(views::all(p)); // views::all is needed here after P2281.
87   auto i = v.begin();
88   VERIFY( ranges::equal(*i++, "the"sv) );
89   VERIFY( ranges::equal(*i++, "quick"sv) );
90   VERIFY( ranges::equal(*i++, "brown"sv) );
91   VERIFY( ranges::equal(*i++, "fox"sv) );
92   VERIFY( i == v.end() );
93 }
94 
95 void
test05()96 test05()
97 {
98   auto as_string = [](ranges::view auto rng) {
99     auto in = rng | views::common;
100     return std::string(in.begin(), in.end());
101   };
102   std::string str
103     = "Now is the time for all good men to come to the aid of their county.";
104   auto rng
105     = str | views::split(' ') | views::transform(as_string) | views::common;
106   std::vector<std::string> words(rng.begin(), rng.end());
107   auto not_space_p = [](char c) { return c != ' '; };
108   VERIFY( ranges::equal(words | views::join,
109 			str | views::filter(not_space_p)) );
110 }
111 
112 void
test06()113 test06()
114 {
115   std::string str = "hello world";
116   auto v = str | views::transform(std::identity{}) | views::split(' ');
117 
118   // Verify that _Iterator<false> is implicitly convertible to _Iterator<true>.
119   static_assert(!std::same_as<decltype(ranges::begin(v)),
120 			      decltype(ranges::cbegin(v))>);
121   auto b = ranges::cbegin(v);
122   b = ranges::begin(v);
123 }
124 
125 void
test07()126 test07()
127 {
128   char str[] = "banana split";
129   auto split = str | views::split(' ');
130   auto val = *split.begin();
131   auto b = val.begin();
132   auto b2 = b++;
133   static_assert( noexcept(iter_move(b)) );
134   static_assert( noexcept(iter_swap(b, b2)) );
135 }
136 
137 void
test08()138 test08()
139 {
140   char x[] = "the quick brown fox";
141   test_range<char, input_iterator_wrapper> rx(x, x+sizeof(x)-1);
142   auto v = rx | views::split(' ');
143   auto i = v.begin();
144   VERIFY( ranges::equal(*i, "the"sv) );
145   ++i;
146   VERIFY( ranges::equal(*i, "quick"sv) );
147   ++i;
148   VERIFY( ranges::equal(*i, "brown"sv) );
149   ++i;
150   VERIFY( ranges::equal(*i, "fox"sv) );
151   ++i;
152   VERIFY( i == v.end() );
153 }
154 
155 template<auto split = views::split>
156 void
test09()157 test09()
158 {
159   // Verify SFINAE behavior.
160   std::string s, p;
161   static_assert(!requires { split(); });
162   static_assert(!requires { split(s, p, 0); });
163   static_assert(!requires { split(p)(); });
164   static_assert(!requires { s | split; });
165 
166   static_assert(!requires { s | split(p); });
167   static_assert(!requires { split(p)(s); });
168   static_assert(!requires { s | (split(p) | views::all); });
169   static_assert(!requires { (split(p) | views::all)(s); });
170 
171   static_assert(requires { s | split(views::all(p)); });
172   static_assert(requires { split(views::all(p))(s); });
173   static_assert(requires { s | (split(views::all(p)) | views::all); });
174   static_assert(requires { (split(views::all(p)) | views::all)(s); });
175 
176   auto adapt = split(p);
177   static_assert(requires { s | adapt; });
178   static_assert(requires { adapt(s); });
179 
180   auto adapt2 = split(p) | views::all;
181   static_assert(requires { s | adapt2; });
182   static_assert(requires { adapt2(s); });
183 }
184 
185 void
test10()186 test10()
187 {
188   // LWG 3505
189   auto to_string = [] (auto r) {
190     return std::string(r.begin(), ranges::next(r.begin(), r.end()));
191   };
192   auto v = "xxyx"sv | views::split("xy"sv) | views::transform(to_string);
193   VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) );
194 }
195 
196 int
main()197 main()
198 {
199   test01();
200   test02();
201   test03();
202   test04();
203   test05();
204   test06();
205   test07();
206   test08();
207   test09();
208   test10();
209 }
210