Last active
December 28, 2015 16:59
-
-
Save mavam/7532997 to your computer and use it in GitHub Desktop.
Factored new-style ranges based on ideas from Eric Niebler. See http://ericniebler.com/2013/11/07/input-iterators-vs-input-ranges/ for details.
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
#include <iostream> | |
#include <vector> | |
#include "vast/util/range.h" | |
namespace util { | |
template <typename Derived> | |
class range | |
{ | |
Derived& derived() | |
{ | |
return static_cast<Derived&>(*this); | |
} | |
Derived const& derived() const | |
{ | |
return static_cast<Derived const&>(*this); | |
} | |
public: | |
explicit operator bool() const | |
{ | |
return ! empty(); | |
} | |
bool operator!() const | |
{ | |
return empty(); | |
} | |
bool empty() const | |
{ | |
return derived().begin() == derived().end(); | |
} | |
}; | |
template <typename Range> | |
class range_iterator | |
: public iterator_facade< | |
range_iterator<Range>, | |
std::forward_iterator_tag, | |
decltype(std::declval<Range>().dereference()) | |
> | |
{ | |
friend Range; | |
friend iterator_access; | |
public: | |
range_iterator() = default; | |
private: | |
explicit range_iterator(Range& rng) | |
: rng_{&rng} | |
{ | |
} | |
bool equals(range_iterator const& other) const | |
{ | |
return rng_ == other.rng_; | |
} | |
void increment() | |
{ | |
assert(rng_); | |
if (! rng_->increment()) | |
rng_ = nullptr; | |
} | |
auto dereference() const | |
-> decltype(std::declval<Range>().dereference()) | |
{ | |
return rng_->dereference(); | |
} | |
Range* rng_ = nullptr; | |
}; | |
template <typename Derived> | |
class range_facade : public range<range_facade<Derived>> | |
{ | |
public: | |
using iterator = range_iterator<range_facade<Derived>>; | |
using const_iterator = iterator; | |
iterator begin() const | |
{ | |
return iterator{const_cast<range_facade&>(*this)}; | |
} | |
iterator end() const | |
{ | |
return iterator{}; | |
} | |
private: | |
friend iterator; | |
Derived const& derived() const | |
{ | |
return static_cast<Derived const&>(*this); | |
} | |
bool increment() | |
{ | |
return static_cast<Derived*>(this)->next(); | |
} | |
template <typename Hack = Derived> | |
auto dereference() const | |
-> decltype(std::declval<Hack&>().state()) | |
{ | |
return derived().state(); | |
} | |
}; | |
} // namespace util | |
template <typename T> | |
class vector_range : public util::range_facade<vector_range<T>> | |
{ | |
public: | |
explicit vector_range(std::vector<T> const& v) | |
: vec_{&v} | |
{ | |
} | |
private: | |
friend util::range_facade<vector_range<T>>; | |
bool next() | |
{ | |
return ++pos_ < vec_->size(); | |
} | |
T const& state() const | |
{ | |
assert(vec_); | |
assert(vec_ && pos_ < vec_->size()); | |
return vec_->at(pos_); | |
} | |
size_t pos_ = 0; | |
std::vector<T> const* vec_; | |
}; | |
int main() | |
{ | |
std::vector<int> x = {1, 2, 3}; | |
vector_range<int> r{x}; | |
for (auto i : r) | |
std::cout << i << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment