raw_ostream: Add the capability for subclasses to manually install an external
authorDaniel Dunbar <daniel@zuster.org>
Tue, 18 Aug 2009 23:42:36 +0000 (23:42 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Tue, 18 Aug 2009 23:42:36 +0000 (23:42 +0000)
buffer.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@79382 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/raw_ostream.h
lib/Support/raw_ostream.cpp

index 5e20deb16644d282eb7ee5e7c8adae5f931f42fd..339a143b67fa66b8124650ca94853fd350e3f1aa 100644 (file)
@@ -42,12 +42,25 @@ private:
   /// need to take the slow path to write a single character.
   ///
   /// The buffer is in one of three states:
-  ///  1. Unbuffered (Unbuffered == true)
-  ///  1. Uninitialized (Unbuffered == false && OutBufStart == 0).
-  ///  2. Buffered (Unbuffered == false && OutBufStart != 0 &&
+  ///  1. Unbuffered (BufferMode == Unbuffered)
+  ///  1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0).
+  ///  2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 &&
   ///               OutBufEnd - OutBufStart >= 64).
+  ///
+  /// If buffered, then the raw_ostream owns the buffer if (BufferMode ==
+  /// InternalBuffer); otherwise the buffer has been set via SetBuffer and is
+  /// managed by the subclass.
+  ///
+  /// If a subclass installs an external buffer using SetBuffer then it can wait
+  /// for a \see write_impl() call to handle the data which has been put into
+  /// this buffer.
   char *OutBufStart, *OutBufEnd, *OutBufCur;
-  bool Unbuffered;
+  
+  enum BufferKind {
+    Unbuffered = 0,
+    InternalBuffer,
+    ExternalBuffer
+  } BufferMode;
 
   /// Error This flag is true if an error of any kind has been detected.
   ///
@@ -68,7 +81,7 @@ public:
   };
 
   explicit raw_ostream(bool unbuffered=false)
-    : Unbuffered(unbuffered), Error(false) {
+    : BufferMode(unbuffered ? Unbuffered : InternalBuffer), Error(false) {
     // Start out ready to flush.
     OutBufStart = OutBufEnd = OutBufCur = 0;
   }
@@ -100,9 +113,12 @@ public:
   /// determined buffer size.
   void SetBuffered();
 
-  /// SetBufferrSize - Set the stream to be buffered, using the
+  /// SetBufferSize - Set the stream to be buffered, using the
   /// specified buffer size.
-  void SetBufferSize(size_t Size);
+  void SetBufferSize(size_t Size) {
+    flush();
+    SetBufferAndMode(new char[Size], Size, InternalBuffer);
+  }
 
   size_t GetBufferSize() {
     // If we're supposed to be buffered but haven't actually gotten around
@@ -118,7 +134,10 @@ public:
   /// unbuffered, the stream will flush after every write. This routine
   /// will also flush the buffer immediately when the stream is being
   /// set to unbuffered.
-  void SetUnbuffered();
+  void SetUnbuffered() {
+    flush();
+    SetBufferAndMode(0, 0, Unbuffered);
+  }
 
   size_t GetNumBytesInBuffer() const {
     return OutBufCur - OutBufStart;
@@ -175,7 +194,9 @@ public:
     return *this;
   }
 
-  raw_ostream &operator<<(const std::string& Str) {
+  raw_ostream &operator<<(const std::string &Str) {
+    // Avoid the fast path, it would only increase code size for a marginal win.
+
     write(Str.data(), Str.length());
     return *this;
   }
@@ -232,6 +253,13 @@ private:
   /// by subclasses.  This writes the \args Size bytes starting at
   /// \arg Ptr to the underlying stream.
   /// 
+  /// This function is guaranteed to only be called at a point at which it is
+  /// safe for the subclass to install a new buffer via SetBuffer.
+  ///
+  /// \arg Ptr - The start of the data to be written. For buffered streams this
+  /// is guaranteed to be the start of the buffer.
+  /// \arg Size - The number of bytes to be written.
+  ///
   /// \invariant { Size > 0 }
   virtual void write_impl(const char *Ptr, size_t Size) = 0;
 
@@ -243,6 +271,14 @@ private:
   virtual uint64_t current_pos() = 0;
 
 protected:
+  /// SetBuffer - Use the provided buffer as the raw_ostream buffer. This is
+  /// intended for use only by subclasses which can arrange for the output to go
+  /// directly into the desired output buffer, instead of being copied on each
+  /// flush.
+  void SetBuffer(char *BufferStart, size_t Size) {
+    SetBufferAndMode(BufferStart, Size, ExternalBuffer);
+  }
+
   /// preferred_buffer_size - Return an efficient buffer size for the
   /// underlying output mechanism.
   virtual size_t preferred_buffer_size();
@@ -259,6 +295,9 @@ protected:
   // Private Interface
   //===--------------------------------------------------------------------===//
 private:
+  /// SetBufferAndMode - Install the given buffer and mode.
+  void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode);
+
   /// flush_nonempty - Flush the current buffer, which is known to be
   /// non-empty. This outputs the currently buffered data and resets
   /// the buffer to empty.
@@ -422,7 +461,7 @@ class raw_svector_ostream : public raw_ostream {
   /// counting the bytes currently in the buffer.
   virtual uint64_t current_pos();
 public:
-  explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {}
+  explicit raw_svector_ostream(SmallVectorImpl<char> &O);
   ~raw_svector_ostream();
 
   /// tell - Return the current offset with the stream.
index ac9bc6418f438fd48fed6d469856b4bf573777b9..044b963ee1238afd5181c17131ac83dee31bb7d9 100644 (file)
@@ -52,7 +52,8 @@ raw_ostream::~raw_ostream() {
   assert(OutBufCur == OutBufStart &&
          "raw_ostream destructor called with non-empty buffer!");
 
-  delete [] OutBufStart;
+  if (BufferMode == InternalBuffer)
+    delete [] OutBufStart;
 
   // If there are any pending errors, report them now. Clients wishing
   // to avoid llvm_report_error calls should check for errors with
@@ -79,24 +80,21 @@ void raw_ostream::SetBuffered() {
     SetUnbuffered();
 }
 
-void raw_ostream::SetBufferSize(size_t Size) {
-  assert(Size >= 64 &&
-         "Buffer size must be somewhat large for invariants to hold");
-  flush();
+void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size, 
+                                    BufferKind Mode) {
+  assert(((Mode == Unbuffered && BufferStart == 0 && Size == 0) || 
+          (Mode != Unbuffered && BufferStart && Size >= 64)) &&
+         "stream must be unbuffered, or have >= 64 bytes of buffer");
+  // Make sure the current buffer is free of content (we can't flush here; the
+  // child buffer management logic will be in write_impl).
+  assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
 
-  delete [] OutBufStart;
-  OutBufStart = new char[Size];
+  if (BufferMode == InternalBuffer)
+    delete [] OutBufStart;
+  OutBufStart = BufferStart;
   OutBufEnd = OutBufStart+Size;
   OutBufCur = OutBufStart;
-  Unbuffered = false;
-}
-
-void raw_ostream::SetUnbuffered() {
-  flush();
-
-  delete [] OutBufStart;
-  OutBufStart = OutBufEnd = OutBufCur = 0;
-  Unbuffered = true;
+  BufferMode = Mode;
 }
 
 raw_ostream &raw_ostream::operator<<(unsigned long N) {
@@ -180,14 +178,15 @@ raw_ostream &raw_ostream::operator<<(const void *P) {
 
 void raw_ostream::flush_nonempty() {
   assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
-  write_impl(OutBufStart, OutBufCur - OutBufStart);
-  OutBufCur = OutBufStart;    
+  size_t Length = OutBufCur - OutBufStart;
+  OutBufCur = OutBufStart;
+  write_impl(OutBufStart, Length);
 }
 
 raw_ostream &raw_ostream::write(unsigned char C) {
   // Group exceptional cases into a single branch.
   if (OutBufCur >= OutBufEnd) {
-    if (Unbuffered) {
+    if (BufferMode == Unbuffered) {
       write_impl(reinterpret_cast<char*>(&C), 1);
       return *this;
     }
@@ -198,7 +197,7 @@ raw_ostream &raw_ostream::write(unsigned char C) {
       SetBuffered();
       // It's possible for the underlying stream to decline
       // buffering, so check this condition again.
-      if (Unbuffered) {
+      if (BufferMode == Unbuffered) {
         write_impl(reinterpret_cast<char*>(&C), 1);
         return *this;
       }
@@ -213,7 +212,7 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
   // Group exceptional cases into a single branch.
   if (BUILTIN_EXPECT(OutBufCur+Size > OutBufEnd, false)) {
     if (BUILTIN_EXPECT(!OutBufStart, false)) {
-      if (Unbuffered) {
+      if (BufferMode == Unbuffered) {
         write_impl(Ptr, Size);
         return *this;
       }
@@ -498,6 +497,9 @@ void raw_string_ostream::write_impl(const char *Ptr, size_t Size) {
 //  raw_svector_ostream
 //===----------------------------------------------------------------------===//
 
+raw_svector_ostream::raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
+}
+
 raw_svector_ostream::~raw_svector_ostream() {
   flush();
 }