Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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/item-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
118namespace std {
119 template<typename T, class A> class vector;
120 template<typename K, typename CMP, class A> class set;
121}
122
123
124namespace 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>
137 template<class CON>
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 &>
170 {
171 using StlRange<CON>::StlRange;
172 };
173
174
189 template<class ISO>
191 : public ISO::iterator
192 {
193 using Iterator = 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&
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;
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>
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 = 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");
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 = 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 {
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 = _CommonT::ResType;
340 using value_type = _CommonT::value_type;
341 using reference = _CommonT::reference;
342 using pointer = _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>
387 {
389 template<typename F, typename SEL =void>
391 {
393 };
394
396 template<typename F>
397 struct FunDetector<F, disable_if<_Fun<F>> >
398 {
399 using Arg = std::add_lvalue_reference<SRC>::type;
400 using Ret = decltype(std::declval<F>() (std::declval<Arg>()));
401 using Sig = Ret(Arg);
402 };
403
404
406 using Arg = _Fun<Sig>::Args::List::Head; // assuming function with a single argument
408 static_assert (meta::is_UnaryFun<Sig>());
409
410
411
413 template<class ARG, class SEL =void>
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 = 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
468 {
469 using Res = _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>
483
484
485
486
487
504 template<class SRC>
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>
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 = _Trait::ResIter;
561 using RootExpandFunctor = function<RES(SRC&)>;
562 using ChldExpandFunctor = function<RES(ResIter&)>;
563
566
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
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_);
618 }
619
620
621 public: /* === Iteration control API for IterableDecorator === */
622
624 using YieldRes = _Trait::YieldRes;
625 using value_type = _Trait::value_type;
626 using reference = _Trait::reference;
627 using pointer = _Trait::pointer;
628
629
630 bool
632 {
633 ENSURE (invariant());
634
635 return hasChildren()
636 or SRC::isValid();
637 }
638
640 yield() const
641 {
642 return hasChildren()? **expansions_
643 : **this;
644 }
645
646 void
648 {
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
664 {
665 if (hasChildren())
666 ++(*expansions_);
667 else
668 ++(*this);
669 }
670
671
672 protected:
673 bool
675 {
676 return 0 < depth();
677 }
678
680 ResIter&
682 {
683 REQUIRE (hasChildren());
684 return *expansions_;
685 }
686
687 void
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
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
745 {
746 shallExpand_ = true;
747 }
748
749 void
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
792
793 public:
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;
807 : SRC{o}
808 , trafo_{o.trafo_}
809 , treated_{/* deliberately empty: force re-engage */}
810 { }
812 : SRC{move (o)}
813 , trafo_{move (o.trafo_)}
814 , treated_{/* deliberately empty: force re-engage */}
815 { }
818 {
819 swap (*this,changed);
820 return *this;
821 }
822 friend void
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
848 {
849 return bool(srcIter());
850 }
851
853 yield() const
854 {
855 return unConst(this)->invokeTransformation();
856 }
857
858 void
860 {
861 ++ srcIter();
862 treated_.reset();
863 }
864
865 private:
866 SRC&
867 srcIter() const
868 {
869 return unConst(*this);
870 }
871
874 {
875 if (not treated_) // invoke transform function once per src item
877 return *treated_;
878 }
879 };
880
881
882
891 template<class SRC, class RES, uint grp>
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 = Group::iterator;
900 struct Buffer
902 {
903 Group& group(){ return *this; }
904 Iter begin() { return group().begin();}
905 Iter end() { return group().end(); }
906 };
909
910
911 public:
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
964 {
965 return pos_ == grp;
966 }
967
969 yield() const
970 {
971 return unConst(buff_).group();
972 }
973
974 void
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:
1032 using Grouping = function<GRP(SRC&)>;
1033 using Aggregator = function<void(AGG&, SrcValue&)>;
1034
1035 std::optional<AGG> agg_{};
1036
1039
1040 public:
1044
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
1061 {
1062 return bool(agg_);
1063 }
1064
1065 reference
1066 yield() const
1067 {
1068 return *unConst(this)->agg_;
1069 }
1070
1071 void
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>
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
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
1151 {
1152 return bool(srcIter());
1153 }
1154
1155 SRC::reference
1156 yield() const
1157 {
1158 return *srcIter();
1159 }
1160
1161 void
1163 {
1164 ++ srcIter();
1165 pullFilter();
1166 }
1167
1168
1169 protected:
1170 SRC&
1171 srcIter() const
1172 {
1173 return unConst(*this);
1174 }
1175
1176 bool
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 {
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
1385 using Cond = function<bool(SRC&)>;
1386
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
1405 {
1406 return Core::checkPoint()
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 = SRC::value_type;
1450
1452 public:
1453 using Parent::Parent;
1454
1455 virtual Val*
1457 {
1458 Parent::wrappedIter().expandChildren();
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
1501 // inherited default copy operations
1502
1503
1504 void
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)
1524 : IterSource<VAL>::iterator {
1525 IterSource<VAL>::build (
1526 new iter_explorer::PackagedIterExplorerSource<IT> {
1527 move (opaqueSrcPipeline)})}
1528 { }
1529
1530 Expandable&
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:
1589
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 = iter_explorer::_FunTraits<FUN,SRC>::Res;
1644
1646 using ResIter = _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 = _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 {
1695 using ResIter = _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 {
1716
1718 using ResIter = _DecoratorTraits<ResCore>::SrcIter;
1719
1720 return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(transformFunctor)});
1721 }
1722
1723
1732 template<uint grp>
1733 auto
1735 {
1738 using ResIter = _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 {
1760
1761 static_assert (meta::is_BinaryFun<FAGG>());
1762 using ArgType1 = _Fun<FAGG>::Args::List::Head;
1763 using Aggregate = meta::RefTraits<ArgType1>::Value;
1764
1766 using ResIter = _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 {
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 = _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 = _DecoratorTraits<ResCore>::SrcIter;
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 = _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 = _DecoratorTraits<ResCore>::SrcIter;
1867
1868 return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
1869 }
1870
1871
1872 auto
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 = _DecoratorTraits<ResCore>::SrcIter;
1897
1898 return IterExplorer<ResIter> (ResCore {move(*this)});
1899 }
1900
1901
1902
1904 auto
1906 {
1908 static_assert (not std::is_pointer_v<Val>);
1909 return IterExplorer::transform ([](Val& ref){ return &ref; });
1910 }
1911
1913 auto
1915 {
1917 return IterExplorer::transform ([](Ptr ptr){ return *ptr; });
1918 }
1919
1920
1924 template<template<typename> class SET =std::set>
1925 auto
1927 {
1929 using ResCore = ContainerCore<SET<Value>>;
1930 using ResIter = _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>
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 = 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 = SRC::TAG_IterExplorer_Src;
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 = _PipelineDetector<IT>::RawIter; // possibly strip an underlying IterExplorer
2192 using SrcIter = _DecoratorTraits<RawIter>::SrcIter; // then decide how to adapt the source / iterator
2193 using Base = _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 */
Adapter to »piggy-back« a STL iterable container inline and expose it as »state core«.
Adapter to build a demand-driven tree expanding and exploring computation based on a custom opaque st...
auto mutableFilter(FUN &&filterPredicate)
attach a special filter adapter, allowing to change the filter predicate while iterating.
auto expandAll(FUN &&expandFunctor)
shortcut notation to invoke expand(expandFunctor) followed by expandAll()
auto derefPtr()
preconfigured transformer to dereference pointers into references
void effuse(CON &con)
_terminal builder to fill an existing container with all results from this Pipeline
auto iterWhile(FUN &&whileCond)
adapt this IterExplorer to iterate only as long as a condition holds true.
auto expand(FUN &&expandFunctor)
preconfigure this IterExplorer to allow for »expansion of children«.
auto expandOnIteration()
extension functionality to be used on top of expand(), to perform expansion on next iteration.
auto groupedBy(FGRP &&groupFun, FAGG &&aggFun)
adapt this IterExplorer to group elements by a custom criterium and aggregate the group members.
meta::ValueTypeBinding< SRC >::pointer pointer
auto grouped()
adapt this IterExplorer to group result elements into fixed size chunks, packaged as std::array.
auto effuse(CON &&sink) -> CON
auto resultSum()
simplified terminal builder to reduce by numeric sum.
bool and_all()
simplified terminal builder to check if all results yields true (short-circuit)
auto processingLayer()
builder function to attach a custom extension layer.
meta::ValueTypeBinding< SRC >::value_type value_type
auto transform(FUN &&transformFunctor)
adapt this IterExplorer to pipe each result value through a transformation function.
auto deduplicate()
preconfigured decorator to materialise, sort and deduplicate all source elements.
auto iterUntil(FUN &&untilCond)
adapt this IterExplorer to iterate until a condition becomes first true.
IterExploreSource< value_type > asIterSource()
terminal builder to package the processing pipeline as IterSource.
SRC asIterator()
terminal builder to strip the IterExplorer and expose the built Pipeline.
auto asPtr()
preconfigured transformer to pass pointers down the pipeline
auto filter(FUN &&filterPredicate)
adapt this IterExplorer to filter results, by invoking the given functor to approve them.
auto groupedBy(FGRP &&groupFun)
simplified grouping to sum / combine all values in a group
auto expandAll()
extension functionality to be used on top of expand(), to perform expansion automatically.
size_t count()
simplified terminal builder to count number of elements from this sequence.
bool has_any()
simplified terminal builder to check if any result yields true (short-circuit)
meta::ValueTypeBinding< SRC >::reference reference
auto effuse()
terminal builder to pour and materialise all results from this Pipeline.
Iteration source interface to abstract a data source, which then can be accessed through IterAdapter ...
Adapter to dress up an existing »Lumiera Forward Iterator« as »state core«.
Decorator-Adapter to make a »*State Core*« iterable as Lumiera Forward Iterator.
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
std::remove_reference< reference >::type value_type
Block of raw uninitialised storage with array like access.
Standard implementation of the IterSource interface: a wrapped "Lumiera Forward Iterator".
Interface to indicate and expose the ability for child expansion.
void rootCurrent()
lock into the current child sequence.
void expandChildren()
core operation: expand current head element
IterStack< ResIter > expansions_
size_t depth() const
diagnostics: current level of nested child expansion
function< RES(SRC &)> RootExpandFunctor
_ExpanderTraits< SRC, RES > _Trait
function< RES(ResIter &)> ChldExpandFunctor
Expander(SRC &&parentExplorer, FUN &&expandFunctor)
void expandChildren()
refresh state when other layers manipulate the source sequence.
SRC::reference yield() const
Filter(SRC &&dataSrc, FUN &&filterFun)
function< bool(SRC &)> FilterPredicate
meta::ValueTypeBinding< SRC >::value_type SrcValue
GroupAggregator(SRC &&dataSrc, FGRP &&groupFun, FAGG &&aggFun)
meta::RefTraits< AGG >::Reference reference
function< void(AGG &, SrcValue &)> Aggregator
meta::RefTraits< AGG >::Value value_type
meta::RefTraits< AGG >::Pointer pointer
void expandChildren()
refresh state when other layers manipulate the source sequence.
auto getRestElms()
Retrieve the tail elements produced by the source, which did not suffice to fill a full group.
std::array< RES, grp > Group
auto getGroupedElms()
Iterate over the Elements in the current group.
Adapt an IterSource to make it iterable.
IterSourceIter(ISO *heapObject)
own and manage a heap allocated IterSource
IterSourceIter(ISO &externalSource)
link to existing IterSource (without memory management)
void setNewFilter(COND &&entirelyDifferentPredicate)
replace the existing predicate with the given, entirely different predicate
void andFilter(COND &&conjunctiveClause)
remould existing predicate to require in addition the given clause to hold
void andNotFilter(COND &&conjunctiveClause)
remould existing predicate to require in addition the negation of the given clause to hold
void remouldFilter(COND &&additionalClause, COMB buildCombinedClause)
void orNotFilter(COND &&disjunctiveClause)
remould existing predicate to require either the old OR the negation of a new clause to hold
void orFilter(COND &&disjunctiveClause)
remould existing predicate to require either the old OR the given new clause to hold
void flipFilter()
remould existing predicate to negate the meaning of the existing clause
void disableFilter()
discard filter predicates and disable any filtering
MutableFilter(SRC &&dataSrc, FUN &&filterFun)
StopTrigger(SRC &&dataSrc, FUN &&condition)
bool checkPoint() const
adapt the iteration control API for IterableDecorator: check the stop condition first and block event...
Transformer(Transformer const &o)
meta::ValueTypeBinding< RES >::pointer pointer
void expandChildren()
refresh state when other layers manipulate the source sequence
meta::ValueTypeBinding< RES >::reference reference
function< RES(SRC &)> TransformFunctor
meta::ValueTypeBinding< RES >::value_type value_type
friend void swap(Transformer &t1, Transformer &t2)
Transformer & operator=(Transformer changed)
Transformer(SRC &&dataSrc, FUN &&transformFunctor)
Trait template to detect a type usable immediately as "Lumiera Forward Iterator" in a specialised for...
Definition trait.hpp:511
Trait template to detect a type usable with the STL for-each loop.
Definition trait.hpp:556
Trait template to detect a type exposing a »state core« API.
Definition trait.hpp:535
Metaprogramming helpers to check for specific properties of a type in question.
Lumiera error handling (C++ interface).
Metaprogramming tools for detecting and transforming function types.
unsigned int uint
Definition integral.hpp:29
Adapter to store and hold an element of arbitrary type in local storage.
Helper template(s) for creating Lumiera Forward Iterators.
Extension module to build an opaque data source, accessible as Lumiera Forward Iterator.
Conveniently iterable stack and queue containers.
Detect if given source was already built by IterExplorer;.
Detect and remove typical adapter layers added by a preceding IterExplorer usage.
lib::meta::RefTraits< Result >::Value ResVal
meta::Strip< CON >::TypeReferred::iterator iterator
constexpr auto IDENTITY
meta::Strip< CON >::TypeReferred::const_iterator const_iterator
iter_explorer::_FunTraits< FUN, SRC >::Res Result
constexpr auto ACCEPT_ALL
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition meta/util.hpp:99
RefTraits< TY >::Reference reference
RefTraits< TY >::Value value_type
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Unwrap< TypePlain >::Type Type
Definition trait.hpp:261
enable_if_c< not Cond::value, T >::type disable_if
Definition meta/util.hpp:90
RefTraits< TY >::Pointer pointer
Helper for type analysis: tries to strip all kinds of type adornments.
Definition trait.hpp:251
Type re-binding helper template for creating nested typedefs usable by custom containers and iterator...
Implementation namespace for support and library code.
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
LumieraError< LERR_(STATE)> State
Definition error.hpp:209
STL namespace.
bool isnil(lib::time::Duration const &dur)
Iterator front-end to manage and operate a IterExplorer pipeline opaquely.
Expandable & expandableSource() const
IterExploreSource(IT &&opaqueSrcPipeline)
A Stack which can be popped by iterating.
size_t size() const
IterStack & push(TY const &elm)
helper to derive a suitable common type when expanding children
meta::CommonResultYield< SrcYield, ResYield > _CommonT
void expandChildren()
collaboration: recurse into nested scope
size_t depth() const
collaboration: number of nested scopes
Adapt STL compliant container.
adapt to a functor, which accesses the source iterator or embedded "state core"
static decltype(auto) wrap(FUN &&rawFunctor)
decltype(std::declval< F >()(std::declval< Arg >())) Ret
_Fun< Sig >::Args::List::Head Arg
static auto adaptFunctor(FUN &&rawFunctor)
builder to create a nested/wrapping functor, suitably adapting the arguments
FunDetector< FUN >::Sig Sig
handle all regular "function-like" entities
Trait template for uniform access to function signature types.
Definition function.hpp:144
helper to check if another metafunction produced a result type
Helpers for type detection, type rewriting and metaprogramming.
A raw memory block with proper alignment and array access.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...