From 8b458f6af2c27485d3398de6b893f58ee2a5c4bd Mon Sep 17 00:00:00 2001
From: Timo Koch <timo.koch@iws.uni-stuttgart.de>
Date: Tue, 27 Nov 2018 22:51:32 +0100
Subject: [PATCH] [common] Implement partial function for referencing parts of
 a tuple

---
 dumux/common/partial.hh     | 69 +++++++++++++++++++++++++++++++++++
 test/common/CMakeLists.txt  |  2 +
 test/common/test_partial.cc | 73 +++++++++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+)
 create mode 100644 dumux/common/partial.hh
 create mode 100644 test/common/test_partial.cc

diff --git a/dumux/common/partial.hh b/dumux/common/partial.hh
new file mode 100644
index 0000000000..b71be7a825
--- /dev/null
+++ b/dumux/common/partial.hh
@@ -0,0 +1,69 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \ingroup Common
+ * \brief Get only parts of a container or tuple
+ */
+#ifndef DUMUX_COMMON_PARTIAL_HH
+#define DUMUX_COMMON_PARTIAL_HH
+
+#include <tuple>
+#include <type_traits>
+
+#include <dune/istl/multitypeblockvector.hh>
+
+namespace Dumux {
+
+/*!
+ * \brief a function to get a MultiTypeBlockVector with references to some entries of another MultiTypeBlockVector
+ * \param v a MultiTypeBlockVector
+ * \param indices the indices of the entries that should be referenced
+ */
+template<class ...Args, std::size_t ...i>
+auto partial(Dune::MultiTypeBlockVector<Args...>& v, Dune::index_constant<i>... indices)
+{
+    return Dune::MultiTypeBlockVector<std::add_lvalue_reference_t<std::decay_t<std::tuple_element_t<indices, std::tuple<Args...>>>>...>(v[indices]...);
+}
+
+/*!
+ * \brief a function to get a tuple with references to some entries of another tuple
+ * \param v a tuple
+ * \param indices a tuple of indices of the entries that should be referenced
+ */
+template<class ...Args, std::size_t ...i>
+auto partial(std::tuple<Args...>& v, Dune::index_constant<i>... indices)
+{
+    return std::tuple<std::add_lvalue_reference_t<std::decay_t<std::tuple_element_t<indices, std::tuple<Args...>>>>...>(std::get<indices>(v)...);
+}
+
+/*!
+ * \brief a function to get a MultiTypeBlockVector with references to some entries of another MultiTypeBlockVector
+ * \param t an std::tuple or Dune::MultiTypeBlockVector
+ * \param indices a tuple of indices of the entries that should be referenced
+ */
+template<class T, std::size_t ...i>
+auto partial(T& t, std::tuple<Dune::index_constant<i>...> indices)
+{
+    return partial(t, Dune::index_constant<i>{}...);
+}
+
+} // end namespace Dumux
+
+#endif
diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt
index ad388d297d..6670d7e49d 100644
--- a/test/common/CMakeLists.txt
+++ b/test/common/CMakeLists.txt
@@ -6,3 +6,5 @@ add_subdirectory(propertysystem)
 add_subdirectory(spline)
 add_subdirectory(timeloop)
 add_subdirectory(typetraits)
+
+dune_add_test(SOURCES test_partial.cc)
diff --git a/test/common/test_partial.cc b/test/common/test_partial.cc
new file mode 100644
index 0000000000..4166c149e3
--- /dev/null
+++ b/test/common/test_partial.cc
@@ -0,0 +1,73 @@
+#include <config.h>
+
+#include <iostream>
+#include <tuple>
+
+#include <dune/common/indices.hh>
+#include <dune/common/classname.hh>
+#include <dune/common/exceptions.hh>
+#include <dune/common/float_cmp.hh>
+#include <dune/common/fvector.hh>
+#include <dune/istl/bvector.hh>
+#include <dune/istl/multitypeblockvector.hh>
+
+#include <dumux/common/partial.hh>
+
+namespace Dumux {
+
+template<template<class...> class T>
+void runTest()
+{
+    using Block1 = Dune::BlockVector<Dune::FieldVector<double, 1>>;
+    using Block2 = Dune::BlockVector<Dune::FieldVector<double, 3>>;
+
+    Block1 a, b;
+    Block2 c;
+
+    a = {1, 3, 4};
+    b = {4, 5, 6, 7};
+    c = {{1, 2, 3}, {1, 2, 3}};
+
+    using namespace Dune::Indices;
+
+    T<Block1, Block1, Block2> m;
+
+    std::cout << "Testing " << Dune::className(m) << '\n' << std::endl;
+
+    std::get<0>(m) = a;
+    std::get<1>(m) = b;
+    std::get<2>(m) = c;
+
+    auto p = partial(m, _0, _2);
+
+    if (!std::is_same<T<Block1&, Block2&>, std::decay_t<decltype(p)>>::value)
+        DUNE_THROW(Dune::Exception, "Dumux::partial() returned wrong type: " << Dune::className(p));
+
+    std::get<1>(p)[0][0] = 5.0;
+
+    if (!Dune::FloatCmp::eq(std::get<2>(m)[0][0], 5.0))
+        DUNE_THROW(Dune::Exception, "Modifying referenced partial vector failed! (m = " << std::get<2>(m)[0][0] << ", p = " << std::get<1>(p)[0][0] << ")");
+}
+
+} // end namespace Dumux
+
+int main(int argc, char* argv[]) try
+{
+    using namespace Dumux;
+
+    runTest<Dune::MultiTypeBlockVector>();
+    runTest<std::tuple>();
+
+    return 0;
+
+}
+catch (const Dune::Exception& e)
+{
+    std::cout << e << std::endl;
+    return 1;
+}
+catch (...)
+{
+    std::cout << "Unknown exception thrown!" << std::endl;
+    return 1;
+}
-- 
GitLab