1 | //===-- llvm/Support/circular_raw_ostream.h - Buffered streams --*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains raw_ostream implementations for streams to do circular |
10 | // buffering of their output. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H |
15 | #define LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H |
16 | |
17 | #include "llvm/Support/raw_ostream.h" |
18 | |
19 | namespace llvm { |
20 | /// circular_raw_ostream - A raw_ostream which *can* save its data |
21 | /// to a circular buffer, or can pass it through directly to an |
22 | /// underlying stream if specified with a buffer of zero. |
23 | /// |
24 | class circular_raw_ostream : public raw_ostream { |
25 | public: |
26 | /// TAKE_OWNERSHIP - Tell this stream that it owns the underlying |
27 | /// stream and is responsible for cleanup, memory management |
28 | /// issues, etc. |
29 | /// |
30 | static constexpr bool TAKE_OWNERSHIP = true; |
31 | |
32 | /// REFERENCE_ONLY - Tell this stream it should not manage the |
33 | /// held stream. |
34 | /// |
35 | static constexpr bool REFERENCE_ONLY = false; |
36 | |
37 | private: |
38 | /// TheStream - The real stream we output to. We set it to be |
39 | /// unbuffered, since we're already doing our own buffering. |
40 | /// |
41 | raw_ostream *TheStream = nullptr; |
42 | |
43 | /// OwnsStream - Are we responsible for managing the underlying |
44 | /// stream? |
45 | /// |
46 | bool OwnsStream; |
47 | |
48 | /// BufferSize - The size of the buffer in bytes. |
49 | /// |
50 | size_t BufferSize; |
51 | |
52 | /// BufferArray - The actual buffer storage. |
53 | /// |
54 | char *BufferArray = nullptr; |
55 | |
56 | /// Cur - Pointer to the current output point in BufferArray. |
57 | /// |
58 | char *Cur; |
59 | |
60 | /// Filled - Indicate whether the buffer has been completely |
61 | /// filled. This helps avoid garbage output. |
62 | /// |
63 | bool Filled = false; |
64 | |
65 | /// Banner - A pointer to a banner to print before dumping the |
66 | /// log. |
67 | /// |
68 | const char *Banner; |
69 | |
70 | /// flushBuffer - Dump the contents of the buffer to Stream. |
71 | /// |
72 | void flushBuffer() { |
73 | if (Filled) |
74 | // Write the older portion of the buffer. |
75 | TheStream->write(Ptr: Cur, Size: BufferArray + BufferSize - Cur); |
76 | // Write the newer portion of the buffer. |
77 | TheStream->write(Ptr: BufferArray, Size: Cur - BufferArray); |
78 | Cur = BufferArray; |
79 | Filled = false; |
80 | } |
81 | |
82 | void write_impl(const char *Ptr, size_t Size) override; |
83 | |
84 | /// current_pos - Return the current position within the stream, |
85 | /// not counting the bytes currently in the buffer. |
86 | /// |
87 | uint64_t current_pos() const override { |
88 | // This has the same effect as calling TheStream.current_pos(), |
89 | // but that interface is private. |
90 | return TheStream->tell() - TheStream->GetNumBytesInBuffer(); |
91 | } |
92 | |
93 | public: |
94 | /// circular_raw_ostream - Construct an optionally |
95 | /// circular-buffered stream, handing it an underlying stream to |
96 | /// do the "real" output. |
97 | /// |
98 | /// As a side effect, if BuffSize is nonzero, the given Stream is |
99 | /// set to be Unbuffered. This is because circular_raw_ostream |
100 | /// does its own buffering, so it doesn't want another layer of |
101 | /// buffering to be happening underneath it. |
102 | /// |
103 | /// "Owns" tells the circular_raw_ostream whether it is |
104 | /// responsible for managing the held stream, doing memory |
105 | /// management of it, etc. |
106 | /// |
107 | circular_raw_ostream(raw_ostream &Stream, const char *, |
108 | size_t BuffSize = 0, bool Owns = REFERENCE_ONLY) |
109 | : raw_ostream(/*unbuffered*/ true), OwnsStream(Owns), |
110 | BufferSize(BuffSize), Banner(Header) { |
111 | if (BufferSize != 0) |
112 | BufferArray = new char[BufferSize]; |
113 | Cur = BufferArray; |
114 | setStream(Stream, Owns); |
115 | } |
116 | |
117 | ~circular_raw_ostream() override { |
118 | flush(); |
119 | flushBufferWithBanner(); |
120 | releaseStream(); |
121 | delete[] BufferArray; |
122 | } |
123 | |
124 | bool is_displayed() const override { |
125 | return TheStream->is_displayed(); |
126 | } |
127 | |
128 | /// setStream - Tell the circular_raw_ostream to output a |
129 | /// different stream. "Owns" tells circular_raw_ostream whether |
130 | /// it should take responsibility for managing the underlying |
131 | /// stream. |
132 | /// |
133 | void setStream(raw_ostream &Stream, bool Owns = REFERENCE_ONLY) { |
134 | releaseStream(); |
135 | TheStream = &Stream; |
136 | OwnsStream = Owns; |
137 | } |
138 | |
139 | /// flushBufferWithBanner - Force output of the buffer along with |
140 | /// a small header. |
141 | /// |
142 | void flushBufferWithBanner(); |
143 | |
144 | private: |
145 | /// releaseStream - Delete the held stream if needed. Otherwise, |
146 | /// transfer the buffer settings from this circular_raw_ostream |
147 | /// back to the underlying stream. |
148 | /// |
149 | void releaseStream() { |
150 | if (!TheStream) |
151 | return; |
152 | if (OwnsStream) |
153 | delete TheStream; |
154 | } |
155 | }; |
156 | } // end llvm namespace |
157 | |
158 | #endif |
159 | |