From 0be82d488c3ab44a51709187f75f2c912ef52d41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carsten=20Gr=C3=A4ser?= <graeser@dune-project.org>
Date: Mon, 12 Dec 2022 12:22:53 +0100
Subject: [PATCH] Improve specializations of Hybrid::size()

The interfaces tested subsequently for `Hybrid::size(const T& t)` are now

* standard tuple-like interface `std::tuple_size<T>::value` (e.g. needed for `std::tuple`),
* static constexpr `T::size()` (e.g. needed for `Dune::TupleVector`),
* dynamic member function `t.size()` (e.g. needed for `std::vector`).

This patch removes a special case for `FieldVector` which is already covered
by the `static constexpr size()` case. To ensure this, a corresponding test
case was added. Also the documentation of the different cases was fixed.

Notice that this does not work necessarily with matrices, because many of them
only provide a (potentially `static constexpr`) method `N()` instead of `size()`.
---
 dune/common/hybridutilities.hh          | 20 ++++++--------------
 dune/common/test/hybridutilitiestest.cc | 14 +++++++++++++-
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/dune/common/hybridutilities.hh b/dune/common/hybridutilities.hh
index 2c120286f..25e74c016 100644
--- a/dune/common/hybridutilities.hh
+++ b/dune/common/hybridutilities.hh
@@ -22,23 +22,15 @@ namespace Hybrid {
 
 namespace Impl {
 
-  // Try if tuple_size is implemented for class
-  template<class T, int i>
-  constexpr auto size(const Dune::FieldVector<T, i>&, const PriorityTag<5>&)
-    -> decltype(std::integral_constant<std::size_t,i>())
-  {
-    return {};
-  }
-
-  // Try if tuple_size is implemented for class
+  // Try if std::tuple_size is implemented for class
   template<class T>
-  constexpr auto size(const T&, const PriorityTag<3>&)
+  constexpr auto size(const T&, const PriorityTag<2>&)
     -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
   {
     return {};
   }
 
-  // Try if there's a static constexpr size()
+  // Try if there's a static constexpr size() method
   template<class T>
   constexpr auto size(const T&, const PriorityTag<1>&)
     -> decltype(std::integral_constant<std::size_t,T::size()>())
@@ -46,7 +38,7 @@ namespace Impl {
     return {};
   }
 
-  // As a last resort try if there's a static constexpr size()
+  // As a last resort try if there's a non-static size()
   template<class T>
   constexpr auto size(const T& t, const PriorityTag<0>&)
   {
@@ -75,8 +67,8 @@ namespace Impl {
  * Supported types for deriving the size at compile time are:
  * * instances of std::integer_sequence
  * * all types std::tuple_size is implemented for
- * * all typed that have a static method ::size()
- * * instances of Dune::FieldVector
+ * * all types that have a static constexpr method ::size()
+ * The latter e.g. includes Dune::FieldVector
  */
 template<class T>
 constexpr auto size(const T& t)
diff --git a/dune/common/test/hybridutilitiestest.cc b/dune/common/test/hybridutilitiestest.cc
index 749ba2e66..41a975b00 100644
--- a/dune/common/test/hybridutilitiestest.cc
+++ b/dune/common/test/hybridutilitiestest.cc
@@ -173,6 +173,7 @@ int main()
 {
   std::size_t one = 1; // run-time value
   auto vector = std::vector<int>{1, 2, 3};
+  auto fieldVector = Dune::FieldVector<double,3>({1, 2, 3});
   auto numberTuple = Dune::makeTupleVector(0.1, 2, 3);
 
   Dune::TestSuite test;
@@ -208,6 +209,10 @@ int main()
   test.check(numberTuple == Dune::makeTupleVector(1.1, 3, 4))
     << "Incrementing tuple entries with Hybrid::forEach failed.";
 
+  incrementAll(fieldVector);
+  test.check(fieldVector == Dune::FieldVector<double,3>({2, 3, 4}))
+    << "Incrementing FieldVector entries with Hybrid::forEach failed.";
+
   addIndex(vector);
   test.check(vector == std::vector<int>{2, 4, 6})
     << "Adding indices to vector entries with Hybrid::forEach failed.";
@@ -215,7 +220,14 @@ int main()
   addIndex(numberTuple);
   test.check(numberTuple == Dune::makeTupleVector(1.1, 4, 6))
     << "Adding indices to vector entries with Hybrid::forEach failed.";
-
+  test.check(Dune::IsIntegralConstant<decltype(Dune::Hybrid::size(numberTuple))>::value)
+    << "Hybrid::size() of std::tuple is not an std::integral_constant.";
+
+  addIndex(fieldVector);
+  test.check(fieldVector == Dune::FieldVector<double,3>({2, 4, 6}))
+    << "Adding indices to FieldVector entries with Hybrid::forEach failed.";
+  test.check(Dune::IsIntegralConstant<decltype(Dune::Hybrid::size(fieldVector))>::value)
+    << "Hybrid::size() of FieldVector is not an std::integral_constant.";
 
   auto mixedTuple = Dune::makeTupleVector(std::string("1"), 2, 3);
   incAndAppendToFirst(mixedTuple);
-- 
GitLab