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");
 
 
 
  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>
 
  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>
 
  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>>();
 
  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>
 
  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: {
 
  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>;
 
  492    std::vector<Enumerator<T> *> inputs;
 
  499        for (
auto *currentInput : inputs)
 
  500            if (currentInput == 
nullptr) 
throw std::logic_error(
"Null iterator in concatenation");
 
  504        for (
auto *currentInput : inputs)
 
  505            if (currentInput == 
nullptr) 
throw std::logic_error(
"Null iterator in concatenation");
 
  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;
 
  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>
 
  605Enumerator<typename Iter::value_type> *Enumerator<T>::createEnumerator(iterator_range<Iter> range) {
 
  606    return new IteratorEnumerator(range.begin(), range.end(), 
"range");
 
 
 
  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>
 
  641Enumerator<typename Iter::value_type> *enumerate(Iter begin, Iter end) {
 
  642    return new IteratorEnumerator(begin, end, 
"iterator");
 
  645template <
typename Iter>
 
  646Enumerator<typename Iter::value_type> *enumerate(iterator_range<Iter> range) {
 
  647    return new IteratorEnumerator(range.begin(), range.end(), 
"range");
 
  650template <
typename Container>
 
  651Enumerator<typename Container::value_type> *enumerate(
const Container &data) {
 
  654    return new IteratorEnumerator(begin(data), end(data), 
typeid(data).name());
 
  659Enumerator<T> *concat(std::initializer_list<Enumerator<T> *> inputs) {
 
  660    return new ConcatEnumerator<T>(inputs);
 
  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
 
bool moveNext() override
Definition enumerator.h:415
 
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:410
 
Concatenation.
Definition enumerator.h:491
 
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
 
void reset() override
Move back to the beginning of the collection.
Definition enumerator.h:537
 
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
 
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:570
 
virtual bool moveNext()=0
 
Enumerator< T > * where(Filter filter)
Return an enumerator returning all elements that pass the filter.
Definition enumerator.h:582
 
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:576
 
static Enumerator< T > * concatAll(Enumerator< Enumerator< T > * > *inputs)
Concatenate all these collections into a single one.
Definition enumerator.h:610
 
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:615
 
Definition enumerator.h:313
 
bool moveNext()
Definition enumerator.h:344
 
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:339
 
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:355
 
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:431
 
bool moveNext()
Definition enumerator.h:449
 
void reset()
Move back to the beginning of the collection.
Definition enumerator.h:440
 
S getCurrent() const
Get current element in the collection.
Definition enumerator.h:470
 
Definition enumerator.h:260
 
T getCurrent() const
Get current element in the collection.
Definition enumerator.h:278
 
bool moveNext()
Definition enumerator.h:265