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