raw_ostream: Lift out flush_nonempty.

- Flush a known non-empty buffers; enforces the interface to
   flush_impl and kills off HandleFlush (which I saw no reason to be
   an inline method, Chris?).

 - Clarify invariant that flush_impl is only called with OutBufCur >
   OutBufStart.

 - This also cleary collects all places where we have to deal with the
   buffer possibly not existing.

 - A few more comments and fixing the unbuffered behavior remain in
   this commit sequence.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@67057 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2009-03-16 22:55:06 +00:00
parent 4752bd3b40
commit cf2a2c6a26
2 changed files with 59 additions and 44 deletions

View File

@ -31,6 +31,10 @@ namespace llvm {
/// a chunk at a time. /// a chunk at a time.
class raw_ostream { class raw_ostream {
protected: protected:
/// \invariant { The buffer is uninitialized (OutBufStart,
/// OutBufEnd, and OutBufCur are non-zero), or none of them are zero
/// and there are at least 64 total bytes in the buffer. }
char *OutBufStart, *OutBufEnd, *OutBufCur; char *OutBufStart, *OutBufEnd, *OutBufCur;
bool Unbuffered; bool Unbuffered;
@ -77,7 +81,7 @@ public:
void flush() { void flush() {
if (OutBufCur != OutBufStart) if (OutBufCur != OutBufStart)
flush_impl(); flush_nonempty();
} }
raw_ostream &operator<<(char C) { raw_ostream &operator<<(char C) {
@ -85,7 +89,7 @@ public:
return write(C); return write(C);
*OutBufCur++ = C; *OutBufCur++ = C;
if (Unbuffered) if (Unbuffered)
flush_impl(); flush_nonempty();
return *this; return *this;
} }
@ -94,7 +98,7 @@ public:
return write(C); return write(C);
*OutBufCur++ = C; *OutBufCur++ = C;
if (Unbuffered) if (Unbuffered)
flush_impl(); flush_nonempty();
return *this; return *this;
} }
@ -103,7 +107,7 @@ public:
return write(C); return write(C);
*OutBufCur++ = C; *OutBufCur++ = C;
if (Unbuffered) if (Unbuffered)
flush_impl(); flush_nonempty();
return *this; return *this;
} }
@ -142,23 +146,25 @@ public:
// Subclass Interface // Subclass Interface
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
protected: private:
/// flush_impl - The is the piece of the class that is implemented by /// flush_impl - The is the piece of the class that is implemented by
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This only outputs the currently buffered data.
/// buffer to empty. ///
/// raw_ostream guarantees to only call this routine when there is
/// buffered data, i.e. OutBufStart != OutBufCur.
virtual void flush_impl() = 0; virtual void flush_impl() = 0;
/// HandleFlush - A stream's implementation of flush should call this after
/// emitting the bytes to the data sink.
void HandleFlush() {
if (OutBufStart == 0)
SetBufferSize(4096);
OutBufCur = OutBufStart;
}
private:
// An out of line virtual method to provide a home for the class vtable. // An out of line virtual method to provide a home for the class vtable.
virtual void handle(); virtual void handle();
//===--------------------------------------------------------------------===//
// Private Interface
//===--------------------------------------------------------------------===//
private:
/// 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.
void flush_nonempty();
}; };
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -192,8 +198,10 @@ public:
~raw_fd_ostream(); ~raw_fd_ostream();
/// flush_impl - The is the piece of the class that is implemented by /// flush_impl - The is the piece of the class that is implemented by
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This only outputs the currently buffered data.
/// buffer to empty. ///
/// raw_ostream guarantees to only call this routine when there is
/// buffered data, i.e. OutBufStart != OutBufCur.
virtual void flush_impl(); virtual void flush_impl();
/// close - Manually flush the stream and close the file. /// close - Manually flush the stream and close the file.
@ -249,8 +257,10 @@ public:
~raw_os_ostream(); ~raw_os_ostream();
/// flush_impl - The is the piece of the class that is implemented by /// flush_impl - The is the piece of the class that is implemented by
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This only outputs the currently buffered data.
/// buffer to empty. ///
/// raw_ostream guarantees to only call this routine when there is
/// buffered data, i.e. OutBufStart != OutBufCur.
virtual void flush_impl(); virtual void flush_impl();
}; };
@ -270,8 +280,10 @@ public:
} }
/// flush_impl - The is the piece of the class that is implemented by /// flush_impl - The is the piece of the class that is implemented by
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This only outputs the currently buffered data.
/// buffer to empty. ///
/// raw_ostream guarantees to only call this routine when there is
/// buffered data, i.e. OutBufStart != OutBufCur.
virtual void flush_impl(); virtual void flush_impl();
}; };
@ -284,8 +296,10 @@ public:
~raw_svector_ostream(); ~raw_svector_ostream();
/// flush_impl - The is the piece of the class that is implemented by /// flush_impl - The is the piece of the class that is implemented by
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This only outputs the currently buffered data.
/// buffer to empty. ///
/// raw_ostream guarantees to only call this routine when there is
/// buffered data, i.e. OutBufStart != OutBufCur.
virtual void flush_impl(); virtual void flush_impl();
}; };

View File

@ -116,17 +116,27 @@ raw_ostream &raw_ostream::operator<<(const void *P) {
return write(CurPtr, EndPtr-CurPtr); return write(CurPtr, EndPtr-CurPtr);
} }
void raw_ostream::flush_nonempty() {
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
flush_impl();
OutBufCur = OutBufStart;
}
raw_ostream &raw_ostream::write(unsigned char C) { raw_ostream &raw_ostream::write(unsigned char C) {
if (OutBufCur >= OutBufEnd) if (!OutBufStart)
flush_impl(); SetBufferSize(4096);
else if (OutBufCur >= OutBufEnd)
flush_nonempty();
*OutBufCur++ = C; *OutBufCur++ = C;
return *this; return *this;
} }
raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) { raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
if (OutBufCur+Size > OutBufEnd) if (!OutBufStart)
flush_impl(); SetBufferSize(4096);
else if (OutBufCur+Size > OutBufEnd)
flush_nonempty();
// Handle short strings specially, memcpy isn't very good at very short // Handle short strings specially, memcpy isn't very good at very short
// strings. // strings.
@ -153,14 +163,14 @@ raw_ostream &raw_ostream::write(const char *Ptr, unsigned Size) {
Ptr += NumToEmit; Ptr += NumToEmit;
Size -= NumToEmit; Size -= NumToEmit;
OutBufCur = OutBufStart + NumToEmit; OutBufCur = OutBufStart + NumToEmit;
flush_impl(); flush_nonempty();
} }
break; break;
} }
OutBufCur += Size; OutBufCur += Size;
if (Unbuffered) if (Unbuffered)
flush_impl(); flush();
return *this; return *this;
} }
@ -260,11 +270,8 @@ raw_fd_ostream::~raw_fd_ostream() {
void raw_fd_ostream::flush_impl() { void raw_fd_ostream::flush_impl() {
assert (FD >= 0 && "File already closed."); assert (FD >= 0 && "File already closed.");
if (OutBufCur-OutBufStart) { pos += (OutBufCur - OutBufStart);
pos += (OutBufCur - OutBufStart); ::write(FD, OutBufStart, OutBufCur-OutBufStart);
::write(FD, OutBufStart, OutBufCur-OutBufStart);
}
HandleFlush();
} }
void raw_fd_ostream::close() { void raw_fd_ostream::close() {
@ -319,9 +326,7 @@ raw_os_ostream::~raw_os_ostream() {
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This outputs the currently buffered data and resets the
/// buffer to empty. /// buffer to empty.
void raw_os_ostream::flush_impl() { void raw_os_ostream::flush_impl() {
if (OutBufCur-OutBufStart) OS.write(OutBufStart, OutBufCur-OutBufStart);
OS.write(OutBufStart, OutBufCur-OutBufStart);
HandleFlush();
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -336,9 +341,7 @@ raw_string_ostream::~raw_string_ostream() {
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This outputs the currently buffered data and resets the
/// buffer to empty. /// buffer to empty.
void raw_string_ostream::flush_impl() { void raw_string_ostream::flush_impl() {
if (OutBufCur-OutBufStart) OS.append(OutBufStart, OutBufCur-OutBufStart);
OS.append(OutBufStart, OutBufCur-OutBufStart);
HandleFlush();
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -353,8 +356,6 @@ raw_svector_ostream::~raw_svector_ostream() {
/// subclasses. This outputs the currently buffered data and resets the /// subclasses. This outputs the currently buffered data and resets the
/// buffer to empty. /// buffer to empty.
void raw_svector_ostream::flush_impl() { void raw_svector_ostream::flush_impl() {
if (OutBufCur-OutBufStart) OS.append(OutBufStart, OutBufCur);
OS.append(OutBufStart, OutBufCur);
HandleFlush();
} }