* </ul>
*
* The usual usage of this class is through the pregenerated object
- * <tt>deallog</tt>. Typical steps are
+ * <tt>deallog</tt>. Typical setup steps are:
* <ul>
- * <li> <tt>deallog.attach(std::ostream)</tt>: write logging information into a file.
* <li> <tt>deallog.depth_console(n)</tt>: restrict output on screen to outer loops.
- * <li> Before entering a new phase of your program, e.g. a new loop,
- * <tt>LogStream::Prefix p("loopname")</tt>.
- * <li> <tt>deallog << anything << std::endl;</tt> to write logging information
- * (Usage of <tt>std::endl</tt> is mandatory!).
- * <li> Destructor of the prefix will pop the prefix text from the stack.
+ * <li> <tt>deallog.attach(std::ostream)</tt>: write logging information into a file.
+ * <li> <tt>deallog.depth_file(n)</tt>: restrict output to file to outer loops.
* </ul>
*
+ * Before entering a new phase of your program, e.g. a new loop,
+ * a new prefix can be set via <tt>LogStream::Prefix p("loopname");</tt>.
+ * The destructor of the prefix will pop the prefix text from the stack.
+ *
+ * Writes via the <tt><<</tt> operator,
+ * <tt> deallog << "This is a log notice";</tt> will be buffered thread
+ * locally until a <tt>std::flush</tt> or <tt>std::endl</tt> is
+ * encountered, which will trigger a writeout to the console and, if set
+ * up, the log file.
+ *
* <h3>LogStream and reproducible regression test output</h3>
*
* Generating reproducible floating point output for regression tests
{
public:
/**
- * A subclass allowing for the
- * safe generation and removal of
- * prefices.
+ * A subclass allowing for the safe generation and removal of prefices.
*
- * Somewhere at the beginning of
- * a block, create one of these
- * objects, and it will appear as
- * a prefix in LogStream output
- * like @p deallog. At the end of
- * the block, the prefix will
- * automatically be removed, when
+ * Somewhere at the beginning of a block, create one of these objects,
+ * and it will appear as a prefix in LogStream output like @p deallog. At
+ * the end of the block, the prefix will automatically be removed, when
* this object is destroyed.
*
- * In other words, the scope of the object so created
- * determines the lifetime of the prefix. The advantage of
- * using such an object is that the prefix is removed
- * whichever way you exit the scope -- by <code>continue</code>,
- * <code>break</code>, <code>return</code>, <code>throw</code>,
- * or by simply reaching the closing brace. In all of these
- * cases, it is not necessary to remember to pop the prefix
- * manually using LogStream::pop. In this, it works just like
- * the better known Threads::Mutex::ScopedLock class.
+ * In other words, the scope of the object so created determines the
+ * lifetime of the prefix. The advantage of using such an object is that
+ * the prefix is removed whichever way you exit the scope -- by
+ * <code>continue</code>, <code>break</code>, <code>return</code>,
+ * <code>throw</code>, or by simply reaching the closing brace. In all of
+ * these cases, it is not necessary to remember to pop the prefix
+ * manually using LogStream::pop. In this, it works just like the better
+ * known Threads::Mutex::ScopedLock class.
*/
class Prefix
{
public:
/**
- * Set a new prefix for
- * @p deallog, which will be
- * removed when the variable
- * is destroyed .
+ * Set a new prefix for @p deallog, which will be removed when the
+ * variable is destroyed.
*/
Prefix(const std::string &text);
/**
- * Set a new prefix for the
- * given stream, which will
- * be removed when the
- * variable is destroyed .
+ * Set a new prefix for the given stream, which will be removed when
+ * the variable is destroyed.
*/
Prefix(const std::string &text,
LogStream &stream);
/**
- * Remove the prefix
- * associated with this
- * variable.
+ * Remove the prefix associated with this variable.
*/
~Prefix ();
SmartPointer<LogStream,LogStream::Prefix> stream;
};
+
/**
- * Standard constructor, since we
- * intend to provide an object
- * <tt>deallog</tt> in the library. Set the
- * standard output stream to <tt>std::cerr</tt>.
+ * Standard constructor, since we intend to provide an object
+ * <tt>deallog</tt> in the library. Set the standard output stream to
+ * <tt>std::cerr</tt>.
*/
LogStream ();
+
/**
* Destructor.
*/
~LogStream();
+
/**
- * Enable output to a second
- * stream <tt>o</tt>.
+ * Enable output to a second stream <tt>o</tt>.
*/
void attach (std::ostream &o);
+
/**
- * Disable output to the second
- * stream. You may want to call
- * <tt>close</tt> on the stream that was
- * previously attached to this object.
+ * Disable output to the second stream. You may want to call
+ * <tt>close</tt> on the stream that was previously attached to this
+ * object.
*/
void detach ();
+
/**
- * Setup the logstream for
- * regression test mode.
+ * Setup the logstream for regression test mode.
*
- * This sets the parameters
- * #double_threshold,
- * #float_threshold, and #offset
- * to nonzero values. The exact
- * values being used have been
- * determined experimentally and
- * can be found in the source
- * code.
+ * This sets the parameters #double_threshold, #float_threshold, and
+ * #offset to nonzero values. The exact values being used have been
+ * determined experimentally and can be found in the source code.
*
- * Called with an argument
- * <tt>false</tt>, switches off
- * test mode and sets all
- * involved parameters to zero.
+ * Called with an argument <tt>false</tt>, switches off test mode and
+ * sets all involved parameters to zero.
*/
void test_mode (bool on=true);
+
/**
* Gives the default stream (<tt>std_out</tt>).
*/
std::ostream &get_console ();
+
/**
* Gives the file stream.
*/
std::ostream &get_file_stream ();
+
/**
- * @return true, if file stream
- * has already been attached.
+ * @return true, if file stream has already been attached.
*/
bool has_file () const;
+
/**
- * Reroutes cerr to LogStream.
- * Works as a switch, turning
- * logging of <tt>cerr</tt> on
- * and off alternatingly with
- * every call.
+ * Reroutes cerr to LogStream. Works as a switch, turning logging of
+ * <tt>cerr</tt> on and off alternatingly with every call.
*/
void log_cerr ();
+
/**
* Return the prefix string.
*/
const std::string &get_prefix () const;
+
/**
- * Push another prefix on the
- * stack. Prefixes are
- * automatically separated by a
- * colon and there is a double
- * colon after the last prefix.
+ * Push another prefix on the stack. Prefixes are automatically separated
+ * by a colon and there is a double colon after the last prefix.
*
- * A simpler way to add a prefix (without the manual
- * need to add the corresponding pop()) is to use the
- * Prefix class.
+ * A simpler way to add a prefix (without the manual need to add the
+ * corresponding pop()) is to use the Prefix class.
*/
void push (const std::string &text);
+
/**
* Remove the last prefix added with push().
*/
void pop ();
+
/**
- * Maximum number of levels to be
- * printed on the console. This
- * function allows to restrict
- * console output to the upmost
- * levels of iterations. Only
- * output with less than <tt>n</tt>
- * prefixes is printed. By calling
- * this function with <tt>n=0</tt>, no
- * console output will be written.
+ * Maximum number of levels to be printed on the console. This function
+ * allows to restrict console output to the upmost levels of iterations.
+ * Only output with less than <tt>n</tt> prefixes is printed. By calling
+ * this function with <tt>n=0</tt>, no console output will be written.
*
- * The previous value of this
- * parameter is returned.
+ * The previous value of this parameter is returned.
*/
unsigned int depth_console (const unsigned int n);
+
/**
- * Maximum number of levels to be
- * written to the log file. The
- * functionality is the same as
- * <tt>depth_console</tt>, nevertheless,
- * this function should be used
- * with care, since it may spoile
- * the value of a log file.
+ * Maximum number of levels to be written to the log file. The
+ * functionality is the same as <tt>depth_console</tt>, nevertheless,
+ * this function should be used with care, since it may spoile the value
+ * of a log file.
*
- * The previous value of this
- * parameter is returned.
+ * The previous value of this parameter is returned.
*/
unsigned int depth_file (const unsigned int n);
+
/**
- * Set time printing flag. If this flag
- * is true, each output line will
- * be prepended by the user time used
- * by the running program so far.
+ * Set time printing flag. If this flag is true, each output line will be
+ * prepended by the user time used by the running program so far.
*
- * The previous value of this
- * parameter is returned.
+ * The previous value of this parameter is returned.
*/
bool log_execution_time (const bool flag);
+
/**
- * Output time differences
- * between consecutive logs. If
- * this function is invoked with
- * <tt>true</tt>, the time difference
- * between the previous log line
- * and the recent one is
- * printed. If it is invoked with
- * <tt>false</tt>, the accumulated
- * time since start of the
- * program is printed (default
- * behavior).
+ * Output time differences between consecutive logs. If this function is
+ * invoked with <tt>true</tt>, the time difference between the previous
+ * log line and the recent one is printed. If it is invoked with
+ * <tt>false</tt>, the accumulated time since start of the program is
+ * printed (default behavior).
*
- * The measurement of times is
- * not changed by this function,
- * just the output.
+ * The measurement of times is not changed by this function, just the
+ * output.
*
- * The previous value of this
- * parameter is returned.
+ * The previous value of this parameter is returned.
*/
bool log_time_differences (const bool flag);
+
/**
- * Write detailed timing
- * information.
- *
- *
+ * Write detailed timing information.
*/
void timestamp();
+
/**
* Log the thread id.
*/
bool log_thread_id (const bool flag);
+
/**
- * Set a threshold for the
- * minimal absolute value of
- * double values. All numbers
- * with a smaller absolute value
- * will be printed as zero.
+ * Set a threshold for the minimal absolute value of double values. All
+ * numbers with a smaller absolute value will be printed as zero.
*
- * The default value for this
- * threshold is zero,
- * i.e. numbers are printed
+ * The default value for this threshold is zero, i.e. numbers are printed
* according to their real value.
*
- * This feature is mostly useful
- * for automated tests: there,
- * one would like to reproduce
- * the exact same solution in
- * each run of a
- * testsuite. However, subtle
- * difference in processor,
- * operating system, or compiler
- * version can lead to
- * differences in the last few
- * digits of numbers, due to
- * different rounding. While one
- * can avoid trouble for most
- * numbers when comparing with
- * stored results by simply
- * limiting the accuracy of
- * output, this does not hold for
- * numbers very close to zero,
- * i.e. zero plus accumulated
- * round-off. For these numbers,
- * already the first digit is
- * tainted by round-off. Using
- * the present function, it is
- * possible to eliminate this
- * source of problems, by simply
- * writing zero to the output in
- * this case.
+ * This feature is mostly useful for automated tests: there, one would
+ * like to reproduce the exact same solution in each run of a testsuite.
+ * However, subtle difference in processor, operating system, or compiler
+ * version can lead to differences in the last few digits of numbers, due
+ * to different rounding. While one can avoid trouble for most numbers
+ * when comparing with stored results by simply limiting the accuracy of
+ * output, this does not hold for numbers very close to zero, i.e. zero
+ * plus accumulated round-off. For these numbers, already the first digit
+ * is tainted by round-off. Using the present function, it is possible to
+ * eliminate this source of problems, by simply writing zero to the
+ * output in this case.
*/
void threshold_double(const double t);
+
+
/**
- * The same as
- * threshold_double(), but for
- * float values.
+ * The same as threshold_double(), but for float values.
*/
void threshold_float(const float t);
+
/**
- * Output a constant something
- * through this stream.
+ * Output a constant something through this stream.
*/
template <typename T>
LogStream &operator << (const T &t);
+
/**
- * Output double precision
- * numbers through this
- * stream.
+ * Output double precision numbers through this stream.
*
- * If they are set, this function
- * applies the methods for making
- * floating point output
- * reproducible as discussed in
- * the introduction.
+ * If they are set, this function applies the methods for making floating
+ * point output reproducible as discussed in the introduction.
*/
LogStream &operator << (const double t);
+
/**
- * Output single precision
- * numbers through this
- * stream.
+ * Output single precision numbers through this stream.
*
- * If they are set, this function
- * applies the methods for making
- * floating point output
- * reproducible as discussed in
- * the introduction.
+ * If they are set, this function applies the methods for making floating
+ * point output reproducible as discussed in the introduction.
*/
LogStream &operator << (const float t);
+
/**
- * Treat ostream
- * manipulators. This passes on
- * the whole thing to the
- * template function with the
- * exception of the
- * <tt>std::endl</tt>
- * manipulator, for which special
- * action is performed: write the
- * temporary stream buffer
- * including a header to the file
- * and <tt>std::cout</tt> and
- * empty the buffer.
+ * Treat ostream manipulators. This passes on the whole thing to the
+ * template function with the exception of the <tt>std::endl</tt>
+ * manipulator, for which special action is performed: write the
+ * temporary stream buffer including a header to the file and
+ * <tt>std::cout</tt> and empty the buffer.
*
- * An overload of this function is needed
- * anyway, since the compiler can't bind
- * manipulators like @p std::endl
- * directly to template arguments @p T
- * like in the previous general
- * template. This is due to the fact that
- * @p std::endl is actually an overloaded
- * set of functions for @p std::ostream,
- * @p std::wostream, and potentially more
- * of this kind. This function is
- * therefore necessary to pick one
- * element from this overload set.
+ * An overload of this function is needed anyway, since the compiler
+ * can't bind manipulators like @p std::endl directly to template
+ * arguments @p T like in the previous general template. This is due to
+ * the fact that @p std::endl is actually an overloaded set of functions
+ * for @p std::ostream, @p std::wostream, and potentially more of this
+ * kind. This function is therefore necessary to pick one element from
+ * this overload set.
*/
LogStream &operator<< (std::ostream& (*p) (std::ostream &));
+
/**
- * Determine an estimate for
- * the memory consumption (in
- * bytes) of this
- * object. Since sometimes
- * the size of objects can
- * not be determined exactly
- * (for example: what is the
- * memory consumption of an
- * STL <tt>std::map</tt> type with a
- * certain number of
- * elements?), this is only
- * an estimate. however often
- * quite close to the true
- * value.
+ * Determine an estimate for the memory consumption (in bytes) of this
+ * object. Since sometimes the size of objects can not be determined
+ * exactly (for example: what is the memory consumption of an STL
+ * <tt>std::map</tt> type with a certain number of elements?), this is
+ * only an estimate. however often quite close to the true value.
*/
std::size_t memory_consumption () const;
+
/**
* Exception.
*/
private:
/**
- * Stack of strings which are printed
- * at the beginning of each line to
- * allow identification where the
- * output was generated.
+ * Stack of strings which are printed at the beginning of each line to
+ * allow identification where the output was generated.
*/
std::stack<std::string> prefixes;
/**
- * Default stream, where the output
- * is to go to. This stream defaults
- * to <tt>std::cerr</tt>, but can be set to another
- * stream through the constructor.
+ * Default stream, where the output is to go to. This stream defaults to
+ * <tt>std::cerr</tt>, but can be set to another stream through the
+ * constructor.
*/
std::ostream *std_out;
/**
- * Pointer to a stream, where a copy of
- * the output is to go to. Usually, this
- * will be a file stream.
+ * Pointer to a stream, where a copy of the output is to go to. Usually,
+ * this will be a file stream.
*
- * You can set and reset this stream
- * by the <tt>attach</tt> function.
+ * You can set and reset this stream by the <tt>attach</tt> function.
*/
std::ostream *file;
/**
- * Value denoting the number of
- * prefixes to be printed to the
- * standard output. If more than
- * this number of prefixes is
- * pushed to the stack, then no
- * output will be generated until
- * the number of prefixes shrinks
+ * Value denoting the number of prefixes to be printed to the standard
+ * output. If more than this number of prefixes is pushed to the stack,
+ * then no output will be generated until the number of prefixes shrinks
* back below this number.
*/
unsigned int std_depth;
/**
- * Same for the maximum depth of
- * prefixes for output to a file.
+ * Same for the maximum depth of prefixes for output to a file.
*/
unsigned int file_depth;
double last_time;
/**
- * Threshold for printing double
- * values. Every number with
- * absolute value less than this
- * is printed as zero.
+ * Threshold for printing double values. Every number with absolute value
+ * less than this is printed as zero.
*/
double double_threshold;
/**
- * Threshold for printing float
- * values. Every number with
- * absolute value less than this
- * is printed as zero.
+ * Threshold for printing float values. Every number with absolute value
+ * less than this is printed as zero.
*/
float float_threshold;
/**
- * An offset added to every float
- * or double number upon
- * output. This is done after the
- * number is compared to
- * #double_threshold or #float_threshold,
- * but before rounding.
+ * An offset added to every float or double number upon output. This is
+ * done after the number is compared to #double_threshold or
+ * #float_threshold, but before rounding.
*
- * This functionality was
- * introduced to produce more
- * reproducible floating point
- * output for regression
- * tests. The rationale is, that
- * an exact output value is much
- * more likely to be 1/8 than
- * 0.124997. If we round to two
- * digits though, 1/8 becomes
- * unreliably either .12 or .13
- * due to machine accuracy. On
- * the other hand, if we add a
- * something above machine
- * accuracy first, we will always
- * get .13.
+ * This functionality was introduced to produce more reproducible
+ * floating point output for regression tests. The rationale is, that an
+ * exact output value is much more likely to be 1/8 than 0.124997. If we
+ * round to two digits though, 1/8 becomes unreliably either .12 or .13
+ * due to machine accuracy. On the other hand, if we add a something
+ * above machine accuracy first, we will always get .13.
*
- * It is safe to leave this
- * value equal to zero. For
- * regression tests, the function
- * test_mode() sets it to a
- * reasonable value.
+ * It is safe to leave this value equal to zero. For regression tests,
+ * the function test_mode() sets it to a reasonable value.
*
- * The offset is relative to the
- * magnitude of the number.
+ * The offset is relative to the magnitude of the number.
*/
double offset;
bool print_thread_id;
/**
- * The value times() returned
- * on initialization.
+ * The value times() returned on initialization.
*/
double reference_time_val;
/**
- * The tms structure times()
- * filled on initialization.
+ * The tms structure times() filled on initialization.
*/
struct tms reference_tms;
/**
- * Original buffer of
- * <tt>std::cerr</tt>. We store
- * the address of that buffer
- * when #log_cerr is called, and
- * reset it to this value if
- * #log_cerr is called a second
- * time, or when the destructor
- * of this class is run.
+ * Original buffer of <tt>std::cerr</tt>. We store the address of that
+ * buffer when #log_cerr is called, and reset it to this value if
+ * #log_cerr is called a second time, or when the destructor of this
+ * class is run.
*/
std::streambuf *old_cerr;
/**
- * Print head of line. This prints
- * optional time information and
- * the contents of the prefix stack.
+ * A flag indicating whether output is currently at a new line
*/
- void print_line_head ();
+ bool at_newline;
/**
- * Actually do the work of
- * writing output. This function
- * unifies the work that is
- * common to the two
- * <tt>operator<<</tt> functions.
+ * Print head of line. This prints optional time information and the
+ * contents of the prefix stack.
*/
- template <typename T>
- void print (const T &t);
+ void print_line_head ();
+
/**
- * Check if we are on a new line
- * and print the header before
- * the data.
+ * Internal wrapper around "thread local" outstreams. This private
+ * function will return the correct internal ostringstream buffer for
+ * operater<<.
*/
std::ostringstream &get_stream();
typedef std::map<unsigned int, std_cxx1x::shared_ptr<std::ostringstream> > stream_map_type;
/**
- * We generate a stringstream for
- * every process that sends log
- * messages.
+ * We generate a stringstream for every process that sends log messages.
*/
stream_map_type outstreams;
/* ----------------------------- Inline functions and templates ---------------- */
-template <class T>
-inline
-void
-LogStream::print (const T &t)
-{
- // if the previous command was an
- // <tt>std::endl</tt>, print the topmost
- // prefix and a colon
- std::ostringstream &stream = get_stream();
- stream << t;
- // print the rest of the message
-// if (prefixes.size() <= std_depth)
-// *std_out << t;
-
-// if (file && (prefixes.size() <= file_depth))
-// *file << t;
-}
-
-
-
template <class T>
inline
LogStream &
LogStream::operator<< (const T &t)
{
- // do the work that is common to
- // the operator<< functions
- print (t);
+ // print to the internal stringstream:
+ get_stream() << t;
return *this;
}
LogStream &
LogStream::operator<< (const double t)
{
- // we have to make sure that we
- // don't catch NaN's and +-Inf's
- // with the test, because for these
- // denormals all comparisons are
- // always false. thus, for a NaN,
- // both t<=0 and t>=0 are false at
- // the same time, which can't be
- // said for any other number
+ // we have to make sure that we don't catch NaN's and +-Inf's with the
+ // test, because for these denormals all comparisons are always false.
+ // thus, for a NaN, both t<=0 and t>=0 are false at the same time, which
+ // can't be said for any other number
if (! (t<=0) && !(t>=0))
- print (t);
+ get_stream() << t;
else if (std::fabs(t) < double_threshold)
- print ('0');
+ get_stream() << '0';
else
- print(t*(1.+offset));
+ get_stream() << t*(1.+offset);
return *this;
}
LogStream &
LogStream::operator<< (const float t)
{
- // we have to make sure that we
- // don't catch NaN's and +-Inf's
- // with the test, because for these
- // denormals all comparisons are
- // always false. thus, for a NaN,
- // both t<=0 and t>=0 are false at
- // the same time, which can't be
- // said for any other number
+ // we have to make sure that we don't catch NaN's and +-Inf's with the
+ // test, because for these denormals all comparisons are always false.
+ // thus, for a NaN, both t<=0 and t>=0 are false at the same time, which
+ // can't be said for any other number
if (! (t<=0) && !(t>=0))
- print (t);
+ get_stream() << t;
else if (std::fabs(t) < float_threshold)
- print ('0');
+ get_stream() << '0';
else
- print(t*(1.+offset));
+ get_stream() << t*(1.+offset);
return *this;
}
std_depth(10000), file_depth(10000),
print_utime(false), diff_utime(false),
last_time (0.), double_threshold(0.), float_threshold(0.),
- offset(0), old_cerr(0)
+ offset(0), old_cerr(0), at_newline(true)
{
prefixes.push("DEAL:");
std_out->setf(std::ios::showpoint | std::ios::left);
LogStream::~LogStream()
{
- // if there was anything left in
- // the stream that is current to
- // this thread, make sure we flush
- // it before it gets lost
+ // if there was anything left in the stream that is current to this
+ // thread, make sure we flush it before it gets lost
{
const unsigned int id = Threads::this_thread_id();
if ((outstreams.find(id) != outstreams.end())
&&
(outstreams[id]->str().length() > 0))
{
- // except the situation is
- // not quite that simple. if
- // this object is the
- // 'deallog' object, then it
- // is destroyed upon exit of
- // the program. since it's
- // defined in a shared
- // library that depends on
- // libstdc++.so, destruction
- // happens before destruction
- // of std::cout/cerr, but
- // after all file variables
- // defined in user programs
- // have been destroyed. in
- // other words, if we get
- // here and the object being
- // destroyed is 'deallog' and
- // if 'deallog' is associated
- // with a file stream, then
- // we're in trouble: we'll
- // try to write to a file
- // that doesn't exist any
- // more, and we're likely
- // going to crash (this is
- // tested by
- // base/log_crash_01). rather
- // than letting it come to
- // this, print a message to
- // the screen (note that we
- // can't issue an assertion
- // here either since Assert
- // may want to write to
- // 'deallog' itself, and
- // AssertThrow will throw an
- // exception that can't be
- // caught)
+ // except the situation is not quite that simple. if this object is
+ // the 'deallog' object, then it is destroyed upon exit of the
+ // program. since it's defined in a shared library that depends on
+ // libstdc++.so, destruction happens before destruction of
+ // std::cout/cerr, but after all file variables defined in user
+ // programs have been destroyed. in other words, if we get here and
+ // the object being destroyed is 'deallog' and if 'deallog' is
+ // associated with a file stream, then we're in trouble: we'll try
+ // to write to a file that doesn't exist any more, and we're likely
+ // going to crash (this is tested by base/log_crash_01). rather
+ // than letting it come to this, print a message to the screen
+ // (note that we can't issue an assertion here either since Assert
+ // may want to write to 'deallog' itself, and AssertThrow will
+ // throw an exception that can't be caught)
if ((this == &deallog) && file)
std::cerr << ("You still have content that was written to 'deallog' "
"but not flushed to the screen or a file while the "
if (old_cerr)
std::cerr.rdbuf(old_cerr);
- // on some systems, destroying the
- // outstreams objects of deallog
- // triggers some sort of memory
- // corruption, in particular when
- // we also link with Trilinos;
- // since this happens at the very
- // end of the program, we take the
- // liberty to simply not do it by
- // putting that object into a
- // deliberate memory leak and
- // instead destroying an empty
- // object
+ // on some systems, destroying the outstreams objects of deallog triggers
+ // some sort of memory corruption, in particular when we also link with
+ // Trilinos; since this happens at the very end of the program, we take
+ // the liberty to simply not do it by putting that object into a
+ // deliberate memory leak and instead destroying an empty object
#ifdef DEAL_II_WITH_TRILINOS
if (this == &deallog)
{
LogStream &
LogStream::operator<< (std::ostream& (*p) (std::ostream &))
{
- // do the work that is common to
- // the operator<< functions
- print (p);
+ std::ostringstream &stream = get_stream();
- // next check whether this is the
- // <tt>endl</tt> manipulator, and if so
- // set a flag
+ // Print to the internal stringstream:
+ stream << p;
+
+ // Next check whether this is the <tt>flush</tt> or <tt>endl</tt>
+ // manipulator, and if so print out the message.
+ std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
std::ostream & (* const p_endl) (std::ostream &) = &std::endl;
- if (p == p_endl)
+ if (p == p_flush || p == p_endl)
{
Threads::Mutex::ScopedLock lock(write_lock);
- print_line_head();
- std::ostringstream &stream = get_stream();
+
+ // Print the line head in case of a newline:
+ if (at_newline)
+ print_line_head();
+
+ if(p == p_flush)
+ at_newline = false;
+
+ if(p == p_endl)
+ at_newline = true;
+
if (prefixes.size() <= std_depth)
*std_out << stream.str();
// Start a new string
stream.str("");
}
+
return *this;
}
}
-
void
LogStream::attach(std::ostream &o)
{