]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Workaround for a problem in LogStream:
authorMatthias Maier <tamiko@kyomu.43-1.org>
Thu, 1 Aug 2013 23:00:22 +0000 (23:00 +0000)
committerMatthias Maier <tamiko@kyomu.43-1.org>
Thu, 1 Aug 2013 23:00:22 +0000 (23:00 +0000)
It is invalid to test for std::flush or std::endl with function pointers,

  std::ostream & (* const p_flush) (std::ostream &) = &std::flush; p ==
  p_flush ? ...,

as there could be multiple versions of of it.

And in fact, LLVM's libc++ implements std::flush and std::endl in a way
that every shared library and executable has its local copy.

Fix this by implementing a custom streambuf class that queries this sort of
information.

git-svn-id: https://svn.dealii.org/trunk@30213 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/source/base/logstream.cc

index ba7f8773f35290d9948b6518ba1cbf0d0c167966..e05f28a89bb977eddf9ed352400bcd1d5f653344 100644 (file)
@@ -137,23 +137,65 @@ LogStream::operator<< (std::ostream& (*p) (std::ostream &))
   // 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_flush || p == p_endl)
+
+  // This is a bloody hack until LogStream got reimplemented as a proper
+  // child of std::streambuf (or similar).
+  //
+  // The problem is that at this point we would like to know whether an
+  // std::flush or std::endl has called us, however, there is no way to
+  // detect this in a sane manner.
+  //
+  // The obvious idea to compare function pointers,
+  //   std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
+  //   p == p_flush ? ...,
+  // is wrong as there doesn't has to be a _single_ std::flush instance...
+  // there could be multiple of it. And in fact, LLVM's libc++ implements
+  // std::flush and std::endl in a way that every shared library and
+  // executable has its local copy... fun...
+  //
+  // - Maier, 2013
+
+  class QueryStreambuf : public std::streambuf
+  {
+    // Implement a minimalistic stream buffer that only stores the fact
+    // whether overflow or sync was called
+    public:
+      QueryStreambuf()
+        : _flushed(false), _newline_written(false)
+      {
+      }
+      bool flushed() { return _flushed; }
+      bool newline_written() { return _newline_written; }
+    private:
+      int_type overflow(int_type ch)
+        {
+          _newline_written = true;
+          return ch;
+        }
+      int sync()
+        {
+          _flushed = true;
+          return 0;
+        }
+      bool _flushed;
+      bool _newline_written;
+  } query_streambuf;
+
+  {
+    // and initialize an ostream with this streambuf:
+    std::ostream inject (&query_streambuf);
+    inject << p;
+  }
+
+  if (query_streambuf.flushed())
     {
       Threads::Mutex::ScopedLock lock(write_lock);
 
-      // Print the line head in case of a newline:
+      // Print the line head in case of a previous newline:
       if (at_newline)
         print_line_head();
 
-      if (p == p_flush)
-        at_newline = false;
-
-      if (p == p_endl)
-        at_newline = true;
+      at_newline = query_streambuf.newline_written();
 
       if (get_prefixes().size() <= std_depth)
         *std_out << stream.str();
@@ -161,7 +203,7 @@ LogStream::operator<< (std::ostream& (*p) (std::ostream &))
       if (file && (get_prefixes().size() <= file_depth))
         *file << stream.str() << std::flush;
 
-      // Start a new string
+      // Start a new string:
       stream.str("");
     }
 

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.