cpp-hocon  0.3.0
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 
10 template<class T> class FwdListIter;
11 
12 template<class T>
13 class 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)) {}
29 public:
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(); }
102 private:
103  std::shared_ptr<const Item> _head;
104 };
105 
106 template<class T, class P>
107 bool 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 
116 template<class T>
117 class FwdListIter : public std::iterator<std::forward_iterator_tag, T>
118 {
119 public:
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  }
137 private:
138  std::shared_ptr<const typename List<T>::Item> _cur;
139 };
140 
141 template<class T>
142 class OutListIter : public std::iterator<std::output_iterator_tag, T>
143 {
144 public:
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; }
153 private:
154  T _val;
155  List<T> _lst;
156 };
157 
158 
159 namespace 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 
173 template<class T>
174 List<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 
181 template<class T, class F>
182 auto 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 
193 template<class T, class P>
194 List<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 
206 template<class T, class U, class F>
207 U 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 
217 template<class T, class U, class F>
218 U 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
229 template<class T>
230 List<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
239 template<class T>
240 List<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 
250 template<class T>
251 List<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 
260 template<class T, class F>
261 void 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 
271 template<class Beg, class End>
272 auto 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 
281 template<class T, class F>
282 List<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!
289 template<class T>
290 void 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 
300 template<class T>
301 std::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 
311 template<class T>
312 List<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 }
OutListIter
Definition: functional_list.hpp:143
List
Definition: functional_list.hpp:14
FwdListIter
Definition: functional_list.hpp:10