Last active
February 8, 2018 15:41
-
-
Save cglosser/9dc68a7aa6eab361352402660fafe82a to your computer and use it in GitHub Desktop.
Stateful, python-like ranges and enumerations for C++ iterables
This file contains hidden or 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
#include <algorithm> | |
#include <iostream> | |
#include <set> | |
#include <vector> | |
template <class T> | |
class Range { | |
public: | |
Range(const T upper) : Range(0, upper, 1) {} | |
Range(const T lower, const T upper) : Range(lower, upper, 1) {} | |
Range(const T lower, const T upper, const T step) | |
: lower_(lower), upper_(upper), step_(step) {} | |
class iterator { | |
public: | |
iterator(const Range &r, const T val) : owner_(r), val_(val) {} | |
T operator*() const { return val_; } | |
bool operator!=(const iterator &other) const { return val_ < other.val_; } | |
iterator operator++() { | |
val_ += owner_.step_; | |
return *this; | |
} | |
iterator reset() { | |
val_ = lower_; | |
return *this; | |
} | |
private: | |
const Range &owner_; | |
T val_; | |
}; | |
iterator begin() const { return iterator(*this, lower_); } | |
iterator end() const { return iterator(*this, upper_); } | |
private: | |
T lower_, upper_, step_; | |
}; | |
template <class T> | |
Range<T> range(T low, T up, T step) { | |
return Range<T>(low, up, step); | |
} | |
template <class T> | |
class Range3D { | |
public: | |
Range3D(const T max) : Range3D({max, max}, {max, max}, {max, max}) {} | |
Range3D(std::pair<T, T> xbounds, std::pair<T, T> ybounds, | |
std::pair<T, T> zbounds) | |
: xbounds_{xbounds}, ybounds_{ybounds}, zbounds_{zbounds} {} | |
class iterator { | |
public: | |
iterator(const Range3D &r, const T x, const T y, const T z) | |
: owner_{r}, x_{x}, y_{y}, z_{z} {} | |
const iterator &operator*() const { return *this; } | |
bool operator!=(const iterator &other) const { | |
return x_ != other.x_ && y_ != other.y_ && z_ != other.z_; | |
} | |
iterator operator++() { | |
++z_; | |
if (z_ == owner_.zbounds_.second) { | |
z_ = owner_.zbounds_.first; | |
++y_; | |
if (y_ == owner_.ybounds_.second) { | |
y_ = owner_.ybounds_.first; | |
++x_; | |
} | |
} | |
return *this; | |
} | |
T x() const { return x_; } | |
T y() const { return y_; } | |
T z() const { return z_; } | |
private: | |
const Range3D &owner_; | |
T x_, y_, z_; | |
}; | |
iterator begin() const { | |
return iterator{*this, xbounds_.first, ybounds_.first, zbounds_.first}; | |
} | |
iterator end() const { | |
return iterator{*this, xbounds_.second, ybounds_.second, zbounds_.second}; | |
} | |
private: | |
std::pair<T, T> xbounds_, ybounds_, zbounds_; | |
}; | |
template <class T, class U> | |
class Enumeration { | |
public: | |
Enumeration(const T &begin, const T &end) : Enumeration(begin, end, 0) {} | |
Enumeration(const T &begin, const T &end, int start_idx) | |
: begin_{begin}, end_{end}, start_idx_{start_idx} {}; | |
class iterator { | |
public: | |
iterator(const Enumeration &e, const T val) | |
: owner_(e), val_(val), idx_(e.start_idx_) {} | |
iterator operator*() const { return *this; } | |
bool operator!=(const iterator &other) const { return val_ != other.val_; } | |
iterator operator++() { | |
++val_; | |
++idx_; | |
return *this; | |
} | |
int idx() const { return idx_; } | |
U value() const { return *val_; } | |
private: | |
const Enumeration &owner_; | |
T val_; | |
int idx_; | |
}; | |
iterator begin() { return iterator{*this, begin_}; } | |
iterator end() { return iterator{*this, end_}; } | |
private: | |
T begin_, end_; | |
int start_idx_; | |
}; | |
template <class T> | |
auto enumerate(const T &begin, const T &end, int i0 = 0) { | |
return Enumeration<T, decltype(*begin)>(begin, end, i0); | |
} | |
int main() { | |
std::vector<int> x{10, 20, 30, 40, 50}; | |
for (const auto &e : enumerate(x.begin(), x.end())) { | |
std::cout << e.idx() << " " << e.value() << std::endl; | |
} | |
std::cout << std::endl; | |
std::set<int> y{10, 20, 3, 3, 40, 10, 50}; | |
for (const auto &e : enumerate(y.begin(), y.end())) { | |
std::cout << e.idx() << " " << e.value() << std::endl; | |
} | |
std::cout << std::endl; | |
std::string s{"The cake is a lie!"}; | |
for (const auto &e : enumerate(s.begin(), s.end())) { | |
std::cout << e.idx() << " " << e.value() << std::endl; | |
} | |
for(const auto &i : Range3D<int>({0, 3}, {0, 3}, {0, 3})) { | |
std::cout << i.x() << " " << i.y() << " " << i.z() << std::endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment