diff --git a/format-test.cc b/format-test.cc index ebee78e6..e8778f95 100644 --- a/format-test.cc +++ b/format-test.cc @@ -209,33 +209,31 @@ TEST(ArrayTest, Ctor) { #if FMT_USE_RVALUE_REFERENCES +void CheckMoveArray(const char *str, Array &array) { + Array array2(std::move(array)); + // Move shouldn't destroy the inline content of the first array. + EXPECT_EQ(str, std::string(&array[0], array.size())); + EXPECT_EQ(str, std::string(&array2[0], array2.size())); + EXPECT_EQ(5, array2.capacity()); +} + TEST(ArrayTest, MoveCtor) { Array array; const char test[] = "test"; array.append(test, test + 4); - { - Array array2(std::move(array)); - // Moving shouldn't destroy the inline content of the first array. - EXPECT_EQ(test, std::string(&array[0], array.size())); - EXPECT_EQ(test, std::string(&array2[0], array2.size())); - EXPECT_EQ(5, array2.capacity()); - } + CheckMoveArray("test", array); + // Adding one more character fills the inline buffer, but doesn't cause + // dynamic allocation. array.push_back('a'); - { - Array array2(std::move(array)); - // Moving shouldn't destroy the inline content of the first array. - EXPECT_EQ("testa", std::string(&array[0], array.size())); - EXPECT_EQ("testa", std::string(&array2[0], array2.size())); - EXPECT_EQ(5, array2.capacity()); - } + CheckMoveArray("testa", array); + // Adding one more character causes the content to move from the inline to + // a dynamically allocated buffer. array.push_back('b'); - { - Array array2(std::move(array)); - // Moving should rip the guts of the first array. - EXPECT_TRUE(!&array[0]); - EXPECT_EQ("testab", std::string(&array2[0], array2.size())); - EXPECT_GT(array2.capacity(), 5); - } + Array array2(std::move(array)); + // Move should rip the guts of the first array. + EXPECT_TRUE(!&array[0]); + EXPECT_EQ("testab", std::string(&array2[0], array2.size())); + EXPECT_GT(array2.capacity(), 5); } #endif // FMT_USE_RVALUE_REFERENCES @@ -317,6 +315,37 @@ TEST(WriterTest, Ctor) { EXPECT_EQ("", w.str()); } +#if FMT_USE_RVALUE_REFERENCES + +void CheckMoveWriter(const std::string &str, Writer &w) { + Writer w2(std::move(w)); + // Move shouldn't destroy the inline content of the first writer. + EXPECT_EQ(str, w.str()); + EXPECT_EQ(str, w2.str()); +} + +TEST(WriterTest, MoveCtor) { + Writer w; + w << "test"; + CheckMoveWriter("test", w); + // This fills the inline buffer, but doesn't cause dynamic allocation. + std::string s; + for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) + s += '*'; + w.Clear(); + w << s; + CheckMoveWriter(s, w); + // Adding one more character causes the content to move from the inline to + // a dynamically allocated buffer. + w << '*'; + Writer w2(std::move(w)); + // Move should rip the guts of the first writer. + EXPECT_TRUE(!w.data()); + EXPECT_EQ(s + '*', w2.str()); +} + +#endif // FMT_USE_RVALUE_REFERENCES + TEST(WriterTest, Data) { Writer w; w << 42; diff --git a/format.h b/format.h index c0faa26f..3c00294b 100644 --- a/format.h +++ b/format.h @@ -693,7 +693,8 @@ inline StrFormatSpec pad( template class BasicWriter { private: - mutable internal::Array buffer_; // Output buffer. + // Output buffer. + mutable internal::Array buffer_; // Make BasicFormatter a friend so that it can access ArgInfo and Arg. friend class BasicFormatter; @@ -897,7 +898,13 @@ class BasicWriter { BasicStringRef format, std::size_t num_args, const ArgInfo *args); }; - public: + public: + BasicWriter() {} + +#if FMT_USE_RVALUE_REFERENCES + BasicWriter(BasicWriter &&other) : buffer_(std::move(other.buffer_)) {} +#endif + /** Returns the number of characters written to the output buffer. */