Skip to content

Commit e18ea6f

Browse files
committed
Support: Skip buffering buffer_unique_ostream's owned stream
Change buffer_unique_ostream's constructor to call raw_ostream::SetUnbuffered() on its owned stream. Otherwise, buffer_unique_ostream's destructor could cause the owned stream to temporarily allocate a buffer only to be immediately flushed. Also add some tests for buffer_ostream and buffer_unique_ostream. Use the same naming scheme as other raw_ostream-related tests (e.g., `raw_ostreamTest` for the fixture, `raw_ostream_test.cpp` for the filename). (I considered changing buffer_ostream in the same way (calling SetUnbuffered on the referenced stream), but that seemed like overreach since the client may have more things to write.) (I considered merging buffer_ostream and buffer_unique_ostream into a single class (with a `raw_ostream&` and a `std::unique_ptr` that is only sometimes used), but that makes the class bigger and the small amount of code deduplication seems uncompelling.) Differential Revision: https://reviews.llvm.org/D110369
1 parent b83242e commit e18ea6f

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

llvm/include/llvm/Support/raw_ostream.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,11 @@ class buffer_unique_ostream : public raw_svector_ostream {
721721

722722
public:
723723
buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
724-
: raw_svector_ostream(Buffer), OS(std::move(OS)) {}
724+
: raw_svector_ostream(Buffer), OS(std::move(OS)) {
725+
// Turn off buffering on OS, which we now own, to avoid allocating a buffer
726+
// when the destructor writes only to be immediately flushed again.
727+
this->OS->SetUnbuffered();
728+
}
725729
~buffer_unique_ostream() override { *OS << str(); }
726730
};
727731

llvm/unittests/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ add_llvm_unittest(SupportTests
9292
WithColorTest.cpp
9393
YAMLIOTest.cpp
9494
YAMLParserTest.cpp
95+
buffer_ostream_test.cpp
9596
formatted_raw_ostream_test.cpp
9697
raw_fd_stream_test.cpp
9798
raw_ostream_test.cpp
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===- buffer_ostream_test.cpp - buffer_ostream tests ---------------------===//
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/ADT/SmallString.h"
10+
#include "llvm/Support/raw_ostream.h"
11+
#include "gtest/gtest.h"
12+
13+
using namespace llvm;
14+
15+
namespace {
16+
17+
/// Naive version of raw_svector_ostream that is buffered (by default) and
18+
/// doesn't support pwrite.
19+
class NaiveSmallVectorStream : public raw_ostream {
20+
public:
21+
uint64_t current_pos() const override { return Vector.size(); }
22+
void write_impl(const char *Ptr, size_t Size) override {
23+
Vector.append(Ptr, Ptr + Size);
24+
}
25+
26+
explicit NaiveSmallVectorStream(SmallVectorImpl<char> &Vector)
27+
: Vector(Vector) {}
28+
~NaiveSmallVectorStream() override { flush(); }
29+
30+
SmallVectorImpl<char> &Vector;
31+
};
32+
33+
TEST(buffer_ostreamTest, Reference) {
34+
SmallString<128> Dest;
35+
{
36+
NaiveSmallVectorStream DestOS(Dest);
37+
buffer_ostream BufferOS(DestOS);
38+
39+
// Writing and flushing should have no effect on Dest.
40+
BufferOS << "abcd";
41+
static_cast<raw_ostream &>(BufferOS).flush();
42+
EXPECT_EQ("", Dest);
43+
DestOS.flush();
44+
EXPECT_EQ("", Dest);
45+
}
46+
47+
// Write should land when constructor is called.
48+
EXPECT_EQ("abcd", Dest);
49+
}
50+
51+
TEST(buffer_ostreamTest, Owned) {
52+
SmallString<128> Dest;
53+
{
54+
auto DestOS = std::make_unique<NaiveSmallVectorStream>(Dest);
55+
56+
// Confirm that NaiveSmallVectorStream is buffered by default.
57+
EXPECT_NE(0u, DestOS->GetBufferSize());
58+
59+
// Confirm that passing ownership to buffer_unique_ostream sets it to
60+
// unbuffered. Also steal a reference to DestOS.
61+
NaiveSmallVectorStream &DestOSRef = *DestOS;
62+
buffer_unique_ostream BufferOS(std::move(DestOS));
63+
EXPECT_EQ(0u, DestOSRef.GetBufferSize());
64+
65+
// Writing and flushing should have no effect on Dest.
66+
BufferOS << "abcd";
67+
static_cast<raw_ostream &>(BufferOS).flush();
68+
EXPECT_EQ("", Dest);
69+
DestOSRef.flush();
70+
EXPECT_EQ("", Dest);
71+
}
72+
73+
// Write should land when constructor is called.
74+
EXPECT_EQ("abcd", Dest);
75+
}
76+
77+
} // end namespace

0 commit comments

Comments
 (0)