Document BasicStringWriter
diff --git a/doc/api.rst b/doc/api.rst
index 4ed9ae8..2cde812 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -157,6 +157,9 @@
.. doxygenclass:: fmt::BasicArrayWriter
:members:
+.. doxygenclass:: fmt::BasicStringWriter
+ :members:
+
.. doxygenfunction:: bin(int)
.. doxygenfunction:: oct(int)
diff --git a/fmt/string.h b/fmt/string.h
index 4fc1f76..1f82f95 100644
--- a/fmt/string.h
+++ b/fmt/string.h
@@ -14,6 +14,89 @@
namespace fmt {
+namespace internal {
+
+// A buffer that stores data in ``std::string``.
+template <typename Char>
+class StringBuffer : public Buffer<Char> {
+ private:
+ std::string data_;
+
+ protected:
+ virtual void grow(std::size_t size) {
+ data_.resize(size);
+ this->ptr_ = &data_[0];
+ this->capacity_ = size;
+ }
+
+ public:
+ // Moves the data to ``str`` clearing the buffer.
+ void move_to(std::string &str) {
+ data_.resize(this->size_);
+ str.swap(data_);
+ this->capacity_ = this->size_ = 0;
+ this->ptr_ = 0;
+ }
+};
+} // namespace internal
+
+/**
+ \rst
+ This class template provides operations for formatting and writing data
+ into a character stream. The output is stored in ``std::string`` that grows
+ dynamically.
+
+ You can use one of the following typedefs for common character types
+ and the standard allocator:
+
+ +---------------+----------------------------+
+ | Type | Definition |
+ +===============+============================+
+ | StringWriter | BasicStringWriter<char> |
+ +---------------+----------------------------+
+ | WStringWriter | BasicStringWriter<wchar_t> |
+ +---------------+----------------------------+
+
+ **Example**::
+
+ StringWriter out;
+ out << "The answer is " << 42 << "\n";
+
+ This will write the following output to the ``out`` object:
+
+ .. code-block:: none
+
+ The answer is 42
+
+ The output can be moved to an ``std::string`` with ``out.move_to()``.
+ \endrst
+ */
+template <typename Char>
+class BasicStringWriter : public BasicWriter<Char> {
+ private:
+ internal::StringBuffer<Char> buffer_;
+
+ public:
+ /**
+ \rst
+ Constructs a :class:`fmt::BasicStringWriter` object.
+ \endrst
+ */
+ BasicStringWriter() : Writer(buffer_) {}
+
+ /**
+ \rst
+ Moves the buffer content to *str* clearing the buffer.
+ \endrst
+ */
+ void move_to(std::string &str) {
+ buffer_.move_to(str);
+ }
+};
+
+typedef BasicStringWriter<char> StringWriter;
+typedef BasicStringWriter<wchar_t> WStringWriter;
+
/**
\rst
Converts *value* to ``std::string`` using the default format for type *T*.
diff --git a/test/string-test.cc b/test/string-test.cc
index 5ef8877..06265da 100644
--- a/test/string-test.cc
+++ b/test/string-test.cc
@@ -10,6 +10,63 @@
#include "fmt/string.h"
#include "gtest/gtest.h"
+using fmt::internal::StringBuffer;
+
+TEST(StringBufferTest, Empty) {
+ StringBuffer<char> buffer;
+ EXPECT_EQ(0, buffer.size());
+ EXPECT_EQ(0, buffer.capacity());
+ std::string data;
+ // std::string may have initial capacity.
+ std::size_t capacity = data.capacity();
+ buffer.move_to(data);
+ EXPECT_EQ("", data);
+ EXPECT_EQ(capacity, data.capacity());
+}
+
+TEST(StringBufferTest, Reserve) {
+ StringBuffer<char> buffer;
+ std::size_t capacity = std::string().capacity() + 10;
+ buffer.reserve(capacity);
+ EXPECT_EQ(0, buffer.size());
+ EXPECT_EQ(capacity, buffer.capacity());
+ std::string data;
+ buffer.move_to(data);
+ EXPECT_EQ("", data);
+}
+
+TEST(StringBufferTest, Resize) {
+ StringBuffer<char> buffer;
+ std::size_t size = std::string().capacity() + 10;
+ buffer.resize(size);
+ EXPECT_EQ(size, buffer.size());
+ EXPECT_EQ(size, buffer.capacity());
+ std::string data;
+ buffer.move_to(data);
+ EXPECT_EQ(size, data.size());
+}
+
+TEST(StringBufferTest, MoveTo) {
+ StringBuffer<char> buffer;
+ std::size_t size = std::string().capacity() + 10;
+ buffer.resize(size);
+ const char *p = &buffer[0];
+ std::string data;
+ buffer.move_to(data);
+ EXPECT_EQ(p, &data[0]);
+ EXPECT_EQ(0, buffer.size());
+ EXPECT_EQ(0, buffer.capacity());
+}
+
+TEST(StringWriterTest, MoveTo) {
+ fmt::StringWriter out;
+ out << "The answer is " << 42 << "\n";
+ std::string s;
+ out.move_to(s);
+ EXPECT_EQ("The answer is 42\n", s);
+ EXPECT_EQ(0, out.size());
+}
+
TEST(StringTest, ToString) {
EXPECT_EQ("42", fmt::to_string(42));
}