From: bangerth Date: Fri, 21 Oct 2011 21:14:07 +0000 (+0000) Subject: Also pad below columns if necessary. X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1de09890fed2f63ae025d82b5cdca6ec08315772;p=dealii-svn.git Also pad below columns if necessary. git-svn-id: https://svn.dealii.org/trunk@24654 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/include/deal.II/base/table_handler.h b/deal.II/include/deal.II/base/table_handler.h index e131d4b3ad..5e0e73ba7a 100644 --- a/deal.II/include/deal.II/base/table_handler.h +++ b/deal.II/include/deal.II/base/table_handler.h @@ -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 above the element that + * is being added to a column. However, there is also a case where we have to pad + * below. 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 columns; + mutable std::map columns; /** * Maps each supercolumn key to @@ -633,14 +661,8 @@ class TableHandler }; -// inline and template functions namespace internal { - inline - TableEntry::TableEntry () - {} - - template TableEntry::TableEntry (const T &t) : @@ -649,7 +671,6 @@ namespace internal template - 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(value); - } - catch (...) - {} - - - // ... then with unsigned int... - try - { - return boost::get(value); - } - catch (...) - {} - - // ...and finally with double precision: - try - { - return boost::get(value); - } - catch (...) - { - Assert (false, ExcMessage ("The number stored by this element of the " - "table is not a number.")) - } - - return 0; - } - - - - template - 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(&value)) - { - char c = 'i'; - ar & c & *p; - } - else if (const unsigned int *p = boost::get(&value)) - { - char c = 'u'; - ar & c & *p; - } - else if (const double *p = boost::get(&value)) - { - char c = 'd'; - ar & c & *p; - } - else if (const std::string *p = boost::get(&value)) - { - char c = 's'; - ar & c & *p; - } - else - Assert (false, ExcInternalError()); - } - - - - template - 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 void TableHandler::add_value (const std::string &key, const T value) diff --git a/deal.II/source/base/table_handler.cc b/deal.II/source/base/table_handler.cc index 2ec8f10ca0..baaec2a236 100644 --- a/deal.II/source/base/table_handler.cc +++ b/deal.II/source/base/table_handler.cc @@ -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(value); + } + catch (...) + {} + + + // ... then with unsigned int... + try + { + return boost::get(value); + } + catch (...) + {} + + // ...and finally with double precision: + try + { + return boost::get(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 + 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 + 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(&value)) + { + char c = 'i'; + ar & c & *p; + } + else if (const unsigned int *p = boost::get(&value)) + { + char c = 'u'; + ar & c & *p; + } + else if (const double *p = boost::get(&value)) + { + char c = 'd'; + ar & c & *p; + } + else if (const std::string *p = boost::get(&value)) + { + char c = 's'; + ar & c & *p; + } + else + Assert (false, ExcInternalError()); + } + + + + template + 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::const_iterator p = columns.begin(); + p != columns.end(); ++p) + max_rows = std::max(max_rows, p->second.entries.size()); + + for (std::map::iterator p = columns.begin(); + p != columns.end(); ++p) + p->second.pad_column_below (max_rows); + } + std::vector 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::const_iterator p = columns.begin(); + p != columns.end(); ++p) + max_rows = std::max(max_rows, p->second.entries.size()); + + for (std::map::iterator p = columns.begin(); + p != columns.end(); ++p) + p->second.pad_column_below (max_rows); + } + std::vector 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 index 0000000000..5bfd844df0 --- /dev/null +++ b/tests/base/table_handler_05.cc @@ -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 +#include +#include + +#include +#include +#include +#include + + +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 index 0000000000..d5f405dae8 --- /dev/null +++ b/tests/base/table_handler_05/cmp/generic @@ -0,0 +1,6 @@ + +key1 key2 key3 +0 0 "" +1 0 "" +2 13 a +1 0 ""