Lumiera  0.pre.03
»edit your freedom«
iter-explorer.hpp
Go to the documentation of this file.
1 /*
2  ITER-EXPLORER.hpp - building blocks for iterator evaluation strategies
3 
4  Copyright (C)
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6  2024, Hermann Vosseler <Ichthyostega@web.de>
7 
8   **Lumiera** is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2 of the License, or (at your
11   option) any later version. See the file COPYING for further details.
12 
13 */
14 
97 #ifndef LIB_ITER_EXPLORER_H
98 #define LIB_ITER_EXPLORER_H
99 
100 
101 #include "lib/error.hpp"
104 #include "lib/meta/function.hpp"
105 #include "lib/meta/trait.hpp"
106 #include "lib/wrapper.hpp"
107 #include "lib/iter-adapter.hpp"
108 #include "lib/iter-source.hpp"
109 #include "lib/iter-stack.hpp"
110 #include "lib/util.hpp"
111 
112 #include <functional>
113 #include <optional>
114 #include <utility>
115 
116 
117 //Forward declaration to allow a default result container for IterExplorer::effuse
118 namespace std {
119  template<typename T, class A> class vector;
120  template<typename K, typename CMP, class A> class set;
121 }
122 
123 
124 namespace lib {
125 
126  using std::move;
127  using std::forward;
128  using std::function;
129  using util::isnil;
130 
131  namespace error = lumiera::error;
132 
133  namespace iter_explorer { // basic iterator wrappers...
134 
135  template<class CON>
136  using iterator = typename meta::Strip<CON>::TypeReferred::iterator;
137  template<class CON>
138  using const_iterator = typename meta::Strip<CON>::TypeReferred::const_iterator;
139 
145  template<class CON>
146  struct StlRange
147  : RangeIter<iterator<CON>>
148  {
149  StlRange() =default;
150  StlRange (CON& container)
151  : RangeIter<iterator<CON>> {begin(container), end(container)}
152  { }
153  // standard copy operations acceptable
154  };
155 
156  template<class CON>
157  struct StlRange<const CON>
158  : RangeIter<const_iterator<CON>>
159  {
160  StlRange() =default;
161  StlRange (CON const& container)
162  : RangeIter<const_iterator<CON>> {begin(container), end(container)}
163  { }
164  // standard copy operations acceptable
165  };
166 
167  template<class CON>
168  struct StlRange<CON &>
169  : StlRange<CON>
170  {
172  };
173 
174 
189  template<class ISO>
191  : public ISO::iterator
192  {
193  using Iterator = typename ISO::iterator;
194 
195  public:
196  IterSourceIter() =default;
197  // standard copy operations
198 
200  IterSourceIter (ISO& externalSource)
201  : Iterator{ISO::build (externalSource)}
202  { }
203 
205  IterSourceIter (ISO* heapObject)
206  : Iterator{heapObject? ISO::build (heapObject)
207  : Iterator()}
208  { }
209 
210  using Source = ISO;
211 
212  Source&
213  source()
214  {
215  REQUIRE (ISO::iterator::isValid());
216  return static_cast<ISO&> (*ISO::iterator::source());
217  }
218  };
219 
220  }//(End) namespace iter_explorer : basic iterator wrappers
221 
222 
223 
224 
225  namespace { // IterExplorer traits
226 
227  using meta::enable_if;
228  using meta::disable_if;
229  using meta::Yes_t;
230  using meta::No_t;
231  using meta::_Fun;
232  using std::__and_;
233  using std::__not_;
234  using std::is_const_v;
235  using std::is_base_of;
236  using std::common_type;
237  using std::common_type_t;
238  using std::conditional_t;
239  using std::is_convertible;
240  using std::remove_reference_t;
241  using meta::is_StateCore;
242  using meta::can_IterForEach;
243  using meta::can_STL_ForEach;
245  using meta::has_TypeResult;
246 
247 
248  template<class SRC>
250  : __and_<can_STL_ForEach<SRC>
251  ,__not_<can_IterForEach<SRC>>
252  >
253  { };
254 
255  template<class SRC>
257  : __and_<can_IterForEach<SRC>
258  ,__not_<is_StateCore<SRC>>
259  >
260  { };
261 
262 
263 
267  template<class SRC, typename SEL=void>
269  {
270  static_assert (!sizeof(SRC), "Can not build IterExplorer: Unable to figure out how to iterate the given SRC type.");
271  };
272 
273  template<class SRC>
274  struct _DecoratorTraits<SRC, enable_if<is_StateCore<SRC>>>
275  {
276  using SrcRaw = typename lib::meta::Strip<SRC>::Type;
277  using SrcVal = typename meta::RefTraits<iter::CoreYield<SrcRaw>>::Value;
279  };
280 
281  template<class SRC>
282  struct _DecoratorTraits<SRC, enable_if<shall_use_Lumiera_Iter<SRC>>>
283  {
284  using SrcIter = remove_reference_t<SRC>;
285  using SrcVal = typename SrcIter::value_type;
286  };
287 
288  template<class SRC>
289  struct _DecoratorTraits<SRC, enable_if<shall_wrap_STL_Iter<SRC>>>
290  {
291  static_assert (not std::is_rvalue_reference<SRC>::value,
292  "container needs to exist elsewhere during the lifetime of the iteration");
294  using SrcVal = typename SrcIter::value_type;
295  };
296 
297  template<class ISO>
298  struct _DecoratorTraits<ISO*, enable_if<is_base_of<IterSource<typename ISO::value_type>, ISO>>>
299  {
301  using SrcVal = typename ISO::value_type;
302  };
303 
304  template<class ISO>
305  struct _DecoratorTraits<ISO*&, enable_if<is_base_of<IterSource<typename ISO::value_type>, ISO>>>
307  { };
308 
309  template<class ISO>
310  struct _DecoratorTraits<ISO&, enable_if<is_base_of<IterSource<typename ISO::value_type>, ISO>>>
312  { };
313 
314 
315 
324  template<class SRC, class RES>
326  {
327  using ResIter = typename _DecoratorTraits<RES>::SrcIter;
328  using SrcYield = iter::Yield<SRC>;
329  using ResYield = iter::Yield<ResIter>;
331  static constexpr bool can_reconcile = _CommonT::value;
332  static constexpr bool isRefResult = _CommonT::isRef;
333 
334  static_assert (can_reconcile,
335  "source iterator and result from the expansion must yield compatible values");
336  static_assert (is_const_v<SrcYield> == is_const_v<ResYield>,
337  "source and expanded types differ in const-ness");
338 
339  using YieldRes = typename _CommonT::ResType;
340  using value_type = typename _CommonT::value_type;
341  using reference = typename _CommonT::reference;
342  using pointer = typename _CommonT::pointer;
343  };
344 
345  }//(End) IterExplorer traits
346 
347 
348 
349 
350 
351  namespace iter_explorer { // Implementation of Iterator decorating layers...
352 
353  constexpr auto ACCEPT_ALL = [](auto){return true;};
354  constexpr auto IDENTITY = [](auto it){return *it;};
355 
385  template<class FUN, typename SRC>
386  struct _FunTraits
387  {
389  template<typename F, typename SEL =void>
390  struct FunDetector
391  {
392  using Sig = typename _Fun<F>::Sig;
393  };
394 
396  template<typename F>
397  struct FunDetector<F, disable_if<_Fun<F>> >
398  {
399  using Arg = typename std::add_lvalue_reference<SRC>::type;
400  using Ret = decltype(std::declval<F>() (std::declval<Arg>()));
401  using Sig = Ret(Arg);
402  };
403 
404 
405  using Sig = typename FunDetector<FUN>::Sig;
406  using Arg = typename _Fun<Sig>::Args::List::Head; // assuming function with a single argument
407  using Res = typename _Fun<Sig>::Ret;
408  static_assert (meta::is_UnaryFun<Sig>());
409 
410 
411 
413  template<class ARG, class SEL =void>
414  struct ArgAdapter
415  {
416  using FunArgType = remove_reference_t<Arg>;
417  static_assert (std::is_convertible<ARG, FunArgType>::value,
418  "the bound functor must accept the source iterator or state core as parameter");
419 
420  static decltype(auto)
421  wrap (FUN&& rawFunctor)
422  {
423  return forward<FUN> (rawFunctor);
424  }
425  };
426 
428  template<class IT>
429  struct ArgAdapter<IT, enable_if<__and_<is_convertible<iter::Yield<IT>, Arg>
430  ,__not_<is_convertible<IT, Arg>>>>> // need to exclude the latter, since IterableDecorator
431  { // often seems to accept IT::value_type (while in fact it doesn't)
432  static auto
433  wrap (function<Sig> rawFun)
434  {
435  return [rawFun](IT& srcIter) -> Res { return rawFun(*srcIter); };
436  }
437  };
438 
440  template<class IT>
441  struct ArgAdapter<IT, enable_if<__and_< is_base_of<IterSource<typename IT::value_type>, typename IT::Source>
442  , is_base_of<IterSource<typename IT::value_type>, remove_reference_t<Arg>>
443  > >>
444  {
445  using Source = typename IT::Source;
446 
447  static auto
448  wrap (function<Sig> rawFun)
449  {
450  return [rawFun](IT& iter) -> Res { return rawFun(iter.source()); };
451  }
452  };
453 
454 
455 
457  static auto
458  adaptFunctor (FUN&& rawFunctor)
459  {
460  return function<Res(SRC&)> {ArgAdapter<SRC>::wrap (forward<FUN> (rawFunctor))};
461  }
462  };
463 
464 
465  template<typename FUN, typename SRC>
466  inline void
467  static_assert_isPredicate()
468  {
469  using Res = typename _FunTraits<FUN,SRC>::Res;
470  static_assert(std::is_constructible<bool, Res>::value, "Functor must be a predicate");
471  }
472 
473 
477  template<class SRC, class FUN>
479  {
480  using Result = typename iter_explorer::_FunTraits<FUN,SRC>::Res;
481  using ResVal = typename lib::meta::RefTraits<Result>::Value;
482  };
483 
484 
485 
486 
487 
504  template<class SRC>
505  struct BaseAdapter
506  : SRC
507  {
508  BaseAdapter() = default;
509  BaseAdapter(SRC const& src) : SRC{src} { }
510  BaseAdapter(SRC && src) : SRC{forward<SRC> (src)} { }
511 
512  void expandChildren() { }
513  size_t depth() const { return 0; }
514 
516  };
517 
518 
553  template<class SRC, class RES>
554  class Expander
555  : public SRC
556  {
557  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
558 
559  using _Trait = _ExpanderTraits<SRC,RES>;
560  using ResIter = typename _Trait::ResIter;
561  using RootExpandFunctor = function<RES(SRC&)>;
562  using ChldExpandFunctor = function<RES(ResIter&)>;
563 
564  RootExpandFunctor expandRoot_;
565  ChldExpandFunctor expandChild_;
566 
567  IterStack<ResIter> expansions_;
568 
569  public:
570  Expander() =default;
571  // inherited default copy operations
572 
573  template<typename FUN>
574  Expander (SRC&& parentExplorer, FUN&& expandFunctor)
575  : SRC{move (parentExplorer)} // NOTE: slicing move to strip IterExplorer (Builder)
576  , expandRoot_ {_FunTraits<FUN,SRC> ::adaptFunctor (forward<FUN> (expandFunctor))} // adapt to accept SRC&
577  , expandChild_{_FunTraits<FUN,ResIter>::adaptFunctor (forward<FUN> (expandFunctor))} // adapt to accept RES&
578  , expansions_{}
579  { }
580 
581 
582 
584  void
586  {
587  REQUIRE (this->checkPoint(), "attempt to expand an empty explorer");
588  REQUIRE (invariant());
589 
590  ResIter expanded{ hasChildren()? expandChild_(*expansions_)
591  : expandRoot_(*this)};
592  if (not isnil(expanded))
593  expansions_.push (move(expanded)); // note: source of expansion retained
594  else
595  iterNext(); // expansion unsuccessful, thus consume source immediately
596 
597  ENSURE (invariant());
598  }
599 
601  size_t
602  depth() const
603  {
604  return expansions_.size();
605  }
606 
612  void
614  {
615  if (not hasChildren()) return;
616  static_cast<SRC&> (*this) = move (*expansions_);
617  expansions_.clear();
618  }
619 
620 
621  public: /* === Iteration control API for IterableDecorator === */
622 
624  using YieldRes = typename _Trait::YieldRes;
625  using value_type = typename _Trait::value_type;
626  using reference = typename _Trait::reference;
627  using pointer = typename _Trait::pointer;
628 
629 
630  bool
631  checkPoint() const
632  {
633  ENSURE (invariant());
634 
635  return hasChildren()
636  or SRC::isValid();
637  }
638 
639  YieldRes
640  yield() const
641  {
642  return hasChildren()? **expansions_
643  : **this;
644  }
645 
646  void
647  iterNext()
648  {
649  incrementCurrent();
650  dropExhaustedChildren();
651  ENSURE (invariant());
652  }
653 
654  private:
655  bool
656  invariant() const
657  {
658  return not hasChildren()
659  or expansions_->isValid();
660  }
661 
662  void
663  incrementCurrent()
664  {
665  if (hasChildren())
666  ++(*expansions_);
667  else
668  ++(*this);
669  }
670 
671 
672  protected:
673  bool
674  hasChildren() const
675  {
676  return 0 < depth();
677  }
678 
680  ResIter&
682  {
683  REQUIRE (hasChildren());
684  return *expansions_;
685  }
686 
687  void
688  dropExhaustedChildren()
689  {
690  while (not invariant())
691  {
692  ++expansions_; // pop expansion stack (to reinstate invariant)
693  incrementCurrent(); // consume source of innermost expansion
694  }
695  }
696  };
697 
698 
699 
708  template<class SRC>
710  : public SRC
711  {
712  static_assert(is_StateCore<SRC>::value, "need wrapped state core as predecessor in pipeline");
713 
714  public:
716  using SRC::SRC;
717 
718  void
719  iterNext()
720  {
721  SRC::__throw_if_empty();
722  SRC::expandChildren();
723  }
724  };
725 
726 
727 
731  template<class SRC>
733  : public SRC
734  {
735  static_assert(is_StateCore<SRC>::value, "need wrapped state core as predecessor in pipeline");
736 
737  bool shallExpand_ = false;
738 
739  public:
741  using SRC::SRC;
742 
743  void
744  expandChildren()
745  {
746  shallExpand_ = true;
747  }
748 
749  void
750  iterNext()
751  {
752  if (shallExpand_)
753  {
754  SRC::__throw_if_empty();
755  SRC::expandChildren();
756  shallExpand_ = false;
757  }
758  else
759  SRC::iterNext();
760  }
761  };
762 
763 
764 
781  template<class SRC, class RES>
783  : public SRC
784  {
785  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
786 
787  using TransformFunctor = function<RES(SRC&)>;
789 
790  TransformFunctor trafo_;
791  TransformedItem treated_;
792 
793  public:
794  using value_type = typename meta::ValueTypeBinding<RES>::value_type;
795  using reference = typename meta::ValueTypeBinding<RES>::reference;
796  using pointer = typename meta::ValueTypeBinding<RES>::pointer;
797 
798 
799  template<typename FUN>
800  Transformer (SRC&& dataSrc, FUN&& transformFunctor)
801  : SRC{move (dataSrc)} // NOTE: slicing move to strip IterExplorer (Builder)
802  , trafo_{_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (transformFunctor))}
803  { }
804 
805  Transformer() =default;
806  Transformer (Transformer const& o)
807  : SRC{o}
808  , trafo_{o.trafo_}
809  , treated_{/* deliberately empty: force re-engage */}
810  { }
811  Transformer (Transformer && o)
812  : SRC{move (o)}
813  , trafo_{move (o.trafo_)}
814  , treated_{/* deliberately empty: force re-engage */}
815  { }
816  Transformer&
817  operator= (Transformer changed)
818  {
819  swap (*this,changed);
820  return *this;
821  }
822  friend void
823  swap (Transformer& t1, Transformer& t2)
824  {
825  using std::swap;
826  t1.treated_.reset();
827  t2.treated_.reset();
828  swap (t1.trafo_, t2.trafo_);
829  }
830 
831 
837  void
839  {
840  treated_.reset();
841  SRC::expandChildren();
842  }
843 
844  public: /* === Iteration control API for IterableDecorator === */
845 
846  bool
847  checkPoint() const
848  {
849  return bool(srcIter());
850  }
851 
852  reference
853  yield() const
854  {
855  return unConst(this)->invokeTransformation();
856  }
857 
858  void
859  iterNext()
860  {
861  ++ srcIter();
862  treated_.reset();
863  }
864 
865  private:
866  SRC&
867  srcIter() const
868  {
869  return unConst(*this);
870  }
871 
872  reference
873  invokeTransformation ()
874  {
875  if (not treated_) // invoke transform function once per src item
876  treated_ = trafo_(srcIter());
877  return *treated_;
878  }
879  };
880 
881 
882 
891  template<class SRC, class RES, uint grp>
892  class Grouping
893  : public SRC
894  {
895  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
896 
897  protected:
898  using Group = std::array<RES, grp>;
899  using Iter = typename Group::iterator;
900  struct Buffer
901  : lib::UninitialisedStorage<RES,grp>
902  {
903  Group& group(){ return *this; }
904  Iter begin() { return group().begin();}
905  Iter end() { return group().end(); }
906  };
907  Buffer buff_;
908  uint pos_{0};
909 
910 
911  public:
912  using value_type = Group;
913  using reference = Group&;
914  using pointer = Group*;
915 
916  Grouping() =default;
917  // inherited default copy operations
918 
919  Grouping (SRC&& dataSrc)
920  : SRC{move (dataSrc)}
921  {
922  pullGroup(); // initially pull to establish the invariant
923  }
924 
925 
930  auto
932  {
933  ENSURE (buff_.begin()+pos_ <= buff_.end());
934  // Array iterators are actually pointers
935  return RangeIter{buff_.begin(), buff_.begin()+pos_};
936  }
937 
944  auto
946  {
947  return checkPoint()? RangeIter<Iter>()
948  : getGroupedElms();
949  }
950 
953  void
955  {
956  SRC::expandChildren();
957  pullGroup();
958  }
959 
960  public: /* === Iteration control API for IterableDecorator === */
961 
962  bool
963  checkPoint() const
964  {
965  return pos_ == grp;
966  }
967 
968  reference
969  yield() const
970  {
971  return unConst(buff_).group();
972  }
973 
974  void
975  iterNext()
976  {
977  pullGroup();
978  }
979 
980 
981  protected:
982  SRC&
983  srcIter() const
984  {
985  return unConst(*this);
986  }
987 
990  void
992  {
993  for (pos_=0
994  ; pos_<grp and srcIter()
995  ; ++pos_,++srcIter()
996  )
997  buff_.group()[pos_] = *srcIter();
998  }
999  };
1000 
1001 
1002 
1024  template<class SRC, typename AGG, class GRP>
1026  : public SRC
1027  {
1028  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
1029 
1030  protected:
1031  using SrcValue = typename meta::ValueTypeBinding<SRC>::value_type;
1032  using Grouping = function<GRP(SRC&)>;
1033  using Aggregator = function<void(AGG&, SrcValue&)>;
1034 
1035  std::optional<AGG> agg_{};
1036 
1037  Grouping grouping_;
1038  Aggregator aggregate_;
1039 
1040  public:
1041  using value_type = typename meta::RefTraits<AGG>::Value;
1042  using reference = typename meta::RefTraits<AGG>::Reference;
1043  using pointer = typename meta::RefTraits<AGG>::Pointer;
1044 
1045  GroupAggregator() =default;
1046  // inherited default copy operations
1047 
1048  template<class FGRP, class FAGG>
1049  GroupAggregator (SRC&& dataSrc, FGRP&& groupFun, FAGG&& aggFun)
1050  : SRC{move (dataSrc)}
1051  , grouping_{_FunTraits<FGRP,SRC>::adaptFunctor (forward<FGRP> (groupFun))}
1052  , aggregate_{forward<FAGG> (aggFun)}
1053  {
1054  pullGroup(); // initially pull to establish the invariant
1055  }
1056 
1057 
1058  public: /* === Iteration control API for IterableDecorator === */
1059  bool
1060  checkPoint() const
1061  {
1062  return bool(agg_);
1063  }
1064 
1065  reference
1066  yield() const
1067  {
1068  return *unConst(this)->agg_;
1069  }
1070 
1071  void
1072  iterNext()
1073  {
1074  if (srcIter())
1075  pullGroup();
1076  else
1077  agg_ = std::nullopt;
1078  }
1079 
1080 
1081  protected:
1082  SRC&
1083  srcIter() const
1084  {
1085  return unConst(*this);
1086  }
1087 
1090  void
1092  {
1093  GRP group = grouping_(srcIter());
1094  agg_ = AGG{};
1095  do{
1096  aggregate_(*agg_, *srcIter());
1097  ++ srcIter();
1098  }
1099  while (srcIter() and group == grouping_(srcIter()));
1100  }
1101  };
1102 
1103 
1104 
1105 
1113  template<class SRC>
1114  class Filter
1115  : public SRC
1116  {
1117  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
1118 
1119  protected:
1120  using FilterPredicate = function<bool(SRC&)>;
1121 
1122  FilterPredicate predicate_;
1123 
1124  public:
1125 
1126  Filter() =default;
1127  // inherited default copy operations
1128 
1129  template<typename FUN>
1130  Filter (SRC&& dataSrc, FUN&& filterFun)
1131  : SRC{move (dataSrc)}
1132  , predicate_{_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (filterFun))}
1133  {
1134  pullFilter(); // initially pull to establish the invariant
1135  }
1136 
1137 
1140  void
1142  {
1143  SRC::expandChildren();
1144  pullFilter();
1145  }
1146 
1147  public: /* === Iteration control API for IterableDecorator === */
1148 
1149  bool
1150  checkPoint() const
1151  {
1152  return bool(srcIter());
1153  }
1154 
1155  typename SRC::reference
1156  yield() const
1157  {
1158  return *srcIter();
1159  }
1160 
1161  void
1162  iterNext()
1163  {
1164  ++ srcIter();
1165  pullFilter();
1166  }
1167 
1168 
1169  protected:
1170  SRC&
1171  srcIter() const
1172  {
1173  return unConst(*this);
1174  }
1175 
1176  bool
1177  isDisabled() const
1178  {
1179  return not bool{predicate_};
1180  }
1181 
1185  void
1187  {
1188  if (isDisabled()) return;
1189  while (srcIter() and not predicate_(srcIter()))
1190  ++srcIter();
1191  }
1192  };
1193 
1194 
1195 
1213  template<class SRC>
1215  : public Filter<SRC>
1216  {
1217  using _Filter = Filter<SRC>;
1218  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
1219 
1220  public:
1221  MutableFilter() =default;
1222  // inherited default copy operations
1223 
1224  template<typename FUN>
1225  MutableFilter (SRC&& dataSrc, FUN&& filterFun)
1226  : _Filter{move (dataSrc), forward<FUN> (filterFun)}
1227  { }
1228 
1229 
1230  public: /* === API to Remould the Filter condition underway === */
1231 
1233  template<typename COND>
1234  void
1235  andFilter (COND&& conjunctiveClause)
1236  {
1237  remouldFilter (forward<COND> (conjunctiveClause)
1238  ,[](auto first, auto chain)
1239  {
1240  return [=](auto& val)
1241  {
1242  return first(val)
1243  and chain(val);
1244  };
1245  });
1246  }
1247 
1249  template<typename COND>
1250  void
1251  andNotFilter (COND&& conjunctiveClause)
1252  {
1253  remouldFilter (forward<COND> (conjunctiveClause)
1254  ,[](auto first, auto chain)
1255  {
1256  return [=](auto& val)
1257  {
1258  return first(val)
1259  and not chain(val);
1260  };
1261  });
1262  }
1263 
1265  template<typename COND>
1266  void
1267  orFilter (COND&& disjunctiveClause)
1268  {
1269  remouldFilter (forward<COND> (disjunctiveClause)
1270  ,[](auto first, auto chain)
1271  {
1272  return [=](auto& val)
1273  {
1274  return first(val)
1275  or chain(val);
1276  };
1277  });
1278  }
1279 
1281  template<typename COND>
1282  void
1283  orNotFilter (COND&& disjunctiveClause)
1284  {
1285  remouldFilter (forward<COND> (disjunctiveClause)
1286  ,[](auto first, auto chain)
1287  {
1288  return [=](auto& val)
1289  {
1290  return first(val)
1291  or not chain(val);
1292  };
1293  });
1294  }
1295 
1297  void
1299  {
1300  auto dummy = [](auto){ return false; };
1301  remouldFilter (dummy
1302  ,[](auto currentFilter, auto)
1303  {
1304  return [=](auto& val)
1305  {
1306  return not currentFilter(val);
1307  };
1308  });
1309  }
1310 
1312  template<typename COND>
1313  void
1314  setNewFilter (COND&& entirelyDifferentPredicate)
1315  {
1316  remouldFilter (forward<COND> (entirelyDifferentPredicate)
1317  ,[](auto, auto chain)
1318  {
1319  return [=](auto& val)
1320  {
1321  return chain(val);
1322  };
1323  });
1324  }
1325 
1327  void
1329  {
1330  _Filter::predicate_ = nullptr;
1331  }
1332 
1333 
1334  private:
1350  template<typename COND, class COMB>
1351  void
1352  remouldFilter (COND&& additionalClause, COMB buildCombinedClause)
1353  {
1354  static_assert_isPredicate<COND,SRC>();
1355 
1356  if (_Filter::isDisabled())
1357  _Filter::predicate_ = ACCEPT_ALL;
1358 
1359  _Filter::predicate_ = buildCombinedClause (_Filter::predicate_ // pick up the existing filter predicate
1360  ,_FunTraits<COND,SRC>::adaptFunctor (forward<COND> (additionalClause))
1361  ); // wrap the extension predicate in a similar way
1362  _Filter::pullFilter(); // then pull to re-establish the Invariant
1363  }
1364  };
1365 
1366 
1367 
1378  template<class SRC>
1380  : public IterStateCore<SRC>
1381  {
1382  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
1383 
1384  using Core = IterStateCore<SRC>;
1385  using Cond = function<bool(SRC&)>;
1386 
1387  Cond whileCondition_;
1388 
1389  public:
1390 
1391  StopTrigger() =default;
1392  // inherited default copy operations
1393 
1394  template<typename FUN>
1395  StopTrigger (SRC&& dataSrc, FUN&& condition)
1396  : Core{move (dataSrc)}
1397  , whileCondition_{_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (condition))}
1398  { }
1399 
1400 
1403  bool
1404  checkPoint() const
1405  {
1406  return Core::checkPoint()
1407  and whileCondition_(Core::srcIter());
1408  }
1409  };
1410 
1411 
1412 
1413 
1425  template<typename VAL>
1427  {
1428  protected:
1430  public:
1431  virtual VAL* expandChildren() =0;
1432  virtual size_t depth() const =0;
1433  };
1434 
1443  template<class SRC>
1445  : public WrappedLumieraIter<SRC>
1446  , public ChildExpandableSource<typename SRC::value_type>
1447  {
1449  using Val = typename SRC::value_type;
1450 
1452  public:
1453  using Parent::Parent;
1454 
1455  virtual Val*
1456  expandChildren() override
1457  {
1458  Parent::wrappedIter().expandChildren();
1459  return Parent::wrappedIter()? & *Parent::wrappedIter()
1460  : nullptr;
1461  }
1462 
1463  virtual size_t
1464  depth() const override
1465  {
1466  return Parent::wrappedIter().depth();
1467  }
1468  };
1469 
1470  }//(End)Iterator decorating layer implementation
1471 
1472 
1473 
1474 
1475 
1493  template<typename VAL>
1495  : IterSource<VAL>::iterator
1496  {
1498 
1499 
1500  IterExploreSource() =default;
1501  // inherited default copy operations
1502 
1503 
1504  void
1505  expandChildren()
1506  {
1507  VAL* changedResult = expandableSource().expandChildren();
1508  this->resetPos (changedResult);
1509  }
1510 
1511  size_t
1512  depth() const
1513  {
1514  return expandableSource().depth();
1515  }
1516 
1517 
1518  private:
1519  template<class SRC>
1520  friend class IterExplorer;
1521 
1522  template<class IT>
1523  IterExploreSource (IT&& opaqueSrcPipeline)
1527  move (opaqueSrcPipeline)})}
1528  { }
1529 
1530  Expandable&
1531  expandableSource() const
1532  {
1533  if (not this->source())
1534  throw error::State ("operating on a disabled default constructed IterExplorer"
1535  ,error::LUMIERA_ERROR_BOTTOM_VALUE);
1536 
1537  auto source = unConst(this)->source().get();
1538  return dynamic_cast<Expandable&> (*source);
1539  }
1540  };
1541 
1542 
1543 
1544 
1545 
1546  /* ======= IterExplorer pipeline builder and iterator ======= */
1547 
1578  template<class SRC>
1580  : public SRC
1581  {
1582  static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
1583 
1584 
1585  public:
1586  using value_type = typename meta::ValueTypeBinding<SRC>::value_type;
1587  using reference = typename meta::ValueTypeBinding<SRC>::reference;
1588  using pointer = typename meta::ValueTypeBinding<SRC>::pointer;
1589 
1590  using TAG_IterExplorer_Src = SRC;
1591 
1593  using SRC::SRC;
1594 
1595 
1596 
1597  /* ==== Builder functions ==== */
1598 
1639  template<class FUN>
1640  auto
1641  expand (FUN&& expandFunctor)
1642  {
1643  using ExpandedChildren = typename iter_explorer::_FunTraits<FUN,SRC>::Res;
1644 
1646  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1647 
1648  return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(expandFunctor)});
1649  }
1650 
1651 
1663  auto
1665  {
1666  using ResCore = iter_explorer::AutoExpander<SRC>;
1667  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1668 
1669  return IterExplorer<ResIter> (ResCore {move(*this)});
1670  }
1671 
1673  template<class FUN>
1674  auto
1675  expandAll (FUN&& expandFunctor)
1676  {
1677  return this->expand (forward<FUN> (expandFunctor))
1678  .expandAll();
1679  }
1680 
1681 
1691  auto
1693  {
1694  using ResCore = iter_explorer::ScheduledExpander<SRC>;
1695  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1696 
1697  return IterExplorer<ResIter> (ResCore {move(*this)});
1698  }
1699 
1700 
1711  template<class FUN>
1712  auto
1713  transform (FUN&& transformFunctor)
1714  {
1715  using Product = typename iter_explorer::_FunTraits<FUN,SRC>::Res;
1716 
1718  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1719 
1720  return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(transformFunctor)});
1721  }
1722 
1723 
1732  template<uint grp>
1733  auto
1735  {
1736  using Value = typename meta::ValueTypeBinding<SRC>::value_type;
1738  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1739 
1740  return IterExplorer<ResIter> (ResCore {move(*this)});
1741  }
1742 
1743 
1755  template<class FGRP, class FAGG>
1756  auto
1757  groupedBy (FGRP&& groupFun, FAGG&& aggFun)
1758  {
1759  using GroupVal = typename iter_explorer::_FunTraits<FGRP,SRC>::Res;
1760 
1761  static_assert (meta::is_BinaryFun<FAGG>());
1762  using ArgType1 = typename _Fun<FAGG>::Args::List::Head;
1763  using Aggregate = typename meta::RefTraits<ArgType1>::Value;
1764 
1766  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1767 
1768  return IterExplorer<ResIter> (ResCore {move(*this)
1769  ,forward<FGRP> (groupFun)
1770  ,forward<FAGG> (aggFun)});
1771  }
1772 
1774  template<class FGRP>
1775  auto
1776  groupedBy (FGRP&& groupFun)
1777  {
1778  using Value = typename meta::ValueTypeBinding<SRC>::value_type;
1779  return groupedBy (forward<FGRP> (groupFun)
1780  ,[](Value& agg, Value const& val){ agg += val; }
1781  );
1782  }
1783 
1784 
1788  template<class FUN>
1789  auto
1790  iterWhile (FUN&& whileCond)
1791  {
1792  iter_explorer::static_assert_isPredicate<FUN,SRC>();
1793 
1794  using ResCore = iter_explorer::StopTrigger<SRC>;
1795  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1796 
1797  return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(whileCond)});
1798  }
1799 
1800 
1804  template<class FUN>
1805  auto
1806  iterUntil (FUN&& untilCond)
1807  {
1808  iter_explorer::static_assert_isPredicate<FUN,SRC>();
1809 
1810  using ResCore = iter_explorer::StopTrigger<SRC>;
1811  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1812  using ArgType = typename iter_explorer::_FunTraits<FUN,SRC>::Arg;
1813 
1814  return IterExplorer<ResIter> (ResCore { move(*this)
1815  ,[whileCond = forward<FUN>(untilCond)](ArgType val)
1816  {
1817  return not whileCond(val);
1818  }
1819  });
1820  }
1821 
1822 
1829  template<class FUN>
1830  auto
1831  filter (FUN&& filterPredicate)
1832  {
1833  iter_explorer::static_assert_isPredicate<FUN,SRC>();
1834 
1835  using ResCore = iter_explorer::Filter<SRC>;
1836  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1837 
1838  return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
1839  }
1840 
1841 
1859  template<class FUN>
1860  auto
1861  mutableFilter (FUN&& filterPredicate)
1862  {
1863  iter_explorer::static_assert_isPredicate<FUN,SRC>();
1864 
1865  using ResCore = iter_explorer::MutableFilter<SRC>;
1866  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1867 
1868  return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
1869  }
1870 
1871 
1872  auto
1873  mutableFilter()
1874  {
1875  return mutableFilter (iter_explorer::ACCEPT_ALL);
1876  }
1877 
1878 
1879 
1891  template<template<class> class LAY>
1892  auto
1894  {
1895  using ResCore = LAY<SRC>;
1896  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1897 
1898  return IterExplorer<ResIter> (ResCore {move(*this)});
1899  }
1900 
1901 
1902 
1904  auto
1906  {
1907  using Val = typename meta::ValueTypeBinding<SRC>::value_type;
1908  static_assert (not std::is_pointer_v<Val>);
1909  return IterExplorer::transform ([](Val& ref){ return &ref; });
1910  }
1911 
1913  auto
1915  {
1916  using Ptr = typename meta::ValueTypeBinding<SRC>::value_type;
1917  return IterExplorer::transform ([](Ptr ptr){ return *ptr; });
1918  }
1919 
1920 
1924  template<template<typename> class SET =std::set>
1925  auto
1927  {
1928  using Value = typename meta::ValueTypeBinding<SRC>::value_type;
1929  using ResCore = ContainerCore<SET<Value>>;
1930  using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
1931  SET<Value> buffer;
1932  for (auto& val : *this)
1933  buffer.emplace (val);
1934  // »piggiy-back« the collected data into the result iterator
1935  return IterExplorer<ResIter>{ResCore{move (buffer)}};
1936  }
1937 
1938 
1939 
1950  {
1951  return IterExploreSource<value_type> {move(*this)};
1952  }
1953 
1954 
1958  SRC
1960  {
1961  return SRC {move(*this)};
1962  }
1963 
1968  template<class FUN>
1969  void
1970  foreach (FUN&& consumer)
1971  {
1972  auto consumeFun = iter_explorer::_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (consumer));
1973  SRC& pipeline = *this;
1974  for ( ; pipeline; ++pipeline)
1975  consumeFun (pipeline);
1976  }
1977 
1978 
1988  template<class FUN
1989  ,typename COMB =decltype(std::plus<>())
1990  ,typename VAL =typename iter_explorer::_ReduceTraits<SRC,FUN>::ResVal>
1991  VAL
1992  reduce (FUN&& accessor
1993  ,COMB junctor =COMB()
1994  ,VAL seedVal =VAL())
1995  {
1996  auto accessVal = iter_explorer::_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (accessor));
1997 
1998  VAL sum{move(seedVal)};
1999  IterExplorer::foreach ([&](SRC& srcIter){ sum = junctor (sum, accessVal(srcIter)); });
2000  return sum;
2001  }
2002 
2004  auto
2006  {
2007  return IterExplorer::reduce ([](const reference val){ return val; });
2008  }
2009 
2011  size_t
2013  {
2014  return IterExplorer::reduce ([](auto){ return size_t(1); });
2015  }
2016 
2018  bool
2020  {
2021  static_assert (std::is_constructible<bool,value_type>());
2022  SRC& pipeline = *this;
2023  for ( ; pipeline; ++pipeline)
2024  if (*pipeline)
2025  return true;
2026  return false;
2027  }
2028 
2030  bool
2032  {
2033  static_assert (std::is_constructible<bool,value_type>());
2034  SRC& pipeline = *this;
2035  for ( ; pipeline; ++pipeline)
2036  if (not *pipeline)
2037  return false;
2038  return true;
2039  }
2040 
2041 
2047  template<template<typename> class CON =std::vector>
2048  auto
2050  {
2051  CON<value_type> con{};
2052  this->effuse (con);
2053  return con;
2054  }
2055 
2056  template<class CON>
2057  auto
2058  effuse (CON&& sink) -> CON
2059  {
2060  CON con{move(sink)};
2061  this->effuse (con);
2062  return con;
2063  }
2064 
2066  template<class CON>
2067  void
2068  effuse (CON& con)
2069  {
2070  for (auto& val : *this)
2071  con.push_back (val);
2072  }
2073  };
2074 
2075 
2076  namespace {// internal logic to pick suitable pipeline adapters...
2077 
2086  template<class SRC, class SEL =void>
2088  {
2090  };
2091 
2092  template<class SRC> // used when type tag is present on some baseclass
2093  struct _BaseDetector<SRC, std::void_t<typename SRC::TAG_IterExplorer_BaseAdapter> >
2094  {
2095  using BaseAdapter = SRC;
2096  };
2097 
2098 
2100  template<class SRC, class SEL =void>
2102  {
2103  using RawIter = SRC;
2104  };
2105 
2106  template<class COR> // used when actually a CheckedCore was attached
2107  struct _UnstripAdapter<COR, std::void_t<typename COR::TAG_CheckedCore_Raw> >
2108  {
2109  using RawIter = typename COR::TAG_CheckedCore_Raw;
2110  };
2111 
2112 
2118  template<class SRC, class SEL =void>
2120  {
2121  using RawIter = SRC;
2122  };
2123  template<class SRC>
2124  struct _PipelineDetector<SRC, std::void_t<typename SRC::TAG_IterExplorer_Src> >
2125  {
2126  using _SrcIT = typename SRC::TAG_IterExplorer_Src;
2127  using RawIter = typename _UnstripAdapter<_SrcIT>::RawIter;
2128  };
2129  }//(End)internal adapter logic
2130 
2131 
2132 
2133 
2134 
2135 
2136 
2137  /* ==== convenient builder free functions ==== */
2138 
2187  template<class IT>
2188  inline auto
2189  explore (IT&& srcSeq)
2190  {
2191  using RawIter = typename _PipelineDetector<IT>::RawIter; // possibly strip an underlying IterExplorer
2192  using SrcIter = typename _DecoratorTraits<RawIter>::SrcIter; // then decide how to adapt the source / iterator
2193  using Base = typename _BaseDetector<SrcIter>::BaseAdapter; // detect if a BaseAdapter exists or must be added
2194 
2195  return IterExplorer<Base> (std::forward<IT> (srcSeq));
2196  }
2197 
2198 
2199 } // namespace lib
2200 #endif /* LIB_ITER_EXPLORER_H */
IterSourceIter(ISO &externalSource)
link to existing IterSource (without memory management)
typename _Trait::YieldRes YieldRes
static auto adaptFunctor(FUN &&rawFunctor)
builder to create a nested/wrapping functor, suitably adapting the arguments
auto asPtr()
preconfigured transformer to pass pointers down the pipeline
void expandChildren()
refresh state when other layers manipulate the source sequence.
Detect if given source was already built by IterExplorer;.
bool and_all()
simplified terminal builder to check if all results yields true (short-circuit)
VAL reduce(FUN &&accessor, COMB junctor=COMB(), VAL seedVal=VAL())
terminal builder to sum up or reduce values from the pipeline.
void expandChildren()
collaboration: recurse into nested scope
void disableFilter()
discard filter predicates and disable any filtering
void remouldFilter(COND &&additionalClause, COMB buildCombinedClause)
auto groupedBy(FGRP &&groupFun, FAGG &&aggFun)
adapt this IterExplorer to group elements by a custom criterium and aggregate the group members...
Trait template to detect a type usable with the STL for-each loop.
Definition: trait.hpp:555
size_t depth() const
collaboration: number of nested scopes
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
size_t count()
simplified terminal builder to count number of elements from this sequence.
Helper template(s) for creating Lumiera Forward Iterators.
auto processingLayer()
builder function to attach a custom extension layer. Any template in compliance with the general cons...
void effuse(CON &con)
_terminal builder to fill an existing container with all results from this Pipeline ...
Conveniently iterable stack and queue containers.
IterExploreSource< value_type > asIterSource()
terminal builder to package the processing pipeline as IterSource.
bool has_any()
simplified terminal builder to check if any result yields true (short-circuit)
STL namespace.
handle all regular "function-like" entities
Trait template to detect a type exposing a »state core« API.
Definition: trait.hpp:534
bool checkPoint() const
adapt the iteration control API for IterableDecorator: check the stop condition first and block event...
Helper for uniform access to function signature types.
Definition: function.hpp:99
auto expandAll()
extension functionality to be used on top of expand(), to perform expansion automatically.
auto iterWhile(FUN &&whileCond)
adapt this IterExplorer to iterate only as long as a condition holds true.
auto getRestElms()
Retrieve the tail elements produced by the source, which did not suffice to fill a full group...
Adapter to dress up an existing »Lumiera Forward Iterator« as »state core«.
auto mutableFilter(FUN &&filterPredicate)
attach a special filter adapter, allowing to change the filter predicate while iterating.
helper to check if another metafunction produced a result type
Definition: meta/util.hpp:126
Iterator front-end to manage and operate a IterExplorer pipeline opaquely.
auto expandOnIteration()
extension functionality to be used on top of expand(), to perform expansion on next iteration...
void andNotFilter(COND &&conjunctiveClause)
remould existing predicate to require in addition the negation of the given clause to hold ...
Detect and remove typical adapter layers added by a preceding IterExplorer usage. ...
typename std::remove_reference< reference >::type value_type
Implementation namespace for support and library code.
auto resultSum()
simplified terminal builder to reduce by numeric sum.
typename enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition: meta/util.hpp:83
auto effuse()
terminal builder to pour and materialise all results from this Pipeline.
void rootCurrent()
lock into the current child sequence.
Adapt STL compliant container.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
auto grouped()
adapt this IterExplorer to group result elements into fixed size chunks, packaged as std::array...
Iteration source interface to abstract a data source, which then can be accessed through IterAdapter ...
Definition: iter-source.hpp:79
Metaprogramming tools for transforming functor types.
auto filter(FUN &&filterPredicate)
adapt this IterExplorer to filter results, by invoking the given functor to approve them...
void orFilter(COND &&disjunctiveClause)
remould existing predicate to require either the old OR the given new clause to hold ...
auto transform(FUN &&transformFunctor)
adapt this IterExplorer to pipe each result value through a transformation function.
IterSourceIter(ISO *heapObject)
own and manage a heap allocated IterSource
int reduce(Gtk::Button &icon)
attempt to reduce space consumption
void expandChildren()
refresh state when other layers manipulate the source sequence
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
auto expandAll(FUN &&expandFunctor)
shortcut notation to invoke expand(expandFunctor) followed by expandAll()
Block of raw uninitialised storage with array like access.
auto deduplicate()
preconfigured decorator to materialise, sort and deduplicate all source elements. ...
Trait template to detect a type usable immediately as "Lumiera Forward Iterator" in a specialised for...
Definition: trait.hpp:510
adapt to a functor, which accesses the source iterator or embedded "state core"
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition: meta/util.hpp:95
auto derefPtr()
preconfigured transformer to dereference pointers into references
auto expand(FUN &&expandFunctor)
preconfigure this IterExplorer to allow for »expansion of children«.
auto iterUntil(FUN &&untilCond)
adapt this IterExplorer to iterate until a condition becomes first true.
auto groupedBy(FGRP &&groupFun)
simplified grouping to sum / combine all values in a group
void flipFilter()
remould existing predicate to negate the meaning of the existing clause
A raw memory block with proper alignment and array access.
Helpers for type detection, type rewriting and metaprogramming.
auto getGroupedElms()
Iterate over the Elements in the current group.
Lumiera error handling (C++ interface).
void setNewFilter(COND &&entirelyDifferentPredicate)
replace the existing predicate with the given, entirely different predicate
size_t depth() const
diagnostics: current level of nested child expansion
Adapter to »piggy-back« a STL iterable container inline and expose it as »state core«.
void expandChildren()
refresh state when other layers manipulate the source sequence.
Decorator-Adapter to make a »*State Core*« iterable as Lumiera Forward Iterator.
void expandChildren()
core operation: expand current head element
helper to derive a suitable common type when expanding children
Type definition helper for pointer and reference types.
Definition: trait.hpp:275
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
Decision helper to select between returning results by value or reference.
Adapter to build a demand-driven tree expanding and exploring computation based on a custom opaque st...
Type re-binding helper template for creating nested typedefs usable by custom containers and iterator...
void andFilter(COND &&conjunctiveClause)
remould existing predicate to require in addition the given clause to hold
SRC asIterator()
terminal builder to strip the IterExplorer and expose the built Pipeline.
Interface to indicate and expose the ability for child expansion.
Extension module to build an opaque data source, accessible as Lumiera Forward Iterator.
Standard implementation of the IterSource interface: a wrapped "Lumiera Forward Iterator".
Library implementation: smart-pointer variations, wrappers and managing holders.
Metaprogramming helpers to check for specific properties of a type in question.
void orNotFilter(COND &&disjunctiveClause)
remould existing predicate to require either the old OR the negation of a new clause to hold ...
Adapt an IterSource to make it iterable.