Skip to content

Commit 664b08a

Browse files
rebase and review comments
Created using spr 1.3.5
1 parent e575483 commit 664b08a

File tree

5 files changed

+394
-0
lines changed

5 files changed

+394
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===- raw_ostream_proxy.h - Proxies for raw output 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+
#ifndef LLVM_SUPPORT_RAW_OSTREAM_PROXY_H
10+
#define LLVM_SUPPORT_RAW_OSTREAM_PROXY_H
11+
12+
#include "llvm/Support/raw_ostream.h"
13+
14+
namespace llvm {
15+
16+
/// Common bits for \a raw_ostream_proxy_adaptor<>, split out to dedup in
17+
/// template instantions.
18+
class raw_ostream_proxy_adaptor_base {
19+
protected:
20+
raw_ostream_proxy_adaptor_base() = delete;
21+
raw_ostream_proxy_adaptor_base(const raw_ostream_proxy_adaptor_base &) =
22+
delete;
23+
24+
explicit raw_ostream_proxy_adaptor_base(raw_ostream &OS)
25+
: OS(&OS), PreferredBufferSize(OS.GetBufferSize()) {
26+
// Drop OS's buffer to make this->flush() forward. This proxy will add a
27+
// buffer in its place.
28+
OS.SetUnbuffered();
29+
}
30+
31+
~raw_ostream_proxy_adaptor_base() {
32+
assert(!OS && "Derived objects should call resetProxiedOS()");
33+
}
34+
35+
/// Stop proxying the stream, taking the derived object by reference as \p
36+
/// ThisProxyOS. Updates \p ThisProxyOS to stop buffering before setting \a
37+
/// OS to \c nullptr, ensuring that future writes crash immediately.
38+
void resetProxiedOS(raw_ostream &ThisProxyOS) {
39+
ThisProxyOS.SetUnbuffered();
40+
OS = nullptr;
41+
}
42+
43+
bool hasProxiedOS() const { return OS; }
44+
raw_ostream &getProxiedOS() const {
45+
assert(OS && "raw_ostream_proxy_adaptor use after reset");
46+
return *OS;
47+
}
48+
size_t getPreferredBufferSize() const { return PreferredBufferSize; }
49+
50+
private:
51+
raw_ostream *OS;
52+
53+
/// Caches the value of OS->GetBufferSize() at construction time.
54+
size_t PreferredBufferSize;
55+
};
56+
57+
/// Adaptor to create a stream class that proxies another \a raw_ostream.
58+
///
59+
/// Use \a raw_ostream_proxy_adaptor<> directly to implement an abstract
60+
/// derived class of \a raw_ostream as a proxy. Otherwise use \a
61+
/// raw_ostream_proxy.
62+
///
63+
/// Most operations are forwarded to the proxied stream.
64+
///
65+
/// If the proxied stream is buffered, the buffer is dropped and moved to this
66+
/// stream. This allows \a flush() to work correctly, flushing immediately from
67+
/// the proxy through to the final stream, and avoids any wasteful
68+
/// double-buffering.
69+
///
70+
/// \a enable_colors() changes both the proxied stream and the proxy itself.
71+
/// \a is_displayed() and \a has_colors() are forwarded to the proxy. \a
72+
/// changeColor(), resetColor(), and \a reverseColor() are not forwarded, since
73+
/// they need to call \a flush() and the buffer lives in the proxy.
74+
template <class RawOstreamT = raw_ostream>
75+
class raw_ostream_proxy_adaptor : public RawOstreamT,
76+
public raw_ostream_proxy_adaptor_base {
77+
void write_impl(const char *Ptr, size_t Size) override {
78+
getProxiedOS().write(Ptr, Size);
79+
}
80+
uint64_t current_pos() const override { return getProxiedOS().tell(); }
81+
size_t preferred_buffer_size() const override {
82+
return getPreferredBufferSize();
83+
}
84+
85+
public:
86+
void reserveExtraSpace(uint64_t ExtraSize) override {
87+
getProxiedOS().reserveExtraSpace(ExtraSize);
88+
}
89+
bool is_displayed() const override { return getProxiedOS().is_displayed(); }
90+
bool has_colors() const override { return getProxiedOS().has_colors(); }
91+
void enable_colors(bool enable) override {
92+
RawOstreamT::enable_colors(enable);
93+
getProxiedOS().enable_colors(enable);
94+
}
95+
96+
~raw_ostream_proxy_adaptor() override { resetProxiedOS(); }
97+
98+
protected:
99+
template <class... ArgsT>
100+
explicit raw_ostream_proxy_adaptor(raw_ostream &OS, ArgsT &&...Args)
101+
: RawOstreamT(std::forward<ArgsT>(Args)...),
102+
raw_ostream_proxy_adaptor_base(OS) {}
103+
104+
/// Stop proxying the stream. Flush and set up a crash for future writes.
105+
///
106+
/// For example, this can simplify logic when a subclass might have a longer
107+
/// lifetime than the stream it proxies.
108+
void resetProxiedOS() {
109+
raw_ostream_proxy_adaptor_base::resetProxiedOS(*this);
110+
}
111+
void resetProxiedOS(raw_ostream &) = delete;
112+
};
113+
114+
/// Adaptor for creating a stream that proxies a \a raw_pwrite_stream.
115+
template <class RawPwriteStreamT = raw_pwrite_stream>
116+
class raw_pwrite_stream_proxy_adaptor
117+
: public raw_ostream_proxy_adaptor<RawPwriteStreamT> {
118+
using RawOstreamAdaptorT = raw_ostream_proxy_adaptor<RawPwriteStreamT>;
119+
120+
void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override {
121+
this->flush();
122+
getProxiedOS().pwrite(Ptr, Size, Offset);
123+
}
124+
125+
protected:
126+
raw_pwrite_stream_proxy_adaptor() = default;
127+
template <class... ArgsT>
128+
explicit raw_pwrite_stream_proxy_adaptor(raw_pwrite_stream &OS,
129+
ArgsT &&...Args)
130+
: RawOstreamAdaptorT(OS, std::forward<ArgsT>(Args)...) {}
131+
132+
raw_pwrite_stream &getProxiedOS() const {
133+
return static_cast<raw_pwrite_stream &>(RawOstreamAdaptorT::getProxiedOS());
134+
}
135+
};
136+
137+
/// Non-owning proxy for a \a raw_ostream. Enables passing a stream into of an
138+
/// API that takes ownership.
139+
class raw_ostream_proxy : public raw_ostream_proxy_adaptor<> {
140+
void anchor() override;
141+
142+
public:
143+
raw_ostream_proxy(raw_ostream &OS) : raw_ostream_proxy_adaptor<>(OS) {}
144+
};
145+
146+
/// Non-owning proxy for a \a raw_pwrite_stream. Enables passing a stream
147+
/// into of an API that takes ownership.
148+
class raw_pwrite_stream_proxy : public raw_pwrite_stream_proxy_adaptor<> {
149+
void anchor() override;
150+
151+
public:
152+
raw_pwrite_stream_proxy(raw_pwrite_stream &OS)
153+
: raw_pwrite_stream_proxy_adaptor<>(OS) {}
154+
};
155+
156+
} // end namespace llvm
157+
158+
#endif // LLVM_SUPPORT_RAW_OSTREAM_PROXY_H

llvm/lib/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ add_llvm_component_library(LLVMSupport
261261
YAMLTraits.cpp
262262
raw_os_ostream.cpp
263263
raw_ostream.cpp
264+
raw_ostream_proxy.cpp
264265
raw_socket_stream.cpp
265266
regcomp.c
266267
regerror.c
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//===- raw_ostream_proxy.cpp - Implement the raw_ostream proxies ----------===//
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+
#include "llvm/Support/raw_ostream_proxy.h"
10+
11+
using namespace llvm;
12+
13+
void raw_ostream_proxy::anchor() {}
14+
15+
void raw_pwrite_stream_proxy::anchor() {}

llvm/unittests/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ add_llvm_unittest(SupportTests
104104
formatted_raw_ostream_test.cpp
105105
raw_fd_stream_test.cpp
106106
raw_ostream_test.cpp
107+
raw_ostream_proxy_test.cpp
107108
raw_pwrite_stream_test.cpp
108109
raw_sha1_ostream_test.cpp
109110
raw_socket_stream_test.cpp

0 commit comments

Comments
 (0)