diff options
-rw-r--r-- | include/llvm/Support/raw_ostream.h | 71 | ||||
-rw-r--r-- | lib/Support/raw_ostream.cpp | 50 |
2 files changed, 116 insertions, 5 deletions
diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h index 34e40da517..58d5be2741 100644 --- a/include/llvm/Support/raw_ostream.h +++ b/include/llvm/Support/raw_ostream.h @@ -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 { diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index d776fa583f..104dc77149 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -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 //===----------------------------------------------------------------------===// |