On Friday 18 December 2009 13:56, David Greene wrote:> On Friday 18 December 2009 13:53, David Greene wrote: > > > > + void releaseStream() { > > > > + // Delete the stream if needed. Otherwise, transfer the buffer > > > > + // settings from this raw_ostream back to the underlying > > > > stream. + if (!TheStream) > > > > + return; > > > > + if (DeleteStream) > > > > + delete TheStream; > > > > + else if (BufferSize > 0) > > > > + TheStream->SetBufferSize(BufferSize); > > > > + else > > > > + TheStream->SetUnbuffered(); > > > > > > Another issue is that this is transfering the circular stream's > > > buffer to the underlying stream. Would it make more sense and would it > > > be worth it to save the underlying streams buffer size and restore it > > > in releaseStream? > > > > Oh, I think this code is just wrong. I'll rework it. > > No, it's right. It's not transferring the buffer at all. It's just > setting the buffer size of the held stream when we release it. This code > is identical to the code in formatted_raw_ostream.Here's the updated patch. -Dave + /// DELETE_STREAM - Tell the destructor to delete the held stream. + /// + static const bool DELETE_STREAM = true; + + /// PRESERVE_STREAM - Tell the destructor to not delete the held + /// stream. + /// + static const bool PRESERVE_STREAM = false; + + private: + /// TheStream - The real stream we output to. We set it to be + /// unbuffered, since we're already doing our own buffering. + /// + raw_ostream *TheStream; + + /// DeleteStream - Do we need to delete TheStream in the + /// destructor? + /// + bool DeleteStream; + + /// BufferSize - The size of the buffer in bytes. + /// + size_t BufferSize; + + /// BufferArray - The actual buffer storage. + /// + char *BufferArray; + + /// Cur - Pointer to the current output point in BufferArray. + /// + char *Cur; + + /// printLog - Dump the contents of the buffer to Stream. + /// + void printLog(void) { + TheStream->write(BufferArray, BufferSize); + Cur = BufferArray; + } + + virtual void write_impl(const char *Ptr, size_t Size); + + /// current_pos - Return the current position within the stream, + /// not counting the bytes currently in the buffer. + virtual uint64_t current_pos() { + // This has the same effect as calling TheStream.current_pos(), + // but that interface is private. + return TheStream->tell() - TheStream->GetNumBytesInBuffer(); + } + + public: + /// circular_raw_ostream - Open the specified file for + /// writing. + /// + /// As a side effect, if BuffSize is nonzero, the given Stream is + /// set to be Unbuffered. This is because circular_raw_ostream + /// does its own buffering, so it doesn't want another layer of + /// buffering to be happening underneath it. + /// + circular_raw_ostream(raw_ostream &Stream, size_t BuffSize = 8192, + bool Delete = false) + : raw_ostream(/*unbuffered*/true), + TheStream(0), + DeleteStream(PRESERVE_STREAM), + BufferSize(BuffSize), + BufferArray(0) { + if (BufferSize > 0) + BufferArray = new char[BufferSize]; + Cur = BufferArray; + setStream(Stream, Delete); + } + explicit circular_raw_ostream() + : raw_ostream(/*unbuffered*/true), + TheStream(0), + DeleteStream(PRESERVE_STREAM), + BufferArray(0) { + Cur = BufferArray; + } + + ~circular_raw_ostream() { + flush(); + dumpLog(); + releaseStream(); + delete[] BufferArray; + } + + void setStream(raw_ostream &Stream, bool Delete = false) { + releaseStream(); + + TheStream = &Stream; + DeleteStream = Delete; + + if (BufferSize > 0) { + // This circular_raw_ostream will do its own buffering and it + // doesn't need or want TheStream to do another layer of + // buffering underneath. Tell TheStream not to do its own + // buffering. + TheStream->SetUnbuffered(); + } + } + + /// dumpLog - Force output of the buffer along with a small + /// header. + /// + void dumpLog(void); + + private: + void releaseStream() { + // Delete the stream if needed. Otherwise, transfer the buffer + // settings from this raw_ostream back to the underlying stream. + if (!TheStream) + return; + if (DeleteStream) + delete TheStream; + else if (BufferSize > 0) + TheStream->SetBufferSize(BufferSize); + else + TheStream->SetUnbuffered(); + } + }; +} // end llvm namespace + + +#endif Index: lib/Support/circular_raw_ostream.cpp ==================================================================--- lib/Support/circular_raw_ostream.cpp (revision 0) +++ lib/Support/circular_raw_ostream.cpp (revision 0) @@ -0,0 +1,46 @@ +//===- circulat_raw_ostream.cpp - Implement the circular_raw_ostream class -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements support for circular buffered streams. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/circular_raw_ostream.h" + +#include <algorithm> + +using namespace llvm; + +void circular_raw_ostream::write_impl(const char *Ptr, size_t Size) { + if (BufferSize > 0) { + // Write into the buffer, wrapping if necessary. + while (Size > 0) { + unsigned Bytes = std::min(Size, BufferSize); + memcpy(Cur, Ptr, Bytes); + Size -= Bytes; + if (Cur == BufferArray + BufferSize) + // Reset the output pointer to the start of the buffer. + Cur = BufferArray; + } + } + else { + TheStream->write(Ptr, Size); + } +} + +void circular_raw_ostream::dumpLog(void) { + if (BufferSize > 0) { + // Write out the buffer + const char *msg = "*** Log Output ***\n"; + int num = std::strlen(msg); + + TheStream->write(msg, num); + printLog(); + } +}
On Friday 18 December 2009 17:22, David Greene wrote:> On Friday 18 December 2009 13:56, David Greene wrote: > > On Friday 18 December 2009 13:53, David Greene wrote: > > > > > + void releaseStream() { > > > > > + // Delete the stream if needed. Otherwise, transfer the > > > > > buffer + // settings from this raw_ostream back to the > > > > > underlying stream. + if (!TheStream) > > > > > + return; > > > > > + if (DeleteStream) > > > > > + delete TheStream; > > > > > + else if (BufferSize > 0) > > > > > + TheStream->SetBufferSize(BufferSize); > > > > > + else > > > > > + TheStream->SetUnbuffered(); > > > > > > > > Another issue is that this is transfering the circular stream's > > > > buffer to the underlying stream. Would it make more sense and would > > > > it be worth it to save the underlying streams buffer size and restore > > > > it in releaseStream? > > > > > > Oh, I think this code is just wrong. I'll rework it. > > > > No, it's right. It's not transferring the buffer at all. It's just > > setting the buffer size of the held stream when we release it. This code > > is identical to the code in formatted_raw_ostream. > > Here's the updated patch.Well, that didn't go through right. Here it is again. -Dave Index: include/llvm/Support/circular_raw_ostream.h ==================================================================--- include/llvm/Support/circular_raw_ostream.h (revision 0) +++ include/llvm/Support/circular_raw_ostream.h (revision 0) @@ -0,0 +1,149 @@ +//===-- llvm/Support/circular_raw_ostream.h - Buffered streams --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains raw_ostream implementations for streams to do circular +// buffering of their output. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H +#define LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H + +#include "llvm/Support/raw_ostream.h" + +namespace llvm +{ + /// circular_raw_ostream - A raw_ostream that saves its output in a + /// circular buffer. + /// + class circular_raw_ostream : public raw_ostream { + public: + /// DELETE_STREAM - Tell the destructor to delete the held stream. + /// + static const bool DELETE_STREAM = true; + + /// PRESERVE_STREAM - Tell the destructor to not delete the held + /// stream. + /// + static const bool PRESERVE_STREAM = false; + + private: + /// TheStream - The real stream we output to. We set it to be + /// unbuffered, since we're already doing our own buffering. + /// + raw_ostream *TheStream; + + /// DeleteStream - Do we need to delete TheStream in the + /// destructor? + /// + bool DeleteStream; + + /// BufferSize - The size of the buffer in bytes. + /// + size_t BufferSize; + + /// BufferArray - The actual buffer storage. + /// + char *BufferArray; + + /// Cur - Pointer to the current output point in BufferArray. + /// + char *Cur; + + /// printLog - Dump the contents of the buffer to Stream. + /// + void printLog(void) { + TheStream->write(BufferArray, BufferSize); + Cur = BufferArray; + } + + virtual void write_impl(const char *Ptr, size_t Size); + + /// current_pos - Return the current position within the stream, + /// not counting the bytes currently in the buffer. + virtual uint64_t current_pos() { + // This has the same effect as calling TheStream.current_pos(), + // but that interface is private. + return TheStream->tell() - TheStream->GetNumBytesInBuffer(); + } + + public: + /// circular_raw_ostream - Open the specified file for + /// writing. + /// + /// As a side effect, if BuffSize is nonzero, the given Stream is + /// set to be Unbuffered. This is because circular_raw_ostream + /// does its own buffering, so it doesn't want another layer of + /// buffering to be happening underneath it. + /// + circular_raw_ostream(raw_ostream &Stream, size_t BuffSize = 8192, + bool Delete = false) + : raw_ostream(/*unbuffered*/true), + TheStream(0), + DeleteStream(PRESERVE_STREAM), + BufferSize(BuffSize), + BufferArray(0) { + if (BufferSize > 0) + BufferArray = new char[BufferSize]; + Cur = BufferArray; + setStream(Stream, Delete); + } + explicit circular_raw_ostream() + : raw_ostream(/*unbuffered*/true), + TheStream(0), + DeleteStream(PRESERVE_STREAM), + BufferArray(0) { + Cur = BufferArray; + } + + ~circular_raw_ostream() { + flush(); + dumpLog(); + releaseStream(); + delete[] BufferArray; + } + + void setStream(raw_ostream &Stream, bool Delete = false) { + releaseStream(); + + TheStream = &Stream; + DeleteStream = Delete; + + if (BufferSize > 0) { + // This circular_raw_ostream will do its own buffering and it + // doesn't need or want TheStream to do another layer of + // buffering underneath. Tell TheStream not to do its own + // buffering. + TheStream->SetUnbuffered(); + } + } + + /// dumpLog - Force output of the buffer along with a small + /// header. + /// + void dumpLog(void); + + private: + void releaseStream() { + // Delete the stream if needed. Otherwise, transfer the buffer + // settings from this raw_ostream back to the underlying stream. + if (!TheStream) + return; + if (DeleteStream) + delete TheStream; + else if (BufferSize > 0) + TheStream->SetBufferSize(BufferSize); + else + TheStream->SetUnbuffered(); + } + }; +} // end llvm namespace + + +#endif Index: lib/Support/circular_raw_ostream.cpp ==================================================================--- lib/Support/circular_raw_ostream.cpp (revision 0) +++ lib/Support/circular_raw_ostream.cpp (revision 0) @@ -0,0 +1,46 @@ +//===- circulat_raw_ostream.cpp - Implement the circular_raw_ostream class -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements support for circular buffered streams. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/circular_raw_ostream.h" + +#include <algorithm> + +using namespace llvm; + +void circular_raw_ostream::write_impl(const char *Ptr, size_t Size) { + if (BufferSize > 0) { + // Write into the buffer, wrapping if necessary. + while (Size > 0) { + unsigned Bytes = std::min(Size, BufferSize); + memcpy(Cur, Ptr, Bytes); + Size -= Bytes; + if (Cur == BufferArray + BufferSize) + // Reset the output pointer to the start of the buffer. + Cur = BufferArray; + } + } + else { + TheStream->write(Ptr, Size); + } +} + +void circular_raw_ostream::dumpLog(void) { + if (BufferSize > 0) { + // Write out the buffer + const char *msg = "*** Log Output ***\n"; + int num = std::strlen(msg); + + TheStream->write(msg, num); + printLog(); + } +}
On Friday 18 December 2009 17:27, David Greene wrote:> > Here's the updated patch. > > Well, that didn't go through right. Here it is again.Argh! Stupid bug fixed. :) Index: include/llvm/Support/circular_raw_ostream.h ==================================================================--- include/llvm/Support/circular_raw_ostream.h (revision 0) +++ include/llvm/Support/circular_raw_ostream.h (revision 0) @@ -0,0 +1,149 @@ +//===-- llvm/Support/circular_raw_ostream.h - Buffered streams --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains raw_ostream implementations for streams to do circular +// buffering of their output. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H +#define LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H + +#include "llvm/Support/raw_ostream.h" + +namespace llvm +{ + /// circular_raw_ostream - A raw_ostream that saves its output in a + /// circular buffer. + /// + class circular_raw_ostream : public raw_ostream { + public: + /// DELETE_STREAM - Tell the destructor to delete the held stream. + /// + static const bool DELETE_STREAM = true; + + /// PRESERVE_STREAM - Tell the destructor to not delete the held + /// stream. + /// + static const bool PRESERVE_STREAM = false; + + private: + /// TheStream - The real stream we output to. We set it to be + /// unbuffered, since we're already doing our own buffering. + /// + raw_ostream *TheStream; + + /// DeleteStream - Do we need to delete TheStream in the + /// destructor? + /// + bool DeleteStream; + + /// BufferSize - The size of the buffer in bytes. + /// + size_t BufferSize; + + /// BufferArray - The actual buffer storage. + /// + char *BufferArray; + + /// Cur - Pointer to the current output point in BufferArray. + /// + char *Cur; + + /// printLog - Dump the contents of the buffer to Stream. + /// + void printLog(void) { + TheStream->write(BufferArray, BufferSize); + Cur = BufferArray; + } + + virtual void write_impl(const char *Ptr, size_t Size); + + /// current_pos - Return the current position within the stream, + /// not counting the bytes currently in the buffer. + virtual uint64_t current_pos() { + // This has the same effect as calling TheStream.current_pos(), + // but that interface is private. + return TheStream->tell() - TheStream->GetNumBytesInBuffer(); + } + + public: + /// circular_raw_ostream - Open the specified file for + /// writing. + /// + /// As a side effect, if BuffSize is nonzero, the given Stream is + /// set to be Unbuffered. This is because circular_raw_ostream + /// does its own buffering, so it doesn't want another layer of + /// buffering to be happening underneath it. + /// + circular_raw_ostream(raw_ostream &Stream, size_t BuffSize = 8192, + bool Delete = false) + : raw_ostream(/*unbuffered*/true), + TheStream(0), + DeleteStream(PRESERVE_STREAM), + BufferSize(BuffSize), + BufferArray(0) { + if (BufferSize > 0) + BufferArray = new char[BufferSize]; + Cur = BufferArray; + setStream(Stream, Delete); + } + explicit circular_raw_ostream() + : raw_ostream(/*unbuffered*/true), + TheStream(0), + DeleteStream(PRESERVE_STREAM), + BufferArray(0) { + Cur = BufferArray; + } + + ~circular_raw_ostream() { + flush(); + dumpLog(); + releaseStream(); + delete[] BufferArray; + } + + void setStream(raw_ostream &Stream, bool Delete = false) { + releaseStream(); + + TheStream = &Stream; + DeleteStream = Delete; + + if (BufferSize > 0) { + // This circular_raw_ostream will do its own buffering and it + // doesn't need or want TheStream to do another layer of + // buffering underneath. Tell TheStream not to do its own + // buffering. + TheStream->SetUnbuffered(); + } + } + + /// dumpLog - Force output of the buffer along with a small + /// header. + /// + void dumpLog(void); + + private: + void releaseStream() { + // Delete the stream if needed. Otherwise, transfer the buffer + // settings from this raw_ostream back to the underlying stream. + if (!TheStream) + return; + if (DeleteStream) + delete TheStream; + else if (BufferSize > 0) + TheStream->SetBufferSize(BufferSize); + else + TheStream->SetUnbuffered(); + } + }; +} // end llvm namespace + + +#endif Index: lib/Support/circular_raw_ostream.cpp ==================================================================--- lib/Support/circular_raw_ostream.cpp (revision 0) +++ lib/Support/circular_raw_ostream.cpp (revision 0) @@ -0,0 +1,47 @@ +//===- circulat_raw_ostream.cpp - Implement the circular_raw_ostream class -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements support for circular buffered streams. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/circular_raw_ostream.h" + +#include <algorithm> + +using namespace llvm; + +void circular_raw_ostream::write_impl(const char *Ptr, size_t Size) { + if (BufferSize > 0) { + // Write into the buffer, wrapping if necessary. + while (Size > 0) { + unsigned Bytes = std::min(Size, BufferSize - (Cur - BufferArray)); + memcpy(Cur, Ptr, Bytes); + Size -= Bytes; + Cur += Bytes; + if (Cur == BufferArray + BufferSize) + // Reset the output pointer to the start of the buffer. + Cur = BufferArray; + } + } + else { + TheStream->write(Ptr, Size); + } +} + +void circular_raw_ostream::dumpLog(void) { + if (BufferSize > 0) { + // Write out the buffer + const char *msg = "*** Log Output ***\n"; + int num = std::strlen(msg); + + TheStream->write(msg, num); + printLog(); + } +}