From 4589fa74b79cbb88e3fbf5f43d156cca97c13ad5 Mon Sep 17 00:00:00 2001
From: Felix Schindler <felix.schindler@wwu.de>
Date: Fri, 10 Jul 2020 23:22:54 +0200
Subject: [PATCH] [print] add matrix printer

---
 dune/xt/common/print.hh | 95 +++++++++++++++++++++++++++++++++++------
 1 file changed, 81 insertions(+), 14 deletions(-)

diff --git a/dune/xt/common/print.hh b/dune/xt/common/print.hh
index e92b881e4..9d23f672b 100644
--- a/dune/xt/common/print.hh
+++ b/dune/xt/common/print.hh
@@ -20,6 +20,7 @@
 #include <dune/xt/common/filesystem.hh>
 #include <dune/xt/common/ranges.hh>
 #include <dune/xt/common/string.hh>
+#include <dune/xt/common/vector.hh>
 #include <dune/xt/common/type_traits.hh>
 
 namespace Dune {
@@ -99,10 +100,6 @@ public:
 template <class T, bool use_repr>
 class VectorPrinter : public internal::DefaultPrinter<T, use_repr>
 {
-  static_assert(is_vector<T>::value, "");
-
-  using V = VectorAbstraction<T>;
-
 public:
   const std::string class_name;
 
@@ -118,9 +115,9 @@ public:
     if (sz > 0) {
       const std::string delim =
           (std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point() == ',') ? ";" : ",";
-      out << "{" << V::get_entry(this->value, 0);
+      out << "{" << print(this->value[0], this->opts) /*V::get_entry(this->value, 0)*/;
       for (auto&& ii : value_range(decltype(sz)(1), sz))
-        out << delim << " " << V::get_entry(this->value, ii);
+        out << delim << " " << print(this->value[ii], this->opts) /*V::get_entry(this->value, ii)*/;
       out << "}";
     }
     out << ")";
@@ -134,15 +131,75 @@ public:
     else {
       const std::string delim =
           (std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point() == ',') ? ";" : ",";
-      out << "[" << V::get_entry(this->value, 0);
+      out << "[" << print(this->value[0], this->opts) /*V::get_entry(this->value, 0)*/;
       for (auto&& ii : value_range(decltype(sz)(1), sz))
-        out << delim << " " << V::get_entry(this->value, ii);
+        out << delim << " " << print(this->value[ii], this->opts) /*V::get_entry(this->value, ii)*/;
       out << "]";
     }
   } // ... str(...)
 }; // class VectorPrinter
 
 
+/// \note Should be used to derive from when specializing Printer for matrices.
+/// \sa Printer
+/// \sa DefaultPrinter
+template <class T, bool use_repr>
+class MatrixPrinter : public internal::DefaultPrinter<T, use_repr>
+{
+  static_assert(is_matrix<T>::value, "");
+
+  using M = MatrixAbstraction<T>;
+
+public:
+  const std::string class_name;
+
+  MatrixPrinter(const T& val, const Configuration& cfg = {}, const std::string& clss_nm = Typename<T>::value())
+    : internal::DefaultPrinter<T, use_repr>(val, cfg)
+    , class_name(clss_nm)
+  {}
+
+  void repr(std::ostream& out) const override
+  {
+    out << class_name << "(";
+    const auto rows = M::rows(this->value);
+    const auto cols = M::cols(this->value);
+    if (rows * cols > 0) {
+      out << "{";
+      const std::string delim =
+          (std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point() == ',') ? ";" : ",";
+      const std::string newline = "\n";
+      for (auto&& ii : value_range(rows)) {
+        out << (ii == 0 ? "{" : " ") << "{" << print(M::get_entry(this->value, ii, 0), this->opts);
+        for (auto&& jj : value_range(decltype(cols)(1), cols))
+          out << delim << " " << print(M::get_entry(this->value, ii, jj), this->opts);
+        out << "}" << ((ii == rows - 1) ? "" : ",") << ((ii == rows - 1) ? "" : newline);
+      }
+      out << "}";
+    }
+    out << ")";
+  } // ... repr(...)
+
+  void str(std::ostream& out) const override
+  {
+    const auto rows = M::rows(this->value);
+    const auto cols = M::cols(this->value);
+    out << "[";
+    if (rows * cols > 0) {
+      const std::string delim =
+          (std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point() == ',') ? ";" : ",";
+      const std::string newline = this->opts.get("oneline", false) ? "" : "\n";
+      for (auto&& ii : value_range(rows)) {
+        out << (ii == 0 ? "" : " ") << "[" << print(M::get_entry(this->value, ii, 0), this->opts);
+        for (auto&& jj : value_range(decltype(cols)(1), cols))
+          out << delim << " " << print(M::get_entry(this->value, ii, jj), this->opts);
+        out << "]" << ((ii == rows - 1) ? "" : ",") << ((ii == rows - 1) ? "" : newline);
+      }
+    }
+    out << "]";
+  } // ... str(...)
+}; // class MatrixPrinter
+
+
 } // namespace internal
 
 
@@ -192,14 +249,24 @@ public:
 };
 
 
-/// Specialization of Printer for std::vector<T> with arithmetic T
-template <class T, bool use_repr>
-class Printer<std::vector<T>, use_repr, std::enable_if_t<std::is_arithmetic<T>::value>>
-  : public internal::VectorPrinter<std::vector<T>, use_repr>
+/// Specialization of Printer for all our vectors
+template <class V, bool use_repr>
+class Printer<V, use_repr, std::enable_if_t<is_vector<V>::value>> : public internal::VectorPrinter<V, use_repr>
+{
+public:
+  Printer(const V& val, const Configuration& param)
+    : internal::VectorPrinter<V, use_repr>(val, param)
+  {}
+}; // class Printer
+
+
+/// Specialization of Printer for all our matrices
+template <class M, bool use_repr>
+class Printer<M, use_repr, std::enable_if_t<is_matrix<M>::value>> : public internal::MatrixPrinter<M, use_repr>
 {
 public:
-  Printer(const std::vector<T>& val, const Configuration& param = {})
-    : internal::VectorPrinter<std::vector<T>, use_repr>(val, param)
+  Printer(const M& val, const Configuration& param = {{"oneline", "false"}})
+    : internal::MatrixPrinter<M, use_repr>(val, param)
   {}
 }; // class Printer
 
-- 
GitLab