20#ifndef LIB_ENUMERATOR_H_
21#define LIB_ENUMERATOR_H_
25#include <initializer_list>
32#include "iterator_range.h"
35enum class EnumeratorState { NotStarted, Valid, PastEnd };
48class EnumeratorHandle {
51 explicit EnumeratorHandle(
Enumerator<T> *enumerator) : enumerator(enumerator) {}
55 using iterator_category = std::input_iterator_tag;
56 using difference_type = std::ptrdiff_t;
61 reference operator*()
const;
62 const EnumeratorHandle<T> &operator++();
63 bool operator==(
const EnumeratorHandle<T> &other)
const;
64 bool operator!=(
const EnumeratorHandle<T> &other)
const;
71 EnumeratorState state = EnumeratorState::NotStarted;
75 friend class Enumerator;
76 static std::vector<T> emptyVector;
78 friend class EnumeratorHandle;
83 Enumerator() { this->
reset(); }
85 virtual ~Enumerator() =
default;
93 virtual void reset() { this->state = EnumeratorState::NotStarted; }
99 EnumeratorHandle<T> end() {
return EnumeratorHandle<T>(
nullptr); }
101 const char *stateName()
const {
102 switch (this->state) {
103 case EnumeratorState::NotStarted:
105 case EnumeratorState::Valid:
107 case EnumeratorState::PastEnd:
110 throw std::logic_error(
"Unexpected state " + std::to_string(
static_cast<int>(this->state)));
114 template <
typename Container>
116 "Use Util::enumerate() instead")]]
static Enumerator<typename Container::value_type> *
117 createEnumerator(
const Container &data);
118 static Enumerator<T> *emptyEnumerator();
119 template <
typename Iter>
120 [[deprecated(
"Use Util::enumerate() instead")]]
static Enumerator<typename Iter::value_type> *
121 createEnumerator(Iter begin, Iter end);
122 template <
typename Iter>
123 [[deprecated(
"Use Util::enumerate() instead")]]
static Enumerator<typename Iter::value_type> *
124 createEnumerator(iterator_range<Iter> range);
127 template <
typename Filter>
128 Enumerator<T> *
where(Filter filter);
130 template <
typename Mapper>
131 Enumerator<std::invoke_result_t<Mapper, T>> *
map(Mapper
map);
133 template <
typename S>
136 virtual Enumerator<T> *
concat(Enumerator<T> *other);
138 static Enumerator<T> *
concatAll(Enumerator<Enumerator<T> *> *inputs);
140 std::vector<T> toVector() {
141 std::vector<T> result;
159 if (!
next)
throw std::logic_error(
"There is no element for `single()'");
162 if (
next)
throw std::logic_error(
"There are multiple elements when calling `single()'");
170 if (!
next)
return T{};
173 if (
next)
throw std::logic_error(
"There are multiple elements when calling `single()'");
180 if (!
next)
return T{};
187 if (!
next)
throw std::logic_error(
"There is no element for `next()'");
199template <
typename Iter>
200class IteratorEnumerator :
public Enumerator<typename std::iterator_traits<Iter>::value_type> {
206 friend class Enumerator<typename
std::iterator_traits<Iter>::value_type>;
209 IteratorEnumerator(Iter begin, Iter end, const char *name)
210 : Enumerator<typename std::iterator_traits<Iter>::value_type>(),
216 [[nodiscard]] std::string toString()
const {
217 return std::string(this->name) +
":" + this->stateName();
221 switch (this->state) {
222 case EnumeratorState::NotStarted:
223 this->current = this->begin;
224 if (this->current == this->end) {
225 this->state = EnumeratorState::PastEnd;
228 this->state = EnumeratorState::Valid;
231 case EnumeratorState::PastEnd:
233 case EnumeratorState::Valid:
235 if (this->current == this->end) {
236 this->state = EnumeratorState::PastEnd;
242 throw std::runtime_error(
"Unexpected enumerator state");
245 typename std::iterator_traits<Iter>::value_type
getCurrent()
const override {
246 switch (this->state) {
247 case EnumeratorState::NotStarted:
248 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
249 case EnumeratorState::PastEnd:
250 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
251 case EnumeratorState::Valid:
252 return *this->current;
254 throw std::runtime_error(
"Unexpected enumerator state");
258template <
typename Iter>
259IteratorEnumerator(Iter begin, Iter end,
const char *name) -> IteratorEnumerator<Iter>;
264class SingleEnumerator :
public Enumerator<T> {
268 explicit SingleEnumerator(T v) : Enumerator<T>(), value(v) {}
270 switch (this->state) {
271 case EnumeratorState::NotStarted:
272 this->state = EnumeratorState::Valid;
274 case EnumeratorState::PastEnd:
276 case EnumeratorState::Valid:
277 this->state = EnumeratorState::PastEnd;
280 throw std::runtime_error(
"Unexpected enumerator state");
283 switch (this->state) {
284 case EnumeratorState::NotStarted:
285 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
286 case EnumeratorState::PastEnd:
287 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
288 case EnumeratorState::Valid:
291 throw std::runtime_error(
"Unexpected enumerator state");
301 [[nodiscard]] std::string toString()
const {
return "EmptyEnumerator"; }
305 throw std::logic_error(
"You cannot call 'getCurrent' on an EmptyEnumerator");
316template <
typename T,
typename Filter>
317class FilterEnumerator final :
public Enumerator<T> {
318 Enumerator<T> *input;
323 FilterEnumerator(Enumerator<T> *input, Filter filter)
324 : input(input), filter(std::move(filter)) {}
328 this->state = EnumeratorState::Valid;
329 while (this->input->moveNext()) {
330 this->current = this->input->getCurrent();
331 bool match = this->filter(this->current);
332 if (match)
return true;
334 this->state = EnumeratorState::PastEnd;
339 [[nodiscard]] std::string toString()
const {
340 return "FilterEnumerator(" + this->input->toString() +
"):" + this->stateName();
344 this->input->reset();
349 switch (this->state) {
350 case EnumeratorState::NotStarted:
351 case EnumeratorState::Valid:
352 return this->advance();
353 case EnumeratorState::PastEnd:
356 throw std::runtime_error(
"Unexpected enumerator state");
360 switch (this->state) {
361 case EnumeratorState::NotStarted:
362 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
363 case EnumeratorState::PastEnd:
364 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
365 case EnumeratorState::Valid:
366 return this->current;
368 throw std::runtime_error(
"Unexpected enumerator state");
380template <
typename From,
typename To,
typename =
void>
381static constexpr bool can_be_casted =
false;
383template <
typename From,
typename To>
385 can_be_casted<From *, To *, std::void_t<decltype(std::declval<From *>()->template to<To>())>> =
390template <
typename T,
typename S>
391class AsEnumerator final :
public Enumerator<S> {
392 template <
typename U = S>
393 typename std::enable_if_t<!Detail::can_be_casted<T, S>, U> getCurrentImpl()
const {
394 T current = input->getCurrent();
395 return dynamic_cast<S
>(current);
398 template <
typename U = S>
399 typename std::enable_if_t<Detail::can_be_casted<T, S>, U> getCurrentImpl()
const {
400 T current = input->getCurrent();
401 return current->template to<std::remove_pointer_t<S>>();
405 Enumerator<T> *input;
408 explicit AsEnumerator(Enumerator<T> *input) : input(input) {}
410 std::string toString()
const {
411 return "AsEnumerator(" + this->input->toString() +
"):" + this->stateName();
416 this->input->
reset();
420 bool result = this->input->
moveNext();
422 this->state = EnumeratorState::Valid;
424 this->state = EnumeratorState::PastEnd;
434template <
typename T,
typename S,
typename Mapper>
435class MapEnumerator final :
public Enumerator<S> {
437 Enumerator<T> *input;
442 MapEnumerator(Enumerator<T> *input, Mapper map) : input(input), map(std::move(map)) {}
445 this->input->
reset();
449 [[nodiscard]] std::string toString()
const {
450 return "MapEnumerator(" + this->input->toString() +
"):" + this->stateName();
454 switch (this->state) {
455 case EnumeratorState::NotStarted:
456 case EnumeratorState::Valid: {
457 bool success = input->moveNext();
460 this->current = this->map(currentInput);
461 this->state = EnumeratorState::Valid;
464 this->state = EnumeratorState::PastEnd;
468 case EnumeratorState::PastEnd:
471 throw std::runtime_error(
"Unexpected enumerator state");
475 switch (this->state) {
476 case EnumeratorState::NotStarted:
477 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
478 case EnumeratorState::PastEnd:
479 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
480 case EnumeratorState::Valid:
481 return this->current;
483 throw std::runtime_error(
"Unexpected enumerator state");
487template <
typename T,
typename Mapper>
488MapEnumerator(Enumerator<T> *,
489 Mapper) -> MapEnumerator<T, typename std::invoke_result_t<Mapper, T>, Mapper>;
495class ConcatEnumerator final :
public Enumerator<T> {
496 std::vector<Enumerator<T> *> inputs;
500 ConcatEnumerator() =
default;
502 explicit ConcatEnumerator(std::vector<Enumerator<T> *> &&inputs) : inputs(std::move(inputs)) {
503 for (
auto *currentInput : inputs)
504 if (currentInput ==
nullptr)
throw std::logic_error(
"Null iterator in concatenation");
507 ConcatEnumerator(std::initializer_list<Enumerator<T> *> inputs) : inputs(inputs) {
508 for (
auto *currentInput : inputs)
509 if (currentInput ==
nullptr)
throw std::logic_error(
"Null iterator in concatenation");
511 explicit ConcatEnumerator(Enumerator<Enumerator<T> *> *inputs)
512 : ConcatEnumerator(inputs->toVector()) {}
514 [[nodiscard]] std::string toString()
const {
return "ConcatEnumerator:" + this->stateName(); }
518 this->state = EnumeratorState::Valid;
519 for (
auto *currentInput : inputs) {
520 if (currentInput->moveNext()) {
521 this->currentResult = currentInput->getCurrent();
526 this->state = EnumeratorState::PastEnd;
531 Enumerator<T> *
concat(Enumerator<T> *other)
override {
533 if (this->state == EnumeratorState::PastEnd)
534 throw std::runtime_error(
"Invalid enumerator state to concatenate");
536 inputs.push_back(other);
542 for (
auto *currentInput : inputs) currentInput->reset();
547 switch (this->state) {
548 case EnumeratorState::NotStarted:
549 case EnumeratorState::Valid:
550 return this->advance();
551 case EnumeratorState::PastEnd:
554 throw std::runtime_error(
"Unexpected enumerator state");
558 switch (this->state) {
559 case EnumeratorState::NotStarted:
560 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
561 case EnumeratorState::PastEnd:
562 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
563 case EnumeratorState::Valid:
564 return this->currentResult;
566 throw std::runtime_error(
"Unexpected enumerator state");
573template <
typename Mapper>
585template <
typename Filter>
591template <
typename Container>
597Enumerator<T> *Enumerator<T>::emptyEnumerator() {
598 return new EmptyEnumerator<T>();
602template <
typename Iter>
603Enumerator<typename Iter::value_type> *Enumerator<T>::createEnumerator(Iter begin, Iter end) {
604 return new IteratorEnumerator(begin, end,
"iterator");
608template <
typename Iter>
626T EnumeratorHandle<T>::operator*()
const {
627 if (enumerator ==
nullptr)
throw std::logic_error(
"Dereferencing end() iterator");
628 return enumerator->getCurrent();
632const EnumeratorHandle<T> &EnumeratorHandle<T>::operator++() {
633 enumerator->moveNext();
638bool EnumeratorHandle<T>::operator==(
const EnumeratorHandle<T> &other)
const {
639 return !(*
this != other);
644 if (this->enumerator == other.enumerator)
return true;
645 if (other.enumerator !=
nullptr)
throw std::logic_error(
"Comparison with different iterator");
646 return this->enumerator->state == EnumeratorState::Valid;
649template <
typename Iter>
654template <
typename Iter>
659template <
typename Container>
672template <
typename... Args>
673auto concat(Args &&...inputs) {
674 using FirstEnumeratorTy =
675 std::remove_pointer_t<std::decay_t<std::tuple_element_t<0, std::tuple<Args...>>>>;
676 std::initializer_list<Enumerator<typename FirstEnumeratorTy::value_type> *> init{
677 std::forward<Args>(inputs)...};
Casts each element.
Definition enumerator.h:391
S getCurrent() const override
Get current element in the collection.
Definition enumerator.h:428
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:414
bool moveNext() override
Definition enumerator.h:419
Concatenation.
Definition enumerator.h:495
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:541
bool moveNext() override
Definition enumerator.h:546
T getCurrent() const override
Get current element in the collection.
Definition enumerator.h:557
Enumerator< T > * concat(Enumerator< T > *other) override
Append all elements of other after all elements of this.
Definition enumerator.h:531
Always empty iterator (equivalent to end())
Definition enumerator.h:299
bool moveNext() override
Always returns false.
Definition enumerator.h:303
T getCurrent() const override
Get current element in the collection.
Definition enumerator.h:304
Definition enumerator.h:48
Type-erased Enumerator interface.
Definition enumerator.h:69
Enumerator< S > * as()
Cast to an enumerator of S objects.
Definition enumerator.h:580
Enumerator< std::invoke_result_t< Mapper, T > > * map(Mapper map)
Apply specified function to all elements of this enumerator.
Definition enumerator.h:574
virtual bool moveNext()=0
virtual Enumerator< T > * concat(Enumerator< T > *other)
Append all elements of other after all elements of this.
Definition enumerator.h:619
T nextOrDefault()
Next element, or the default value if none exists.
Definition enumerator.h:178
T single()
The only next element; throws if the enumerator does not have exactly 1 element.
Definition enumerator.h:157
virtual void reset()
Move back to the beginning of the collection.
Definition enumerator.h:93
bool any()
True if the enumerator has at least one element.
Definition enumerator.h:154
virtual T getCurrent() const =0
Get current element in the collection.
T next()
Next element; throws if there are no elements.
Definition enumerator.h:185
uint64_t count()
Enumerate all elements and return the count.
Definition enumerator.h:147
T singleOrDefault()
Definition enumerator.h:168
Enumerator< T > * where(Filter filter)
Return an enumerator returning all elements that pass the filter.
Definition enumerator.h:586
static Enumerator< T > * concatAll(Enumerator< Enumerator< T > * > *inputs)
Concatenate all these collections into a single one.
Definition enumerator.h:614
Definition enumerator.h:317
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:359
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:343
bool moveNext()
Definition enumerator.h:348
A generic iterator returning elements of type T.
Definition enumerator.h:200
bool moveNext() override
Definition enumerator.h:220
std::iterator_traits< Iter >::value_type getCurrent() const override
Get current element in the collection.
Definition enumerator.h:245
Transforms all elements from type T to type S.
Definition enumerator.h:435
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:444
bool moveNext()
Definition enumerator.h:453
S getCurrent() const
Get current element in the collection.
Definition enumerator.h:474
bool moveNext()
Definition enumerator.h:269
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:282
Definition iterator_range.h:44