xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.split/general.pass.cpp (revision fb855eb941b6d740cc6560297d0b4d3201dcaf9f)
1a2b3ab8fSHui //===----------------------------------------------------------------------===//
2a2b3ab8fSHui //
3a2b3ab8fSHui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a2b3ab8fSHui // See https://llvm.org/LICENSE.txt for license information.
5a2b3ab8fSHui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a2b3ab8fSHui //
7a2b3ab8fSHui //===----------------------------------------------------------------------===//
8a2b3ab8fSHui 
9a2b3ab8fSHui // UNSUPPORTED: c++03, c++11, c++14, c++17
10a2b3ab8fSHui 
11a2b3ab8fSHui // Some basic examples of how split_view might be used in the wild. This is a general
12a2b3ab8fSHui // collection of sample algorithms and functions that try to mock general usage of
13a2b3ab8fSHui // this view.
14a2b3ab8fSHui 
15a2b3ab8fSHui // These test check the output `split_view` produces for a variety of inputs, including many corner cases, with no
16a2b3ab8fSHui // restrictions on which member functions can be called.
17a2b3ab8fSHui 
18a2b3ab8fSHui #include <algorithm>
19a2b3ab8fSHui #include <array>
20a2b3ab8fSHui #include <cassert>
21a2b3ab8fSHui #include <concepts>
22a2b3ab8fSHui #include <map>
23a2b3ab8fSHui #include <ranges>
24a2b3ab8fSHui #include <string>
25a2b3ab8fSHui #include <string_view>
26a2b3ab8fSHui #include <utility>
27a2b3ab8fSHui #include <vector>
28a2b3ab8fSHui 
29a2b3ab8fSHui #include "test_macros.h"
30a2b3ab8fSHui 
31a2b3ab8fSHui template <std::ranges::view View, std::ranges::range Expected>
is_equal(View & view,const Expected & expected)32a2b3ab8fSHui constexpr bool is_equal(View& view, const Expected& expected) {
33a2b3ab8fSHui   return std::ranges::equal(view, expected, std::ranges::equal);
34a2b3ab8fSHui }
35a2b3ab8fSHui 
36*fb855eb9SMark de Wever template <class T, class Separator, class U, std::size_t M>
test_function_call(T && input,Separator && separator,std::array<U,M> expected)37a2b3ab8fSHui constexpr bool test_function_call(T&& input, Separator&& separator, std::array<U, M> expected) {
38a2b3ab8fSHui   std::ranges::split_view v(input, separator);
39a2b3ab8fSHui   return is_equal(v, expected);
40a2b3ab8fSHui }
41a2b3ab8fSHui 
42*fb855eb9SMark de Wever template <class T, class Separator, class U, std::size_t M>
test_with_piping(T && input,Separator && separator,std::array<U,M> expected)43a2b3ab8fSHui constexpr bool test_with_piping(T&& input, Separator&& separator, std::array<U, M> expected) {
44a2b3ab8fSHui   auto expected_it = expected.begin();
45a2b3ab8fSHui   for (auto e : input | std::ranges::views::split(separator)) {
46a2b3ab8fSHui     if (expected_it == expected.end())
47a2b3ab8fSHui       return false;
48a2b3ab8fSHui     if (!std::ranges::equal(e, *expected_it))
49a2b3ab8fSHui       return false;
50a2b3ab8fSHui 
51a2b3ab8fSHui     ++expected_it;
52a2b3ab8fSHui   }
53a2b3ab8fSHui 
54a2b3ab8fSHui   return expected_it == expected.end();
55a2b3ab8fSHui }
56a2b3ab8fSHui 
test_l_r_values()57a2b3ab8fSHui constexpr bool test_l_r_values() {
58a2b3ab8fSHui   using namespace std::string_view_literals;
59a2b3ab8fSHui 
60a2b3ab8fSHui   // Both lvalues and rvalues can be used as input.
61a2b3ab8fSHui   {
62a2b3ab8fSHui     // Lvalues.
63a2b3ab8fSHui     {
64a2b3ab8fSHui       auto input = "abc"sv;
65a2b3ab8fSHui       auto sep   = " "sv;
66a2b3ab8fSHui       [[maybe_unused]] std::ranges::split_view v(input, sep);
67a2b3ab8fSHui     }
68a2b3ab8fSHui 
69a2b3ab8fSHui     // Const lvalues.
70a2b3ab8fSHui     {
71a2b3ab8fSHui       const auto input = "abc"sv;
72a2b3ab8fSHui       const auto sep   = " "sv;
73a2b3ab8fSHui       [[maybe_unused]] std::ranges::split_view v(input, sep);
74a2b3ab8fSHui     }
75a2b3ab8fSHui 
76a2b3ab8fSHui     // Rvalues.
77a2b3ab8fSHui     {
78a2b3ab8fSHui       auto input = "abc"sv;
79a2b3ab8fSHui       auto sep   = " "sv;
80a2b3ab8fSHui       [[maybe_unused]] std::ranges::split_view v(std::move(input), std::move(sep));
81a2b3ab8fSHui     }
82a2b3ab8fSHui 
83a2b3ab8fSHui     // Const rvalues.
84a2b3ab8fSHui     {
85a2b3ab8fSHui       const auto input = "abc"sv;
86a2b3ab8fSHui       const auto sep   = " "sv;
87a2b3ab8fSHui       [[maybe_unused]] std::ranges::split_view v(std::move(input), std::move(sep));
88a2b3ab8fSHui     }
89a2b3ab8fSHui   }
90a2b3ab8fSHui 
91a2b3ab8fSHui   return true;
92a2b3ab8fSHui }
93a2b3ab8fSHui 
test_string_literal_separator()94a2b3ab8fSHui constexpr bool test_string_literal_separator() {
95a2b3ab8fSHui   using namespace std::string_view_literals;
96a2b3ab8fSHui 
97a2b3ab8fSHui   // Splitting works as expected when the separator is a single character literal.
98a2b3ab8fSHui   {
99a2b3ab8fSHui     std::ranges::split_view v("abc def"sv, ' ');
100a2b3ab8fSHui     assert(is_equal(v, std::array{"abc"sv, "def"sv}));
101a2b3ab8fSHui   }
102a2b3ab8fSHui 
103a2b3ab8fSHui   // Counterintuitively, a seemingly equivalent separator expressed as a string literal doesn't match anything. This is
104a2b3ab8fSHui   // because of the implicit terminating null in the literal.
105a2b3ab8fSHui   {
106a2b3ab8fSHui     std::ranges::split_view v("abc def"sv, " ");
107a2b3ab8fSHui     assert(is_equal(v, std::array{"abc def"sv}));
108a2b3ab8fSHui   }
109a2b3ab8fSHui 
110a2b3ab8fSHui   // To illustrate the previous point further, the separator is actually a two-character string literal: `{' ', '\0'}`.
111a2b3ab8fSHui   // Should the input string contain that two-character sequence, the separator would match.
112a2b3ab8fSHui   {
113a2b3ab8fSHui     std::ranges::split_view v("abc \0def"sv, " ");
114a2b3ab8fSHui     assert(is_equal(v, std::array{"abc"sv, "def"sv}));
115a2b3ab8fSHui   }
116a2b3ab8fSHui 
117a2b3ab8fSHui   return true;
118a2b3ab8fSHui }
119a2b3ab8fSHui 
120a2b3ab8fSHui // Make sure that a string literal and a `string_view` produce the same results (which isn't always the case, see
121a2b3ab8fSHui // below).
122a2b3ab8fSHui template <class T>
sv(T && str)123a2b3ab8fSHui constexpr std::string_view sv(T&& str) {
124a2b3ab8fSHui   return std::string_view(str);
125a2b3ab8fSHui };
126a2b3ab8fSHui 
127*fb855eb9SMark de Wever template <class T, class Separator, class U, std::size_t M>
test_one(T && input,Separator && separator,std::array<U,M> expected)128a2b3ab8fSHui constexpr void test_one(T&& input, Separator&& separator, std::array<U, M> expected) {
129a2b3ab8fSHui   assert(test_function_call(input, separator, expected));
130a2b3ab8fSHui   assert(test_with_piping(input, separator, expected));
131a2b3ab8fSHui }
132a2b3ab8fSHui 
test_string_literals()133a2b3ab8fSHui constexpr bool test_string_literals() {
134a2b3ab8fSHui   // These tests show characteristic examples of how using string literals with `split_view` produces unexpected
135a2b3ab8fSHui   // results due to the implicit terminating null that is treated as part of the range.
136a2b3ab8fSHui 
137a2b3ab8fSHui   using namespace std::string_view_literals;
138a2b3ab8fSHui 
139a2b3ab8fSHui   char short_sep = ' ';
140a2b3ab8fSHui   auto long_sep  = "12"sv;
141a2b3ab8fSHui 
142a2b3ab8fSHui   // When splitting a string literal, only the last segment will be null-terminated (getting the terminating null from
143a2b3ab8fSHui   // the original range).
144a2b3ab8fSHui   {
145a2b3ab8fSHui     std::array expected = {"abc"sv, std::string_view("def", sizeof("def"))};
146a2b3ab8fSHui 
147a2b3ab8fSHui     assert(test_function_call("abc def", short_sep, expected));
148a2b3ab8fSHui     assert(test_with_piping("abc def", short_sep, expected));
149a2b3ab8fSHui     assert(test_function_call("abc12def", long_sep, expected));
150a2b3ab8fSHui     assert(test_with_piping("abc12def", long_sep, expected));
151a2b3ab8fSHui   }
152a2b3ab8fSHui 
153a2b3ab8fSHui   // Empty string.
154a2b3ab8fSHui   {
155a2b3ab8fSHui     // Because an empty string literal contains an implicit terminating null, the output will contain one segment.
156a2b3ab8fSHui     std::array expected = {std::string_view("", 1)};
157a2b3ab8fSHui 
158a2b3ab8fSHui     assert(test_function_call("", short_sep, expected));
159a2b3ab8fSHui     assert(test_with_piping("", short_sep, expected));
160a2b3ab8fSHui     assert(test_function_call("", long_sep, expected));
161a2b3ab8fSHui     assert(test_with_piping("", long_sep, expected));
162a2b3ab8fSHui   }
163a2b3ab8fSHui 
164a2b3ab8fSHui   // Terminating null in the separator -- the character literal `' '` and the seemingly equivalent string literal `" "`
165a2b3ab8fSHui   // are treated differently due to the presence of an implicit `\0` in the latter.
166a2b3ab8fSHui   {
167a2b3ab8fSHui     const char input[]          = "abc def";
168a2b3ab8fSHui     std::array expected_unsplit = {std::string_view(input, sizeof(input))};
169a2b3ab8fSHui     std::array expected_split   = {"abc"sv, std::string_view("def", sizeof("def"))};
170a2b3ab8fSHui 
171a2b3ab8fSHui     assert(test_function_call(input, " ", expected_unsplit));
172a2b3ab8fSHui     assert(test_function_call("abc \0def", " ", expected_split));
173a2b3ab8fSHui     // Note: string literals don't work with piping because arrays decay to pointers, and pointers don't model `range`.
174a2b3ab8fSHui   }
175a2b3ab8fSHui 
176a2b3ab8fSHui   // Empty separator.
177a2b3ab8fSHui   {
178a2b3ab8fSHui     auto empty_sep      = ""sv;
179a2b3ab8fSHui     std::array expected = {"a"sv, "b"sv, "c"sv, "\0"sv};
180a2b3ab8fSHui 
181a2b3ab8fSHui     assert(test_function_call("abc", empty_sep, expected));
182a2b3ab8fSHui     assert(test_with_piping("abc", empty_sep, expected));
183a2b3ab8fSHui   }
184a2b3ab8fSHui 
185a2b3ab8fSHui   return true;
186a2b3ab8fSHui }
187a2b3ab8fSHui 
test_nontrivial_characters()188a2b3ab8fSHui bool test_nontrivial_characters() {
189a2b3ab8fSHui   // Try a deliberately heavyweight "character" type to see if it triggers any corner cases.
190a2b3ab8fSHui 
191a2b3ab8fSHui   using Map = std::map<std::string, int>;
192a2b3ab8fSHui   using Vec = std::vector<Map>;
193a2b3ab8fSHui 
194a2b3ab8fSHui   Map sep = {{"yyy", 999}};
195a2b3ab8fSHui   Map m1  = {
196a2b3ab8fSHui       {"a", 1},
197a2b3ab8fSHui       {"bc", 2},
198a2b3ab8fSHui   };
199a2b3ab8fSHui   Map m2 = {
200a2b3ab8fSHui       {"def", 3},
201a2b3ab8fSHui   };
202a2b3ab8fSHui   Map m3 = {
203a2b3ab8fSHui       {"g", 4},
204a2b3ab8fSHui       {"hijk", 5},
205a2b3ab8fSHui   };
206a2b3ab8fSHui 
207a2b3ab8fSHui   Vec expected1 = {m1, m2};
208a2b3ab8fSHui   Vec expected2 = {m3};
209a2b3ab8fSHui 
210a2b3ab8fSHui   std::ranges::split_view v(Vec{m1, m2, sep, m3}, sep);
211a2b3ab8fSHui 
212a2b3ab8fSHui   // Segment 1: {m1, m2}
213a2b3ab8fSHui   auto outer = v.begin();
214a2b3ab8fSHui   assert(outer != v.end());
215a2b3ab8fSHui   auto inner = (*outer).begin();
216a2b3ab8fSHui   assert(*inner++ == m1);
217a2b3ab8fSHui   assert(*inner++ == m2);
218a2b3ab8fSHui   assert(inner == (*outer).end());
219a2b3ab8fSHui 
220a2b3ab8fSHui   // Segment 2: {m3}
221a2b3ab8fSHui   ++outer;
222a2b3ab8fSHui   assert(outer != v.end());
223a2b3ab8fSHui   inner = (*outer).begin();
224a2b3ab8fSHui   assert(*inner++ == m3);
225a2b3ab8fSHui   assert(inner == (*outer).end());
226a2b3ab8fSHui 
227a2b3ab8fSHui   ++outer;
228a2b3ab8fSHui   assert(outer == v.end());
229a2b3ab8fSHui 
230a2b3ab8fSHui   return true;
231a2b3ab8fSHui }
232a2b3ab8fSHui 
main_test()233a2b3ab8fSHui constexpr bool main_test() {
234a2b3ab8fSHui   using namespace std::string_view_literals;
235a2b3ab8fSHui 
236a2b3ab8fSHui   char short_sep = ' ';
237a2b3ab8fSHui   auto long_sep  = "12"sv;
238a2b3ab8fSHui 
239a2b3ab8fSHui   // One separator.
240a2b3ab8fSHui   {
241a2b3ab8fSHui     std::array expected = {"abc"sv, "def"sv};
242a2b3ab8fSHui     test_one("abc def"sv, short_sep, expected);
243a2b3ab8fSHui     test_one("abc12def"sv, long_sep, expected);
244a2b3ab8fSHui   }
245a2b3ab8fSHui 
246a2b3ab8fSHui   // Several separators in a row.
247a2b3ab8fSHui   {
248a2b3ab8fSHui     std::array expected = {"abc"sv, ""sv, ""sv, ""sv, "def"sv};
249a2b3ab8fSHui     test_one("abc    def"sv, short_sep, expected);
250a2b3ab8fSHui     test_one("abc12121212def"sv, long_sep, expected);
251a2b3ab8fSHui   }
252a2b3ab8fSHui 
253a2b3ab8fSHui   // Trailing separator.
254a2b3ab8fSHui   {
255a2b3ab8fSHui     std::array expected = {"abc"sv, "def"sv, ""sv};
256a2b3ab8fSHui     test_one("abc def "sv, short_sep, expected);
257a2b3ab8fSHui     test_one("abc12def12"sv, long_sep, expected);
258a2b3ab8fSHui   }
259a2b3ab8fSHui 
260a2b3ab8fSHui   // Leading separator.
261a2b3ab8fSHui   {
262a2b3ab8fSHui     std::array expected = {""sv, "abc"sv, "def"sv};
263a2b3ab8fSHui     test_one(" abc def"sv, short_sep, expected);
264a2b3ab8fSHui     test_one("12abc12def"sv, long_sep, expected);
265a2b3ab8fSHui   }
266a2b3ab8fSHui 
267a2b3ab8fSHui   // No separator.
268a2b3ab8fSHui   {
269a2b3ab8fSHui     std::array expected = {"abc"sv};
270a2b3ab8fSHui     test_one("abc"sv, short_sep, expected);
271a2b3ab8fSHui     test_one("abc"sv, long_sep, expected);
272a2b3ab8fSHui   }
273a2b3ab8fSHui 
274a2b3ab8fSHui   // Input consisting of a single separator.
275a2b3ab8fSHui   {
276a2b3ab8fSHui     std::array expected = {""sv, ""sv};
277a2b3ab8fSHui     test_one(" "sv, short_sep, expected);
278a2b3ab8fSHui     test_one("12"sv, long_sep, expected);
279a2b3ab8fSHui   }
280a2b3ab8fSHui 
281a2b3ab8fSHui   // Input consisting of only separators.
282a2b3ab8fSHui   {
283a2b3ab8fSHui     std::array expected = {""sv, ""sv, ""sv, ""sv};
284a2b3ab8fSHui     test_one("   "sv, short_sep, expected);
285a2b3ab8fSHui     test_one("121212"sv, long_sep, expected);
286a2b3ab8fSHui   }
287a2b3ab8fSHui 
288a2b3ab8fSHui   // The separator and the string use the same character only.
289a2b3ab8fSHui   {
290a2b3ab8fSHui     auto overlapping_sep = "aaa"sv;
291a2b3ab8fSHui     std::array expected  = {""sv, "aa"sv};
292a2b3ab8fSHui     test_one("aaaaa"sv, overlapping_sep, expected);
293a2b3ab8fSHui   }
294a2b3ab8fSHui 
295a2b3ab8fSHui   // Many redundant separators.
296a2b3ab8fSHui   {
297a2b3ab8fSHui     std::array expected = {""sv, ""sv, "abc"sv, ""sv, ""sv, "def"sv, ""sv, ""sv};
298a2b3ab8fSHui     test_one("  abc   def  "sv, short_sep, expected);
299a2b3ab8fSHui     test_one("1212abc121212def1212"sv, long_sep, expected);
300a2b3ab8fSHui   }
301a2b3ab8fSHui 
302a2b3ab8fSHui   // Separators after every character.
303a2b3ab8fSHui   {
304a2b3ab8fSHui     std::array expected = {""sv, "a"sv, "b"sv, "c"sv, ""sv};
305a2b3ab8fSHui     test_one(" a b c "sv, short_sep, expected);
306a2b3ab8fSHui     test_one("12a12b12c12"sv, long_sep, expected);
307a2b3ab8fSHui   }
308a2b3ab8fSHui 
309a2b3ab8fSHui   // Overlap between the separator and the string (see https://wg21.link/lwg3505).
310a2b3ab8fSHui   {
311a2b3ab8fSHui     auto overlapping_sep = "ab"sv;
312a2b3ab8fSHui     std::array expected  = {"a"sv, "aa"sv, ""sv, "b"sv};
313a2b3ab8fSHui     test_one("aabaaababb"sv, overlapping_sep, expected);
314a2b3ab8fSHui   }
315a2b3ab8fSHui 
316a2b3ab8fSHui   // Empty input.
317a2b3ab8fSHui   {
318a2b3ab8fSHui     std::array<std::string_view, 0> expected = {};
319a2b3ab8fSHui     test_one(""sv, short_sep, expected);
320a2b3ab8fSHui     test_one(""sv, long_sep, expected);
321a2b3ab8fSHui   }
322a2b3ab8fSHui 
323a2b3ab8fSHui   // Empty separator.
324a2b3ab8fSHui   {
325a2b3ab8fSHui     auto empty_sep      = ""sv;
326a2b3ab8fSHui     std::array expected = {"a"sv, "b"sv, "c"sv};
327a2b3ab8fSHui     test_one("abc"sv, empty_sep, expected);
328a2b3ab8fSHui     test_one("abc"sv, empty_sep, expected);
329a2b3ab8fSHui   }
330a2b3ab8fSHui 
331a2b3ab8fSHui   // Terminating null as a separator.
332a2b3ab8fSHui   {
333a2b3ab8fSHui     std::array expected = {"abc"sv, "def"sv};
334a2b3ab8fSHui     test_one("abc\0def"sv, '\0', expected);
335a2b3ab8fSHui     test_one("abc\0\0def"sv, "\0\0"sv, expected);
336a2b3ab8fSHui   }
337a2b3ab8fSHui 
338a2b3ab8fSHui   // Different character types.
339a2b3ab8fSHui   {
340a2b3ab8fSHui     // `char`.
341a2b3ab8fSHui     test_function_call("abc def", ' ', std::array{"abc"sv, "def"sv});
342a2b3ab8fSHui #ifndef TEST_HAS_NO_WIDE_CHARACTERS
343a2b3ab8fSHui     // `wchar_t`.
344a2b3ab8fSHui     test_function_call(L"abc def", L' ', std::array{L"abc"sv, L"def"sv});
345a2b3ab8fSHui #endif
346a2b3ab8fSHui     // `char8_t`.
347a2b3ab8fSHui     test_function_call(u8"abc def", u8' ', std::array{u8"abc"sv, u8"def"sv});
348a2b3ab8fSHui     // `char16_t`.
349a2b3ab8fSHui     test_function_call(u"abc def", u' ', std::array{u"abc"sv, u"def"sv});
350a2b3ab8fSHui     // `char32_t`.
351a2b3ab8fSHui     test_function_call(U"abc def", U' ', std::array{U"abc"sv, U"def"sv});
352a2b3ab8fSHui   }
353a2b3ab8fSHui 
354a2b3ab8fSHui   // Non-character input.
355a2b3ab8fSHui   {
356a2b3ab8fSHui     std::array expected = {std::array{1, 2, 3}, std::array{4, 5, 6}};
357a2b3ab8fSHui     test_one(std::array{1, 2, 3, 0, 4, 5, 6}, 0, expected);
358a2b3ab8fSHui     test_one(std::array{1, 2, 3, 0, 0, 0, 4, 5, 6}, std::array{0, 0, 0}, expected);
359a2b3ab8fSHui   }
360a2b3ab8fSHui 
361a2b3ab8fSHui   return true;
362a2b3ab8fSHui }
363a2b3ab8fSHui 
364a2b3ab8fSHui constexpr bool example_test() {
365a2b3ab8fSHui   // example code in the spec
366a2b3ab8fSHui   std::string str{"the quick brown fox"};
367a2b3ab8fSHui   std::vector<std::string_view> result;
368a2b3ab8fSHui   for (auto r : std::views::split(str, ' ')) {
369a2b3ab8fSHui     result.emplace_back(r.begin(), r.end());
370a2b3ab8fSHui   }
371a2b3ab8fSHui   using namespace std::string_view_literals;
372a2b3ab8fSHui   auto expected = {"the"sv, "quick"sv, "brown"sv, "fox"sv};
373a2b3ab8fSHui   assert(std::ranges::equal(result, expected));
374a2b3ab8fSHui 
375a2b3ab8fSHui   return true;
376a2b3ab8fSHui }
377a2b3ab8fSHui 
378a2b3ab8fSHui int main(int, char**) {
379a2b3ab8fSHui   example_test();
380a2b3ab8fSHui   static_assert(example_test());
381a2b3ab8fSHui 
382a2b3ab8fSHui   test_string_literals();
383a2b3ab8fSHui   static_assert(test_string_literals());
384a2b3ab8fSHui 
385a2b3ab8fSHui   test_l_r_values();
386a2b3ab8fSHui   static_assert(test_l_r_values());
387a2b3ab8fSHui 
388a2b3ab8fSHui   test_string_literal_separator();
389a2b3ab8fSHui   static_assert(test_string_literal_separator());
390a2b3ab8fSHui 
391a2b3ab8fSHui   // Note: map is not `constexpr`, so this test is runtime-only.
392a2b3ab8fSHui   test_nontrivial_characters();
393a2b3ab8fSHui 
394a2b3ab8fSHui   return 0;
395a2b3ab8fSHui }
396