-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSplit.h
85 lines (79 loc) · 2.05 KB
/
Split.h
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#ifndef SFL_SPLIT_H
#define SFL_SPLIT_H
#include <vector>
#include <cassert>
#include "sfl/Prelude.h"
#include "sfl/ImmutableList.h"
namespace sfl
{
/**
* chunk(n,range) splits a range into length/n pieces. The last piece will be shorter if n does
* not evenly divide the length of the list.
*/
template<typename R>
std::vector<R> chunk(size_t n, const R &r)
{
std::vector<R> ret;
ret.reserve((r.size() + n -1) / n);
int pos = 0;
while ((r.size() - pos) >= n) {
ret.push_back(R(r.begin() + pos, r.begin() + pos + n));
pos += n;
}
if ((r.size() - pos) > 0) {
ret.push_back(R(r.begin() + pos, r.end()));
}
return std::move(ret);
}
/**
* chunk(n,range) splits a range into length-n pieces. The last piece will be shorter if n does
* not evenly divide the length of the list.
* Note that if R is an std::vector, this takes O(n^2) copies, while if an ImmutableVector
* is supplied, there is no copy at all, while calling toImmutableVector takes O(n)
*
* This is a recursive version. If stack overflow is a concern, avoid it.
*/
template<typename R>
ImmutableList<R> chunkR(size_t n, const R &r)
{
return length(r) <= n
? List::singleton(r)
: cons(take(n,r), chunkR(n, drop(n,r)));
}
/**
* Split on the given sublist. Equivalent to split . dropDelims . onSublist. For example:
* splitOn(string(".."),string("a..b...c....d..")) == ["a","b",".c","","d",""]
*/
template<typename R>
std::vector<R> splitOn(const R &on, const R &r)
{
if (on.empty()) {
return std::vector<R>({r});
}
std::vector<R> ret;
auto itLastEnd = r.begin();
for (auto it = r.begin() ; (it + on.size()) <= r.end();) {
bool last = (it + on.size()) == r.end();
if (R(it, it+on.size()) == on) {
ret.push_back(R(itLastEnd, it));
if (last && on.empty()) {
break;
}
it += on.size();
itLastEnd = it;
if (last) {
break;
}
} else {
if (last) {
break;
}
++it;
}
}
assert(itLastEnd <= r.end());
ret.push_back(R(itLastEnd, r.end()));
return ret;
}
}
#endif