[llvm-commits] [llvm] r55246 - in /llvm/trunk: include/llvm/Support/raw_ostream.h lib/Support/raw_ostream.cpp

Chris Lattner sabre at nondot.org
Sat Aug 23 12:23:10 PDT 2008


Author: lattner
Date: Sat Aug 23 14:23:10 2008
New Revision: 55246

URL: http://llvm.org/viewvc/llvm-project?rev=55246&view=rev
Log:
add a simple mechanism for formatted output.  This gives raw_ostream's 
all the power and risk of fprintf format strings.  Use them like this:

  OS << format("%10.4f", 42.0) << "\n" << format("%x", 42) << '\n';


Modified:
    llvm/trunk/include/llvm/Support/raw_ostream.h
    llvm/trunk/lib/Support/raw_ostream.cpp

Modified: llvm/trunk/include/llvm/Support/raw_ostream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/raw_ostream.h?rev=55246&r1=55245&r2=55246&view=diff

==============================================================================
--- llvm/trunk/include/llvm/Support/raw_ostream.h (original)
+++ llvm/trunk/include/llvm/Support/raw_ostream.h Sat Aug 23 14:23:10 2008
@@ -21,7 +21,8 @@
 #include <iosfwd>
 
 namespace llvm {
-
+  class format_object_base;
+  
 /// raw_ostream - This class implements an extremely fast bulk output stream
 /// that can *only* output to a stream.  It does not support seeking, reopening,
 /// rewinding, line buffered disciplines etc. It is a simple buffer that outputs
@@ -92,11 +93,8 @@
   }
   
   raw_ostream &operator<<(unsigned long N);
-  
   raw_ostream &operator<<(long N);
-  
   raw_ostream &operator<<(unsigned long long N);
-  
   raw_ostream &operator<<(long long N);
   
   raw_ostream &operator<<(unsigned int N) {
@@ -111,9 +109,11 @@
     return this->operator<<(ftostr(N));
   }
   
-  
   raw_ostream &write(const char *Ptr, unsigned Size);
   
+  // Formatted output, see the format() function below.
+  raw_ostream &operator<<(const format_object_base &Fmt);
+  
   //===--------------------------------------------------------------------===//
   // Subclass Interface
   //===--------------------------------------------------------------------===//
@@ -137,6 +137,63 @@
   virtual void handle();
 };
   
+//===----------------------------------------------------------------------===//
+// Formatted Output
+//===----------------------------------------------------------------------===//
+
+/// format_object_base - This is a helper class used for handling formatted
+/// output.  It is the abstract base class of a templated derived class.
+class format_object_base {
+protected:
+  const char *Fmt;
+  virtual void home(); // Out of line virtual method.
+public:
+  format_object_base(const char *fmt) : Fmt(fmt) {}
+  virtual ~format_object_base() {}
+  
+  /// print - Format the object into the specified buffer.  On success, this
+  /// returns the length of the formatted string.  If the buffer is too small,
+  /// this returns a length to retry with, which will be larger than BufferSize.
+  virtual unsigned print(char *Buffer, unsigned BufferSize) const = 0;
+};
+  
+/// format_object - This is a templated helper class used by the format function
+/// that captures the object to be formated and the format string.  When
+/// actually printed, this synthesizes the string into a temporary buffer
+/// provided and returns whether or not it is big enough.
+template <typename T>
+  class format_object : public format_object_base {
+  T Val;
+public:
+  format_object(const char *fmt, const T &val)
+    : format_object_base(fmt), Val(val) {
+  }
+  
+  /// print - Format the object into the specified buffer.  On success, this
+  /// returns the length of the formatted string.  If the buffer is too small,
+  /// this returns a length to retry with, which will be larger than BufferSize.
+  virtual unsigned print(char *Buffer, unsigned BufferSize) const {
+    int N = snprintf(Buffer, BufferSize-1, Fmt, Val);
+    if (N < 0)             // VC++ and old GlibC return negative on overflow.
+      return BufferSize*2;
+    if (unsigned(N) >= BufferSize-1)// Other impls yield number of bytes needed.
+      return N+1;
+    // If N is positive and <= BufferSize-1, then the string fit, yay.
+    return N;
+  }
+};
+
+/// format - This is a helper function that is used to produce formatted output.
+/// This is typically used like:  OS << format("%0.4f", myfloat) << '\n';
+template <typename T>
+inline format_object<T> format(const char *Fmt, const T &Val) {
+  return format_object<T>(Fmt, Val);
+}
+  
+//===----------------------------------------------------------------------===//
+// File Output Streams
+//===----------------------------------------------------------------------===//
+  
 /// raw_fd_ostream - A raw_ostream that writes to a file descriptor.
 ///
 class raw_fd_ostream : public raw_ostream {
@@ -187,6 +244,10 @@
 raw_ostream &errs();
   
   
+//===----------------------------------------------------------------------===//
+// Bridge Output Streams
+//===----------------------------------------------------------------------===//
+  
 /// raw_os_ostream - A raw_ostream that writes to an std::ostream.  This is a
 /// simple adaptor class.
 class raw_os_ostream : public raw_ostream {

Modified: llvm/trunk/lib/Support/raw_ostream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/raw_ostream.cpp?rev=55246&r1=55245&r2=55246&view=diff

==============================================================================
--- llvm/trunk/lib/Support/raw_ostream.cpp (original)
+++ llvm/trunk/lib/Support/raw_ostream.cpp Sat Aug 23 14:23:10 2008
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Config/config.h"
 #include <ostream>
 
@@ -134,6 +135,55 @@
   return *this;
 }
 
+// Formatted output.
+raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
+  // If we have more than a few bytes left in our output buffer, try formatting
+  // directly onto its end.
+  unsigned NextBufferSize = 127;
+  if (OutBufEnd-OutBufCur > 3) {
+    unsigned BufferBytesLeft = OutBufEnd-OutBufCur;
+    unsigned BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
+    
+    // Common case is that we have plenty of space.
+    if (BytesUsed < BufferBytesLeft) {
+      OutBufCur += BytesUsed;
+      return *this;
+    }
+    
+    // Otherwise, we overflowed and the return value tells us the size to try
+    // again with.
+    NextBufferSize = BytesUsed;
+  }
+  
+  // If we got here, we didn't have enough space in the output buffer for the
+  // string.  Try printing into a SmallVector that is resized to have enough
+  // space.  Iterate until we win.
+  SmallVector<char, 128> V;
+  
+  while (1) {
+    V.resize(NextBufferSize);
+    
+    // Try formatting into the SmallVector.
+    unsigned BytesUsed = Fmt.print(&V[0], NextBufferSize);
+    
+    // If BytesUsed fit into the vector, we win.
+    if (BytesUsed < NextBufferSize)
+      return write(&V[0], BytesUsed);
+    
+    // Otherwise, try again with a new size.
+    assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
+    NextBufferSize = BytesUsed;
+  }
+}
+
+//===----------------------------------------------------------------------===//
+//  Formatted Output
+//===----------------------------------------------------------------------===//
+
+// Out of line virtual method.
+void format_object_base::home() {
+}
+
 //===----------------------------------------------------------------------===//
 //  raw_fd_ostream
 //===----------------------------------------------------------------------===//





More information about the llvm-commits mailing list