aboutsummaryrefslogtreecommitdiffstats
path: root/liblfjail/split.hh
blob: 419b4790a76dd1f99914f076120f22c623f208d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
 * This source code is released into the public domain.
 */

#ifndef	LFJAIL_SPLIT_HH
#define	LFJAIL_SPLIT_HH

#include "generator.hh"

namespace lfjail {

/*
 * split: split a range of items on a given predicate and return each element
 * as a subrange.  This is intended to be used with strings, but in theory it
 * can accept any range.
 *
 * The input range is never copied, so the returned ranges reference the
 * input range.
 */

template<std::ranges::range Range,
	 std::indirect_unary_predicate<std::ranges::iterator_t<Range>> Pred>
auto split(Range &&range, Pred &&pred)
	-> std::generator<decltype(std::ranges::subrange(range))>
{
	auto pos = std::ranges::begin(range);
	auto end = std::ranges::end(range);

	for (;;) {
		// Skip leading separators.
		while (pos != end && pred(*pos))
			++pos;

		if (pos == end)
			co_return;

		auto const split_point = std::find_if(pos, end, pred);

		// Yield this value.
		co_yield std::ranges::subrange(pos, split_point);

		pos = split_point;
	}
}

/*
 * split_string: helper function to make split() a bit more useful for strings.
 * Instead of returning subranges, it returns basic_string_views.
 */
auto split_string(std::ranges::contiguous_range auto &&string, auto pred)
	-> std::generator<
		std::basic_string_view<
			std::ranges::range_value_t<decltype(string)>>>
{
	using sv_type = std::basic_string_view<
		std::ranges::range_value_t<decltype(string)>>;

	for (auto const &&subrange : split(string, pred))
		co_yield sv_type(subrange);
}

} // namespace lfjail

#endif	// !LFJAIL_SPLIT_HH