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;
70 EnumeratorState state = EnumeratorState::NotStarted;
74 friend class Enumerator;
75 static std::vector<T> emptyVector;
77 friend class EnumeratorHandle;
82 Enumerator() { this->
reset(); }
84 virtual ~Enumerator() =
default;
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>
127 Enumerator<T> *
where(Filter filter);
129 template <
typename Mapper>
130 Enumerator<std::invoke_result_t<Mapper, T>> *
map(Mapper
map);
132 template <
typename S>
135 virtual Enumerator<T> *
concat(Enumerator<T> *other);
137 static Enumerator<T> *
concatAll(Enumerator<Enumerator<T> *> *inputs);
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>
199class IteratorEnumerator :
public Enumerator<typename std::iterator_traits<Iter>::value_type> {
205 friend class Enumerator<typename
std::iterator_traits<Iter>::value_type>;
208 IteratorEnumerator(Iter begin, Iter end, const char *name)
209 : Enumerator<typename std::iterator_traits<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");
244 typename std::iterator_traits<Iter>::value_type
getCurrent()
const {
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");
260class SingleEnumerator :
public Enumerator<T> {
264 explicit SingleEnumerator(T v) : Enumerator<T>(), value(v) {}
266 switch (this->state) {
267 case EnumeratorState::NotStarted:
268 this->state = EnumeratorState::Valid;
270 case EnumeratorState::PastEnd:
272 case EnumeratorState::Valid:
273 this->state = EnumeratorState::PastEnd;
276 throw std::runtime_error(
"Unexpected enumerator state");
279 switch (this->state) {
280 case EnumeratorState::NotStarted:
281 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
282 case EnumeratorState::PastEnd:
283 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
284 case EnumeratorState::Valid:
287 throw std::runtime_error(
"Unexpected enumerator state");
297 [[nodiscard]] std::string toString()
const {
return "EmptyEnumerator"; }
301 throw std::logic_error(
"You cannot call 'getCurrent' on an EmptyEnumerator");
312template <
typename T,
typename Filter>
313class FilterEnumerator final :
public Enumerator<T> {
314 Enumerator<T> *input;
319 FilterEnumerator(Enumerator<T> *input, Filter filter)
320 : input(input), filter(std::move(filter)) {}
324 this->state = EnumeratorState::Valid;
325 while (this->input->moveNext()) {
326 this->current = this->input->getCurrent();
327 bool match = this->filter(this->current);
328 if (match)
return true;
330 this->state = EnumeratorState::PastEnd;
335 [[nodiscard]] std::string toString()
const {
336 return "FilterEnumerator(" + this->input->toString() +
"):" + this->stateName();
340 this->input->reset();
345 switch (this->state) {
346 case EnumeratorState::NotStarted:
347 case EnumeratorState::Valid:
348 return this->advance();
349 case EnumeratorState::PastEnd:
352 throw std::runtime_error(
"Unexpected enumerator state");
356 switch (this->state) {
357 case EnumeratorState::NotStarted:
358 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
359 case EnumeratorState::PastEnd:
360 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
361 case EnumeratorState::Valid:
362 return this->current;
364 throw std::runtime_error(
"Unexpected enumerator state");
376template <
typename From,
typename To,
typename =
void>
377static constexpr bool can_be_casted =
false;
379template <
typename From,
typename To>
381 can_be_casted<From *, To *, std::void_t<decltype(std::declval<From *>()->template to<To>())>> =
386template <
typename T,
typename S>
387class AsEnumerator final :
public Enumerator<S> {
388 template <
typename U = S>
389 typename std::enable_if_t<!Detail::can_be_casted<T, S>, U> getCurrentImpl()
const {
390 T current = input->getCurrent();
391 return dynamic_cast<S
>(current);
394 template <
typename U = S>
395 typename std::enable_if_t<Detail::can_be_casted<T, S>, U> getCurrentImpl()
const {
396 T current = input->getCurrent();
397 return current->template to<std::remove_pointer_t<S>>();
401 Enumerator<T> *input;
404 explicit AsEnumerator(Enumerator<T> *input) : input(input) {}
406 std::string toString()
const {
407 return "AsEnumerator(" + this->input->toString() +
"):" + this->stateName();
412 this->input->
reset();
416 bool result = this->input->
moveNext();
418 this->state = EnumeratorState::Valid;
420 this->state = EnumeratorState::PastEnd;
430template <
typename T,
typename S,
typename Mapper>
431class MapEnumerator final :
public Enumerator<S> {
433 Enumerator<T> *input;
438 MapEnumerator(Enumerator<T> *input, Mapper map) : input(input), map(std::move(map)) {}
441 this->input->
reset();
445 [[nodiscard]] std::string toString()
const {
446 return "MapEnumerator(" + this->input->toString() +
"):" + this->stateName();
450 switch (this->state) {
451 case EnumeratorState::NotStarted:
452 case EnumeratorState::Valid: {
453 bool success = input->moveNext();
456 this->current = this->map(currentInput);
457 this->state = EnumeratorState::Valid;
460 this->state = EnumeratorState::PastEnd;
464 case EnumeratorState::PastEnd:
467 throw std::runtime_error(
"Unexpected enumerator state");
471 switch (this->state) {
472 case EnumeratorState::NotStarted:
473 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
474 case EnumeratorState::PastEnd:
475 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
476 case EnumeratorState::Valid:
477 return this->current;
479 throw std::runtime_error(
"Unexpected enumerator state");
483template <
typename T,
typename Mapper>
484MapEnumerator(Enumerator<T> *,
485 Mapper) -> MapEnumerator<T, typename std::invoke_result_t<Mapper, T>, Mapper>;
491class ConcatEnumerator final :
public Enumerator<T> {
492 std::vector<Enumerator<T> *> inputs;
496 ConcatEnumerator() =
default;
498 explicit ConcatEnumerator(std::vector<Enumerator<T> *> &&inputs) : inputs(std::move(inputs)) {
499 for (
auto *currentInput : inputs)
500 if (currentInput ==
nullptr)
throw std::logic_error(
"Null iterator in concatenation");
503 ConcatEnumerator(std::initializer_list<Enumerator<T> *> inputs) : inputs(inputs) {
504 for (
auto *currentInput : inputs)
505 if (currentInput ==
nullptr)
throw std::logic_error(
"Null iterator in concatenation");
507 explicit ConcatEnumerator(Enumerator<Enumerator<T> *> *inputs)
508 : ConcatEnumerator(inputs->toVector()) {}
510 [[nodiscard]] std::string toString()
const {
return "ConcatEnumerator:" + this->stateName(); }
514 this->state = EnumeratorState::Valid;
515 for (
auto *currentInput : inputs) {
516 if (currentInput->moveNext()) {
517 this->currentResult = currentInput->getCurrent();
522 this->state = EnumeratorState::PastEnd;
527 Enumerator<T> *
concat(Enumerator<T> *other)
override {
529 if (this->state == EnumeratorState::PastEnd)
530 throw std::runtime_error(
"Invalid enumerator state to concatenate");
532 inputs.push_back(other);
538 for (
auto *currentInput : inputs) currentInput->reset();
543 switch (this->state) {
544 case EnumeratorState::NotStarted:
545 case EnumeratorState::Valid:
546 return this->advance();
547 case EnumeratorState::PastEnd:
550 throw std::runtime_error(
"Unexpected enumerator state");
554 switch (this->state) {
555 case EnumeratorState::NotStarted:
556 throw std::logic_error(
"You cannot call 'getCurrent' before 'moveNext'");
557 case EnumeratorState::PastEnd:
558 throw std::logic_error(
"You cannot call 'getCurrent' past the collection end");
559 case EnumeratorState::Valid:
560 return this->currentResult;
562 throw std::runtime_error(
"Unexpected enumerator state");
569template <
typename Mapper>
581template <
typename Filter>
587template <
typename Container>
593Enumerator<T> *Enumerator<T>::emptyEnumerator() {
594 return new EmptyEnumerator<T>();
598template <
typename Iter>
599Enumerator<typename Iter::value_type> *Enumerator<T>::createEnumerator(Iter begin, Iter end) {
600 return new IteratorEnumerator(begin, end,
"iterator");
604template <
typename Iter>
622T EnumeratorHandle<T>::operator*()
const {
623 if (enumerator ==
nullptr)
throw std::logic_error(
"Dereferencing end() iterator");
624 return enumerator->getCurrent();
628const EnumeratorHandle<T> &EnumeratorHandle<T>::operator++() {
629 enumerator->moveNext();
634bool EnumeratorHandle<T>::operator!=(
const EnumeratorHandle<T> &other)
const {
635 if (this->enumerator == other.enumerator)
return true;
636 if (other.enumerator !=
nullptr)
throw std::logic_error(
"Comparison with different iterator");
637 return this->enumerator->state == EnumeratorState::Valid;
640template <
typename Iter>
645template <
typename Iter>
650template <
typename Container>
663template <
typename... Args>
664auto concat(Args &&...inputs) {
665 using FirstEnumeratorTy =
666 std::remove_pointer_t<std::decay_t<std::tuple_element_t<0, std::tuple<Args...>>>>;
667 std::initializer_list<Enumerator<typename FirstEnumeratorTy::value_type> *> init{
668 std::forward<Args>(inputs)...};
Casts each element.
Definition enumerator.h:387
S getCurrent() const override
Get current element in the collection.
Definition enumerator.h:424
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:410
bool moveNext() override
Definition enumerator.h:415
Concatenation.
Definition enumerator.h:491
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:537
bool moveNext() override
Definition enumerator.h:542
T getCurrent() const override
Get current element in the collection.
Definition enumerator.h:553
Enumerator< T > * concat(Enumerator< T > *other) override
Append all elements of other after all elements of this.
Definition enumerator.h:527
Always empty iterator (equivalent to end())
Definition enumerator.h:295
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:300
bool moveNext()
Always returns false.
Definition enumerator.h:299
Definition enumerator.h:48
Type-erased Enumerator interface.
Definition enumerator.h:68
Enumerator< S > * as()
Cast to an enumerator of S objects.
Definition enumerator.h:576
Enumerator< std::invoke_result_t< Mapper, T > > * map(Mapper map)
Apply specified function to all elements of this enumerator.
Definition enumerator.h:570
virtual bool moveNext()=0
virtual Enumerator< T > * concat(Enumerator< T > *other)
Append all elements of other after all elements of this.
Definition enumerator.h:615
T nextOrDefault()
Next element, or the default value if none exists.
Definition enumerator.h:177
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
bool any()
True if the enumerator has at least one element.
Definition enumerator.h:153
virtual T getCurrent() const =0
Get current element in the collection.
T next()
Next element; throws if there are no elements.
Definition enumerator.h:184
uint64_t count()
Enumerate all elements and return the count.
Definition enumerator.h:146
T singleOrDefault()
Definition enumerator.h:167
Enumerator< T > * where(Filter filter)
Return an enumerator returning all elements that pass the filter.
Definition enumerator.h:582
static Enumerator< T > * concatAll(Enumerator< Enumerator< T > * > *inputs)
Concatenate all these collections into a single one.
Definition enumerator.h:610
Definition enumerator.h:313
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:355
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:339
bool moveNext()
Definition enumerator.h:344
A generic iterator returning elements of type T.
Definition enumerator.h:199
bool moveNext()
Definition enumerator.h:219
std::iterator_traits< Iter >::value_type getCurrent() const
Get current element in the collection.
Definition enumerator.h:244
Transforms all elements from type T to type S.
Definition enumerator.h:431
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:440
bool moveNext()
Definition enumerator.h:449
S getCurrent() const
Get current element in the collection.
Definition enumerator.h:470
bool moveNext()
Definition enumerator.h:265
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:278
Definition iterator_range.h:44