-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathenumerable.hpp
More file actions
152 lines (128 loc) · 5.56 KB
/
Copy pathenumerable.hpp
File metadata and controls
152 lines (128 loc) · 5.56 KB
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#pragma once
#ifndef ENUMERABLE_HPP_6UZ88P0F
#define ENUMERABLE_HPP_6UZ88P0F
namespace ftl {
template <typename SourceEnumerator, typename Functor> class SelectEnumerator;
template <typename SourceEnumerator, typename Functor> class RejectEnumerator;
template <typename SourceEnumerator, typename TargetType, typename Functor> class MapEnumerator;
template <typename TargetClass, typename Enumerator = TargetClass>
class Enumerable {
/*
XXX: When deriving from Enumerable, it must be the first parent class.
This is because we want to avoid virtual functions, but Enumerable still needs
to access get_enumerator() on the derived class, so it does an ugly static_cast(this).
*/
public:
template <typename Functor>
SelectEnumerator<Enumerator, Functor> select(Functor func) const;
template <typename Functor>
RejectEnumerator<Enumerator, Functor> reject(Functor func) const;
template <typename TargetType, typename Functor>
MapEnumerator<Enumerator, TargetType, Functor> map(Functor func) const;
template <typename TargetType, typename Functor>
TargetType inject(TargetType base, Functor func) const {
TargetType result = base;
Enumerator e = get_enumerator();
while (e.move_next()) { result = func(result, e.current()); }
return result;
}
template <typename Functor>
Enumerator find(Functor func) const {
Enumerator e = get_enumerator();
while (e.move_next()) { if (func(e.current())) break; }
return e;
}
template <typename Functor>
void each(Functor func) const {
Enumerator e = get_enumerator();
while (e.move_next()) func(e.current());
}
template <typename Functor>
void each_index(Functor func) const {
Enumerator e = get_enumerator();
size_t n = 0;
while (e.move_next()) func(e.current(), n++);
}
size_t count_all() const {
Enumerator e = get_enumerator();
size_t n = 0;
while (e.move_next()) ++n;
return n;
}
template <typename Functor>
size_t count(Functor func) const {
Enumerator e = get_enumerator();
size_t n = 0;
while (e.move_next()) if (func(e.current())) ++n;
return n;
}
template <typename Functor>
bool any(Functor func) const {
return count(func) > 0;
}
template <typename Functor>
bool all(Functor func) const {
return count(func) == count_all();
}
private:
Enumerator get_enumerator() const { return static_cast<const TargetClass*>(this)->get_enumerator(); }
};
template <typename SourceEnumerator, typename Functor>
class SelectEnumerator : public Enumerable<SelectEnumerator<SourceEnumerator, Functor>> {
public:
typedef typename SourceEnumerator::ValueType ValueType;
SelectEnumerator(const SourceEnumerator& e, Functor func) : _enumerator(e), _func(func) {}
SelectEnumerator(const SelectEnumerator& other) : _enumerator(other._enumerator), _func(other._func) {}
bool move_next() { do { if (!_enumerator.move_next()) return false; } while (!_func(current())); return true; }
ValueType current() const { return _enumerator.current(); }
bool at_end() const { return _enumerator.at_end(); }
const SelectEnumerator<SourceEnumerator,Functor>& get_enumerator() const { return *this; }
private:
Functor _func;
SourceEnumerator _enumerator;
};
template <typename SourceEnumerator, typename Functor>
class RejectEnumerator : public Enumerable<RejectEnumerator<SourceEnumerator, Functor>> {
public:
typedef typename SourceEnumerator::ValueType ValueType;
RejectEnumerator(const SourceEnumerator& e, Functor func) : _enumerator(e), _func(func) {}
RejectEnumerator(const RejectEnumerator& other) : _enumerator(other._enumerator), _func(other._func) {}
bool move_next() { do { if (!_enumerator.move_next()) return false; } while (_func(current())); return true; }
ValueType current() const { return _enumerator.current(); }
bool at_end() const { return _enumerator.at_end(); }
const RejectEnumerator<SourceEnumerator,Functor>& get_enumerator() const { return *this; }
private:
Functor _func;
SourceEnumerator _enumerator;
};
template <typename SourceEnumerator, typename TargetType, typename Functor>
class MapEnumerator : public Enumerable<MapEnumerator<SourceEnumerator, TargetType, Functor>> {
public:
typedef TargetType ValueType;
MapEnumerator(const SourceEnumerator& e, Functor func) : _enumerator(e), _func(func) {}
MapEnumerator(const MapEnumerator& other) : _enumerator(other._enumerator), _func(other._func) {}
bool move_next() { return _enumerator.move_next(); }
TargetType current() const { return _func(_enumerator.current()); }
bool at_end() const { return _enumerator.at_end(); }
const MapEnumerator<SourceEnumerator,TargetType,Functor>& get_enumerator() const { return *this; }
private:
Functor _func;
SourceEnumerator _enumerator;
};
template <typename TargetClass, typename Enumerator>
template <typename Functor>
SelectEnumerator<Enumerator, Functor> Enumerable<TargetClass,Enumerator>::select(Functor func) const {
return SelectEnumerator<Enumerator, Functor>(get_enumerator(), func);
}
template <typename TargetClass, typename Enumerator>
template <typename Functor>
RejectEnumerator<Enumerator, Functor> Enumerable<TargetClass,Enumerator>::reject(Functor func) const {
return RejectEnumerator<Enumerator, Functor>(get_enumerator(), func);
}
template <typename TargetClass, typename Enumerator>
template <typename TargetType, typename Functor>
auto Enumerable<TargetClass,Enumerator>::map(Functor func) const -> MapEnumerator<Enumerator, TargetType, Functor> {
return MapEnumerator<Enumerator, TargetType, Functor>(get_enumerator(), func);
}
}
#endif /* end of include guard: ENUMERABLE_HPP_6UZ88P0F */