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 };
55 using iterator_category = std::input_iterator_tag;
56 using difference_type = std::ptrdiff_t;
61 reference operator*()
const;
70 EnumeratorState state = EnumeratorState::NotStarted;
75 static std::vector<T> emptyVector;
92 virtual void reset() { this->state = EnumeratorState::NotStarted; }
98 EnumeratorHandle<T> end() {
return EnumeratorHandle<T>(
nullptr); }
100 const char *stateName()
const {
101 switch (this->state) {
102 case EnumeratorState::NotStarted:
104 case EnumeratorState::Valid:
106 case EnumeratorState::PastEnd:
109 throw std::logic_error(
"Unexpected state " + std::to_string(
static_cast<int>(this->state)));
113 template <
typename Container>
115 "Use Util::enumerate() instead")]]
static Enumerator<typename Container::value_type> *
116 createEnumerator(
const Container &data);
117 static Enumerator<T> *emptyEnumerator();
118 template <
typename Iter>
119 [[deprecated(
"Use Util::enumerate() instead")]]
static Enumerator<typename Iter::value_type> *
120 createEnumerator(Iter begin, Iter end);
121 template <
typename Iter>
122 [[deprecated(
"Use Util::enumerate() instead")]]
static Enumerator<typename Iter::value_type> *
123 createEnumerator(iterator_range<Iter> range);
126 template <
typename Filter>
129 template <
typename Mapper>
132 template <
typename S>
139 std::vector<T> toVector() {
140 std::vector<T> result;
158 if (!
next)
throw std::logic_error(
"There is no element for `single()'");
161 if (
next)
throw std::logic_error(
"There are multiple elements when calling `single()'");
169 if (!
next)
return T{};
172 if (
next)
throw std::logic_error(
"There are multiple elements when calling `single()'");
179 if (!
next)
return T{};
186 if (!
next)
throw std::logic_error(
"There is no element for `next()'");
198template <
typename Iter>
205 friend class Enumerator<typename Iter::value_type>;
215 [[nodiscard]] std::string toString()
const {
216 return std::string(this->name) +
":" + this->stateName();
220 switch (this->state) {
221 case EnumeratorState::NotStarted:
222 this->current = this->begin;
223 if (this->current == this->end) {
224 this->state = EnumeratorState::PastEnd;
227 this->state = EnumeratorState::Valid;
230 case EnumeratorState::PastEnd:
232 case EnumeratorState::Valid:
234 if (this->current == this->end) {
235 this->state = EnumeratorState::PastEnd;
241 throw std::runtime_error(
"Unexpected enumerator state");
245 switch (this->state) {
246 case EnumeratorState::NotStarted:
247 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
248 case EnumeratorState::PastEnd:
249 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
250 case EnumeratorState::Valid:
251 return *this->current;
253 throw std::runtime_error(
"Unexpected enumerator state");
263 [[nodiscard]] std::string toString()
const {
return "EmptyEnumerator"; }
267 throw std::logic_error(
"You cannot call 'getCurrent' on an EmptyEnumerator");
278template <
typename T,
typename Filter>
286 : input(input), filter(std::move(filter)) {}
290 this->state = EnumeratorState::Valid;
291 while (this->input->moveNext()) {
292 this->current = this->input->getCurrent();
293 bool match = this->filter(this->current);
294 if (match)
return true;
296 this->state = EnumeratorState::PastEnd;
301 [[nodiscard]] std::string toString()
const {
302 return "FilterEnumerator(" + this->input->toString() +
"):" + this->stateName();
306 this->input->reset();
311 switch (this->state) {
312 case EnumeratorState::NotStarted:
313 case EnumeratorState::Valid:
314 return this->advance();
315 case EnumeratorState::PastEnd:
318 throw std::runtime_error(
"Unexpected enumerator state");
322 switch (this->state) {
323 case EnumeratorState::NotStarted:
324 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
325 case EnumeratorState::PastEnd:
326 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
327 case EnumeratorState::Valid:
328 return this->current;
330 throw std::runtime_error(
"Unexpected enumerator state");
342template <
typename From,
typename To,
typename =
void>
343static constexpr bool can_be_casted =
false;
345template <
typename From,
typename To>
347 can_be_casted<From *, To *, std::void_t<decltype(std::declval<From *>()->template to<To>())>> =
352template <
typename T,
typename S>
354 template <
typename U = S>
355 typename std::enable_if_t<!Detail::can_be_casted<T, S>, U> getCurrentImpl()
const {
356 T current = input->getCurrent();
357 return dynamic_cast<S
>(current);
360 template <
typename U = S>
361 typename std::enable_if_t<Detail::can_be_casted<T, S>, U> getCurrentImpl()
const {
362 T current = input->getCurrent();
363 return current->template to<std::remove_pointer_t<S>>();
372 std::string toString()
const {
373 return "AsEnumerator(" + this->input->toString() +
"):" + this->stateName();
378 this->input->
reset();
382 bool result = this->input->
moveNext();
384 this->state = EnumeratorState::Valid;
386 this->state = EnumeratorState::PastEnd;
396template <
typename T,
typename S,
typename Mapper>
407 this->input->
reset();
411 [[nodiscard]] std::string toString()
const {
412 return "MapEnumerator(" + this->input->toString() +
"):" + this->stateName();
416 switch (this->state) {
417 case EnumeratorState::NotStarted:
418 case EnumeratorState::Valid: {
422 this->current = this->map(currentInput);
423 this->state = EnumeratorState::Valid;
426 this->state = EnumeratorState::PastEnd;
430 case EnumeratorState::PastEnd:
433 throw std::runtime_error(
"Unexpected enumerator state");
437 switch (this->state) {
438 case EnumeratorState::NotStarted:
439 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
440 case EnumeratorState::PastEnd:
441 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
442 case EnumeratorState::Valid:
443 return this->current;
445 throw std::runtime_error(
"Unexpected enumerator state");
449template <
typename T,
typename Mapper>
450MapEnumerator(Enumerator<T> *,
451 Mapper) -> MapEnumerator<T, typename std::invoke_result_t<Mapper, T>, Mapper>;
458 std::vector<Enumerator<T> *> inputs;
465 for (
auto *currentInput : inputs)
466 if (currentInput ==
nullptr)
throw std::logic_error(
"Null iterator in concatenation");
470 for (
auto *currentInput : inputs)
471 if (currentInput ==
nullptr)
throw std::logic_error(
"Null iterator in concatenation");
476 [[nodiscard]] std::string toString()
const {
return "ConcatEnumerator:" + this->stateName(); }
480 this->state = EnumeratorState::Valid;
481 for (
auto *currentInput : inputs) {
482 if (currentInput->moveNext()) {
483 this->currentResult = currentInput->getCurrent();
488 this->state = EnumeratorState::PastEnd;
495 if (this->state == EnumeratorState::PastEnd)
496 throw std::runtime_error(
"Invalid enumerator state to concatenate");
498 inputs.push_back(other);
504 for (
auto *currentInput : inputs) currentInput->reset();
509 switch (this->state) {
510 case EnumeratorState::NotStarted:
511 case EnumeratorState::Valid:
512 return this->advance();
513 case EnumeratorState::PastEnd:
516 throw std::runtime_error(
"Unexpected enumerator state");
520 switch (this->state) {
521 case EnumeratorState::NotStarted:
522 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
523 case EnumeratorState::PastEnd:
524 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
525 case EnumeratorState::Valid:
526 return this->currentResult;
528 throw std::runtime_error(
"Unexpected enumerator state");
535template <
typename Mapper>
547template <
typename Filter>
553template <
typename Container>
559Enumerator<T> *Enumerator<T>::emptyEnumerator() {
560 return new EmptyEnumerator<T>();
564template <
typename Iter>
565Enumerator<typename Iter::value_type> *Enumerator<T>::createEnumerator(Iter begin, Iter end) {
566 return new IteratorEnumerator(begin, end,
"iterator");
570template <
typename Iter>
571Enumerator<typename Iter::value_type> *Enumerator<T>::createEnumerator(iterator_range<Iter> range) {
572 return new IteratorEnumerator(range.begin(), range.end(),
"range");
589 if (enumerator ==
nullptr)
throw std::logic_error(
"Dereferencing end() iterator");
590 return enumerator->getCurrent();
594const EnumeratorHandle<T> &EnumeratorHandle<T>::operator++() {
595 enumerator->moveNext();
600bool EnumeratorHandle<T>::operator!=(
const EnumeratorHandle<T> &other)
const {
601 if (this->enumerator == other.enumerator)
return true;
602 if (other.enumerator !=
nullptr)
throw std::logic_error(
"Comparison with different iterator");
603 return this->enumerator->state == EnumeratorState::Valid;
606template <
typename Iter>
607Enumerator<typename Iter::value_type> *enumerate(Iter begin, Iter end) {
608 return new IteratorEnumerator(begin, end,
"iterator");
611template <
typename Iter>
612Enumerator<typename Iter::value_type> *enumerate(iterator_range<Iter> range) {
613 return new IteratorEnumerator(range.begin(), range.end(),
"range");
616template <
typename Container>
617Enumerator<typename Container::value_type> *enumerate(
const Container &data) {
620 return new IteratorEnumerator(begin(data), end(data),
typeid(data).name());
625Enumerator<T> *concat(std::initializer_list<Enumerator<T> *> inputs) {
626 return new ConcatEnumerator<T>(inputs);
629template <
typename... Args>
630auto concat(Args &&...inputs) {
631 using FirstEnumeratorTy =
632 std::remove_pointer_t<std::decay_t<std::tuple_element_t<0, std::tuple<Args...>>>>;
633 std::initializer_list<Enumerator<typename FirstEnumeratorTy::value_type> *> init{
634 std::forward<Args>(inputs)...};
Casts each element.
Definition enumerator.h:353
S getCurrent() const override
Get current element in the collection.
Definition enumerator.h:390
bool moveNext() override
Definition enumerator.h:381
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:376
Concatenation.
Definition enumerator.h:457
bool moveNext() override
Definition enumerator.h:508
T getCurrent() const override
Get current element in the collection.
Definition enumerator.h:519
Enumerator< T > * concat(Enumerator< T > *other) override
Append all elements of other after all elements of this.
Definition enumerator.h:493
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:503
Always empty iterator (equivalent to end())
Definition enumerator.h:261
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:266
bool moveNext()
Always returns false.
Definition enumerator.h:265
Definition enumerator.h:48
Type-erased Enumerator interface.
Definition enumerator.h:68
T single()
The only next element; throws if the enumerator does not have exactly 1 element.
Definition enumerator.h:156
virtual void reset()
Move back to the beginning of the collection.
Definition enumerator.h:92
Enumerator< std::invoke_result_t< Mapper, T > > * map(Mapper map)
Apply specified function to all elements of this enumerator.
Definition enumerator.h:536
virtual bool moveNext()=0
Enumerator< T > * where(Filter filter)
Return an enumerator returning all elements that pass the filter.
Definition enumerator.h:548
uint64_t count()
Enumerate all elements and return the count.
Definition enumerator.h:146
Enumerator< S > * as()
Cast to an enumerator of S objects.
Definition enumerator.h:542
static Enumerator< T > * concatAll(Enumerator< Enumerator< T > * > *inputs)
Concatenate all these collections into a single one.
Definition enumerator.h:576
T next()
Next element; throws if there are no elements.
Definition enumerator.h:184
T nextOrDefault()
Next element, or the default value if none exists.
Definition enumerator.h:177
T singleOrDefault()
Definition enumerator.h:167
virtual T getCurrent() const =0
Get current element in the collection.
bool any()
True if the enumerator has at least one element.
Definition enumerator.h:153
virtual Enumerator< T > * concat(Enumerator< T > *other)
Append all elements of other after all elements of this.
Definition enumerator.h:581
Definition enumerator.h:279
bool moveNext()
Definition enumerator.h:310
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:305
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:321
A generic iterator returning elements of type T.
Definition enumerator.h:199
Iter::value_type getCurrent() const
Get current element in the collection.
Definition enumerator.h:244
bool moveNext()
Definition enumerator.h:219
Transforms all elements from type T to type S.
Definition enumerator.h:397
bool moveNext()
Definition enumerator.h:415
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:406
S getCurrent() const
Get current element in the collection.
Definition enumerator.h:436