Last active
August 29, 2015 14:23
-
-
Save Manu343726/cd7b345e91d30271b1de to your computer and use it in GitHub Desktop.
Type-erased C++ ranges
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
// | |
// 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