Skip to content

Instantly share code, notes, and snippets.

@jeremy-rifkin
Last active March 26, 2021 01:06
Show Gist options
  • Save jeremy-rifkin/e875086a478301b59cddd8fd346b29c3 to your computer and use it in GitHub Desktop.
Save jeremy-rifkin/e875086a478301b59cddd8fd346b29c3 to your computer and use it in GitHub Desktop.
C++ range iterator
#include <cmath>
#include <cassert>
#include <type_traits>
template<typename T> int sign(T t) {
return t < 0 ? -1 : 1;
}
template<typename T> class range {
typedef typename std::make_signed<T>::type ST;
T start;
T stop; // stored inclusively internally
ST step;
bool is_inclusive = false;
bool is_reversed = false;
public:
range(T stop) : range(0, stop) {}
range(T start, T stop) : range(start, stop, 1) {}
range(T start, T stop, ST step) : start(start), stop(stop + (start < stop ? -1 : 1)), step(step) {
// check bad range
assert(step != 0);
if(start < stop) assert(step > 0); // forwards range
if(stop < start) assert(step < 0); // null range or backwards range
}
private:
range(T start, T stop, ST step, bool is_inclusive, bool is_reversed)
: start(start), stop(stop), step(step), is_inclusive(is_inclusive), is_reversed(is_reversed) {}
public:
range reverse() {
return *this = range(get_end(), get_start(), -step, is_inclusive, !is_reversed);
}
range inclusive() {
if(!is_inclusive) {
if(is_reversed) {
*this = range(start - sign(step), stop, step, true, is_reversed);
} else {
*this = range(start, stop + sign(step), step, true, is_reversed);
}
}
return *this;
}
T size() const {
return std::abs(get_past_end() - get_start());
}
private:
T get_start() const {
return start;
}
T get_end() const {
if(start < stop) {
return start + (stop - start) / step;
} else {
return start - (stop - start) / step;
}
}
T get_past_end() const {
return get_end() + sign(step);
}
public:
class const_iterator {
T i;
const range& r;
public:
const_iterator(const range& r, int i) : i(i), r(r) {}
const_iterator operator++() { auto i = *this; operator++(0); return i; }
const_iterator operator++(int) { i += r.step; return *this; }
T operator*() const { return i; }
bool operator==(const const_iterator& o) const { return i == o.i; }
bool operator!=(const const_iterator& o) const { return !operator==(o); }
};
const_iterator begin() const { return const_iterator(*this, get_start()); }
const_iterator end() const { return const_iterator(*this, get_past_end()); }
};
// example:
// for(auto i : range(12)) {
// ...
// }
// for(auto i : range(12).inclusive().reverse()) {
// ...
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment