neobytes/src/immer/detail/iterator_facade.hpp
Alexander Block e002c50b04 Add "immer" functional/immutable containers library (#2244)
Add "immer" functional/immutable containers library
2018-08-29 16:31:21 +03:00

203 lines
5.2 KiB
C++

//
// immer: immutable data structures for C++
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
//
// This software is distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
//
#pragma once
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace immer {
namespace detail {
struct iterator_core_access
{
template <typename T>
static decltype(auto) dereference(T&& x)
{ return x.dereference(); }
template <typename T>
static decltype(auto) increment(T&& x)
{ return x.increment(); }
template <typename T>
static decltype(auto) decrement(T&& x)
{ return x.decrement(); }
template <typename T1, typename T2>
static decltype(auto) equal(T1&& x1, T2&& x2)
{ return x1.equal(x2); }
template <typename T, typename D>
static decltype(auto) advance(T&& x, D d)
{ return x.advance(d); }
template <typename T1, typename T2>
static decltype(auto) distance_to(T1&& x1, T2&& x2)
{ return x1.distance_to(x2); }
};
/*!
* Minimalistic reimplementation of boost::iterator_facade
*/
template <typename DerivedT,
typename IteratorCategoryT,
typename T,
typename ReferenceT = T&,
typename DifferenceTypeT = std::ptrdiff_t,
typename PointerT = T*>
class iterator_facade
: public std::iterator<IteratorCategoryT,
T,
DifferenceTypeT,
PointerT,
ReferenceT>
{
protected:
using access_t = iterator_core_access;
constexpr static auto is_random_access =
std::is_base_of<std::random_access_iterator_tag,
IteratorCategoryT>::value;
constexpr static auto is_bidirectional =
std::is_base_of<std::bidirectional_iterator_tag,
IteratorCategoryT>::value;
class reference_proxy
{
friend iterator_facade;
DerivedT iter_;
reference_proxy(DerivedT iter)
: iter_{std::move(iter)} {}
public:
operator ReferenceT() const { return *iter_; }
};
const DerivedT& derived() const
{
static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
"must pass a derived thing");
return *static_cast<const DerivedT*>(this);
}
DerivedT& derived()
{
static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
"must pass a derived thing");
return *static_cast<DerivedT*>(this);
}
public:
ReferenceT operator*() const
{
return access_t::dereference(derived());
}
PointerT operator->() const
{
return &access_t::dereference(derived());
}
reference_proxy operator[](DifferenceTypeT n) const
{
static_assert(is_random_access, "");
return derived() + n;
}
bool operator==(const DerivedT& rhs) const
{
return access_t::equal(derived(), rhs);
}
bool operator!=(const DerivedT& rhs) const
{
return !access_t::equal(derived(), rhs);
}
DerivedT& operator++()
{
access_t::increment(derived());
return derived();
}
DerivedT operator++(int)
{
auto tmp = derived();
access_t::increment(derived());
return tmp;
}
DerivedT& operator--()
{
static_assert(is_bidirectional || is_random_access, "");
access_t::decrement(derived());
return derived();
}
DerivedT operator--(int)
{
static_assert(is_bidirectional || is_random_access, "");
auto tmp = derived();
access_t::decrement(derived());
return tmp;
}
DerivedT& operator+=(DifferenceTypeT n)
{
access_t::advance(derived(), n);
return derived();
}
DerivedT& operator-=(DifferenceTypeT n)
{
access_t::advance(derived(), -n);
return derived();
}
DerivedT operator+(DifferenceTypeT n) const
{
static_assert(is_random_access, "");
auto tmp = derived();
return tmp += n;
}
friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i)
{
static_assert(is_random_access, "");
return i + n;
}
DerivedT operator-(DifferenceTypeT n) const
{
static_assert(is_random_access, "");
auto tmp = derived();
return tmp -= n;
}
DifferenceTypeT operator-(const DerivedT& rhs) const
{
static_assert(is_random_access, "");
return access_t::distance_to(rhs, derived());
}
bool operator<(const DerivedT& rhs) const
{
static_assert(is_random_access, "");
return access_t::distance_to(derived(), rhs) > 0;
}
bool operator<=(const DerivedT& rhs) const
{
static_assert(is_random_access, "");
return access_t::distance_to(derived(), rhs) >= 0;
}
bool operator>(const DerivedT& rhs) const
{
static_assert(is_random_access, "");
return access_t::distance_to(derived(), rhs) < 0;
}
bool operator>=(const DerivedT& rhs) const
{
static_assert(is_random_access, "");
return access_t::distance_to(derived(), rhs) <= 0;
}
};
} // namespace detail
} // namespace immer