Skip to content

Instantly share code, notes, and snippets.

@Manu343726
Last active August 29, 2015 14:23
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 Manu343726/cd7b345e91d30271b1de to your computer and use it in GitHub Desktop.
Save Manu343726/cd7b345e91d30271b1de to your computer and use it in GitHub Desktop.
Type-erased C++ ranges
//
// Created by manu343726 on 16/06/15.
//
#ifndef ERASED_RANGE_HPP
#define ERASED_RANGE_HPP
#include <range/v3/all.hpp>
#include <type_traits>
template<typename ValueType>
struct erased_iterator
{
template<typename It>
erased_iterator(It it) : it_{new PolyIterator<It>{it}}
{}
erased_iterator() = default;
erased_iterator& operator++()
{
it_->next();
return *this;
}
erased_iterator& operator--()
{
it_->prev();
return *this;
}
erased_iterator operator++(int)
{
erased_iterator tmp{*this};
++(*this);
return std::move(tmp);
}
erased_iterator operator--(int)
{
erased_iterator tmp{*this};
--(*this);
return std::move(tmp);
}
template<typename It>
erased_iterator& operator=(It&& it)
{
if(it_ != nullptr) {
it_->~iterator_base();
it_ = new(it_) PolyIterator <typename std::decay<It>::type>{it};
}
else
it_ = new PolyIterator<typename std::decay<It>::type>{it};
return *this;
}
const ValueType& operator*() const
{
return it_->deref();
}
ValueType& operator*()
{
return it_->deref();
}
friend bool operator==(const erased_iterator& lhs, const erased_iterator& rhs)
{
return *(lhs.it_) == *(rhs.it_);
}
friend bool operator!=(const erased_iterator& lhs, const erased_iterator& rhs)
{
return !(lhs == rhs);
}
erased_iterator(const erased_iterator& other) :
it_{other.it_->clone()}
{}
erased_iterator(erased_iterator&& other) :
it_{std::move(other.it_)}
{
other.it_ = nullptr;
}
erased_iterator& operator=(const erased_iterator& other)
{
if(it_ != nullptr)
it_ = other.it_->clone(it_);
else
it_ = other.it_->clone();
return *this;
}
erased_iterator& operator=(erased_iterator&& other)
{
std::swap(*this, other);
return *this;
}
~erased_iterator()
{
delete it_;
}
private:
struct iterator_base
{
virtual iterator_base& next() = 0;
virtual iterator_base& prev() = 0;
virtual const ValueType& deref() const = 0;
virtual ValueType& deref() = 0;
virtual bool equals(const iterator_base& lhs, const iterator_base& rhs) const = 0;
virtual iterator_base* clone() const = 0;
virtual iterator_base* clone(iterator_base*) const = 0;
virtual ~iterator_base() = default;
friend bool operator==(const iterator_base& lhs, const iterator_base& rhs)
{
return lhs.equals(lhs, rhs);
}
friend bool operator !=(const iterator_base& lhs, const iterator_base& rhs)
{
return !(lhs == rhs);
}
};
template<typename It>
struct PolyIterator : public iterator_base
{
friend class erased_iterator;
PolyIterator(It it) : it_{it}
{}
iterator_base& next() override
{
it_ = std::next(it_);
return *this;
}
iterator_base& prev() override
{
it_ = std::prev(it_);
return *this;
}
const ValueType& deref() const override
{
return static_cast<const ValueType&>(*it_);
}
ValueType& deref() override
{
return static_cast<ValueType&>(*it_);
}
bool equals(const iterator_base& lhs, const iterator_base& rhs) const override
{
return reinterpret_cast<const PolyIterator&>(lhs).it_ == reinterpret_cast<const PolyIterator&>(rhs).it_;
}
iterator_base* clone() const override
{
return new PolyIterator{it_};
}
iterator_base* clone(iterator_base* ptr) const override
{
ptr->~iterator_base();
return new(ptr) PolyIterator{it_};
}
private:
It it_;
};
iterator_base* it_ = nullptr;
};
template<typename ValueType>
struct erased_range
{
using iterator = erased_iterator<ValueType>;
using value_type = ValueType;
erased_range() = default;
template<typename Range>
erased_range(const Range& range)
{
auto bounded = ranges::view::bounded(range);
begin_ = std::begin(bounded);
end_ = std::end(bounded);
}
template<typename Range>
erased_range(Range& range)
{
auto bounded = ranges::view::bounded(range);
begin_ = std::begin(bounded);
end_ = std::end(bounded);
}
template<typename Range>
erased_range& operator=(const Range& range)
{
auto bounded = ranges::view::bounded(range);
begin_ = std::begin(range);
end_ = std::end(range);
return *this;
}
template<typename Range>
erased_range& operator=(Range& range)
{
auto bounded = ranges::view::bounded(range);
begin_ = std::begin(range);
end_ = std::end(range);
return *this;
}
iterator begin() const
{
return begin_;
}
iterator end() const
{
return end_;
}
private:
iterator begin_;
iterator end_;
};
#endif //ERASED_RANGE_HPP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment