Elementa v8.0.0
Minimalistic library for any C++ application (C++11 and up)
Loading...
Searching...
No Matches
iterators.h
Go to the documentation of this file.
1
3#include "elementa/license.inc"
4#include "elementa/checks.inc"
5
6#ifndef ELEMENTA_BASE_ITERATORS_H
7#define ELEMENTA_BASE_ITERATORS_H
8
9#include <memory>
10#include <iterator>
11#include <type_traits>
12#include <limits>
13#include <functional>
19
21
22namespace elementa
23{
24
25namespace base
26{
27
105/* ======================================================================
106
107 MULTIPLE-BEHAVIOUR ITERATORS
108
109========================================================================= */
110
111
112/* ***************************************************************************
113
114 Abstract base template class: MultItImpl
115
116*******************************************************************************/
117
119
146template <class Data>
148 public elementa::patterns::ClonableShared<MultItImpl<Data>>
149{
150 public:
151
156 using Ptr = std::shared_ptr<MultItImpl>;
157
165 MultItImpl(void) {}
166
168 MultItImpl(const MultItImpl & oth): Validatable{oth}
169 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"oth. valid = " << oth.valid());}
170
173 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");
174 if (this != &oth) Validatable::operator=(oth);
175 return(*this); }
176
178 MultItImpl(MultItImpl && oth):Validatable{std::move(oth)}
179 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},""); }
180
183 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");
184 if (this != &oth) Validatable::operator=(std::move(oth));
185 return(*this); }
186
188 virtual ~MultItImpl(void) = default;
189
197
198 virtual Data & operator*(void) = 0;
199
201
204 virtual Data * pointedData(void) const = 0;
205
207
208 virtual MultItImpl & operator++(void) = 0;
209
211
213 virtual bool isEnd(void) const
214 { return(valid() && (pointedData()==nullptr)); }
215
216
224 void invalidate(void) { setInvalid(); }
225
227 virtual MultItImpl & operator--(void)
229
231
233 virtual bool operator==(const MultItImpl & oth) const
234 { return(valid() && oth.valid() &&
235 (pointedData() == oth.pointedData())); }
236
238
239 virtual bool operator!=(const MultItImpl & oth) const
240 { return(!operator==(oth)); }
241
243
244 virtual std::string to_string(void) const
245 { return(std::string{"MultItImpl("} +
246 std::to_string(to_number(this)) +
247 "; valid = " +
250 "; pointed = " +
251 std::to_string(to_number(pointedData())) :
252 "") +
253 ")" ); }
254
257 static_assert( !std::is_void<Data>::value,
258 "MultItImpl cannot work with void Data" );
259
260};
261
262
263/* ***************************************************************************
264
265 Template class: MultIterator
266
267*******************************************************************************/
268
270
297template <class Data, bool BIDIR = false>
298class MultIterator final
299{
300 public:
301
306 using Category = std::forward_iterator_tag;
307
309 using T = Data;
310
312 using Distance = std::ptrdiff_t;
313
315 using Pointer = T*;
316
318 using Reference = T&;
319
322
330
333 impl_{impl}
334 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"Creating new multiterator with "
335 << (impl_.get() == nullptr ?
336 "null impl." :
337 impl_->to_string())); }
338
341 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},""); copyFrom(oth); }
342
345 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");copyFrom(oth);return(*this);}
346
349 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},""); copyFrom(oth); }
350
353 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");copyFrom(oth);return(*this);}
354
357
365 bool valid(void) const { return(impl_->valid()); }
366
368 Reference operator*(void) const { return(impl_->operator*()); }
369
372 { impl_->operator++(); return(*this);}
373
376 { MultIterator copyme{*this}; impl_->operator++(); return(copyme); }
377
379 bool operator==(const MultIterator & oth) const
380 { return( impl_->operator==(*(oth.impl_)) ); }
381
383 bool operator!=(const MultIterator & oth) const
384 { return( impl_->operator!=(*(oth.impl_)) ); }
385
387 bool operator<(const MultIterator & oth) const
388 { return( ((impl_->valid()) && (oth.impl_->valid()) &&
389 (impl_->pointedData() < oth.impl_->pointedData())) ); }
390
392 void swap(MultIterator & oth) { std::swap(impl_,oth.impl_); }
393
395 bool isEnd(void) const { return(impl_->isEnd()); }
396
398 std::string to_string(void) const
399 { return(std::string{"FMultIterator(valid = "} +
400 kYesNoCString(impl_->valid()) + ", isend = " +
401 kYesNoCString(isEnd()) + ", " +
402 (impl_.get() != nullptr ? impl_->to_string() : "null impl.") +
403 " )"); }
404
406 ImplementationPtr implementation(void) const { return(impl_); }
407
410 private:
411
412 ImplementationPtr impl_;
413
414 void copyFrom(const MultIterator & oth)
416 ELE_CODE_TRACE({},"Cloning to this the impl of " <<oth.to_string());
417 impl_ = oth.impl_->clone();
418 ELE_CODE_TRACE({},"Cloned: " << to_string());}
419
420 static_assert( !std::is_void<Data>::value,
421 "MultIterator cannot work with void Data" );
422
423};
424
425
427
429template <class Data>
430class MultIterator<Data,true> final
431{
432 public:
433
438 using Category = std::bidirectional_iterator_tag;
439
441 using T = Data;
442
444 using Distance = std::ptrdiff_t;
445
447 using Pointer = T*;
448
450 using Reference = T&;
451
454
462
465 impl_{impl}
466 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"Creating new multiterator with "
467 << (impl_.get() == nullptr ?
468 "null impl." :
469 impl_->to_string())); }
470
473 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},""); copyFrom(oth); }
474
477 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");copyFrom(oth);return(*this);}
478
481 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},""); copyFrom(oth); }
482
485 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");copyFrom(oth);return(*this);}
486
489
497 bool valid(void) const { return(impl_->valid()); }
498
500 Reference operator*(void) const { return(impl_->operator*()); }
501
504 { impl_->operator++(); return(*this);}
505
508 { MultIterator copyme{*this}; impl_->operator++(); return(copyme); }
509
512 { impl_->operator--(); return(*this);}
513
516 { MultIterator copyme{*this}; impl_->operator--(); return(copyme); }
517
519 bool operator==(const MultIterator & oth) const
520 { return( ((impl_->valid()) && (oth.impl_->valid()) &&
521 (impl_->pointedData() == oth.impl_->pointedData())) ); }
522
524 bool operator!=(const MultIterator & oth) const
525 { return(!operator==(oth)); }
526
528 bool operator<(const MultIterator & oth) const
529 { return( ((impl_->valid()) && (oth.impl_->valid()) &&
530 (impl_->pointedData() < oth.impl_->pointedData())) ); }
531
533 void swap(MultIterator & oth)
534 { std::swap(impl_,oth.impl_); }
535
537 bool isEnd(void) const
538 { return((impl_->valid())&&(impl_->pointedData()==nullptr)); }
539
541 std::string to_string(void) const
542 { return(std::string{"BMultIterator( isend = "} +
543 kYesNoCString(isEnd()) + ", " +
544 (impl_.get() != nullptr ? impl_->to_string() : "null impl.") +
545 " )"); }
546
548 ImplementationPtr implementation(void) const { return(impl_); }
549
553 private:
554
555 ImplementationPtr impl_;
556
557 void copyFrom(const MultIterator & oth)
559 ELE_CODE_TRACE({},"Cloning to this the impl of " <<oth.to_string());
560 impl_ = oth.impl_->clone();
561 ELE_CODE_TRACE({},"Cloned: " << to_string());}
562
563 static_assert( !std::is_void<Data>::value,
564 "MultIterator cannot work with void Data" );
565};
566
567
569template <class Data, bool BIDIR>
571 { it1.swap(it2); }
572
573
574
575/* ======================================================================
576
577 RANGE EXTENSIONS
578
579 Ranges are included in C++20. Here is a simple version of them
580 that minimalistically respects their concepts and behaviours.
581
582 The best explanations of ranges/views pre-C++20 final publication
583 are:
584
585 https://hannes.hauswedell.net/post/2018/04/11/view1/
586 https://ezoeryou.github.io/blog/article/2019-01-10-range-view.html
587
588 An existing range-library pre-C++20 final publication is:
589
590 https://github.com/ericniebler/range-v3
591
592========================================================================= */
593
594/* *****************************************************************************
595
596 Abstract template class: Range
597
598*******************************************************************************/
599
601
606template <class It>
607class Range
608{
609 public:
610
612
613 virtual It begin(void) const = 0;
614
616 virtual It end(void) const = 0;
617};
618
619
620/* *****************************************************************************
621
622 Template class: SubView
623
624*******************************************************************************/
625
627
632template <class It>
633class SubView: public Range<It>
634{
635 public:
636
638
642 SubView(const It & itbeg, const It & itend):itbeg_{itbeg},itend_{itend} {}
643
645 It begin(void) const { return(itbeg_); }
646
648 It end(void) const { return(itend_); }
649
650 private:
651
652 It itbeg_;
653 It itend_;
654};
655
656
657/* *****************************************************************************
658
659 Template class: IotaView
660
661*******************************************************************************/
662
664
671template <typename IT = int>
673{
674 public:
675
681 {
682 friend IotaView;
683
684 iterator_t & operator++(void)
685 { if ((!alwaysend_) &&
686 ((unbounded_) || (value_ < bound_)))
687 {
688 if (value_ == std::numeric_limits<IT>::max())
689 alwaysend_ = true;
690 else ++value_;
691 }
692 return(*this); }
693
694 IT operator*(void) const { checkderef(); return(value_); }
695
696 bool operator==(const iterator_t & oth) const noexcept
697 { if (isend()) return(oth.isend());
698 else if (oth.isend()) return(false);
699 return(value_ == oth.value_); }
700
701 bool operator!=(const iterator_t & oth) const noexcept
702 { return(!operator==(oth)); }
703
704 private:
705
706 iterator_t(IT value, IT bound) noexcept:
707 value_{value},bound_{bound},
708 unbounded_{false},alwaysend_{false}
709 {}
710
711 iterator_t(IT value) noexcept: value_{value},
712 unbounded_{true},alwaysend_{false}
713 {}
714
715 iterator_t(void) noexcept: alwaysend_{true},unbounded_{true}
716 {}
717
718 bool isend(void) const noexcept
720 ELE_CODE_TRACE({},"returning " <<
721 ((alwaysend_) ||
722 ((!unbounded_) && (value_ == bound_))) <<
723 " for " << to_number(this));
724 return((alwaysend_) ||
725 ((!unbounded_) && (value_ == bound_))); }
726 void checkderef(void) const
727 { if (isend()) ELE_CODE_INVSTATE("Dereferencing end iterator");}
728
729 IT value_;
730 IT bound_;
731 const bool unbounded_;
732 bool alwaysend_;
733 };
734
742 IotaView(IT start, IT finish) noexcept: start_{start},finish_{finish},
743 bounded_{true},alwaysend_{false}
744 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"Created iotaview[" << start_ <<
745 ", " << finish_ << "]"); }
746
748 IotaView(IT start) noexcept: start_{start},
749 bounded_{false},alwaysend_{false}
750 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"Created iotaview[" << start_ <<
751 ", infinity]"); }
752
754 IotaView(void) noexcept: alwaysend_{true}
755 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"Created always end iotaview"); }
756
764 iterator_t begin(void) const noexcept
765 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},"");
766 return(alwaysend_ ? iterator_t{}:
767 (bounded_ ? iterator_t{start_,finish_} :
768 iterator_t{start_})); }
769
771 iterator_t end(void) const noexcept
772 {ELE_CODE_TRACE_OFF; ELE_CODE_TRACE({},""); return(iterator_t{}); }
773
776 private:
777
778 IT start_;
779 IT finish_;
780 bool bounded_;
781 bool alwaysend_;
782
783 static_assert( std::is_integral<IT>::value,
784 "IotaView only works with integral types" );
785};
786
787 // Iterators
789
790
791} // end namespace base
792
793} // end namespace elementa
794
795#endif
Any class derived from this must be clonable.
Definition: clonable.h:109
#define ELE_CODE_TRACE_OFF
Place this inside local scope (e.g., routine) to deactivate traces there.
Definition: debugging.h:283
constexpr const char * kYesNoCString(bool b)
User-friendly yes/no output.
Definition: definitions.h:85
#define ELE_CODE_INVSTATE(expl)
To throw an invalid-state exception with an explanation.
Definition: exceptions.h:306
#define ELE_CODE_UNIMPLEMENTED
To throw an unimplemented exception.
Definition: exceptions.h:289
LongestUnsigned to_number(const void *p)
Convert a pointer address to a number.
bool operator!=(const MultIterator &oth) const
Inequality.
Definition: iterators.h:383
void swap(MultIterator &oth)
To swap iterators is to swap their internal implementations.
Definition: iterators.h:392
MultIterator & operator=(const MultIterator &oth)
Copy assignment. Makes sure the copy is deep.
Definition: iterators.h:344
MultItImpl & operator=(const MultItImpl &oth)
Copy assignment.
Definition: iterators.h:172
MultIterator & operator--(int)
Postfix decrement.
Definition: iterators.h:515
IotaView(IT start, IT finish) noexcept
Bounded constructor.
Definition: iterators.h:742
bool operator<(const MultIterator &oth) const
Ordering (for using MultIterator in std::maps, for instance).
Definition: iterators.h:387
virtual bool operator!=(const MultItImpl &oth) const
Unequality between iterators.
Definition: iterators.h:239
Reference operator*(void) const
Return a ref to the pointed data, or throw in invalid state.
Definition: iterators.h:500
bool isEnd(void) const
Check for end. If it is invalid or points not to end, return false.
Definition: iterators.h:537
bool isEnd(void) const
Check for end. If it is invalid or points not to end, return false.
Definition: iterators.h:395
bool operator==(const MultIterator &oth) const
Check whether both are valid and point to the same data.
Definition: iterators.h:379
std::ptrdiff_t Distance
Distance between iterators (for STL-compatibility)
Definition: iterators.h:312
ImplementationPtr implementation(void) const
Consulting the implementation.
Definition: iterators.h:548
bool operator==(const MultIterator &oth) const
Check whether both are valid and point to the same data.
Definition: iterators.h:519
MultIterator(ImplementationPtr impl=ImplementationPtr{})
Constructor for a given behavior.
Definition: iterators.h:332
MultItImpl(const MultItImpl &oth)
Copy constructor.
Definition: iterators.h:168
MultIterator(MultIterator &&oth)
Move constructor. Do not move actually, just copy.
Definition: iterators.h:348
virtual bool isEnd(void) const
Detect whether it is end iterator.
Definition: iterators.h:213
MultIterator & operator++(int)
Postfix increment.
Definition: iterators.h:507
It begin(void) const
Provides the begin iterator.
Definition: iterators.h:645
MultIterator & operator++(int)
Postfix increment.
Definition: iterators.h:375
virtual ~MultItImpl(void)=default
Virtual destructor.
virtual Data * pointedData(void) const =0
Must return a pointer to the data under the iterator.
virtual bool operator==(const MultItImpl &oth) const
Equality between iterators. By default, equality of the pointed data.
Definition: iterators.h:233
IotaView(IT start) noexcept
Unbounded constructor.
Definition: iterators.h:748
void invalidate(void)
Invalidate the iterator.
Definition: iterators.h:224
std::string to_string(void) const
Return a string with info about the iterator.
Definition: iterators.h:541
SubView(const It &itbeg, const It &itend)
Create the view, from ITBEG to ITEND.
Definition: iterators.h:642
Data T
Iterated data (for STL-compatibility)
Definition: iterators.h:309
std::string to_string(void) const
Return a string with info about the iterator.
Definition: iterators.h:398
virtual MultItImpl & operator--(void)
Prefix decrement, for possible bidirectional iterations.
Definition: iterators.h:227
std::shared_ptr< MultItImpl > Ptr
A smart pointer to the iterator implementation.
Definition: iterators.h:156
T & Reference
Reference to data (for STL-compatibility)
Definition: iterators.h:318
IotaView(void) noexcept
Always end constructor (begin == end).
Definition: iterators.h:754
~MultIterator(void)
Destructor.
Definition: iterators.h:356
MultItImpl(void)
Default constructor: invalid state.
Definition: iterators.h:165
Reference operator*(void) const
Return a ref to the pointed data, or throw in invalid state.
Definition: iterators.h:368
bool valid(void) const
Return true if the iterator is in valid state.
Definition: iterators.h:365
bool operator<(const MultIterator &oth) const
Ordering (for using MultIterator in std::maps, for instance).
Definition: iterators.h:528
MultItImpl(MultItImpl &&oth)
Move constructor.
Definition: iterators.h:178
T * Pointer
Pointer to data (for STL-compatibility)
Definition: iterators.h:447
bool valid(void) const
Return true if the iterator is in valid state.
Definition: iterators.h:497
It end(void) const
Provides the end iterator.
Definition: iterators.h:648
MultIterator & operator=(MultIterator &&oth)
Move assignment. Do not move actually, just copy.
Definition: iterators.h:352
Data T
Iterated data (for STL-compatibility)
Definition: iterators.h:441
virtual It end(void) const =0
Must return an iterator pointing past the last element.
std::forward_iterator_tag Category
Category of the iterator (for STL-compatibility)
Definition: iterators.h:306
MultIterator(MultIterator &&oth)
Move constructor. Do not move actually, just copy.
Definition: iterators.h:480
MultIterator(ImplementationPtr impl=ImplementationPtr{})
Constructor for a given behavior.
Definition: iterators.h:464
virtual std::string to_string(void) const
Return a string with info about the iterator implementation.
Definition: iterators.h:244
T & Reference
Reference to data (for STL-compatibility)
Definition: iterators.h:450
ImplementationPtr implementation(void) const
Consulting the implementation.
Definition: iterators.h:406
virtual MultItImpl & operator++(void)=0
Prefix increment.
MultIterator & operator++(void)
Prefix increment.
Definition: iterators.h:503
iterator_t begin(void) const noexcept
Provides the begin iterator.
Definition: iterators.h:764
T * Pointer
Pointer to data (for STL-compatibility)
Definition: iterators.h:315
MultIterator(const MultIterator &oth)
Copy constructor. Makes sure the copy is deep.
Definition: iterators.h:340
MultIterator & operator=(MultIterator &&oth)
Move assignment. Do not move actually, just copy.
Definition: iterators.h:484
virtual It begin(void) const =0
Must return an iterator pointing to the first element.
void swap(MultIterator &oth)
To swap iterators is to swap their internal implementations.
Definition: iterators.h:533
virtual Data & operator*(void)=0
Must return a ref to the pointed data, or throw in invalid state.
std::bidirectional_iterator_tag Category
Category of the iterator (for STL-compatibility)
Definition: iterators.h:438
bool operator!=(const MultIterator &oth) const
Inequality.
Definition: iterators.h:524
MultIterator & operator++(void)
Prefix increment.
Definition: iterators.h:371
typename MultItImpl< Data >::Ptr ImplementationPtr
Pointer to an implementation.
Definition: iterators.h:453
MultIterator(const MultIterator &oth)
Copy constructor. Makes sure the copy is deep.
Definition: iterators.h:472
MultIterator & operator=(const MultIterator &oth)
Copy assignment. Makes sure the copy is deep.
Definition: iterators.h:476
typename MultItImpl< Data >::Ptr ImplementationPtr
Pointer to an implementation.
Definition: iterators.h:321
MultItImpl & operator=(MultItImpl &&oth)
Move assignment.
Definition: iterators.h:182
MultIterator & operator--(void)
Prefix decrement.
Definition: iterators.h:511
std::ptrdiff_t Distance
Distance between iterators (for STL-compatibility)
Definition: iterators.h:444
iterator_t end(void) const noexcept
Provides the end iterator.
Definition: iterators.h:771
A view that refers to a sequence of incrementable elements, bounded or not.
Definition: iterators.h:673
Base class for implementing diverse iteration behaviors.
Definition: iterators.h:149
A mutable iterator that can have multiple iteration behaviors. Forward case.
Definition: iterators.h:299
A range is a provider of begin() and end() iterators.
Definition: iterators.h:608
A view that refers to a segment of an existing container.
Definition: iterators.h:634
void swap(MultIterator< Data, BIDIR > &it1, MultIterator< Data, BIDIR > &it2)
Swap function for MultIterators.
Definition: iterators.h:570
bool valid(void) const noexcept
Public method to be used by users of the derived class.
Definition: validatable.h:106
#define ELE_CLASS_VALIDATABLE
Declare a class derived from Validatable.
Definition: validatable.h:82
The iterator type returned by begin() and end().
Definition: iterators.h:681