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';



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@55246 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2008-08-23 19:23:10 +00:00
parent 8ff7ce3dd2
commit 097af7fc8f
2 changed files with 116 additions and 5 deletions

View File

@ -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 @@ public:
}
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 @@ public:
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 @@ private:
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 &outs();
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 {

View File

@ -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 @@ raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
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
//===----------------------------------------------------------------------===//