Last active
October 24, 2023 13:46
-
-
Save maxrt101/aacaabe28dc28f56d9a50531ad13fcff to your computer and use it in GitHub Desktop.
Implementation of range(), enumerate() and zip(), similar in functionality to corresponding python functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* generator.h v1.0 by maxrt101 | |
* Header that provides functionality similar to python's generators, | |
* including implementations for range(), enumarate() and zip() | |
*/ | |
#ifndef _MRT_UTILS_GENERATOR_H_ | |
#define _MRT_UTILS_GENERATOR_H_ 1 | |
#include <exception> | |
#include <functional> | |
#include <utility> | |
namespace mrt { | |
struct GeneratorException : public std::exception { | |
inline GeneratorException() {} | |
}; | |
template <typename T> | |
class Generator { | |
public: | |
using Function = std::function<T(size_t)>; | |
class Iterator { | |
public: | |
inline Iterator() {} | |
inline Iterator(Function fn) : m_function(fn) { | |
operator++(); | |
} | |
inline T operator*() { | |
return m_lastValue; | |
} | |
inline const T operator*() const { | |
return m_lastValue; | |
} | |
inline Iterator& operator++() { | |
try { | |
m_lastValue = m_function(m_counter++); | |
} catch (GeneratorException e) { | |
m_isEnded = true; | |
} | |
return *this; | |
} | |
inline Iterator operator++(int) { | |
Iterator it = *this; | |
try { | |
m_lastValue = m_function(++m_counter); | |
} catch (GeneratorException e) { | |
m_isEnded = true; | |
} | |
return it; | |
} | |
inline bool operator==(const Iterator& rhs) const { | |
return m_isEnded; | |
} | |
inline bool operator!=(const Iterator& rhs) const { | |
return !m_isEnded; | |
} | |
private: | |
Function m_function; | |
size_t m_counter = 0; | |
T m_lastValue; | |
bool m_isEnded = false; | |
}; | |
public: | |
inline Generator(Function fn) : m_function(fn) {} | |
inline Iterator begin() { | |
return Iterator(m_function); | |
} | |
inline Iterator end() { | |
return Iterator(); | |
} | |
inline Iterator cbegin() const { | |
return Iterator(m_function); | |
} | |
inline Iterator cend() const { | |
return Iterator(); | |
} | |
void foreach(std::function<void(const T&)> f) { | |
for (auto iter : *this) { | |
f(iter); | |
} | |
} | |
private: | |
Function m_function; | |
}; | |
namespace { | |
template <typename T, typename I> | |
struct Enumerator { | |
I begin, end; | |
inline Enumerator(I begin, I end) : begin(begin), end(end) {} | |
inline std::pair<size_t, T> operator()(size_t count) { | |
if (begin == end) throw GeneratorException(); | |
return {count, *begin++}; | |
} | |
}; | |
struct RangeGenerator { | |
size_t begin, end, step, counter = 0; | |
inline RangeGenerator(size_t begin, size_t end, size_t step) : begin(begin), end(end), step(step) { | |
if (end == -1UL) { | |
this->begin = 0; | |
this->end = begin; | |
} | |
} | |
inline size_t operator()(size_t count) { | |
if (begin && counter < begin) counter = begin; | |
if (counter >= end) throw GeneratorException(); | |
size_t result = counter; | |
counter += step; | |
return result; | |
} | |
}; | |
template <typename T1, typename T2, typename I1, typename I2> | |
struct ZipGenerator { | |
I1 begin1, end1; | |
I2 begin2, end2; | |
inline ZipGenerator(I1 begin1, I1 end1, I2 begin2, I2 end2) | |
: begin1(begin1), end1(end1), begin2(begin2), end2(end2) {} | |
inline std::pair<T1, T2> operator()(size_t count) { | |
if (begin1 == end1 || begin2 == end2) throw GeneratorException(); | |
return {*begin1++, *begin2++}; | |
} | |
}; | |
} /* impl */ | |
// yield from generator ??? maybe not yield | |
inline void yield() { | |
throw GeneratorException(); | |
} | |
inline Generator<size_t> range(size_t begin, size_t end = -1UL, size_t step = 1) { | |
return {RangeGenerator(begin, end, step)}; | |
} | |
template <typename T, typename I> | |
inline Generator<std::pair<size_t, T>> enumerate(const I& i) { | |
return {Enumerator<T, decltype(i.cbegin())>(i.cbegin(), i.cend())}; | |
} | |
template <typename T1, typename T2, typename I1, typename I2> | |
inline Generator<std::pair<T1, T2>> zip(const I1& i1, const I2& i2) { | |
return {ZipGenerator<T1, T2, decltype(i1.cbegin()), decltype(i2.cbegin())>( | |
i1.cbegin(), i1.cend(), i2.cbegin(), i2.cend() | |
)}; | |
} | |
} /* namespace mrt */ | |
#endif /* _MRT_UTILS_GENERATOR_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment