Commit d7694d6a authored by Praetorius, Simon's avatar Praetorius, Simon
Browse files

Merge branch 'feature/mapped_range_view' into 'master'

added backport of transformedRangeView from dune-2.7 git branch

See merge request !88
parents 10aab891 989b5b7c
......@@ -3,6 +3,7 @@ install(FILES
LocalBasisCache.hpp
LocalToGlobalAdapter.hpp
MacroGridFactory.hpp
MappedRangeView.hpp
QuadratureFactory.hpp
Twist.hpp
UniqueBorderPartition.hpp
......
#pragma once
#include <iterator>
#include <type_traits>
#include <amdis/common/TypeTraits.hpp>
namespace AMDiS
{
// NOTE: this is a backport of the dune-common TransformedRangeView with added size() function.
namespace Impl
{
// Helper class to mimic a pointer for proxy objects.
// This is needed to implement operator-> on an iterator
// using proxy-values. It stores the proxy value but
// provides operator-> like a pointer.
template <class ProxyType>
class PointerProxy
{
public:
PointerProxy(ProxyType&& p)
: p_(p)
{}
ProxyType* operator->()
{
return &p_;
}
ProxyType p_;
};
// An iterator transforming a wrapped iterator using
// an unary function. It inherits the iterator-category
// of the underlying iterator.
template <class I, class F, class C = typename std::iterator_traits<I>::iterator_category>
class MappedRangeIterator;
template <class I, class F>
class MappedRangeIterator<I,F,std::forward_iterator_tag>
{
public:
using iterator_category = std::forward_iterator_tag;
using reference = decltype(std::declval<F>()(*(std::declval<I>())));
using value_type = std::decay_t<reference>;
using pointer = PointerProxy<value_type>;
// If we later want to allow standalone MappedRangeIterators,
// we could customize the FunctionPointer to be a default-constructible,
// copy-assignable type storing a function but acting like a pointer
// to function.
using FunctionPointer = const F*;
constexpr MappedRangeIterator(const I& it, FunctionPointer f) noexcept
: it_(it)
, f_(f)
{}
// Explicitly initialize members. Using a plain
//
// constexpr MappedRangeIterator() noexcept {}
//
// would default-initialize the members while
//
// constexpr MappedRangeIterator() noexcept : it_(), f_() {}
//
// leads to value-initialization. This is a case where
// both are really different. If it_ is a raw pointer (i.e. POD)
// then default-initialization leaves it uninitialized while
// value-initialization zero-initializes it.
constexpr MappedRangeIterator() noexcept
: it_()
, f_()
{}
// Dereferencing returns a value created by the function
constexpr reference operator*() const noexcept
{
return (*f_)(*it_);
}
// Dereferencing returns a value created by the function
pointer operator->() const noexcept
{
return (*f_)(*it_);
}
constexpr MappedRangeIterator& operator=(MappedRangeIterator const&) = default;
constexpr bool operator==(const MappedRangeIterator& other) const noexcept
{
return (it_ == other.it_);
}
constexpr bool operator!=(const MappedRangeIterator& other) const noexcept
{
return (it_ != other.it_);
}
MappedRangeIterator& operator++() noexcept
{
++it_;
return *this;
}
MappedRangeIterator operator++(int) noexcept
{
MappedRangeIterator copy(*this);
++(*this);
return copy;
}
protected:
I it_;
FunctionPointer f_;
};
template <class I, class F>
class MappedRangeIterator<I,F,std::bidirectional_iterator_tag>
: public MappedRangeIterator<I,F,std::forward_iterator_tag>
{
protected:
using Base = MappedRangeIterator<I,F,std::forward_iterator_tag>;
using Base::it_;
using Base::f_;
public:
using iterator_category = std::bidirectional_iterator_tag;
using reference = typename Base::reference;
using value_type = typename Base::value_type;
using pointer = typename Base::pointer;
using FunctionPointer = typename Base::FunctionPointer;
// inheriting constructor
using Base::Base;
// Member functions of the forward_iterator that need
// to be redefined because the base class methods return a
// forward_iterator.
constexpr MappedRangeIterator& operator=(MappedRangeIterator const&) = default;
MappedRangeIterator& operator++() noexcept
{
++it_;
return *this;
}
MappedRangeIterator operator++(int) noexcept
{
MappedRangeIterator copy(*this);
++(*this);
return copy;
}
// Additional member functions of bidirectional_iterator
MappedRangeIterator& operator--() noexcept
{
--(this->it_);
return *this;
}
MappedRangeIterator operator--(int) noexcept
{
MappedRangeIterator copy(*this);
--(*this);
return copy;
}
};
template <class I, class F>
class MappedRangeIterator<I,F,std::random_access_iterator_tag>
: public MappedRangeIterator<I,F,std::bidirectional_iterator_tag>
{
protected:
using Base = MappedRangeIterator<I,F,std::bidirectional_iterator_tag>;
using Base::it_;
using Base::f_;
public:
using iterator_category = std::random_access_iterator_tag;
using reference = typename Base::reference;
using value_type = typename Base::value_type;
using pointer = typename Base::pointer;
using difference_type = typename std::iterator_traits<I>::difference_type;
using FunctionPointer = typename Base::FunctionPointer;
// inheriting constructor
using Base::Base;
// Member functions of the forward_iterator that need
// to be redefined because the base class methods return a
// forward_iterator.
constexpr MappedRangeIterator& operator=(MappedRangeIterator const&) = default;
MappedRangeIterator& operator++() noexcept
{
++it_;
return *this;
}
MappedRangeIterator operator++(int) noexcept
{
MappedRangeIterator copy(*this);
++(*this);
return copy;
}
// Member functions of the bidirectional_iterator that need
// to be redefined because the base class methods return a
// bidirectional_iterator.
MappedRangeIterator& operator--() noexcept
{
--(this->it_);
return *this;
}
MappedRangeIterator operator--(int) noexcept
{
MappedRangeIterator copy(*this);
--(*this);
return copy;
}
// Additional member functions of random_access_iterator
MappedRangeIterator& operator+=(difference_type n) noexcept
{
it_ += n;
return *this;
}
MappedRangeIterator& operator-=(difference_type n) noexcept
{
it_ -= n;
return *this;
}
bool operator<(const MappedRangeIterator& other) noexcept
{
return it_<other.it_;
}
bool operator<=(const MappedRangeIterator& other) noexcept
{
return it_<=other.it_;
}
bool operator>(const MappedRangeIterator& other) noexcept
{
return it_>other.it_;
}
bool operator>=(const MappedRangeIterator& other) noexcept
{
return it_>=other.it_;
}
reference operator[](difference_type n) noexcept
{
return (*f_)(*(it_+n));
}
friend
MappedRangeIterator operator+(const MappedRangeIterator& it, difference_type n) noexcept
{
return MappedRangeIterator(it.it_+n, it.f_);
}
friend
MappedRangeIterator operator+(difference_type n, const MappedRangeIterator& it) noexcept
{
return MappedRangeIterator(n+it.it_, it.f_);
}
friend
MappedRangeIterator operator-(const MappedRangeIterator& it, difference_type n) noexcept
{
return MappedRangeIterator(it.it_-n, it.f_);
}
friend
difference_type operator-(const MappedRangeIterator& first, const MappedRangeIterator& second) noexcept
{
return first.it_-second.it_;
}
};
} // namespace Impl
/**
* \brief A range transforming the values of another range on-the-fly
*
* This behaves like a range providing `begin()` and `end()`.
* The iterators over this range internally iterate over
* the wrapped range. When dereferencing the iterator,
* the value is transformed on-the-fly using a given
* transformation function leaving the underlying range
* unchanged.
*
* The transformation may either return temorary values
* or l-value references. In the former case the range behaves
* like a proxy-container. In the latter case it forwards these
* references allowing, e.g., to sort a subset of some container
* by applying a transformation to an index-range for those values.
*
* The iterators of the MappedRangeView have the same
* iterator_category as the ones of the wrapped container.
*
* If range is given as r-value, then the returned MappedRangeView
* stores it by value, if range is given as (const) l-value, then the
* MappedRangeView stores it by (const) reference.
*
* If R is a value type, then the MappedRangeView stores the wrapped range by value,
* if R is a reference type, then the MappedRangeView stores the wrapped range by reference.
*
* \tparam R Underlying range.
* \tparam F Unary function used to transform the values in the underlying range.
**/
template <class R, class F>
class MappedRangeView
{
using RawConstIterator = TYPEOF(std::declval<const R>().begin());
using RawIterator = TYPEOF(std::declval<R>().begin());
public:
/**
* \brief Iterator type
*
* This inherits the iterator_category of the iterators
* of the underlying range.
*/
using const_iterator = Impl::MappedRangeIterator<RawConstIterator, F>;
using iterator = Impl::MappedRangeIterator<RawIterator, F>;
/**
* \brief Construct from range and function
*/
template <class RR>
constexpr MappedRangeView(RR&& rawRange, F const& f) noexcept
: rawRange_(FWD(rawRange))
, f_(f)
{}
/**
* \brief Obtain a iterator to the first element
*
* The life time of the returned iterator is bound to
* the life time of the range since it only contains a
* pointer to the transformation function stored
* in the range.
*/
constexpr const_iterator begin() const noexcept
{
return const_iterator(rawRange_.begin(), &f_);
}
constexpr iterator begin() noexcept
{
return iterator(rawRange_.begin(), &f_);
}
/**
* \brief Return the number of elements in the range, if availble.
*
* Note, this function is only availble if the underlying raw range
* knows its size and provides a function `size()`.
*/
template <class RR = R, class = decltype(std::declval<RR>().size())>
constexpr auto size() const noexcept
{
return rawRange_.size();
}
/// Provide element access for random-accessible ranges
template <class RR = R, class = decltype(std::declval<RR>().operator[](std::size_t(0)))>
decltype(auto) operator[](std::size_t i) const
{
return f_(rawRange_[i]);
}
/**
* \brief Checks whether the range is empty
*/
constexpr bool empty() const noexcept
{
return rawRange_.begin() == rawRange_.end();
}
/**
* \brief Obtain a iterator past the last element
*
* The life time of the returned iterator is bound to
* the life time of the range since it only contains a
* pointer to the transformation function stored
* in the range.
*/
constexpr const_iterator end() const noexcept
{
return const_iterator(rawRange_.end(), &f_);
}
constexpr iterator end() noexcept
{
return iterator(rawRange_.end(), &f_);
}
private:
R rawRange_;
F f_;
};
/**
* \brief Create a MappedRangeView
*
* \param range The range the transform
* \param f Unary function that should the applied to the entries of the range.
*
* This behaves like a range providing `begin()` and `end()`.
* The iterators over this range internally iterate over
* the wrapped range. When dereferencing the iterator,
* the value is transformed on-the-fly using a given
* transformation function leaving the underlying range
* unchanged.
*
* The transformation may either return temporary values
* or l-value references. In the former case the range behaves
* like a proxy-container. In the latter case it forwards these
* references allowing, e.g., to sort a subset of some container
* by applying a transformation to an index-range for those values.
*
* The iterators of the MappedRangeView have the same
* iterator_category as the ones of the wrapped container.
*
* If range is an r-value, then the MappedRangeView stores it by value,
* if range is an l-value, then the MappedRangeView stores it by reference.
**/
template <class R, class F>
auto mappedRangeView(R&& range, F const& f)
{
return MappedRangeView<R, F>(FWD(range), f);
}
template <class Iter, class F>
auto mappedIterator(Iter it, F const* f)
{
using iterator = Impl::MappedRangeIterator<Iter, F>;
return iterator(it, f);
}
template <class ConstIter, class F>
auto mappedConstIterator(ConstIter it, F const* f)
{
using const_iterator = Impl::MappedRangeIterator<ConstIter, F>;
return const_iterator(it, f);
}
} // end namespace AMDiS
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment