Skip to content

Instantly share code, notes, and snippets.

@mavam
Last active December 28, 2015 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mavam/7532997 to your computer and use it in GitHub Desktop.
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.
#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