From db793d9986aa201ffb87fba1e35febd20354f986 Mon Sep 17 00:00:00 2001 From: heister Date: Fri, 14 Sep 2012 21:44:56 +0000 Subject: [PATCH] speed up TableHandler::write_text by caching the formatted lines. git-svn-id: https://svn.dealii.org/trunk@26394 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/include/deal.II/base/table_handler.h | 41 +++- deal.II/source/base/table_handler.cc | 196 ++++++++----------- 2 files changed, 123 insertions(+), 114 deletions(-) diff --git a/deal.II/include/deal.II/base/table_handler.h b/deal.II/include/deal.II/base/table_handler.h index 8200af5b22..7fd206e811 100644 --- a/deal.II/include/deal.II/base/table_handler.h +++ b/deal.II/include/deal.II/base/table_handler.h @@ -82,6 +82,20 @@ namespace internal **/ double get_numeric_value () const; + /** + * Cache the contained value with the given formatting and return it. The given parameters + * from the column definition are used for the formatting. The value + * is cached as a string internally in cached_value. The cache needs to be invalidated with this routine + * if the formatting of the column changes. + */ + void cache_string(bool scientific, unsigned int precision) const; + + /** + * Return the value cached using cache_string(). This is just a wrapper around cached_value. + */ + const std::string & get_cached_string() const; + + /** * Return a TableEntry object that has the same data type * of the stored value but with a value that is default @@ -119,6 +133,11 @@ namespace internal */ value_type value; + /** + * cache the current value as a string + */ + mutable std::string cached_value; + friend class dealii::TableHandler; }; } @@ -566,6 +585,13 @@ class TableHandler template void serialize(Archive & ar, const unsigned int version); + + /** + * Invalidates the string cache of all the entries and recomputes + * the maximum length max_length. + */ + void invalidate_cache(); + /** * List of entries within * this column. Values are @@ -628,6 +654,11 @@ class TableHandler * not be computed at all. */ unsigned int flag; + + /** + * This entry caches the maximum length in characters for all entries in this table. + */ + unsigned int max_length; }; /** @@ -858,11 +889,19 @@ void TableHandler::add_value (const std::string &key, n = (n >= p->second.entries.size() ? n : p->second.entries.size()); while (columns[key].entries.size()+1 < n) - columns[key].entries.push_back (internal::TableEntry(T())); + { + columns[key].entries.push_back (internal::TableEntry(T())); + internal::TableEntry & entry = columns[key].entries.back(); + entry.cache_string(columns[key].scientific, columns[key].precision); + columns[key].max_length = std::max(columns[key].max_length, static_cast(entry.get_cached_string().length())); + } } // now push the value given to this function columns[key].entries.push_back (internal::TableEntry(value)); + internal::TableEntry & entry = columns[key].entries.back(); + entry.cache_string(columns[key].scientific, columns[key].precision); + columns[key].max_length = std::max(columns[key].max_length, static_cast(entry.get_cached_string().length())); } diff --git a/deal.II/source/base/table_handler.cc b/deal.II/source/base/table_handler.cc index ee91075742..b0098ca528 100644 --- a/deal.II/source/base/table_handler.cc +++ b/deal.II/source/base/table_handler.cc @@ -70,6 +70,29 @@ namespace internal return 0; } + void TableEntry::cache_string(bool scientific, unsigned int precision) const + { + std::ostringstream ss; + + ss << std::setprecision(precision); + + if (scientific) + ss.setf(std::ios::scientific, std::ios::floatfield); + else + ss.setf(std::ios::fixed, std::ios::floatfield); + + ss << value; + + cached_value = ss.str(); + if (cached_value.size()==0) + cached_value = "\"\""; + } + + const std::string & TableEntry::get_cached_string() const + { + return cached_value; + } + namespace Local { @@ -104,7 +127,8 @@ TableHandler::Column::Column(const std::string &tex_caption) tex_format("c"), precision(4), scientific(0), - flag(0) + flag(0), + max_length(0) {} @@ -115,7 +139,8 @@ TableHandler::Column::Column() tex_format("c"), precision(4), scientific(0), - flag(0) + flag(0), + max_length(0) {} @@ -129,7 +154,25 @@ TableHandler::Column::pad_column_below (const unsigned int size) // add as many elements as necessary while (entries.size() < size) - entries.push_back (entries.back().get_default_constructed_copy()); + { + entries.push_back (entries.back().get_default_constructed_copy()); + internal::TableEntry & entry = entries.back(); + entry.cache_string(scientific, precision); + max_length = std::max(max_length, static_cast(entry.get_cached_string().length())); + } +} + + +void +TableHandler::Column::invalidate_cache() +{ + max_length = 0; + + for (std::vector::iterator it=entries.begin();it!=entries.end();++it) + { + it->cache_string(this->scientific, this->precision); + max_length = std::max(max_length, static_cast(it->get_cached_string().length())); + } } @@ -254,7 +297,11 @@ void TableHandler::set_precision (const std::string &key, const unsigned int precision) { Assert(columns.count(key), ExcColumnNotExistent(key)); - columns[key].precision=precision; + if (columns[key].precision!=precision) + { + columns[key].precision = precision; + columns[key].invalidate_cache(); + } } @@ -262,7 +309,11 @@ void TableHandler::set_scientific (const std::string &key, const bool scientific) { Assert(columns.count(key), ExcColumnNotExistent(key)); - columns[key].scientific=scientific; + if (columns[key].scientific!=scientific) + { + columns[key].scientific = scientific; + columns[key].invalidate_cache(); + } } @@ -318,20 +369,7 @@ void TableHandler::write_text(std::ostream &out, { const Column &column=*(cols[j]); - out << std::setprecision(column.precision); - - if (column.scientific) - out.setf(std::ios::scientific, std::ios::floatfield); - else - out.setf(std::ios::fixed, std::ios::floatfield); - - // write "" instead of an empty string - const std::string * val = boost::get(&(column.entries[i].value)); - if (val!=NULL && val->length()==0) - out << "\"\""; - else - out << column.entries[i].value; - + out << column.entries[i].get_cached_string(); out << ' '; } out << '\n'; @@ -341,59 +379,29 @@ void TableHandler::write_text(std::ostream &out, return; } - // first compute the widths of each - // entry of the table, in order to - // have a nicer alignment - Table<2,unsigned int> entry_widths (nrows, n_cols); - for (unsigned int i=0; i::const_iterator - col_iter = columns.find(key); - Assert(col_iter!=columns.end(), ExcInternalError()); - - const Column & column = col_iter->second; - - // write it into a dummy - // stream, just to get its - // size upon output - std::ostringstream dummy_out; - - dummy_out << std::setprecision(column.precision); - - if (col_iter->second.scientific) - dummy_out.setf (std::ios::scientific, std::ios::floatfield); - else - dummy_out.setf (std::ios::fixed, std::ios::floatfield); - - dummy_out << column.entries[i].value; - - // get size. as a side note, if the - // text printed is in fact the empty - // string, then we get into a bit of - // trouble since readers would skip - // over the resulting whitespaces. as - // a consequence, we'll print "" - // instead in that case. - const unsigned int size = dummy_out.str().length(); - if (size > 0) - entry_widths[i][j] = size; - else - entry_widths[i][j] = 2; - } - - // next compute the width each row - // has to have to suit all entries + // cache the columns and compute the widths of each column for alignment + std::vector cols; std::vector column_widths (n_cols, 0); - for (unsigned int i=0; i::const_iterator + col_iter=columns.find(key); + Assert(col_iter!=columns.end(), ExcInternalError()); + cols.push_back(&(col_iter->second)); + + switch (format) + { + case table_with_headers: + column_widths[j] = std::max(col_iter->second.max_length, static_cast(key.length())); + break; + default: + column_widths[j] = col_iter->second.max_length; + } + } // write the captions - for (unsigned int j=0; j column_widths[j]) - column_widths[j] = key.length(); - // now write key. try to center // it somehow const unsigned int front_padding = (column_widths[j]-key.length())/2, @@ -420,7 +422,6 @@ void TableHandler::write_text(std::ostream &out, // finally column break out << ' '; - break; } @@ -443,45 +444,12 @@ void TableHandler::write_text(std::ostream &out, { for (unsigned int j=0; j::const_iterator - col_iter=columns.find(key); - Assert(col_iter!=columns.end(), ExcInternalError()); - - const Column &column=col_iter->second; - - out << std::setprecision(column.precision); - - if (col_iter->second.scientific) - out.setf(std::ios::scientific, std::ios::floatfield); - else - out.setf(std::ios::fixed, std::ios::floatfield); + const Column &column=*(cols[j]); out << std::setw(column_widths[j]); + out << column.entries[i].get_cached_string(); - // get the string to write into the - // table. we could simply << it - // into the stream but we have to - // be a bit careful about the case - // where the string may be empty, - // in which case we'll print it as - // "". note that ultimately we - // still just << it into the stream - // since we want to use the flags - // of that stream, and the first - // test is only used to determine - // whether the size of the string - // representation is zero - { - std::ostringstream text; - text << column.entries[i].value; - if (text.str().size() > 0) - out << column.entries[i].value; - else - out << "\"\""; - } - - // pad after this column - out << " "; + // pad after this column + out << ' '; } out << '\n'; } @@ -491,6 +459,8 @@ void TableHandler::write_text(std::ostream &out, void TableHandler::write_tex (std::ostream &out, const bool with_header) const { + //TODO[TH]: update code similar to + //write_text() to use the cache AssertThrow (out, ExcIO()); if (with_header) out << "\\documentclass[10pt]{report}" << std::endl -- 2.39.5