cpp-hocon 0.3.0
Loading...
Searching...
No Matches
functional_list.hpp
1#pragma once
2
3#include <cassert>
4#include <memory>
5#include <functional>
6#include <initializer_list>
7#include <iterator>
8#include <iostream> // print
9
10template<class T> class FwdListIter;
11
12template<class T>
13class List
14{
15 struct Item
16 {
17 Item(T v, std::shared_ptr<const Item> tail)
18 : _val(v), _next(std::move(tail))
19 {}
20 // singleton
21 explicit Item(T v) : _val(v) {}
22 // ~Item() { std::cout << "~" << _val << std::endl; }
23 T _val;
24 std::shared_ptr<const Item> _next;
25 };
26 friend Item;
27 explicit List(std::shared_ptr<const Item> items)
28 : _head(std::move(items)) {}
29public:
30 // Empty list
31 List() {}
32 // Cons
33 List(T v, List const & tail)
34 : _head(std::make_shared<Item>(v, tail._head)) {}
35 // Singleton
36 explicit List(T v) : _head(std::make_shared<Item>(v)) {}
37
38 bool isEmpty() const { return !_head; } // conversion to bool
39 T front() const
40 {
41 assert(!isEmpty());
42 return _head->_val;
43 }
44 List popped_front() const
45 {
46 assert(!isEmpty());
47 return List(_head->_next);
48 }
49 // Additional utilities
50 List pushed_front(T v) const
51 {
52 return List(v, *this);
53 }
54 List take(int n)
55 {
56 if (n <= 0 || isEmpty()) return List();
57 return popped_front().take(n - 1).pushed_front(front());
58 }
59 List insertedAt(int i, T v) const
60 {
61 if (i == 0) {
62 return pushed_front(v);
63 } else {
64 assert(!isEmpty());
65 return List<T>(front(), popped_front().insertedAt(i - 1, v));
66 }
67 }
68 List removed(T v) const
69 {
70 if (isEmpty()) return List();
71 if (v == front())
72 return popped_front().removed(v);
73 return List(front(), popped_front().removed(v));
74 }
75 List removed1(T v) const
76 {
77 if (isEmpty()) return List();
78 if (v == front())
79 return popped_front();
80 return List(front(), popped_front().removed(v));
81 }
82 bool member(T v) const
83 {
84 if (isEmpty()) return false;
85 if (v == front()) return true;
86 return popped_front().member(v);
87 }
88 template<class F>
89 void forEach(F f) const
90 {
91 Item const * it = _head.get();
92 while (it != nullptr)
93 {
94 f(it->_val);
95 it = it->_next.get();
96 }
97 }
98
99 friend class FwdListIter<T>;
100 // For debugging
101 int headCount() const { return _head.use_count(); }
102private:
103 std::shared_ptr<const Item> _head;
104};
105
106template<class T, class P>
107bool all(List<T> const & lst, P & p)
108{
109 if (lst.isEmpty())
110 return true;
111 if (!p(lst.front()))
112 return false;
113 return all(lst.popped_front(), p);
114}
115
116template<class T>
117class FwdListIter : public std::iterator<std::forward_iterator_tag, T>
118{
119public:
120 FwdListIter() {} // end
121 FwdListIter(List<T> const & lst) : _cur(lst._head)
122 {}
123 T operator*() const { return _cur->_val; }
124 FwdListIter & operator++()
125 {
126 _cur = _cur->_next;
127 return *this;
128 }
129 bool operator==(FwdListIter<T> const & other)
130 {
131 return _cur == other._cur;
132 }
133 bool operator!=(FwdListIter<T> const & other)
134 {
135 return !(*this == other);
136 }
137private:
138 std::shared_ptr<const typename List<T>::Item> _cur;
139};
140
141template<class T>
142class OutListIter : public std::iterator<std::output_iterator_tag, T>
143{
144public:
145 OutListIter() {}
146 T & operator*() { return _val; }
147 OutListIter & operator++()
148 {
149 _lst = List<T>(_val, _lst);
150 return *this;
151 }
152 List<T> getList() const { return _lst; }
153private:
154 T _val;
155 List<T> _lst;
156};
157
158
159namespace std
160{
161 template<class T>
162 FwdListIter<T> begin(List<T> const & lst)
163 {
164 return FwdListIter<T>(lst);
165 }
166 template<class T>
167 FwdListIter<T> end(List<T> const & lst)
168 {
169 return FwdListIter<T>();
170 }
171}
172
173template<class T>
174List<T> concat(List<T> const & a, List<T> const & b)
175{
176 if (a.isEmpty())
177 return b;
178 return List<T>(a.front(), concat(a.popped_front(), b));
179}
180
181template<class T, class F>
182auto fmap(F f, List<T> lst) -> List<decltype(f(lst.front()))>
183{
184 using U = decltype(f(lst.front()));
185 static_assert(std::is_convertible<F, std::function<U(T)>>::value,
186 "fmap requires a function type U(T)");
187 if (lst.isEmpty())
188 return List<U>();
189 else
190 return List<U>(f(lst.front()), fmap(f, lst.popped_front()));
191}
192
193template<class T, class P>
194List<T> filter(P p, List<T> lst)
195{
196 static_assert(std::is_convertible<P, std::function<bool(T)>>::value,
197 "filter requires a function type bool(T)");
198 if (lst.isEmpty())
199 return List<T>();
200 if (p(lst.front()))
201 return List<T>(lst.front(), filter(p, lst.popped_front()));
202 else
203 return filter(p, lst.popped_front());
204}
205
206template<class T, class U, class F>
207U foldr(F f, U acc, List<T> lst)
208{
209 static_assert(std::is_convertible<F, std::function<U(T, U)>>::value,
210 "foldr requires a function type U(T, U)");
211 if (lst.isEmpty())
212 return acc;
213 else
214 return f(lst.front(), foldr(f, acc, lst.popped_front()));
215}
216
217template<class T, class U, class F>
218U foldl(F f, U acc, List<T> lst)
219{
220 static_assert(std::is_convertible<F, std::function<U(U, T)>>::value,
221 "foldl requires a function type U(U, T)");
222 if (lst.isEmpty())
223 return acc;
224 else
225 return foldl(f, f(acc, lst.front()), lst.popped_front());
226}
227
228// Set difference a \ b
229template<class T>
230List<T> set_diff(List<T> const & as, List<T> const & bs)
231{
232 return foldl([](List<T> const & acc, T x) {
233 return acc.removed(x);
234 }, as, bs);
235}
236
237// Set union of two lists, xs u ys
238// Assume no duplicates inside either list
239template<class T>
240List<T> set_union(List<T> const & xs, List<T> const & ys)
241{
242 // xs u ys = (ys \ xs) ++ xs
243 // removed all xs from ys
244 auto trimmed = foldl([](List<T> const & acc, T x) {
245 return acc.removed(x);
246 }, ys, xs);
247 return concat(trimmed, xs);
248}
249
250template<class T>
251List<T> concatAll(List<List<T>> const & xss)
252{
253 if (xss.isEmpty()) return List<T>();
254 return concat(xss.front(), concatAll(xss.popped_front()));
255}
256
257// consumes the list when called:
258// forEach(std::move(lst), f);
259
260template<class T, class F>
261void forEach(List<T> lst, F f)
262{
263 static_assert(std::is_convertible<F, std::function<void(T)>>::value,
264 "forEach requires a function type void(T)");
265 while (!lst.isEmpty()) {
266 f(lst.front());
267 lst = lst.popped_front();
268 }
269}
270
271template<class Beg, class End>
272auto fromIt(Beg it, End end) -> List<typename Beg::value_type>
273{
274 typedef typename Beg::value_type T;
275 if (it == end)
276 return List<T>();
277 T item = *it;
278 return List<T>(item, fromIt(++it, end));
279}
280
281template<class T, class F>
282List<T> iterateN(F f, T init, int count)
283{
284 if (count <= 0) return List<T>();
285 return iterateN(f, f(init), count - 1).pushed_front(init);
286}
287
288// Pass lst by value not reference!
289template<class T>
290void printRaw(List<T> lst)
291{
292 if (lst.isEmpty()) {
293 std::cout << std::endl;
294 } else {
295 std::cout << "(" << lst.front() << ", " << lst.headCount() - 1 << ") ";
296 printRaw(lst.popped_front());
297 }
298}
299
300template<class T>
301std::ostream& operator<<(std::ostream& os, List<T> const & lst)
302{
303 os << "[";
304 forEach(lst, [&os](T v) {
305 os << v << " ";
306 });
307 os << "]";
308 return os;
309}
310
311template<class T>
312List<T> reversed(List<T> const & lst)
313{
314 return foldl([](List<T> const & acc, T v)
315 {
316 return List<T>(v, acc);
317 }, List<T>(), lst);
318}
STL namespace.