diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel index 45208bd1..2b272ff8 100644 --- a/absl/log/BUILD.bazel +++ b/absl/log/BUILD.bazel @@ -169,9 +169,10 @@ cc_library( ":log", "//absl/base:config", "//absl/base:log_severity", - "//absl/memory", "//absl/strings", "//absl/strings:internal", + "//absl/types:optional", + "//absl/utility", ], ) diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index a803ca8f..20f1b686 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -506,9 +506,10 @@ absl_cc_library( absl::config absl::log absl::log_severity - absl::memory + absl::optional absl::strings absl::strings_internal + absl::utility PUBLIC ) diff --git a/absl/log/log_streamer.h b/absl/log/log_streamer.h index c3776cec..20327455 100644 --- a/absl/log/log_streamer.h +++ b/absl/log/log_streamer.h @@ -31,9 +31,10 @@ #include "absl/base/config.h" #include "absl/base/log_severity.h" #include "absl/log/log.h" -#include "absl/memory/memory.h" #include "absl/strings/internal/ostringstream.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -81,8 +82,7 @@ class LogStreamer final { : severity_(severity), line_(line), file_(file), - stream_( - absl::make_unique(&buf_)) { + stream_(absl::in_place, &buf_) { // To match `LOG`'s defaults: stream_->setf(std::ios_base::showbase | std::ios_base::boolalpha); } @@ -94,10 +94,8 @@ class LogStreamer final { line_(that.line_), file_(std::move(that.file_)), buf_(std::move(that.buf_)), - stream_(that.stream_ - ? absl::make_unique( - &buf_) - : nullptr) { + stream_(std::move(that.stream_)) { + if (stream_.has_value()) stream_->str(&buf_); that.stream_.reset(); } LogStreamer& operator=(LogStreamer&& that) { @@ -106,10 +104,8 @@ class LogStreamer final { file_ = std::move(that.file_); line_ = that.line_; buf_ = std::move(that.buf_); - stream_ = - that.stream_ - ? absl::make_unique(&buf_) - : nullptr; + stream_ = std::move(that.stream_); + if (stream_.has_value()) stream_->str(&buf_); that.stream_.reset(); return *this; } @@ -118,7 +114,8 @@ class LogStreamer final { // // Logs this LogStreamer's buffered content as if by LOG. ~LogStreamer() { - LOG_IF(LEVEL(severity_), stream_).AtLocation(file_, line_) << buf_; + LOG_IF(LEVEL(severity_), stream_.has_value()).AtLocation(file_, line_) + << buf_; } // LogStreamer::stream() @@ -132,11 +129,9 @@ class LogStreamer final { int line_; std::string file_; std::string buf_; - // TODO(durandal): de-pointerize this once we are off of our old mostly-C++11 - // libstdc++ (which lacks move constructors for std streams). - // `stream_` is null in a moved-from `LogStreamer`; this is in fact how we - // recognize one to avoid logging when it is destroyed or reassigned. - std::unique_ptr stream_; + // A disengaged `stream_` indicates a moved-from `LogStreamer` that should not + // `LOG` upon destruction. + absl::optional stream_; }; // LogInfoStreamer() diff --git a/absl/log/log_streamer_test.cc b/absl/log/log_streamer_test.cc index d7beb5bc..328d70d0 100644 --- a/absl/log/log_streamer_test.cc +++ b/absl/log/log_streamer_test.cc @@ -15,6 +15,7 @@ #include "absl/log/log_streamer.h" +#include #include #include @@ -300,48 +301,51 @@ TEST(LogStreamerTest, MoveConstruction) { EXPECT_CALL( test_sink, - Send(AllOf( - SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)), - LogSeverity(Eq(absl::LogSeverity::kInfo)), - TextMessage(Eq("hello world")), - ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "hello world" })pb")), - Stacktrace(IsEmpty())))); + Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)), + LogSeverity(Eq(absl::LogSeverity::kInfo)), + TextMessage(Eq("hello 0x10 world 0x10")), + ENCODED_MESSAGE(EqualsProto(R"pb(value { + str: "hello 0x10 world 0x10" + })pb")), + Stacktrace(IsEmpty())))); test_sink.StartCapturingLogs(); auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234); - streamer1.stream() << "hello"; + streamer1.stream() << "hello " << std::hex << 16; absl::LogStreamer streamer2(std::move(streamer1)); - streamer2.stream() << " world"; + streamer2.stream() << " world " << 16; } TEST(LogStreamerTest, MoveAssignment) { absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + testing::InSequence seq; EXPECT_CALL( test_sink, - Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)), - LogSeverity(Eq(absl::LogSeverity::kInfo)), - TextMessage(Eq("hello")), - ENCODED_MESSAGE(EqualsProto(R"pb(value { str: "hello" })pb")), + Send(AllOf(SourceFilename(Eq("path/file2.cc")), SourceLine(Eq(5678)), + LogSeverity(Eq(absl::LogSeverity::kWarning)), + TextMessage(Eq("something else")), + ENCODED_MESSAGE(EqualsProto(R"pb(value { + str: "something else" + })pb")), Stacktrace(IsEmpty())))); - EXPECT_CALL( test_sink, - Send(AllOf(SourceFilename(Eq("elsewhere/name.cc")), SourceLine(Eq(5678)), - LogSeverity(Eq(absl::LogSeverity::kWarning)), - TextMessage(Eq("world; goodbye")), + Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)), + LogSeverity(Eq(absl::LogSeverity::kInfo)), + TextMessage(Eq("hello 0x10 world 0x10")), ENCODED_MESSAGE(EqualsProto(R"pb(value { - str: "world; goodbye" + str: "hello 0x10 world 0x10" })pb")), Stacktrace(IsEmpty())))); test_sink.StartCapturingLogs(); auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234); - streamer1.stream() << "hello"; - auto streamer2 = absl::LogWarningStreamer("elsewhere/name.cc", 5678); - streamer2.stream() << "world"; - streamer1 = std::move(streamer2); - streamer1.stream() << "; goodbye"; + streamer1.stream() << "hello " << std::hex << 16; + auto streamer2 = absl::LogWarningStreamer("path/file2.cc", 5678); + streamer2.stream() << "something else"; + streamer2 = std::move(streamer1); + streamer2.stream() << " world " << 16; } TEST(LogStreamerTest, CorrectDefaultFlags) {