**/
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
* 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
*/
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
/**
* 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
};
-// inline and template functions
namespace internal
{
- inline
- TableEntry::TableEntry ()
- {}
-
-
template <typename T>
TableEntry::TableEntry (const T &t)
:
template <typename T>
- inline
T TableEntry::get () const
{
// we don't quite know the data type in 'value', but
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)
/*---------------------------------------------------------------------*/
+// 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)
:
+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());
+}
+
+
/*---------------------------------------------------------------------*/
{
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);
<< "\\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);
--- /dev/null
+//-----------------------------------------------------------------------------
+// $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());
+}
--- /dev/null
+
+key1 key2 key3
+0 0 ""
+1 0 ""
+2 13 a
+1 0 ""