]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Also pad below columns if necessary.
authorbangerth <bangerth@0785d39b-7218-0410-832d-ea1e28bc413d>
Fri, 21 Oct 2011 21:14:07 +0000 (21:14 +0000)
committerbangerth <bangerth@0785d39b-7218-0410-832d-ea1e28bc413d>
Fri, 21 Oct 2011 21:14:07 +0000 (21:14 +0000)
git-svn-id: https://svn.dealii.org/trunk@24654 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/include/deal.II/base/table_handler.h
deal.II/source/base/table_handler.cc
tests/base/table_handler_05.cc [new file with mode: 0644]
tests/base/table_handler_05/cmp/generic [new file with mode: 0644]

index e131d4b3adeb15ee4ed5b59122a4104c63824eb1..5e0e73ba7ae7503d5fd89a2d6c6228ff0d144d00 100644 (file)
@@ -82,6 +82,14 @@ namespace internal
      **/
     double get_numeric_value () const;
 
+    /**
+     * Return a TableEntry object that has the same data type
+     * of the stored value but with a value that is default
+     * constructed for this data type. This is used to pad
+     * columns below previously set ones.
+     */
+    TableEntry get_default_constructed_copy() const;
+    
     /**
      * Write the data of this object to a
      * stream for the purpose of
@@ -223,6 +231,14 @@ namespace internal
  * a column that will always be added to; or, you may want to start every iteration
  * by adding the number of the iteration to the table, for example in column 1.
  *
+ * In the case above, we have always padded columns <b>above</b> the element that
+ * is being added to a column. However, there is also a case where we have to pad
+ * <b>below</b>. Namely, if a previous row has been completely filled using
+ * TableHandler::add_value(), subsequent rows have been filled partially, and we
+ * then ask for output via write_text() or write_tex(). In that case, the last
+ * few rows that have been filled only partially need to be padded below the last
+ * element that has been added to them. As before, we do that by using default
+ * constructed objects of the same type as the last element of that column.
  *
  * @ingroup textoutput
  * @author Ralf Hartmann, 1999; Wolfgang Bangerth, 2011
@@ -475,6 +491,12 @@ class TableHandler
                                           */
         Column (const std::string &tex_caption);
 
+       /**
+        * Pad this column with default constructed elements to the
+        * number of rows given by the argument.
+        */
+       void pad_column_below (const unsigned int length);
+       
                                         /**
                                          * Read or write the data of this
                                          * object to or from a stream for
@@ -587,8 +609,14 @@ class TableHandler
                                      /**
                                       * Maps the column keys to the
                                       * columns (not supercolumns).
+                                     * 
+                                     * The field is declared mutable so
+                                     * that the write_text() and write_tex()
+                                     * functions can be const, even though they
+                                     * may pad columns below if auto_fill_mode
+                                     * is on.
                                       */
-    std::map<std::string,Column> columns;
+    mutable std::map<std::string,Column> columns;
 
                                      /**
                                       * Maps each supercolumn key to
@@ -633,14 +661,8 @@ class TableHandler
 };
 
 
-// inline and template functions
 namespace internal
 {
-  inline
-  TableEntry::TableEntry ()
-  {}
-
-
   template <typename T>
   TableEntry::TableEntry (const T &t)
   :
@@ -649,7 +671,6 @@ namespace internal
 
 
   template <typename T>
-  inline
   T TableEntry::get () const
   {
     // we don't quite know the data type in 'value', but
@@ -667,135 +688,9 @@ namespace internal
       Assert(false, ExcMessage ("This TableEntry object does not store a datum of type T"));
       throw;
     }
-  }
-
-
-  inline
-  double TableEntry::get_numeric_value () const
-  {
-    // we don't quite know the data type in 'value', but
-    // it must be one of the ones in the type list of the
-    // boost::variant. Go through this list and return
-    // the value if this happens to be a number
-    //
-    // first try with int
-    try
-    {
-      return boost::get<int>(value);
-    }
-    catch (...)
-    {}
-
-
-    // ... then with unsigned int...
-    try
-    {
-      return boost::get<unsigned int>(value);
-    }
-    catch (...)
-    {}
-
-    // ...and finally with double precision:
-    try
-    {
-      return boost::get<double>(value);
-    }
-    catch (...)
-    {
-      Assert (false, ExcMessage ("The number stored by this element of the "
-      "table is not a number."))
-    }
-
-    return 0;
-  }
-
-
-
-  template <class Archive>
-  void TableEntry::save (Archive & ar,
-                        const unsigned int) const
-  {
-                                    // write first an identifier for the kind
-                                    // of data stored and then the actual
-                                    // data, in its correct data type
-    if (const int *p = boost::get<int>(&value))
-      {
-       char c = 'i';
-       ar & c & *p;
-      }
-    else if (const unsigned int *p = boost::get<unsigned int>(&value))
-      {
-       char c = 'u';
-       ar & c & *p;
-      }
-    else if (const double *p = boost::get<double>(&value))
-      {
-       char c = 'd';
-       ar & c & *p;
-      }
-    else if (const std::string *p = boost::get<std::string>(&value))
-      {
-       char c = 's';
-       ar & c & *p;
-      }
-    else
-      Assert (false, ExcInternalError());
-  }
-
-
-
-  template <class Archive>
-  void TableEntry::load (Archive & ar,
-                        const unsigned int)
-  {
-                                    // following what we do in the save()
-                                    // function, first read in the data type
-                                    // as a one-character id, and then read
-                                    // the data
-    char c;
-    ar & c;
-
-    switch (c)
-      {
-       case 'i':
-       {
-         int val;
-         ar & val;
-         value = val;
-         break;
-       }
-
-       case 'u':
-       {
-         unsigned int val;
-         ar & val;
-         value = val;
-         break;
-       }
-
-       case 'd':
-       {
-         double val;
-         ar & val;
-         value = val;
-         break;
-       }
-
-       case 's':
-       {
-         std::string val;
-         ar & val;
-         value = val;
-         break;
-       }
-
-       default:
-             Assert (false, ExcInternalError());
-      }
-  }
+  }  
 }
 
-
 template <typename T>
 void TableHandler::add_value (const std::string &key,
                              const T            value)
index 2ec8f10ca024aee9ca5e33f088f0181ab8c7308f..baaec2a236225bcc2ab28395e019fe458e6f5cd6 100644 (file)
@@ -26,6 +26,160 @@ DEAL_II_NAMESPACE_OPEN
 
 /*---------------------------------------------------------------------*/
 
+// inline and template functions
+namespace internal
+{
+  TableEntry::TableEntry ()
+  {}
+
+
+  double TableEntry::get_numeric_value () const
+  {
+    // we don't quite know the data type in 'value', but
+    // it must be one of the ones in the type list of the
+    // boost::variant. Go through this list and return
+    // the value if this happens to be a number
+    //
+    // first try with int
+    try
+    {
+      return boost::get<int>(value);
+    }
+    catch (...)
+    {}
+
+
+    // ... then with unsigned int...
+    try
+    {
+      return boost::get<unsigned int>(value);
+    }
+    catch (...)
+    {}
+
+    // ...and finally with double precision:
+    try
+    {
+      return boost::get<double>(value);
+    }
+    catch (...)
+    {
+      Assert (false, ExcMessage ("The number stored by this element of the "
+      "table is not a number."))
+    }
+
+    return 0;
+  }
+
+
+  namespace Local
+  {
+    // see which type we can cast to, then use this type to create
+    // a default constructed object
+    struct GetDefaultValue : public boost::static_visitor<>
+    {
+      template <typename T>
+      void operator()( T & operand ) const
+      {
+       operand = T();
+      }
+    };
+  }
+
+  TableEntry TableEntry::get_default_constructed_copy () const
+  {
+    TableEntry new_entry = *this;
+    boost::apply_visitor(Local::GetDefaultValue(), new_entry.value);
+    
+    return new_entry;
+  }
+
+
+  template <class Archive>
+  void TableEntry::save (Archive & ar,
+                        const unsigned int) const
+  {
+                                    // write first an identifier for the kind
+                                    // of data stored and then the actual
+                                    // data, in its correct data type
+    if (const int *p = boost::get<int>(&value))
+      {
+       char c = 'i';
+       ar & c & *p;
+      }
+    else if (const unsigned int *p = boost::get<unsigned int>(&value))
+      {
+       char c = 'u';
+       ar & c & *p;
+      }
+    else if (const double *p = boost::get<double>(&value))
+      {
+       char c = 'd';
+       ar & c & *p;
+      }
+    else if (const std::string *p = boost::get<std::string>(&value))
+      {
+       char c = 's';
+       ar & c & *p;
+      }
+    else
+      Assert (false, ExcInternalError());
+  }
+
+
+
+  template <class Archive>
+  void TableEntry::load (Archive & ar,
+                        const unsigned int)
+  {
+                                    // following what we do in the save()
+                                    // function, first read in the data type
+                                    // as a one-character id, and then read
+                                    // the data
+    char c;
+    ar & c;
+
+    switch (c)
+      {
+       case 'i':
+       {
+         int val;
+         ar & val;
+         value = val;
+         break;
+       }
+
+       case 'u':
+       {
+         unsigned int val;
+         ar & val;
+         value = val;
+         break;
+       }
+
+       case 'd':
+       {
+         double val;
+         ar & val;
+         value = val;
+         break;
+       }
+
+       case 's':
+       {
+         std::string val;
+         ar & val;
+         value = val;
+         break;
+       }
+
+       default:
+             Assert (false, ExcInternalError());
+      }
+  }
+}
+
+/* ------------------------------------------------ */
 
 TableHandler::Column::Column(const std::string &tex_caption)
                 :
@@ -49,6 +203,19 @@ TableHandler::Column::Column()
 
 
 
+void
+TableHandler::Column::pad_column_below (const unsigned int size)
+{
+  // we should never have a column that is completely
+  // empty and that needs to be padded
+  Assert (entries.size() > 0, ExcInternalError());
+  
+  // add as many elements as necessary
+  while (entries.size() < size)
+    entries.push_back (entries.back().get_default_constructed_copy());
+}
+
+
 /*---------------------------------------------------------------------*/
 
 
@@ -186,6 +353,19 @@ void TableHandler::write_text(std::ostream &out) const
 {
   AssertThrow (out, ExcIO());
 
+  // first pad the table from below if necessary
+  if (auto_fill_mode == true)
+  {
+    unsigned int max_rows = 0;
+    for (std::map<std::string, Column>::const_iterator p = columns.begin();
+        p != columns.end(); ++p)
+      max_rows = std::max<unsigned int>(max_rows, p->second.entries.size());
+
+    for (std::map<std::string, Column>::iterator p = columns.begin();
+        p != columns.end(); ++p)
+      p->second.pad_column_below (max_rows);
+  }
+  
   std::vector<std::string> sel_columns;
   get_selected_columns(sel_columns);
 
@@ -331,6 +511,19 @@ void TableHandler::write_tex (std::ostream &out, const bool with_header) const
       << "\\begin{center}" << std::endl
       << "\\begin{tabular}{|";
 
+  // first pad the table from below if necessary
+  if (auto_fill_mode == true)
+  {
+    unsigned int max_rows = 0;
+    for (std::map<std::string, Column>::const_iterator p = columns.begin();
+        p != columns.end(); ++p)
+      max_rows = std::max<unsigned int>(max_rows, p->second.entries.size());
+
+    for (std::map<std::string, Column>::iterator p = columns.begin();
+        p != columns.end(); ++p)
+      p->second.pad_column_below (max_rows);
+  }
+
   std::vector<std::string> sel_columns;
   get_selected_columns(sel_columns);
 
diff --git a/tests/base/table_handler_05.cc b/tests/base/table_handler_05.cc
new file mode 100644 (file)
index 0000000..5bfd844
--- /dev/null
@@ -0,0 +1,55 @@
+//-----------------------------------------------------------------------------
+//    $Id$
+//    Version: $Name$
+//
+//    Copyright (C) 2010, 2011 by the deal.II authors
+//
+//    This file is subject to QPL and may not be  distributed
+//    without copyright and license information. Please refer
+//    to the file deal.II/doc/license.html for the  text  and
+//    further information on this license.
+//
+//-----------------------------------------------------------------------------
+
+// pad columns if we don't fill them in each iteration. also fill them below
+// the last element if we create output
+
+
+#include "../tests.h"
+#include <deal.II/base/data_out_base.h>
+#include <deal.II/base/table_handler.h>
+#include <deal.II/base/logstream.h>
+
+#include <vector>
+#include <iomanip>
+#include <fstream>
+#include <string>
+
+
+int main ()
+{
+  std::ofstream logfile("table_handler_05/output");
+  deallog.attach(logfile);
+  deallog.depth_console(0);
+  deallog.threshold_double(1.e-10);
+
+  TableHandler table;
+  table.set_auto_fill_mode (true);
+
+  std::string keys[3] = { "key1", "key2", "key3" };
+
+                                  // fill rows 1 and 2 partially
+  table.add_value(keys[0], 0);
+  table.add_value(keys[0], 1);
+                                  // now fill row 3 completely
+  table.add_value(keys[0], 2);
+  table.add_value(keys[1], 13);
+  table.add_value(keys[2], std::string("a"));
+
+                                  // now again fill row 4 partially
+  table.add_value(keys[0], 1);
+
+                                  // produce output. hope that row 4 is
+                                  // completely padded
+  table.write_text(deallog.get_file_stream());
+}
diff --git a/tests/base/table_handler_05/cmp/generic b/tests/base/table_handler_05/cmp/generic
new file mode 100644 (file)
index 0000000..d5f405d
--- /dev/null
@@ -0,0 +1,6 @@
+
+key1 key2 key3 
+0    0    ""   
+1    0    ""   
+2    13   a    
+1    0    ""   

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.