From 989b5b7c9517ae8fa74d70020c19f70150d3542c Mon Sep 17 00:00:00 2001 From: "Praetorius, Simon" <simon.praetorius@tu-dresden.de> Date: Wed, 28 Aug 2019 12:33:31 +0200 Subject: [PATCH] added backport of transformedRangeView from dune-2.7 git branch --- src/amdis/utility/CMakeLists.txt | 1 + src/amdis/utility/MappedRangeView.hpp | 467 ++++++++++++++++++++++++++ 2 files changed, 468 insertions(+) create mode 100644 src/amdis/utility/MappedRangeView.hpp diff --git a/src/amdis/utility/CMakeLists.txt b/src/amdis/utility/CMakeLists.txt index ec1450c4..18282991 100644 --- a/src/amdis/utility/CMakeLists.txt +++ b/src/amdis/utility/CMakeLists.txt @@ -3,6 +3,7 @@ install(FILES LocalBasisCache.hpp LocalToGlobalAdapter.hpp MacroGridFactory.hpp + MappedRangeView.hpp QuadratureFactory.hpp Twist.hpp UniqueBorderPartition.hpp diff --git a/src/amdis/utility/MappedRangeView.hpp b/src/amdis/utility/MappedRangeView.hpp new file mode 100644 index 00000000..bc137787 --- /dev/null +++ b/src/amdis/utility/MappedRangeView.hpp @@ -0,0 +1,467 @@ +#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 -- GitLab