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