Lumiera  0.pre.03
»edit your freedom«
itertools.hpp
Go to the documentation of this file.
1 /*
2  ITERTOOLS.hpp - collection of tools for building and combining iterators
3 
4  Copyright (C)
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
67 #ifndef LIB_ITERTOOLS_H
68 #define LIB_ITERTOOLS_H
69 
70 
71 #include "lib/iter-adapter.hpp"
73 #include "lib/meta/function.hpp"
74 #include "lib/meta/trait.hpp"
75 #include "lib/wrapper.hpp"
76 #include "lib/util.hpp"
77 
78 #include <functional>
79 #include <utility>
80 
81 
82 
83 namespace lib {
84 
85  using std::forward;
86  using std::function;
87  using util::unConst;
88 
90 
91 
92 
104  template<class IT>
106  {
107  IT source_;
108 
109  IdentityCore (IT&& orig)
110  : source_{forward<IT>(orig)}
111  { }
112  IdentityCore (IT const& orig)
113  : source_{orig}
114  { }
115 
116  IT&
117  pipe ()
118  {
119  return source_;
120  }
121 
122  IT const&
123  pipe () const
124  {
125  return source_;
126  }
127 
128  void
129  advance ()
130  {
131  ++source_;
132  }
133 
134  bool
135  evaluate () const
136  {
137  return bool(source_);
138  }
139 
140  typedef typename IT::pointer pointer;
141  typedef typename IT::reference reference;
142  typedef typename IT::value_type value_type;
143  };
144 
145 
154  template<class CORE>
155  class IterTool
156  {
157 
158  protected: /* == iteration control == */
159  CORE core_;
160 
161  bool
162  hasData() const
163  {
164  return core_.evaluate()
165  || unConst(this)->iterate();
166  } // to skip irrelevant results doesn't count as "mutation"
167 
168  bool
169  iterate ()
170  {
171  if (!core_.pipe()) return false;
172 
173  do core_.advance();
174  while (core_.pipe() && !core_.evaluate());
175 
176  return bool{core_.pipe()};
177  }
178 
179  void
180  _maybe_throw() const
181  {
182  if (!isValid())
183  _throwIterExhausted();
184  }
185 
186 
187 
188  public:
189  typedef typename CORE::pointer pointer;
190  typedef typename CORE::reference reference;
191  typedef typename CORE::value_type value_type;
192 
193 
194  IterTool (CORE&& setup)
195  : core_{std::move(setup)}
196  {
197  hasData();
198  }
199 
200  explicit
201  operator bool() const
202  {
203  return isValid();
204  }
205 
206 
207 
208  /* === lumiera forward iterator concept === */
209 
210  reference
211  operator*() const
212  {
213  _maybe_throw();
214  return *core_.pipe();
215  }
216 
217  pointer
218  operator->() const
219  {
220  _maybe_throw();
221  return & *core_.pipe();
222  }
223 
224  IterTool&
225  operator++()
226  {
227  _maybe_throw();
228  iterate();
229  return *this;
230  }
231 
232  bool
233  isValid () const
234  {
235  return hasData();
236  }
237 
238  bool
239  empty () const
240  {
241  return not isValid();
242  }
243 
244  };
245 
246 
247  template<class CX>
248  inline bool
249  operator== (IterTool<CX> const& it1, IterTool<CX> const& it2)
250  {
251  return (!it1 && !it2 )
252  || ( it1 && it2 && (*it1) == (*it2) )
253  ;
254  }
255 
256  template<class CX>
257  inline bool
258  operator!= (IterTool<CX> const& ito1, IterTool<CX> const& ito2)
259  {
260  return not (ito1 == ito2);
261  }
262 
263 
264 
265 
266 
267 
268 
269 
278  template<class IT>
279  struct FilterCore
280  : IdentityCore<IT>
281  {
282  using Raw = IdentityCore<IT>;
283  using Val = iter::Yield<IT>;
284 
285 
286  function<bool(Val)> predicate_;
287 
288  bool
289  evaluate () const
290  {
291  return Raw::pipe()
292  && currVal_isOK();
293  }
294 
295 
296  mutable bool cached_;
297  mutable bool isOK_;
298 
299  bool
300  currVal_isOK () const
301  {
302  return (cached_ && isOK_)
303  || (cached_ = true
304  &&(isOK_ = predicate_(*Raw::pipe())));
305  }
306 
307  void
308  advance ()
309  {
310  cached_ = false;
311  Raw::advance();
312  }
313 
314 
315  template<typename PRED>
316  FilterCore (IT&& source, PRED prediDef)
317  : Raw{forward<IT>(source)}
318  , predicate_(prediDef) // induces a signature check
319  , cached_(false) // not yet cached
320  , isOK_(false) // not yet relevant
321  { }
322 
323  template<typename PRED>
324  FilterCore (IT const& source, PRED prediDef)
325  : Raw{source}
326  , predicate_(prediDef)
327  , cached_(false)
328  , isOK_(false)
329  { }
330  };
331 
332 
336  template<class IT>
338  : public IterTool<FilterCore<IT>>
339  {
340  typedef FilterCore<IT> _Filter;
341  typedef IterTool<_Filter> _Impl;
342 
343  public:
344  static bool acceptAll(typename _Filter::Val) { return true; }
345 
346 
347  FilterIter ()
348  : _Impl{FilterCore<IT>(IT(), acceptAll)}
349  { }
350 
351  template<typename PRED>
352  FilterIter (IT const& src, PRED filterPredicate)
353  : _Impl{_Filter(src, filterPredicate)}
354  { }
355 
356  template<typename PRED>
357  FilterIter (IT&& src, PRED filterPredicate)
358  : _Impl{_Filter(forward<IT>(src), filterPredicate)}
359  { }
360 
362  };
363 
364 
370  template<class IT, typename PRED>
371  inline auto
372  filterIterator (IT const& src, PRED filterPredicate)
373  {
374  return FilterIter<IT>{src, filterPredicate};
375  }
376 
377  template<class IT, typename PRED>
378  inline auto
379  filterIterator (IT&& src, PRED filterPredicate)
380  {
381  using SrcIT = typename std::remove_reference<IT>::type;
382  return FilterIter<SrcIT>{forward<IT>(src), filterPredicate};
383  }
384 
385 
409  template<class IT>
411  : public FilterIter<IT>
412  {
413  using _Filter = FilterCore<IT>;
414  using Val = typename _Filter::Val;
415 
416  void
417  reEvaluate()
418  {
419  this->core_.cached_ = false;
420  this->hasData(); // re-evaluate head element
421  }
422 
423  public:
425 
426  template<typename PRED>
427  ExtensibleFilterIter (IT&& src, PRED initialFilterPredicate)
428  : FilterIter<IT>{forward<IT>(src), initialFilterPredicate}
429  { }
430  template<typename PRED>
431  ExtensibleFilterIter (IT const& src, PRED initialFilterPredicate)
432  : FilterIter<IT>{src, initialFilterPredicate}
433  { }
434 
435  ExtensibleFilterIter (IT&& src)
437  { }
438 
439  // standard copy operations acceptable
440 
441 
444  IT&
445  underlying()
446  {
447  return this->core_.source_;
448  }
449 
450 
451  template<typename COND>
453  andFilter (COND conjunctiveClause)
454  {
455  function<bool(Val)>& filter = this->core_.predicate_;
456 
457  filter = [=](Val val)
458  {
459  return filter(val)
460  and conjunctiveClause(val);
461  };
462  reEvaluate();
463  return *this;
464  }
465 
466  template<typename COND>
468  andNotFilter (COND conjunctiveClause)
469  {
470  function<bool(Val)>& filter = this->core_.predicate_;
471 
472  filter = [=](Val val)
473  {
474  return filter(val)
475  and not conjunctiveClause(val);
476  };
477  reEvaluate();
478  return *this;
479  }
480 
481  template<typename COND>
483  orFilter (COND disjunctiveClause)
484  {
485  function<bool(Val)>& filter = this->core_.predicate_;
486 
487  filter = [=](Val val)
488  {
489  return filter(val)
490  or disjunctiveClause(val);
491  };
492  reEvaluate();
493  return *this;
494  }
495 
496  template<typename COND>
498  orNotFilter (COND disjunctiveClause)
499  {
500  function<bool(Val)>& filter = this->core_.predicate_;
501 
502  filter = [=](Val val)
503  {
504  return filter(val)
505  or not disjunctiveClause(val);
506  };
507  reEvaluate();
508  return *this;
509  }
510 
511 
512  template<typename COND>
514  setNewFilter (COND entirelyDifferentPredicate)
515  {
516  this->core_.predicate_ = entirelyDifferentPredicate;
517  reEvaluate();
518  return *this;
519  }
520 
522  flipFilter ()
523  {
524  function<bool(Val)>& filter = this->core_.predicate_;
525 
526  filter = [=](Val val)
527  {
528  return not filter(val);
529  };
530  reEvaluate();
531  return *this;
532  }
533  };
534 
535 
536 
542  template<typename VAL>
544  {
546 
547  Item prev_;
548 
549  public:
550  bool
551  operator() (VAL const& elm)
552  {
553  if (prev_ &&
554  (*prev_ == elm))
555  return false;
556 
557  // element differs from predecessor
558  prev_ = elm;
559  return true;
560  }
561 
562  typedef bool result_type;
563  };
564 
565 
566 
567 
568 
569 
570 
571 
572 
573 
578  template<typename VAL>
580  {
582 
583  Item theValue_;
584 
585  public:
587 
588  SingleValCore (VAL&& something)
589  : theValue_{forward<VAL> (something)}
590  { }
591 
592  Item const&
593  pipe () const
594  {
595  return theValue_;
596  }
597 
598  void
599  advance ()
600  {
601  theValue_.reset();
602  }
603 
604  bool
605  evaluate () const
606  {
607  return theValue_.isValid();
608  }
609 
610  typedef std::remove_reference_t<VAL> * pointer;
611  typedef std::remove_reference_t<VAL> & reference;
612  typedef std::remove_reference_t<VAL> value_type;
613  };
614 
615 
625  template<class VAL>
627  : public IterTool<SingleValCore<VAL>>
628  {
631 
632  public:
633  SingleValIter ()
635  { }
636 
637  SingleValIter (VAL&& something)
638  : _IteratorImpl{_ValHolder{forward<VAL>(something)}}
639  { }
640 
642  };
643 
644 
645 
653  template<class VAL>
654  inline auto
655  singleValIterator (VAL&& something)
656  {
657  return SingleValIter<VAL>{forward<VAL>(something)};
658  }
659 
660 
662  template<class VAL>
663  inline auto
665  {
666  return SingleValIter<VAL>();
667  }
668 
669 
670 
671 
672 
678  template<class IT, class VAL>
680  {
681  using InType = iter::Yield<IT>;
683 
684  function<VAL(InType)> trafo_;
685 
686  IT source_;
687  Item treated_;
688 
689  void
690  processItem ()
691  {
692  if (source_)
693  treated_ = trafo_(*source_);
694  else
695  treated_.reset();
696  }
697 
698 
699 
700  public:
701  TransformingCore ()
702  : trafo_()
703  , source_()
704  , treated_()
705  { }
706 
707  template<typename FUN>
708  TransformingCore (IT&& orig, FUN processor)
709  : trafo_(processor) // induces a signature check
710  , source_(forward<IT> (orig))
711  {
712  processItem();
713  }
714 
715  template<typename FUN>
716  TransformingCore (IT const& orig, FUN processor)
717  : trafo_(processor) // induces a signature check
718  , source_(orig)
719  {
720  processItem();
721  }
722 
723  Item const&
724  pipe () const
725  {
726  return treated_;
727  }
728 
729  void
730  advance ()
731  {
732  ++source_;
733  processItem();
734  }
735 
736  bool
737  evaluate () const
738  {
739  return bool(source_);
740  }
741 
742  using pointer = typename ValueTypeBinding<VAL>::pointer;
743  using reference = typename ValueTypeBinding<VAL>::reference;
744  using value_type = typename ValueTypeBinding<VAL>::value_type;
745  };
746 
747 
753  template<class IT, class VAL>
755  : public IterTool<TransformingCore<IT,VAL>>
756  {
759 
760  public:
761  TransformIter ()
762  : _IteratorImpl(_Trafo())
763  { }
764 
765  template<typename FUN>
766  TransformIter (IT&& src, FUN trafoFunc)
767  : _IteratorImpl{_Trafo(forward<IT>(src), trafoFunc)}
768  { }
769  template<typename FUN>
770  TransformIter (IT const& src, FUN trafoFunc)
771  : _IteratorImpl{_Trafo(src, trafoFunc)}
772  { }
773 
775  };
776 
777 
778 
779 
780 
786  template<class IT, typename FUN>
787  inline auto
788  transformIterator (IT const& src, FUN processingFunc)
789  {
790  using OutVal = typename lib::meta::_Fun<FUN>::Ret;
791  return TransformIter<IT,OutVal>{src,processingFunc};
792  }
793 
794  template<class IT, typename FUN>
795  inline auto
796  transformIterator (IT&& src, FUN processingFunc)
797  {
798  using SrcIT = typename std::remove_reference<IT>::type;
799  using OutVal = typename lib::meta::_Fun<FUN>::Ret;
800  return TransformIter<SrcIT,OutVal>{forward<IT>(src), processingFunc};
801  }
802 
803 
804 
805 
806  /* === utility functions === */
807 
808  template<class IT, class CON>
809  inline void
810  append_all (IT iter, CON& container)
811  {
812  for ( ; iter; ++iter )
813  container.push_back (*iter);
814  }
815 
816 
817  template<class IT>
818  inline typename IT::value_type
819  pull_last (IT iter)
820  {
821  using Val = typename IT::value_type;
822  using Item = wrapper::ItemWrapper<Val>;
823 
824  Item lastElm;
825 
826  while (iter)
827  {
828  lastElm = *iter;
829  ++iter;
830  }
831 
832  if (lastElm)
833  return *lastElm;
834  else
835  throw lumiera::error::State ("attempt to retrieve the last element "
836  "of an exhausted or empty iterator"
837  ,lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
838  }
839 
840 
841 
844  template<class IT>
845  inline auto
846  filterRepetitions (IT const& source)
847  {
848  using Val = typename meta::ValueTypeBinding<IT>::value_type;
849  return filterIterator (source, SkipRepetition<Val>());
850  }
851 
852  template<class IT>
853  inline auto
854  filterRepetitions (IT&& source)
855  {
856  using Val = typename meta::ValueTypeBinding<IT>::value_type;
857  return filterIterator (forward<IT>(source), SkipRepetition<Val>() );
858  }
859 
860 
861 
862 
863 
864 } // namespace lib
865 #endif
Iterator tool filtering pulled data according to a predicate.
Definition: itertools.hpp:337
bool currVal_isOK() const
<
Definition: itertools.hpp:300
SingleValCore()
passive and empty
Definition: itertools.hpp:586
A neutral identity-function core, also serving as point-of reference how any core is intended to work...
Definition: itertools.hpp:105
bool filter(Placement< DummyMO > const &candidate)
a filter predicate to pick some objects from a resultset.
Implementation of a singleton value holder, which discards the contained value once "iterated"...
Definition: itertools.hpp:579
Helper template(s) for creating Lumiera Forward Iterators.
Type re-binding helper template for custom containers and adapters.
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
Helper for uniform access to function signature types.
Definition: function.hpp:99
Additional capabilities for FilterIter, allowing to extend the filter condition underway.
Definition: itertools.hpp:410
#define ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(ITER)
use a given Lumiera Forward Iterator in standard "range for loops"
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Metaprogramming tools for transforming functor types.
Standard functionality to build up any iterator tool.
Definition: itertools.hpp:155
auto nilIterator()
not-anything-at-all iterator
Definition: itertools.hpp:664
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Iterator tool treating pulled data by a custom transformation (function)
Definition: itertools.hpp:754
Helper: predicate returning true whenever the argument value changes during a sequence of invocations...
Definition: itertools.hpp:543
auto singleValIterator(VAL &&something)
Build a SingleValIter: convenience free function shortcut, to pick up just any value and wrap it as L...
Definition: itertools.hpp:655
Helpers for type detection, type rewriting and metaprogramming.
Implementation of the filter logic.
Definition: itertools.hpp:279
auto setup(FUN &&workFun)
Helper: setup a Worker-Pool configuration for the test.
Pseudo-Iterator to yield just a single value.
Definition: itertools.hpp:626
Implementation of custom processing logic.
Definition: itertools.hpp:679
Type re-binding helper template for creating nested typedefs usable by custom containers and iterator...
auto filterIterator(IT const &src, PRED filterPredicate)
Build a FilterIter: convenience free function shortcut, picking up the involved types automatically...
Definition: itertools.hpp:372
auto transformIterator(IT const &src, FUN processingFunc)
Build a TransformIter: convenience free function shortcut, picking up the involved types automaticall...
Definition: itertools.hpp:788
Library implementation: smart-pointer variations, wrappers and managing holders.
auto filterRepetitions(IT const &source)
filters away repeated values emitted by source iterator
Definition: itertools.hpp:846