Lumiera  0.pre.03
»edit your freedom«
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 
112 
113 namespace util { // see lib/util.hpp
114  template<class OBJ>
115  OBJ* unConst (const OBJ*);
116  template<class OBJ>
117  OBJ& unConst (OBJ const&);
118 }
119 
120 namespace lib {
121 
122 
123  namespace { // internal helpers
124  inline void
125  _throwIterExhausted()
126  {
127  throw lumiera::error::Invalid ("Can't iterate further",
128  lumiera::error::LUMIERA_ERROR_ITER_EXHAUST);
129  }
130  }
131 
133 #define ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(ITER) \
134  friend ITER begin (ITER const& it){ return it; } \
135  friend ITER&& begin (ITER&& it) { return static_cast<ITER&&> (it); } \
136  friend ITER end (ITER const&) { return ITER(); } \
137  using iterator_category = std::input_iterator_tag; \
138  using difference_type = size_t;
139 
141 #define LIFT_PARENT_INCREMENT_OPERATOR(_BASECLASS_)\
142  auto& \
143  operator++() \
144  { \
145  _BASECLASS_::operator++(); \
146  return *this; \
147  }
148 
149 
150  namespace iter {
152  template<class IT>
153  using Yield = decltype(std::declval<IT>().operator*());
154 
156  template<class COR>
157  using CoreYield = decltype(std::declval<COR>().yield());
158 
159  }
160 
161 
162 
205  template<class POS, class CON>
207  {
208  CON source_;
209  mutable POS pos_;
210 
212 
213  public:
214  using value_type = typename _ValTrait::value_type;
215  using reference = typename _ValTrait::reference;
216  using pointer = typename _ValTrait::pointer;
217 
218 
219  IterAdapter (CON src, POS const& startpos)
220  : source_(src)
221  , pos_(startpos)
222  {
223  check();
224  }
225 
226  IterAdapter ()
227  : source_()
228  , pos_()
229  { }
230 
231  explicit
232  operator bool() const
233  {
234  return isValid();
235  }
236 
237 
238  /* === lumiera forward iterator concept === */
239 
240  reference
241  operator*() const
242  {
243  _maybe_throw();
244  return *pos_;
245  }
246 
247  pointer
248  operator->() const
249  {
250  _maybe_throw();
251  return & *pos_;
252  }
253 
254  IterAdapter&
255  operator++()
256  {
257  _maybe_throw();
258  iterate();
259  return *this;
260  }
261 
262  bool
263  isValid () const
264  {
265  return check();
266  }
267 
268  bool
269  empty () const
270  {
271  return not isValid();
272  }
273 
274 
275  protected: /* === iteration control interface === */
276 
282  bool
283  check() const
284  {
285  return source_ && checkPoint (source_,pos_); // extension point: free function checkPoint(...)
286  }
287 
293  void
295  {
296  iterNext (source_,pos_); // extension point: free function iterNext(...)
297  check();
298  } // checkPoint() might mark end condition
299  // for comparison with IterAdapter{}
300 
301 
302 
303  protected:
304  using ConRef = typename meta::RefTraits<CON>::Reference;
305 
307  ConRef source() { return source_; }
308  const ConRef source() const { return unConst(this)->source_; }
309 
310  void
311  resetPos (POS otherPos)
312  {
313  pos_ = otherPos;
314  check();
315  }
316 
317  private:
318  void
319  _maybe_throw() const
320  {
321  if (not isValid())
322  _throwIterExhausted();
323  }
324 
325 
326  public:
328 
330  template<class P1, class P2, class CX>
331  friend bool operator== (IterAdapter<P1,CX> const&, IterAdapter<P2,CX> const&);
332  };
333 
334 
336  template<class P1, class P2, class CON>
337  inline bool operator== (IterAdapter<P1,CON> const& il, IterAdapter<P2,CON> const& ir) { return il.pos_ == ir.pos_; }
338 
339  template<class P1, class P2, class CON>
340  inline bool operator!= (IterAdapter<P1,CON> const& il, IterAdapter<P2,CON> const& ir) { return not (il == ir); }
341 
342 
343 
344 
372  template<class ST, typename T =iter::CoreYield<ST>>
374  {
375  ST core_;
376 
377  public:
378  using value_type = typename meta::RefTraits<T>::Value;
379  using reference = typename meta::RefTraits<T>::Reference;
380  using pointer = typename meta::RefTraits<T>::Pointer;
381 
382  IterStateWrapper (ST&& initialState)
383  : core_(std::forward<ST>(initialState))
384  { }
385 
386  IterStateWrapper (ST const& initialState)
387  : core_(initialState)
388  { }
389 
391  : core_()
392  { }
393 
394  explicit
395  operator bool() const
396  {
397  return isValid();
398  }
399 
400 
401  /* === lumiera forward iterator concept === */
402 
403  T
404  operator*() const
405  {
406  __throw_if_empty();
407  return core_.yield(); // core interface: yield
408  }
409 
410  pointer
411  operator->() const
412  {
413  if constexpr (meta::isLRef_v<T>)
414  {
415  __throw_if_empty();
416  return & core_.yield(); // core interface: yield
417  }
418  else
419  static_assert (!sizeof(T),
420  "can not provide operator-> "
421  "since iterator pipeline generates a value");
422  }
423 
425  operator++()
426  {
427  __throw_if_empty();
428  core_.iterNext(); // core interface: iterNext
429  return *this;
430  }
431 
432  bool
433  isValid () const
434  {
435  return core_.checkPoint(); // core interface: checkPoint
436  }
437 
438  bool
439  empty () const
440  {
441  return not isValid();
442  }
443 
444  protected:
445 
448  ST & stateCore() { return core_; }
449  ST const& stateCore() const { return core_; }
450 
451  void
452  __throw_if_empty() const
453  {
454  if (not isValid())
455  _throwIterExhausted();
456  }
457 
458 
459 
460  public:
462 
464  template<class STX, class T1, class T2>
466  };
467 
468 
469 
471  template<class ST, class T1, class T2>
472  inline bool
474  {
475  return (il.empty() and ir.empty())
476  or (il.isValid() and ir.isValid() and il.core_ == ir.core_);
477  }
478 
479  template<class ST, class T1, class T2>
480  inline bool
481  operator!= (IterStateWrapper<ST,T1> const& il, IterStateWrapper<ST,T2> const& ir)
482  {
483  return not (il == ir);
484  }
485 
486 
487 
488 
498  template<class IT>
500  : public IT
501  {
503  ,"Lumiera Iterator required as source");
504  protected:
505  IT&
506  srcIter() const
507  {
508  return util::unConst(*this);
509  }
510 
511  public:
512  using IT::IT;
513 
514  /* === state protocol API for IterStateWrapper === */
515  bool
516  checkPoint() const
517  {
518  return bool(srcIter());
519  }
520 
521  typename IT::reference
522  yield() const
523  {
524  return *srcIter();
525  }
526 
527  void
528  iterNext()
529  {
530  ++ srcIter();
531  }
532  };
533 
534 
535 
543  template<class COR>
545  : public COR
546  {
548  ,"Adapted type must expose a »state core« API");
549  protected:
550  COR&
551  _rawCore() const
552  {
553  return util::unConst(*this);
554  }
555 
556  void
557  __throw_if_empty() const
558  {
559  if (not checkPoint())
560  _throwIterExhausted();
561  }
562 
563  public:
567  template<typename...ARGS>
568  CheckedCore (ARGS&& ...init)
569  : COR(std::forward<ARGS>(init)...)
570  { }
571 
572  CheckedCore() =default;
573  CheckedCore (CheckedCore&&) =default;
574  CheckedCore (CheckedCore const&) =default;
575  CheckedCore& operator= (CheckedCore&&) =default;
576  CheckedCore& operator= (CheckedCore const&) =default;
577 
578  using TAG_CheckedCore_Raw = COR;
579 
580 
581  /* === state protocol API for IterStateWrapper === */
582  bool
583  checkPoint() const
584  {
585  return _rawCore().checkPoint();
586  }
587 
588  decltype(auto)
589  yield() const
590  {
591  __throw_if_empty();
592  return _rawCore().yield();
593  }
594 
595  void
596  iterNext()
597  {
598  __throw_if_empty();
599  _rawCore().iterNext();
600  }
601  };
602 
603 
604 
612  template<class CON>
614  : public CON
615  {
616  using Iter = typename CON::iterator;
617 
618  Iter p_;
619 
620  public:
621  ContainerCore (CON&& container)
622  : CON(std::forward<CON>(container))
623  , p_{CON::begin()}
624  { }
625 
626  // copy and assignment acceptable (warning!)
627 
628 
629  /* === »state core« protocol API === */
630  bool
631  checkPoint() const
632  {
633  return p_ != CON::end();
634  }
635 
636  decltype(auto)
637  yield() const
638  {
639  return *p_;
640  }
641 
642  void
643  iterNext()
644  {
645  ++p_;
646  }
647  };
648 
649 
650 
651 
679  template<class COR>
681  : public COR
682  {
683  COR & _core() { return static_cast<COR&> (*this); }
684  COR const& _core() const { return static_cast<COR const&> (*this); }
685 
686  protected:
687  void
688  __throw_if_empty() const
689  {
690  if (not isValid())
691  _throwIterExhausted();
692  }
693 
694  public:
695  using YieldRes = iter::CoreYield<COR>;
696  using value_type = typename meta::RefTraits<YieldRes>::Value;
697  using reference = typename meta::RefTraits<YieldRes>::Reference;
698  using pointer = typename meta::RefTraits<YieldRes>::Pointer;
699 
700 
706  template<typename...ARGS>
707  IterableDecorator (ARGS&& ...init)
708  : COR(std::forward<ARGS>(init)...)
709  { }
710 
711  IterableDecorator() =default;
713  IterableDecorator (IterableDecorator const&) =default;
714  IterableDecorator& operator= (IterableDecorator&&) =default;
715  IterableDecorator& operator= (IterableDecorator const&) =default;
716 
717 
718  /* === lumiera forward iterator concept === */
719 
720  explicit operator bool() const { return isValid(); }
721 
722  YieldRes
723  operator*() const
724  {
725  return _core().yield(); // core interface: yield
726  }
727 
728  pointer
729  operator->() const
730  {
731  if constexpr (meta::isLRef_v<YieldRes>)
732  return & _core().yield(); // core interface: yield
733  else
734  static_assert (!sizeof(COR),
735  "can not provide operator-> "
736  "since iterator pipeline generates a value");
737  }
738 
740  operator++()
741  {
742  _core().iterNext(); // core interface: iterNext
743  return *this;
744  }
745 
746  bool
747  isValid () const
748  {
749  return _core().checkPoint(); // core interface: checkPoint
750  }
751 
752  bool
753  empty () const
754  {
755  return not isValid();
756  }
757 
758 
759 
761 
762 
764  friend bool
766  {
767  return (il.empty() and ir.empty())
768  or (il.isValid() and ir.isValid() and il._core() == ir._core());
769  }
770  friend bool
771  operator!= (IterableDecorator const& il, IterableDecorator const& ir)
772  {
773  return not (il == ir);
774  }
775  };
776 
777 
778 
779 
780 
781 
782 
796  template<class IT>
797  class RangeIter
798  {
799  IT p_;
800  IT e_;
801 
803 
804  public:
805  using pointer = typename _ValTrait::pointer;
806  using reference = typename _ValTrait::reference;
807 
809  using value_type = typename std::remove_reference<reference>::type;
810 
811 
812  RangeIter (IT const& start, IT const& end)
813  : p_(start)
814  , e_(end)
815  { }
816 
817  RangeIter ()
818  : p_()
819  , e_()
820  { }
821 
822 
826  template<class I2>
827  RangeIter (I2 const& oIter)
828  : p_(oIter.getPos())
829  , e_(oIter.getEnd())
830  { }
831 
832  explicit
833  operator bool() const
834  {
835  return isValid();
836  }
837 
838 
839  /* === lumiera forward iterator concept === */
840 
841  reference
842  operator*() const
843  {
844  _maybe_throw();
845  return *p_;
846  }
847 
848  pointer
849  operator->() const
850  {
851  _maybe_throw();
852  return &(*p_);
853  }
854 
855  RangeIter&
856  operator++()
857  {
858  _maybe_throw();
859  ++p_;
860  return *this;
861  }
862 
863  bool
864  isValid () const
865  {
866  return (p_!= IT()) && (p_ != e_);
867  }
868 
869  bool
870  empty () const
871  {
872  return not isValid();
873  }
874 
875 
877  const IT& getPos() const { return p_; }
878  const IT& getEnd() const { return e_; }
879 
880 
882 
883 
884  private:
885 
886  void
887  _maybe_throw() const
888  {
889  if (!isValid())
890  _throwIterExhausted();
891  }
892  };
893 
894 
895 
897  template<class I1, class I2>
898  inline bool operator== (RangeIter<I1> const& il, RangeIter<I2> const& ir) { return (!il && !ir) || (il.getPos() == ir.getPos()); }
899 
900  template<class I1, class I2>
901  inline bool operator!= (RangeIter<I1> const& il, RangeIter<I2> const& ir) { return !(il == ir); }
902 
903 
904 
905 
906 
918  template<typename INT>
919  class NumIter
920  {
921  INT i_;
922  INT e_;
923 
924  public:
925  typedef INT* pointer;
926  typedef INT& reference;
927  typedef INT value_type;
928 
929  NumIter (INT start, INT end)
930  : i_(start)
931  , e_(end)
932  { }
933 
934  template<typename X>
935  NumIter (X&& start, X&& end)
936  : i_(std::forward<X>(start))
937  , e_(std::forward<X>(end))
938  { }
939 
940  NumIter ()
941  : i_()
942  , e_()
943  { }
944 
945  // standard copy operations acceptable
946 
947  explicit
948  operator bool() const
949  {
950  return isValid();
951  }
952 
953 
954 
955  /* === lumiera forward iterator concept === */
956 
957  value_type
958  operator*() const
959  {
960  _maybe_throw();
961  return i_;
962  }
963 
964  NumIter&
965  operator++()
966  {
967  _maybe_throw();
968  ++i_;
969  return *this;
970  }
971 
972  bool
973  isValid () const
974  {
975  return i_ < e_; // NOTE: use comparison to detect iteration end
976  }
977 
978  bool
979  empty () const
980  {
981  return not isValid();
982  }
983 
984 
986  INT& getPos() const { return i_; }
987  INT& getEnd() const { return e_; }
988 
989 
991 
992 
994  bool operator!= (NumIter const& o) const { return not operator==(o); }
995  bool operator== (NumIter const& o) const { return (empty() and o.empty()) // empty iters must be equal (Lumiera iter requirement)
996  or (i_ == o.i_ and e_ == o.e_); }
997 
998  private:
999  void
1000  _maybe_throw() const
1001  {
1002  if (!isValid())
1003  _throwIterExhausted();
1004  }
1005  };
1006 
1007 
1008 
1009 
1010 
1011 
1013  template<typename INT>
1014  inline NumIter<INT>
1015  eachNum (INT start = std::numeric_limits<INT>::min()
1016  ,INT end = std::numeric_limits<INT>::max())
1017  {
1018  return NumIter<INT> (start, end);
1019  }
1020 
1021 
1022 
1023 
1024 
1025 
1026 
1031  template<class TY>
1032  struct IterType;
1033 
1034  template<template<class,class> class Iter, class TY, class CON>
1035  struct IterType<Iter<TY,CON>>
1036  {
1037  typedef CON Container;
1038  typedef TY ElemType;
1039 
1040  template<class T2>
1041  struct SimilarIter
1042  {
1043  typedef Iter<T2,CON> Type;
1044  };
1045  };
1046 
1047  template<class IT>
1048  struct IterType<RangeIter<IT>>
1049  : IterType<IT>
1050  {
1051  template<class T2>
1052  struct SimilarIter
1053  {
1054  typedef typename IterType<IT>::template SimilarIter<T2>::Type WrappedIter;
1055  typedef RangeIter<WrappedIter> Type;
1056  };
1057  };
1058 
1059 
1060 
1062  template<class IT>
1064  {
1065  IT i_;
1066 
1067 
1068  public:
1069  typedef const typename IT::value_type value_type;
1070  typedef const typename IT::pointer pointer;
1071  typedef const typename IT::reference reference;
1072 
1073  ConstIter (IT srcIter)
1074  : i_(srcIter)
1075  { }
1076 
1077  explicit
1078  operator bool() const
1079  {
1080  return isValid();
1081  }
1082 
1083 
1084 
1085  /* === lumiera forward iterator concept === */
1086 
1087  reference
1088  operator*() const
1089  {
1090  return *i_;
1091  }
1092 
1093  pointer
1094  operator->() const
1095  {
1096  return i_.operator->();
1097  }
1098 
1099  ConstIter&
1100  operator++()
1101  {
1102  ++i_;
1103  return *this;
1104  }
1105 
1106  bool
1107  isValid () const
1108  {
1109  return bool(i_);
1110  }
1111 
1112  bool
1113  empty () const
1114  {
1115  return not isValid();
1116  }
1117 
1118 
1120  IT const&
1121  getBase() const
1122  {
1123  return i_;
1124  }
1125 
1126 
1128  };
1129 
1130 
1132  template<class I1, class I2>
1133  inline bool operator== (ConstIter<I1> const& il, ConstIter<I2> const& ir) { return il.getBase() == ir.getBase(); }
1134 
1135  template<class I1, class I2>
1136  inline bool operator!= (ConstIter<I1> const& il, ConstIter<I2> const& ir) { return not (il == ir); }
1137 
1138 
1139 
1140 }// namespace lib
1141 #endif /*LIB_ITER_ADAPTER_H*/
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
const IT & getPos() const
access wrapped STL iterator
ST & stateCore()
allow derived classes to access state representation
Helper for type rewritings: get the element type for an iterator like entity.
CheckedCore(ARGS &&...init)
blindly pass-down any argument...
Adapter to add sanity checks to a »state core«.
Type re-binding helper template for custom containers and adapters.
STL namespace.
Trait template to detect a type exposing a »state core« API.
Definition: trait.hpp:534
IterableDecorator(ARGS &&...init)
by default, pass anything down for initialisation of the core.
#define ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(ITER)
use a given Lumiera Forward Iterator in standard "range for loops"
ConRef source()
allow derived classes to access backing container
Adapter to dress up an existing »Lumiera Forward Iterator« as »state core«.
typename std::remove_reference< reference >::type value_type
Implementation namespace for support and library code.
Enumerate all "numbers" within a range.
bool operator==(ConstIter< I1 > const &il, ConstIter< I2 > const &ir)
Supporting equality comparisons...
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
COR TAG_CheckedCore_Raw
marker to allow unwrapping the raw core
IT const & getBase() const
access the wrapped implementation iterator
Another Lumiera Forward Iterator building block, based on incorporating a state type as »*State Core*...
Trait template to detect a type usable immediately as "Lumiera Forward Iterator" in a specialised for...
Definition: trait.hpp:510
wrapper to expose values as const
RangeIter(I2 const &oIter)
allow copy, when the underlying iterators are compatible or convertible
decltype(std::declval< IT >().operator*()) Yield
type binding helper: an iterato&#39;s actual result type
Lumiera error handling (C++ interface).
INT & getPos() const
access wrapped index elements
IT i_
nested source iterator
decltype(std::declval< COR >().yield()) CoreYield
the result type yielded by a »state core«
Adapter to »piggy-back« a STL iterable container inline and expose it as »state core«.
bool check() const
ask the controlling container if this position is valid.
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...
Type re-binding helper template for creating nested typedefs usable by custom containers and iterator...
void iterate()
ask the controlling container to yield the next position.
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
NumIter< INT > eachNum(INT start=std::numeric_limits< INT >::min(), INT end=std::numeric_limits< INT >::max())
convenience function to iterate "each number"