Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
iter-adapter.hpp
Go to the documentation of this file.
1/*
2 ITER-ADAPTER.hpp - helpers for building simple forward iterators
3
4 Copyright (C)
5 2009, Hermann Vosseler <Ichthyostega@web.de>
6 2017,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
103#ifndef LIB_ITER_ADAPTER_H
104#define LIB_ITER_ADAPTER_H
105
106
107#include "lib/error.hpp"
109
110#include <iterator>
111#include <limits>
112
113
114namespace util { // see lib/util.hpp
115 template<class OBJ>
116 OBJ* unConst (const OBJ*);
117 template<class OBJ>
118 OBJ& unConst (OBJ const&);
119}
120
121namespace lib {
122
123
124 namespace { // internal helpers
125 inline void
127 {
128 throw lumiera::error::Invalid ("Can't iterate further",
129 lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
130 }
131 }
132
134#define ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(ITER) \
135 friend ITER begin (ITER const& it){ return it; } \
136 friend ITER&& begin (ITER&& it) { return static_cast<ITER&&> (it); } \
137 friend ITER end (ITER const&) { return ITER(); } \
138 using iterator_category = std::input_iterator_tag; \
139 using difference_type = size_t;
140
142#define LIFT_PARENT_INCREMENT_OPERATOR(_BASECLASS_)\
143 auto& \
144 operator++() \
145 { \
146 _BASECLASS_::operator++(); \
147 return *this; \
148 }
149
150
151 namespace iter {
153 template<class IT>
154 using Yield = decltype(std::declval<IT>().operator*());
155
157 template<class COR>
158 using CoreYield = decltype(std::declval<COR>().yield());
159
160 }
161
162
163
206 template<class POS, class CON>
208 {
210 mutable POS pos_;
211
213
214 public:
215 using value_type = _ValTrait::value_type;
216 using reference = _ValTrait::reference;
217 using pointer = _ValTrait::pointer;
218
219
220 IterAdapter (CON src, POS const& startpos)
221 : source_(src)
222 , pos_(startpos)
223 {
224 check();
225 }
226
228 : source_()
229 , pos_()
230 { }
231
232 explicit
233 operator bool() const
234 {
235 return isValid();
236 }
237
238
239 /* === lumiera forward iterator concept === */
240
242 operator*() const
243 {
244 _maybe_throw();
245 return *pos_;
246 }
247
248 pointer
250 {
251 _maybe_throw();
252 return & *pos_;
253 }
254
257 {
258 _maybe_throw();
259 iterate();
260 return *this;
261 }
262
263 bool
264 isValid () const
265 {
266 return check();
267 }
268
269 bool
270 empty () const
271 {
272 return not isValid();
273 }
274
275
276 protected: /* === iteration control interface === */
277
283 bool
284 check() const
285 {
286 return source_ and checkPoint (source_,pos_); // extension point: free function checkPoint(...)
287 }
288
294 void
296 {
297 iterNext (source_,pos_); // extension point: free function iterNext(...)
298 check();
299 } // checkPoint() might mark end condition
300 // for comparison with IterAdapter{}
301
302
303
304 protected:
306
308 ConRef source() { return source_; }
309 const ConRef source() const { return unConst(this)->source_; }
310
311 void
312 resetPos (POS otherPos)
313 {
314 pos_ = otherPos;
315 check();
316 }
317
318 private:
319 void
321 {
322 if (not isValid())
323 _throwIterExhausted();
324 }
325
326
327 public:
329
331 template<class P1, class P2, class CX>
333 };
334
335
337 template<class P1, class P2, class CON>
338 inline bool operator== (IterAdapter<P1,CON> const& il, IterAdapter<P2,CON> const& ir) { return il.pos_ == ir.pos_; }
339
340 template<class P1, class P2, class CON>
341 inline bool operator!= (IterAdapter<P1,CON> const& il, IterAdapter<P2,CON> const& ir) { return not (il == ir); }
342
343
344
345
373 template<class ST, typename T =iter::CoreYield<ST>>
375 {
377
378 public:
382
383 IterStateWrapper (ST&& initialState)
384 : core_(std::forward<ST>(initialState))
385 { }
386
387 IterStateWrapper (ST const& initialState)
388 : core_(initialState)
389 { }
390
392 : core_()
393 { }
394
395 explicit
396 operator bool() const
397 {
398 return isValid();
399 }
400
401
402 /* === lumiera forward iterator concept === */
403
404 T
405 operator*() const
406 {
408 return core_.yield(); // core interface: yield
409 }
410
411 pointer
413 {
414 if constexpr (meta::isLRef_v<T>)
415 {
417 return & core_.yield(); // core interface: yield
418 }
419 else
420 static_assert (!sizeof(T),
421 "can not provide operator-> "
422 "since iterator pipeline generates a value");
423 }
424
427 {
429 core_.iterNext(); // core interface: iterNext
430 return *this;
431 }
432
433 bool
434 isValid () const
435 {
436 return core_.checkPoint(); // core interface: checkPoint
437 }
438
439 bool
440 empty () const
441 {
442 return not isValid();
443 }
444
445 protected:
446
449 ST & stateCore() { return core_; }
450 ST const& stateCore() const { return core_; }
451
452 void
454 {
455 if (not isValid())
456 _throwIterExhausted();
457 }
458
459
460
461 public:
463
465 template<class STX, class T1, class T2>
467 };
468
469
470
472 template<class ST, class T1, class T2>
473 inline bool
475 {
476 return (il.empty() and ir.empty())
477 or (il.isValid() and ir.isValid() and il.core_ == ir.core_);
478 }
479
480 template<class ST, class T1, class T2>
481 inline bool
483 {
484 return not (il == ir);
485 }
486
487
488
489
499 template<class IT>
501 : public IT
502 {
504 ,"Lumiera Iterator required as source");
505 protected:
506 IT&
507 srcIter() const
508 {
509 return util::unConst(*this);
510 }
511
512 public:
513 using IT::IT;
514
515 /* === state protocol API for IterStateWrapper === */
516 bool
518 {
519 return bool(srcIter());
520 }
521
522 IT::reference
523 yield() const
524 {
525 return *srcIter();
526 }
527
528 void
530 {
531 ++ srcIter();
532 }
533 };
534
535
536
544 template<class COR>
546 : public COR
547 {
549 ,"Adapted type must expose a »state core« API");
550 protected:
551 COR&
552 _rawCore() const
553 {
554 return util::unConst(*this);
555 }
556
557 void
559 {
560 if (not checkPoint())
561 _throwIterExhausted();
562 }
563
564 public:
568 template<typename...ARGS>
569 CheckedCore (ARGS&& ...init)
570 : COR(std::forward<ARGS>(init)...)
571 { }
572
573 CheckedCore() =default;
575 CheckedCore (CheckedCore const&) =default;
578
580
581
582 /* === state protocol API for IterStateWrapper === */
583 bool
585 {
586 return _rawCore().checkPoint();
587 }
588
589 decltype(auto)
590 yield() const
591 {
593 return _rawCore().yield();
594 }
595
596 void
598 {
600 _rawCore().iterNext();
601 }
602 };
603
604
605
613 template<class CON>
615 : public CON
616 {
617 using Iter = CON::iterator;
618
620
621 public:
622 ContainerCore (CON&& container)
623 : CON(std::forward<CON>(container))
624 , p_{CON::begin()}
625 { }
626
627 // copy and assignment acceptable (warning!)
628
629
630 /* === »state core« protocol API === */
631 bool
633 {
634 return p_ != CON::end();
635 }
636
637 decltype(auto)
638 yield() const
639 {
640 return *p_;
641 }
642
643 void
645 {
646 ++p_;
647 }
648 };
649
650
651
652
680 template<class COR>
682 : public COR
683 {
684 COR & _core() { return static_cast<COR&> (*this); }
685 COR const& _core() const { return static_cast<COR const&> (*this); }
686
687 protected:
688 void
690 {
691 if (not isValid())
692 _throwIterExhausted();
693 }
694
695 public:
696 using YieldRes = iter::CoreYield<COR>;
700
701
707 template<typename...ARGS>
708 IterableDecorator (ARGS&& ...init)
709 : COR(std::forward<ARGS>(init)...)
710 { }
711
717
718
719 /* === lumiera forward iterator concept === */
720
721 explicit operator bool() const { return isValid(); }
722
724 operator*() const
725 {
726 return _core().yield(); // core interface: yield
727 }
728
729 pointer
731 {
732 if constexpr (meta::isLRef_v<YieldRes>)
733 return & _core().yield(); // core interface: yield
734 else
735 static_assert (!sizeof(COR),
736 "can not provide operator-> "
737 "since iterator pipeline generates a value");
738 }
739
742 {
743 _core().iterNext(); // core interface: iterNext
744 return *this;
745 }
746
747 bool
748 isValid () const
749 {
750 return _core().checkPoint(); // core interface: checkPoint
751 }
752
753 bool
754 empty () const
755 {
756 return not isValid();
757 }
758
759
760
762
763
765 friend bool
767 {
768 return (il.empty() and ir.empty())
769 or (il.isValid() and ir.isValid() and il._core() == ir._core());
770 }
771 friend bool
773 {
774 return not (il == ir);
775 }
776 };
777
778
779
780
781
782
783
797 template<class IT>
799 {
800 IT p_;
801 IT e_;
802
804
805 public:
806 using pointer = _ValTrait::pointer;
807 using reference = _ValTrait::reference;
808
810 using value_type = std::remove_reference<reference>::type;
811
812
813 RangeIter (IT const& start, IT const& end)
814 : p_(start)
815 , e_(end)
816 { }
817
819 : p_()
820 , e_()
821 { }
822
823
827 template<class I2>
828 RangeIter (I2 const& oIter)
829 : p_(oIter.getPos())
830 , e_(oIter.getEnd())
831 { }
832
833 explicit
834 operator bool() const
835 {
836 return isValid();
837 }
838
839
840 /* === lumiera forward iterator concept === */
841
843 operator*() const
844 {
845 _maybe_throw();
846 return *p_;
847 }
848
849 pointer
851 {
852 _maybe_throw();
853 return &(*p_);
854 }
855
856 RangeIter&
858 {
859 _maybe_throw();
860 ++p_;
861 return *this;
862 }
863
864 bool
865 isValid () const
866 {
867 return (p_!= IT()) and (p_ != e_);
868 }
869
870 bool
871 empty () const
872 {
873 return not isValid();
874 }
875
876
878 const IT& getPos() const { return p_; }
879 const IT& getEnd() const { return e_; }
880
881
883
884
885 private:
886
887 void
889 {
890 if (!isValid())
891 _throwIterExhausted();
892 }
893 };
894
895
896
898 template<class I1, class I2>
899 inline bool operator== (RangeIter<I1> const& il, RangeIter<I2> const& ir) { return (!il and !ir) or (il.getPos() == ir.getPos()); }
900
901 template<class I1, class I2>
902 inline bool operator!= (RangeIter<I1> const& il, RangeIter<I2> const& ir) { return not (il == ir); }
903
904
905
906
907
919 template<typename INT>
921 {
922 INT i_;
923 INT e_;
924
925 public:
926 using pointer = INT*;
927 using reference = INT&;
928 using value_type = INT ;
929
930 NumIter (INT start, INT end)
931 : i_(start)
932 , e_(end)
933 { }
934
935 template<typename X>
936 NumIter (X&& start, X&& end)
937 : i_(std::forward<X>(start))
938 , e_(std::forward<X>(end))
939 { }
940
942 : i_()
943 , e_()
944 { }
945
946 // standard copy operations acceptable
947
948 explicit
949 operator bool() const
950 {
951 return isValid();
952 }
953
954
955
956 /* === lumiera forward iterator concept === */
957
959 operator*() const
960 {
961 _maybe_throw();
962 return i_;
963 }
964
965 NumIter&
967 {
968 _maybe_throw();
969 ++i_;
970 return *this;
971 }
972
973 bool
974 isValid () const
975 {
976 return i_ < e_; // NOTE: use comparison to detect iteration end
977 }
978
979 bool
980 empty () const
981 {
982 return not isValid();
983 }
984
985
987 INT& getPos() const { return i_; }
988 INT& getEnd() const { return e_; }
989
990
992
993
995 bool operator!= (NumIter const& o) const { return not operator==(o); }
996 bool operator== (NumIter const& o) const { return (empty() and o.empty()) // empty iters must be equal (Lumiera iter requirement)
997 or (i_ == o.i_ and e_ == o.e_); }
998
999 private:
1000 void
1002 {
1003 if (!isValid())
1004 _throwIterExhausted();
1005 }
1006 };
1007
1008
1009
1010
1011
1012
1014 template<typename INT>
1015 inline NumIter<INT>
1016 eachNum (INT start = std::numeric_limits<INT>::min()
1017 ,INT end = std::numeric_limits<INT>::max())
1018 {
1019 return NumIter<INT> (start, end);
1020 }
1021
1022
1023
1024
1025
1026
1027
1032 template<class TY>
1033 struct IterType;
1034
1035 template<template<class,class> class Iter, class TY, class CON>
1036 struct IterType<Iter<TY,CON>>
1037 {
1038 using Container = CON;
1039 using ElemType = TY ;
1040
1041 template<class T2>
1042 struct SimilarIter
1043 {
1044 using Type = Iter<T2,CON>;
1045 };
1046 };
1047
1048 template<class IT>
1050 : IterType<IT>
1051 {
1052 template<class T2>
1058 };
1059
1060
1061
1063 template<class IT>
1065 {
1066 IT i_;
1067
1068
1069 public:
1070 using value_type = const IT::value_type;
1071 using pointer = const IT::pointer ;
1072 using reference = const IT::reference ;
1073
1074 ConstIter (IT srcIter)
1075 : i_(srcIter)
1076 { }
1077
1078 explicit
1079 operator bool() const
1080 {
1081 return isValid();
1082 }
1083
1084
1085
1086 /* === lumiera forward iterator concept === */
1087
1088 reference
1090 {
1091 return *i_;
1092 }
1093
1094 pointer
1096 {
1097 return i_.operator->();
1098 }
1099
1100 ConstIter&
1102 {
1103 ++i_;
1104 return *this;
1105 }
1106
1107 bool
1108 isValid () const
1109 {
1110 return bool(i_);
1111 }
1112
1113 bool
1114 empty () const
1115 {
1116 return not isValid();
1117 }
1118
1119
1121 IT const&
1122 getBase() const
1123 {
1124 return i_;
1125 }
1126
1127
1129 };
1130
1131
1133 template<class I1, class I2>
1134 inline bool operator== (ConstIter<I1> const& il, ConstIter<I2> const& ir) { return il.getBase() == ir.getBase(); }
1135
1136 template<class I1, class I2>
1137 inline bool operator!= (ConstIter<I1> const& il, ConstIter<I2> const& ir) { return not (il == ir); }
1138
1139
1140
1141}// namespace lib
1142#endif /*LIB_ITER_ADAPTER_H*/
Adapter to add sanity checks to a »state core«.
CheckedCore(ARGS &&...init)
blindly pass-down any argument...
decltype(auto) yield() const
void __throw_if_empty() const
bool checkPoint() const
CheckedCore & operator=(CheckedCore &&)=default
CheckedCore()=default
CheckedCore(CheckedCore const &)=default
COR TAG_CheckedCore_Raw
marker to allow unwrapping the raw core
COR & _rawCore() const
CheckedCore(CheckedCore &&)=default
wrapper to expose values as const
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(ConstIter)
bool isValid() const
bool empty() const
ConstIter(IT srcIter)
const IT::value_type value_type
IT const & getBase() const
access the wrapped implementation iterator
const IT::reference reference
ConstIter & operator++()
reference operator*() const
IT i_
nested source iterator
const IT::pointer pointer
pointer operator->() const
Adapter to »piggy-back« a STL iterable container inline and expose it as »state core«.
decltype(auto) yield() const
bool checkPoint() const
ContainerCore(CON &&container)
Adapter for building an implementation of the »Lumiera Forward Iterator« concept.
meta::ValueTypeBinding< std::remove_pointer_t< POS > > _ValTrait
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(IterAdapter)
ConRef source()
allow derived classes to access backing container
IterAdapter & operator++()
void iterate()
ask the controlling container to yield the next position.
void _maybe_throw() const
const ConRef source() const
IterAdapter(CON src, POS const &startpos)
bool isValid() const
meta::RefTraits< CON >::Reference ConRef
_ValTrait::pointer pointer
bool empty() const
bool check() const
ask the controlling container if this position is valid.
friend bool operator==(IterAdapter< P1, CX > const &, IterAdapter< P2, CX > const &)
comparison is allowed to access impl iterator
void resetPos(POS otherPos)
_ValTrait::value_type value_type
reference operator*() const
_ValTrait::reference reference
pointer operator->() const
Adapter to dress up an existing »Lumiera Forward Iterator« as »state core«.
bool checkPoint() const
IT::reference yield() const
Another Lumiera Forward Iterator building block, based on incorporating a state type as »*State Core*...
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(IterStateWrapper)
IterStateWrapper(ST &&initialState)
friend bool operator==(IterStateWrapper< STX, T1 > const &, IterStateWrapper< STX, T2 > const &)
comparison is allowed to access state implementation core
void __throw_if_empty() const
IterStateWrapper(ST const &initialState)
meta::RefTraits< T >::Pointer pointer
ST const & stateCore() const
meta::RefTraits< T >::Reference reference
ST & stateCore()
allow derived classes to access state representation
pointer operator->() const
IterStateWrapper & operator++()
meta::RefTraits< T >::Value value_type
Decorator-Adapter to make a »*State Core*« iterable as Lumiera Forward Iterator.
IterableDecorator & operator=(IterableDecorator &&)=default
YieldRes operator*() const
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(IterableDecorator)
void __throw_if_empty() const
iter::CoreYield< COR > YieldRes
IterableDecorator & operator++()
meta::RefTraits< YieldRes >::Reference reference
IterableDecorator(ARGS &&...init)
by default, pass anything down for initialisation of the core.
friend bool operator!=(IterableDecorator const &il, IterableDecorator const &ir)
meta::RefTraits< YieldRes >::Value value_type
COR const & _core() const
meta::RefTraits< YieldRes >::Pointer pointer
IterableDecorator(IterableDecorator &&)=default
pointer operator->() const
IterableDecorator(IterableDecorator const &)=default
friend bool operator==(IterableDecorator const &il, IterableDecorator const &ir)
Supporting equality comparisons of equivalent iterators (equivalent state core)...
Enumerate all "numbers" within a range.
void _maybe_throw() const
bool operator!=(NumIter const &o) const
Supporting equality comparisons...
bool isValid() const
bool empty() const
INT & getEnd() const
INT & getPos() const
access wrapped index elements
value_type operator*() const
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(NumIter)
bool operator==(NumIter const &o) const
NumIter(INT start, INT end)
NumIter & operator++()
NumIter(X &&start, X &&end)
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
RangeIter & operator++()
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(RangeIter)
RangeIter(I2 const &oIter)
allow copy, when the underlying iterators are compatible or convertible
const IT & getEnd() const
void _maybe_throw() const
std::remove_reference< reference >::type value_type
bool isValid() const
_ValTrait::pointer pointer
bool empty() const
meta::ValueTypeBinding< meta::remove_pointer_t< IT > > _ValTrait
reference operator*() const
_ValTrait::reference reference
RangeIter(IT const &start, IT const &end)
const IT & getPos() const
access wrapped STL iterator
pointer operator->() const
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 exposing a »state core« API.
Definition trait.hpp:535
Lumiera error handling (C++ interface).
decltype(std::declval< IT >().operator*()) Yield
type binding helper: an iterato's actual result type
decltype(std::declval< COR >().yield()) CoreYield
the result type yielded by a »state core«
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Implementation namespace for support and library code.
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
bool operator!=(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
NumIter< INT > eachNum(INT start=std::numeric_limits< INT >::min(), INT end=std::numeric_limits< INT >::max())
convenience function to iterate "each number"
Helper for type rewritings: get the element type for an iterator like entity.
LumieraError< LERR_(INVALID)> Invalid
Definition error.hpp:211
STL namespace.
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Definition util.hpp:358
IterType< IT >::template SimilarIter< T2 >::Type WrappedIter
Type re-binding helper template for custom containers and adapters.