Pass buffer instead of writer to format_value
diff --git a/fmt/format.cc b/fmt/format.cc
index 1e34dab..cd8a244 100644
--- a/fmt/format.cc
+++ b/fmt/format.cc
@@ -106,7 +106,7 @@
 
 const char RESET_COLOR[] = "\x1b[0m";
 
-typedef void (*FormatFunc)(writer &, int, StringRef);
+typedef void (*FormatFunc)(buffer &, int, StringRef);
 
 // Portable thread-safe version of strerror.
 // Sets buffer to point to a string describing the error code.
@@ -176,7 +176,7 @@
   return StrError(error_code, buffer, buffer_size).run();
 }
 
-void format_error_code(writer &out, int error_code,
+void format_error_code(buffer &out, int error_code,
                        StringRef message) FMT_NOEXCEPT {
   // Report error code making sure that the output fits into
   // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
@@ -193,18 +193,19 @@
     ++error_code_size;
   }
   error_code_size += internal::count_digits(abs_value);
+  basic_writer<char> w(out);
   if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
-    out.write(message);
-    out.write(SEP);
+    w.write(message);
+    w.write(SEP);
   }
-  out.write(ERROR_STR);
-  out.write(error_code);
+  w.write(ERROR_STR);
+  w.write(error_code);
   assert(out.size() <= internal::INLINE_BUFFER_SIZE);
 }
 
 void report_error(FormatFunc func, int error_code,
                   StringRef message) FMT_NOEXCEPT {
-  MemoryWriter full_message;
+  internal::MemoryBuffer<char> full_message;
   func(full_message, error_code, message);
   // Use Writer::data instead of Writer::c_str to avoid potential memory
   // allocation.
@@ -213,23 +214,13 @@
 }
 }  // namespace
 
-namespace internal {
-
-// This method is used to preserve binary compatibility with fmt 3.0.
-// It can be removed in 4.0.
-FMT_FUNC void format_system_error(
-  writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
-  fmt::format_system_error(out, error_code, message);
-}
-}  // namespace internal
-
 FMT_FUNC void SystemError::init(
     int err_code, CStringRef format_str, args args) {
   error_code_ = err_code;
-  MemoryWriter w;
-  format_system_error(w, err_code, vformat(format_str, args));
+  internal::MemoryBuffer<char> buf;
+  format_system_error(buf, err_code, vformat(format_str, args));
   std::runtime_error &base = *this;
-  base = std::runtime_error(w.str());
+  base = std::runtime_error(to_string(buf));
 }
 
 template <typename T>
@@ -388,7 +379,7 @@
 #endif  // FMT_USE_WINDOWS_H
 
 FMT_FUNC void format_system_error(
-    writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
+    buffer &out, int error_code, StringRef message) FMT_NOEXCEPT {
   FMT_TRY {
     internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
     buffer.resize(internal::INLINE_BUFFER_SIZE);
@@ -396,9 +387,10 @@
       char *system_message = &buffer[0];
       int result = safe_strerror(error_code, system_message, buffer.size());
       if (result == 0) {
-        out.write(message);
-        out.write(": ");
-        out.write(system_message);
+        basic_writer<char> w(out);
+        w.write(message);
+        w.write(": ");
+        w.write(system_message);
         return;
       }
       if (result != ERANGE)
@@ -410,7 +402,7 @@
 }
 
 template <typename Char>
-void internal::FixedBuffer<Char>::grow(std::size_t) {
+void FixedBuffer<Char>::grow(std::size_t) {
   FMT_THROW(std::runtime_error("buffer overflow"));
 }
 
@@ -429,9 +421,9 @@
 #endif
 
 FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) {
-  MemoryWriter w;
-  w.vformat(format_str, args);
-  std::fwrite(w.data(), 1, w.size(), f);
+  internal::MemoryBuffer<char> buffer;
+  vformat_to(buffer, format_str, args);
+  std::fwrite(buffer.data(), 1, buffer.size(), f);
 }
 
 FMT_FUNC void vprint(CStringRef format_str, args args) {
@@ -451,10 +443,11 @@
             args args);
 
 FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) {
-  MemoryWriter w;
-  printf(w, format, args);
-  std::size_t size = w.size();
-  return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
+  internal::MemoryBuffer<char> buffer;
+  printf(buffer, format, args);
+  std::size_t size = buffer.size();
+  return std::fwrite(
+        buffer.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
 }
 
 #ifndef FMT_HEADER_ONLY
@@ -463,11 +456,11 @@
 
 // Explicit instantiations for char.
 
-template void internal::FixedBuffer<char>::grow(std::size_t);
+template void FixedBuffer<char>::grow(std::size_t);
 
 template void internal::ArgMap<context>::init(const args &args);
 
-template void printf_context<char>::format(writer &writer);
+template void printf_context<char>::format(buffer &);
 
 template int internal::CharTraits<char>::format_float(
     char *buffer, std::size_t size, const char *format,
@@ -481,11 +474,11 @@
 
 template class basic_context<wchar_t>;
 
-template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
+template void FixedBuffer<wchar_t>::grow(std::size_t);
 
 template void internal::ArgMap<wcontext>::init(const wargs &args);
 
-template void printf_context<wchar_t>::format(wwriter &writer);
+template void printf_context<wchar_t>::format(wbuffer &);
 
 template int internal::CharTraits<wchar_t>::format_float(
     wchar_t *buffer, std::size_t size, const wchar_t *format,
diff --git a/fmt/format.h b/fmt/format.h
index 3857a11..5b8f5bd 100644
--- a/fmt/format.h
+++ b/fmt/format.h
@@ -365,10 +365,13 @@
 #endif
 
 template <typename Char>
-class basic_writer;
+class basic_buffer;
 
-typedef basic_writer<char> writer;
-typedef basic_writer<wchar_t> wwriter;
+typedef basic_buffer<char> buffer;
+typedef basic_buffer<wchar_t> wbuffer;
+
+template <typename Char>
+class basic_writer;
 
 template <typename Context>
 class basic_arg;
@@ -616,6 +619,9 @@
   /** Returns the capacity of this buffer. */
   std::size_t capacity() const { return capacity_; }
 
+  /** Returns a pointer to the buffer data. */
+  const T *data() const { return ptr_; }
+
   /**
     Resizes the buffer. If T is a POD type new elements may not be initialized.
    */
@@ -662,11 +668,17 @@
   size_ = new_size;
 }
 
+template <typename Char>
+inline std::basic_string<Char> to_string(const basic_buffer<Char>& buffer) {
+  return std::basic_string<Char>(buffer.data(), buffer.size());
+}
+
 namespace internal {
 
 // A memory buffer for trivially copyable/constructible types with the first
 // SIZE elements stored in the object itself.
-template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
+template <typename T, std::size_t SIZE = INLINE_BUFFER_SIZE,
+          typename Allocator = std::allocator<T> >
 class MemoryBuffer : private Allocator, public basic_buffer<T> {
  private:
   T data_[SIZE];
@@ -741,17 +753,6 @@
     Allocator::deallocate(old_ptr, old_capacity);
 }
 
-// A fixed-size buffer.
-template <typename Char>
-class FixedBuffer : public fmt::basic_buffer<Char> {
- public:
-  FixedBuffer(Char *array, std::size_t size)
-    : fmt::basic_buffer<Char>(array, size) {}
-
- protected:
-  FMT_API void grow(std::size_t size);
-};
-
 template <typename Char>
 class BasicCharTraits {
  public:
@@ -988,7 +989,7 @@
   FMT_API int convert(WStringRef s);
 };
 
-FMT_API void format_windows_error(fmt::writer &out, int error_code,
+FMT_API void format_windows_error(fmt::buffer &out, int error_code,
                                   fmt::StringRef message) FMT_NOEXCEPT;
 #endif
 
@@ -1085,7 +1086,7 @@
 template <typename Char>
 struct CustomValue {
   typedef void (*FormatFunc)(
-      basic_writer<Char> &writer, const void *arg, void *ctx);
+      basic_buffer<Char> &buffer, const void *arg, void *ctx);
 
   const void *value;
   FormatFunc format;
@@ -1207,8 +1208,8 @@
   // Formats an argument of a custom type, such as a user-defined class.
   template <typename T>
   static void format_custom_arg(
-      basic_writer<Char> &writer, const void *arg, void *context) {
-    format_value(writer, *static_cast<const T*>(arg),
+      basic_buffer<Char> &buffer, const void *arg, void *context) {
+    format_value(buffer, *static_cast<const T*>(arg),
                  *static_cast<Context*>(context));
   }
 
@@ -1464,7 +1465,7 @@
 #endif
 
 template <typename Formatter, typename T, typename Char>
-void format_value(basic_writer<Char> &, const T &, Formatter &, const Char *) {
+void format_value(basic_buffer<Char> &, const T &, Formatter &, const Char *) {
   FMT_STATIC_ASSERT(False<T>::value,
                     "Cannot format argument. To enable the use of ostream "
                     "operator<< include fmt/ostream.h. Otherwise provide "
@@ -1858,7 +1859,7 @@
   typedef basic_format_specs<Char> format_specs;
 
  private:
-  basic_writer<Char> &writer_;
+  basic_writer<Char> writer_;
   format_specs &spec_;
 
   FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase);
@@ -1901,8 +1902,8 @@
  public:
   typedef Char char_type;
 
-  ArgFormatterBase(basic_writer<Char> &w, format_specs &s)
-  : writer_(w), spec_(s) {}
+  ArgFormatterBase(basic_buffer<Char> &b, format_specs &s)
+  : writer_(b), spec_(s) {}
 
   void operator()(monostate) {
     FMT_ASSERT(false, "invalid argument type");
@@ -1973,12 +1974,6 @@
   }
 };
 
-template <typename Char>
-inline void write(basic_writer<Char> &w, const Char *start, const Char *end) {
-  if (start != end)
-    w.write(BasicStringRef<Char>(start, internal::to_unsigned(end - start)));
-}
-
 template <typename Char, typename Context>
 class context_base {
  private:
@@ -2047,20 +2042,20 @@
   /**
     \rst
     Constructs an argument formatter object.
-    *writer* is a reference to the writer to be used for output,
+    *buffer* is a reference to the buffer to be used for output,
     *ctx* is a reference to the formatting context, *spec* contains
     format specifier information for standard argument types.
     \endrst
    */
-  ArgFormatter(basic_writer<Char> &writer, basic_context<Char> &ctx,
+  ArgFormatter(basic_buffer<Char> &buffer, basic_context<Char> &ctx,
                format_specs &spec)
-  : internal::ArgFormatterBase<Char>(writer, spec), ctx_(ctx) {}
+  : internal::ArgFormatterBase<Char>(buffer, spec), ctx_(ctx) {}
 
   using internal::ArgFormatterBase<Char>::operator();
 
   /** Formats an argument of a custom (user-defined) type. */
   void operator()(internal::CustomValue<Char> c) {
-    c.format(this->writer(), c.value, &ctx_);
+    c.format(this->writer().buffer(), c.value, &ctx_);
   }
 };
 
@@ -2160,7 +2155,7 @@
   may look like "Unknown error -1" and is platform-dependent.
   \endrst
  */
-FMT_API void format_system_error(fmt::writer &out, int error_code,
+FMT_API void format_system_error(fmt::buffer &out, int error_code,
                                  fmt::StringRef message) FMT_NOEXCEPT;
 
 namespace internal {
@@ -2298,13 +2293,12 @@
   template <typename Char_>
   friend class PrintfArgFormatter;
 
- protected:
+ public:
   /**
     Constructs a ``basic_writer`` object.
    */
   explicit basic_writer(basic_buffer<Char> &b) : buffer_(b) {}
 
- public:
   /**
     \rst
     Destroys a ``basic_writer`` object.
@@ -2343,38 +2337,6 @@
     return std::basic_string<Char>(&buffer_[0], buffer_.size());
   }
 
-  void vformat(BasicCStringRef<Char> format,
-               basic_args<basic_context<Char>> args);
-  /**
-    \rst
-    Writes formatted data.
-
-    *args* is an argument list representing arbitrary arguments.
-
-    **Example**::
-
-       MemoryWriter out;
-       out.format("Current point:\n");
-       out.format("({:+f}, {:+f})", -3.14, 3.14);
-
-    This will write the following output to the ``out`` object:
-
-    .. code-block:: none
-
-       Current point:
-       (-3.140000, +3.140000)
-
-    The output can be accessed using :func:`data()`, :func:`c_str` or
-    :func:`str` methods.
-
-    See also :ref:`syntax`.
-    \endrst
-   */
-  template <typename... Args>
-  void format(BasicCStringRef<Char> format, const Args & ... args) {
-    vformat(format, make_args<basic_context<Char>>(args...));
-  }
-
   void write(int value) {
     write_decimal(value);
   }
@@ -2881,6 +2843,23 @@
 typedef BasicMemoryWriter<char> MemoryWriter;
 typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
 
+// A fixed-size buffer.
+template <typename Char>
+class FixedBuffer : public fmt::basic_buffer<Char> {
+ public:
+  /**
+   \rst
+   Constructs a :class:`fmt::FixedBuffer` object for *array* of the
+   given size.
+   \endrst
+   */
+  FixedBuffer(Char *array, std::size_t size)
+    : fmt::basic_buffer<Char>(array, size) {}
+
+ protected:
+  FMT_API void grow(std::size_t size);
+};
+
 /**
   \rst
   This class template provides operations for formatting and writing data
@@ -2904,15 +2883,9 @@
 template <typename Char>
 class BasicArrayWriter : public basic_writer<Char> {
  private:
-  internal::FixedBuffer<Char> buffer_;
+  FixedBuffer<Char> buffer_;
 
  public:
-  /**
-   \rst
-   Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
-   given size.
-   \endrst
-   */
   BasicArrayWriter(Char *array, std::size_t size)
     : basic_writer<Char>(buffer_), buffer_(array, size) {}
 
@@ -3000,10 +2973,34 @@
   vprint_colored(c, format_str, make_args(args...));
 }
 
+template <typename ArgFormatter, typename Char, typename Context>
+void vformat_to(basic_buffer<Char> &buffer, BasicCStringRef<Char> format_str,
+                basic_args<Context> args);
+
+inline void vformat_to(buffer &buf, CStringRef format_str, args args) {
+  vformat_to<ArgFormatter<char>>(buf, format_str, args);
+}
+
+inline void vformat_to(wbuffer &buf, WCStringRef format_str, wargs args) {
+  vformat_to<ArgFormatter<wchar_t>>(buf, format_str, args);
+}
+
+template <typename... Args>
+inline void format_to(buffer &buf, CStringRef format_str,
+                      const Args & ... args) {
+  vformat_to(buf, format_str, make_args(args...));
+}
+
+template <typename... Args>
+inline void format_to(wbuffer &buf, WCStringRef format_str,
+                      const Args & ... args) {
+  vformat_to(buf, format_str, make_args<wcontext>(args...));
+}
+
 inline std::string vformat(CStringRef format_str, args args) {
-  MemoryWriter w;
-  w.vformat(format_str, args);
-  return w.str();
+  internal::MemoryBuffer<char> buffer;
+  vformat_to(buffer, format_str, args);
+  return to_string(buffer);
 }
 
 /**
@@ -3021,15 +3018,14 @@
 }
 
 inline std::wstring vformat(WCStringRef format_str, wargs args) {
-  WMemoryWriter w;
-  w.vformat(format_str, args);
-  return w.str();
+  internal::MemoryBuffer<wchar_t> buffer;
+  vformat_to(buffer, format_str, args);
+  return to_string(buffer);
 }
 
 template <typename... Args>
 inline std::wstring format(WCStringRef format_str, const Args & ... args) {
-  auto vargs = make_args<wcontext>(args...);
-  return vformat(format_str, vargs);
+  return vformat(format_str, make_args<wcontext>(args...));
 }
 
 FMT_API void vprint(std::FILE *f, CStringRef format_str, args args);
@@ -3273,15 +3269,15 @@
 template <typename Char, typename Context>
 class CustomFormatter {
  private:
-  basic_writer<Char> &writer_;
+  basic_buffer<Char> &buffer_;
   Context &ctx_;
 
  public:
-  CustomFormatter(basic_writer<Char> &writer, Context &ctx)
-  : writer_(writer), ctx_(ctx) {}
+  CustomFormatter(basic_buffer<Char> &buffer, Context &ctx)
+  : buffer_(buffer), ctx_(ctx) {}
 
   bool operator()(internal::CustomValue<Char> custom) {
-    custom.format(writer_, custom.value, &ctx_);
+    custom.format(buffer_, custom.value, &ctx_);
     return true;
   }
 
@@ -3374,12 +3370,12 @@
 
 // Formats a single argument.
 template <typename ArgFormatter, typename Char, typename Context>
-void do_format_arg(basic_writer<Char> &writer, basic_arg<Context> arg,
+void do_format_arg(basic_buffer<Char> &buffer, basic_arg<Context> arg,
                    Context &ctx) {
   const Char *&s = ctx.ptr();
   basic_format_specs<Char> spec;
   if (*s == ':') {
-    if (visit(internal::CustomFormatter<Char, Context>(writer, ctx), arg))
+    if (visit(internal::CustomFormatter<Char, Context>(buffer, ctx), arg))
       return;
     ++s;
     // Parse fill and alignment.
@@ -3495,13 +3491,13 @@
     FMT_THROW(format_error("missing '}' in format string"));
 
   // Format argument.
-  visit(ArgFormatter(writer, ctx, spec), arg);
+  visit(ArgFormatter(buffer, ctx, spec), arg);
 }
 
-/** Formats arguments and writes the output to the writer. */
+/** Formats arguments and writes the output to the buffer. */
 template <typename ArgFormatter, typename Char, typename Context>
-void vwrite(basic_writer<Char> &writer, BasicCStringRef<Char> format_str,
-             basic_args<Context> args) {
+void vformat_to(basic_buffer<Char> &buffer, BasicCStringRef<Char> format_str,
+                basic_args<Context> args) {
   basic_context<Char> ctx(format_str.c_str(), args);
   const Char *&s = ctx.ptr();
   const Char *start = s;
@@ -3509,26 +3505,19 @@
     Char c = *s++;
     if (c != '{' && c != '}') continue;
     if (*s == c) {
-      internal::write(writer, start, s);
+      buffer.append(start, s);
       start = ++s;
       continue;
     }
     if (c == '}')
       FMT_THROW(format_error("unmatched '}' in format string"));
-    internal::write(writer, start, s - 1);
-    do_format_arg<ArgFormatter>(writer, ctx.parse_arg_id(), ctx);
+    buffer.append(start, s - 1);
+    do_format_arg<ArgFormatter>(buffer, ctx.parse_arg_id(), ctx);
     if (*s != '}')
       FMT_THROW(format_error(fmt::format("unknown format specifier")));
     start = ++s;
   }
-  internal::write(writer, start, s);
-}
-
-template <typename Char>
-inline void basic_writer<Char>::vformat(
-    BasicCStringRef<Char> format,
-    basic_args<basic_context<Char>> args) {
-  vwrite<ArgFormatter<Char>>(*this, format, args);
+  buffer.append(start, s);
 }
 }  // namespace fmt
 
diff --git a/fmt/ostream.cc b/fmt/ostream.cc
index d6f2698..f900664 100644
--- a/fmt/ostream.cc
+++ b/fmt/ostream.cc
@@ -12,10 +12,10 @@
 namespace fmt {
 
 namespace internal {
-FMT_FUNC void write(std::ostream &os, writer &w) {
-  const char *data = w.data();
+FMT_FUNC void write(std::ostream &os, buffer &buf) {
+  const char *data = buf.data();
   typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
-  UnsignedStreamSize size = w.size();
+  UnsignedStreamSize size = buf.size();
   UnsignedStreamSize max_size =
       internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
   do {
@@ -27,10 +27,9 @@
 }
 }
 
-FMT_FUNC void vprint(std::ostream &os, CStringRef format_str,
-                     args args) {
-  MemoryWriter w;
-  w.vformat(format_str, args);
-  internal::write(os, w);
+FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, args args) {
+  internal::MemoryBuffer<char> buffer;
+  vformat_to(buffer, format_str, args);
+  internal::write(os, buffer);
 }
 }  // namespace fmt
diff --git a/fmt/ostream.h b/fmt/ostream.h
index f378035..528ee16 100644
--- a/fmt/ostream.h
+++ b/fmt/ostream.h
@@ -67,28 +67,27 @@
   };
 };
 
-// Write the content of w to os.
-void write(std::ostream &os, writer &w);
+// Write the content of buf to os.
+void write(std::ostream &os, buffer &buf);
 
 template <typename Char, typename T>
-BasicStringRef<Char> format_value(
-    internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> &buffer,
-    const T &value) {
+void format_value(basic_buffer<Char> &buffer, const T &value) {
   internal::FormatBuf<Char> format_buf(buffer);
   std::basic_ostream<Char> output(&format_buf);
   output << value;
-  return BasicStringRef<Char>(&buffer[0], format_buf.size());
+  buffer.resize(format_buf.size());
 }
 }  // namespace internal
 
 // Formats a value.
 template <typename Char, typename T>
-void format_value(basic_writer<Char> &w, const T &value,
+void format_value(basic_buffer<Char> &buf, const T &value,
                   basic_context<Char> &ctx) {
   internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
-  auto str = internal::format_value(buffer, value);
+  internal::format_value(buffer, value);
+  BasicStringRef<Char> str(buffer.data(), buffer.size());
   do_format_arg< ArgFormatter<Char> >(
-        w, internal::make_arg< basic_context<Char> >(str), ctx);
+        buf, internal::make_arg< basic_context<Char> >(str), ctx);
 }
 
 FMT_API void vprint(std::ostream &os, CStringRef format_str, args args);
diff --git a/fmt/printf.h b/fmt/printf.h
index 2fa54d2..0b77ae3 100644
--- a/fmt/printf.h
+++ b/fmt/printf.h
@@ -225,12 +225,12 @@
   /**
     \rst
     Constructs an argument formatter object.
-    *writer* is a reference to the output writer and *spec* contains format
+    *buffer* is a reference to the output buffer and *spec* contains format
     specifier information for standard argument types.
     \endrst
    */
-  PrintfArgFormatter(basic_writer<Char> &writer, format_specs &spec)
-  : internal::ArgFormatterBase<Char>(writer, spec) {}
+  PrintfArgFormatter(basic_buffer<Char> &buffer, format_specs &spec)
+  : internal::ArgFormatterBase<Char>(buffer, spec) {}
 
   using Base::operator();
 
@@ -289,7 +289,7 @@
     const Char format_str[] = {'}', '\0'};
     auto args = basic_args<basic_context<Char>>();
     basic_context<Char> ctx(format_str, args);
-    c.format(this->writer(), c.value, &ctx);
+    c.format(this->writer().buffer(), c.value, &ctx);
   }
 };
 
@@ -331,8 +331,8 @@
                           basic_args<printf_context> args)
     : Base(format_str.c_str(), args) {}
 
-  /** Formats stored arguments and writes the output to the writer. */
-  FMT_API void format(basic_writer<Char> &writer);
+  /** Formats stored arguments and writes the output to the buffer. */
+  FMT_API void format(basic_buffer<Char> &buffer);
 };
 
 template <typename Char, typename AF>
@@ -408,18 +408,18 @@
 }
 
 template <typename Char, typename AF>
-void printf_context<Char, AF>::format(basic_writer<Char> &writer) {
+void printf_context<Char, AF>::format(basic_buffer<Char> &buffer) {
   const Char *start = this->ptr();
   const Char *s = start;
   while (*s) {
     Char c = *s++;
     if (c != '%') continue;
     if (*s == c) {
-      internal::write(writer, start, s);
+      buffer.append(start, s);
       start = ++s;
       continue;
     }
-    internal::write(writer, start, s - 1);
+    buffer.append(start, s - 1);
 
     format_specs spec;
     spec.align_ = ALIGN_RIGHT;
@@ -501,31 +501,30 @@
     start = s;
 
     // Format argument.
-    visit(AF(writer, spec), arg);
+    visit(AF(buffer, spec), arg);
   }
-  internal::write(writer, start, s);
+  buffer.append(start, s);
 }
 
 // Formats a value.
 template <typename Char, typename T>
-void format_value(basic_writer<Char> &w, const T &value,
+void format_value(basic_buffer<Char> &buf, const T &value,
                   printf_context<Char>& ctx) {
-  internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
-  w.write(internal::format_value(buffer, value));
+  internal::format_value(buf, value);
 }
 
 template <typename Char>
-void printf(basic_writer<Char> &w, BasicCStringRef<Char> format,
+void printf(basic_buffer<Char> &buf, BasicCStringRef<Char> format,
             basic_args<printf_context<Char>> args) {
-  printf_context<Char>(format, args).format(w);
+  printf_context<Char>(format, args).format(buf);
 }
 
 typedef basic_args<printf_context<char>> printf_args;
 
 inline std::string vsprintf(CStringRef format, printf_args args) {
-  MemoryWriter w;
-  printf(w, format, args);
-  return w.str();
+  internal::MemoryBuffer<char> buffer;
+  printf(buffer, format, args);
+  return to_string(buffer);
 }
 
 /**
@@ -544,9 +543,9 @@
 
 inline std::wstring vsprintf(
     WCStringRef format, basic_args<printf_context<wchar_t>> args) {
-  WMemoryWriter w;
-  printf(w, format, args);
-  return w.str();
+  internal::MemoryBuffer<wchar_t> buffer;
+  printf(buffer, format, args);
+  return to_string(buffer);
 }
 
 template <typename... Args>
@@ -591,10 +590,10 @@
 }
 
 inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) {
-  MemoryWriter w;
-  printf(w, format_str, args);
-  internal::write(os, w);
-  return static_cast<int>(w.size());
+  internal::MemoryBuffer<char> buffer;
+  printf(buffer, format_str, args);
+  internal::write(os, buffer);
+  return static_cast<int>(buffer.size());
 }
 
 /**
diff --git a/fmt/time.h b/fmt/time.h
index b5482e7..f4ec481 100644
--- a/fmt/time.h
+++ b/fmt/time.h
@@ -15,7 +15,7 @@
 
 namespace fmt {
 
-void format_value(writer &w, const std::tm &tm, context &ctx) {
+void format_value(buffer &buf, const std::tm &tm, context &ctx) {
   const char *&s = ctx.ptr();
   if (*s == ':')
     ++s;
@@ -27,13 +27,12 @@
   internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
   format.append(s, end + 1);
   format[format.size() - 1] = '\0';
-  basic_buffer<char> &buffer = w.buffer();
-  std::size_t start = buffer.size();
+  std::size_t start = buf.size();
   for (;;) {
-    std::size_t size = buffer.capacity() - start;
-    std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
+    std::size_t size = buf.capacity() - start;
+    std::size_t count = std::strftime(&buf[start], size, &format[0], &tm);
     if (count != 0) {
-      buffer.resize(start + count);
+      buf.resize(start + count);
       break;
     }
     if (size >= format.size() * 256) {
@@ -44,7 +43,7 @@
       break;
     }
     const std::size_t MIN_GROWTH = 10;
-    buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
+    buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
   }
   s = end;
 }
diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc
index 01d8b95..4a582c1 100644
--- a/test/custom-formatter-test.cc
+++ b/test/custom-formatter-test.cc
@@ -16,9 +16,9 @@
 // rounded to 0.
 class CustomArgFormatter : public fmt::ArgFormatter<char> {
  public:
-  CustomArgFormatter(fmt::writer &w, fmt::basic_context<char> &ctx,
+  CustomArgFormatter(fmt::buffer &buf, fmt::basic_context<char> &ctx,
                      fmt::format_specs &s)
-  : fmt::ArgFormatter<char>(w, ctx, s) {}
+  : fmt::ArgFormatter<char>(buf, ctx, s) {}
 
   using fmt::ArgFormatter<char>::operator();
 
@@ -33,8 +33,8 @@
 // rounded to 0.
 class CustomPrintfArgFormatter : public PrintfArgFormatter<char> {
  public:
-  CustomPrintfArgFormatter(fmt::basic_writer<char> &w, fmt::format_specs &spec)
-  : PrintfArgFormatter<char>(w, spec) {}
+  CustomPrintfArgFormatter(fmt::buffer &buf, fmt::format_specs &spec)
+  : PrintfArgFormatter<char>(buf, spec) {}
 
   using PrintfArgFormatter<char>::operator();
 
@@ -46,10 +46,10 @@
 };
 
 std::string custom_vformat(fmt::CStringRef format_str, fmt::args args) {
-  fmt::MemoryWriter writer;
-  // Pass custom argument formatter as a template arg to vformat.
-  fmt::vwrite<CustomArgFormatter>(writer, format_str, args);
-  return writer.str();
+  fmt::internal::MemoryBuffer<char> buffer;
+  // Pass custom argument formatter as a template arg to vwrite.
+  fmt::vformat_to<CustomArgFormatter>(buffer, format_str, args);
+  return std::string(buffer.data(), buffer.size());
 }
 
 template <typename... Args>
@@ -64,10 +64,10 @@
 std::string custom_vsprintf(
     const char* format_str,
     fmt::basic_args<CustomPrintfFormatter> args) {
-  fmt::MemoryWriter writer;
+  fmt::internal::MemoryBuffer<char> buffer;
   CustomPrintfFormatter formatter(format_str, args);
-  formatter.format(writer);
-  return writer.str();
+  formatter.format(buffer);
+  return std::string(buffer.data(), buffer.size());
 }
 
 template <typename... Args>
diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc
index 6308273..6c86a48 100644
--- a/test/format-impl-test.cc
+++ b/test/format-impl-test.cc
@@ -107,14 +107,14 @@
   {
     fmt::MemoryWriter w;
     w.write("garbage");
-    fmt::format_error_code(w, 42, "test");
+    fmt::format_error_code(w.buffer(), 42, "test");
     EXPECT_EQ("test: " + msg, w.str());
   }
   {
     fmt::MemoryWriter w;
     std::string prefix(
         fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x');
-    fmt::format_error_code(w, 42, prefix);
+    fmt::format_error_code(w.buffer(), 42, prefix);
     EXPECT_EQ(msg, w.str());
   }
   int codes[] = {42, -1};
@@ -124,14 +124,14 @@
     fmt::MemoryWriter w;
     std::string prefix(
         fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x');
-    fmt::format_error_code(w, codes[i], prefix);
+    fmt::format_error_code(w.buffer(), codes[i], prefix);
     EXPECT_EQ(prefix + sep + msg, w.str());
     std::size_t size = fmt::internal::INLINE_BUFFER_SIZE;
     EXPECT_EQ(size, w.size());
     w.clear();
     // Test with a message that doesn't fit into the buffer.
     prefix += 'x';
-    fmt::format_error_code(w, codes[i], prefix);
+    fmt::format_error_code(w.buffer(), codes[i], prefix);
     EXPECT_EQ(msg, w.str());
   }
 }
diff --git a/test/format-test.cc b/test/format-test.cc
index f10e1b1..02b99fd 100644
--- a/test/format-test.cc
+++ b/test/format-test.cc
@@ -265,12 +265,6 @@
   EXPECT_EQ("42", std::string(w.data(), w.size()));
 }
 
-TEST(WriterTest, WriteWithoutArgs) {
-  MemoryWriter w;
-  w.format("test");
-  EXPECT_EQ("test", std::string(w.data(), w.size()));
-}
-
 TEST(WriterTest, WriteInt) {
   CHECK_WRITE(42);
   CHECK_WRITE(-42);
@@ -476,20 +470,6 @@
   EXPECT_EQ(L"test******", write_wstr(L"test", width=10, fill=L'*'));
 }
 
-TEST(WriterTest, Format) {
-  MemoryWriter w;
-  w.format("part{0}", 1);
-  EXPECT_EQ(strlen("part1"), w.size());
-  EXPECT_STREQ("part1", w.c_str());
-  EXPECT_STREQ("part1", w.data());
-  EXPECT_EQ("part1", w.str());
-  w.format("part{0}", 2);
-  EXPECT_EQ(strlen("part1part2"), w.size());
-  EXPECT_STREQ("part1part2", w.c_str());
-  EXPECT_STREQ("part1part2", w.data());
-  EXPECT_EQ("part1part2", w.str());
-}
-
 TEST(WriterTest, WWriter) {
   EXPECT_EQ(L"cafe", write_wstr(0xcafe, type='x'));
 }
@@ -501,32 +481,43 @@
   EXPECT_STREQ("", w.c_str());
 }
 
+TEST(FormatToTest, FormatWithoutArgs) {
+  fmt::internal::MemoryBuffer<char> buffer;
+  format_to(buffer, "test");
+  EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
+}
+
+TEST(FormatToTest, Format) {
+  fmt::internal::MemoryBuffer<char> buffer;
+  format_to(buffer, "part{0}", 1);
+  EXPECT_EQ(strlen("part1"), buffer.size());
+  EXPECT_EQ("part1", std::string(buffer.data(), buffer.size()));
+  format_to(buffer, "part{0}", 2);
+  EXPECT_EQ(strlen("part1part2"), buffer.size());
+  EXPECT_EQ("part1part2", std::string(buffer.data(), buffer.size()));
+  EXPECT_EQ("part1part2", to_string(buffer));
+}
+
 TEST(ArrayWriterTest, CompileTimeSizeCtor) {
   char array[10] = "garbage";
   fmt::ArrayWriter w(array);
   EXPECT_EQ(0u, w.size());
   EXPECT_STREQ("", w.c_str());
-  w.format("{:10}", 1);
-}
-
-TEST(ArrayWriterTest, Write) {
-  char array[10];
-  fmt::ArrayWriter w(array, sizeof(array));
-  w.format("{}", 42);
-  EXPECT_EQ("42", w.str());
+  format_to(w.buffer(), "{:10}", 1);
 }
 
 TEST(ArrayWriterTest, BufferOverflow) {
   char array[10];
   fmt::ArrayWriter w(array, sizeof(array));
-  w.format("{:10}", 1);
-  EXPECT_THROW_MSG(w.format("{}", 1), std::runtime_error, "buffer overflow");
+  format_to(w.buffer(), "{:10}", 1);
+  EXPECT_THROW_MSG(format_to(w.buffer(), "{}", 1), std::runtime_error,
+                   "buffer overflow");
 }
 
 TEST(ArrayWriterTest, WChar) {
   wchar_t array[10];
   fmt::WArrayWriter w(array);
-  w.format(L"{}", 42);
+  format_to(w.buffer(), L"{}", 42);
   EXPECT_EQ(L"42", w.str());
 }
 
@@ -1366,12 +1357,8 @@
   EXPECT_EQ("test", format("{0}", CStringRef("test")));
 }
 
-void format_value(fmt::writer &w, const Date &d, fmt::context &) {
-  w.write(d.year());
-  w.write('-');
-  w.write(d.month());
-  w.write('-');
-  w.write(d.day());
+void format_value(fmt::buffer &buf, const Date &d, fmt::context &) {
+  fmt::format_to(buf, "{}-{}-{}", d.year(), d.month(), d.day());
 }
 
 TEST(FormatterTest, FormatCustom) {
@@ -1383,8 +1370,8 @@
 class Answer {};
 
 template <typename Char>
-void format_value(basic_writer<Char> &w, Answer, fmt::context &) {
-  w.write("42");
+void format_value(fmt::basic_buffer<Char> &buf, Answer, fmt::context &) {
+  fmt::format_to(buf, "{}", 42);
 }
 
 TEST(FormatterTest, CustomFormat) {
@@ -1417,13 +1404,11 @@
   out.write("The answer is ");
   out.write(42);
   out.write("\n");
-  out.format("({:+f}, {:+f})", -3.14, 3.14);
-  EXPECT_EQ("The answer is 42\n(-3.140000, +3.140000)", out.str());
 
   {
     MemoryWriter writer;
     for (int i = 0; i < 10; i++)
-      writer.format("{}", i);
+      format_to(writer.buffer(), "{}", i);
     std::string s = writer.str(); // s == 0123456789
     EXPECT_EQ("0123456789", s);
   }
@@ -1567,10 +1552,10 @@
 }
 
 std::string vformat_message(int id, const char *format, fmt::args args) {
-  MemoryWriter w;
-  w.format("[{}] ", id);
-  w.vformat(format, args);
-  return w.str();
+  fmt::internal::MemoryBuffer<char> buffer;
+  format_to(buffer, "[{}] ", id);
+  vformat_to(buffer, format, args);
+  return to_string(buffer);
 }
 
 template <typename... Args>
@@ -1643,9 +1628,9 @@
  public:
   typedef fmt::internal::ArgFormatterBase<char> Base;
 
-  MockArgFormatter(fmt::writer &w, fmt::context &ctx,
+  MockArgFormatter(fmt::buffer &b, fmt::context &ctx,
                    fmt::format_specs &s)
-    : fmt::internal::ArgFormatterBase<char>(w, s) {
+    : fmt::internal::ArgFormatterBase<char>(b, s) {
     EXPECT_CALL(*this, call(42));
   }
 
@@ -1657,8 +1642,8 @@
 };
 
 void custom_vformat(fmt::CStringRef format_str, fmt::args args) {
-  fmt::MemoryWriter writer;
-  fmt::vwrite<MockArgFormatter>(writer, format_str, args);
+  fmt::internal::MemoryBuffer<char> buffer;
+  fmt::vformat_to<MockArgFormatter>(buffer, format_str, args);
 }
 
 template <typename... Args>
diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc
index 6a8c567..4de17ee 100644
--- a/test/gtest-extra-test.cc
+++ b/test/gtest-extra-test.cc
@@ -320,7 +320,7 @@
 
 TEST(UtilTest, FormatSystemError) {
   fmt::MemoryWriter out;
-  fmt::format_system_error(out, EDOM, "test message");
+  fmt::format_system_error(out.buffer(), EDOM, "test message");
   EXPECT_EQ(out.str(), format_system_error(EDOM, "test message"));
 }
 
diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc
index 7640d15..5708eef 100644
--- a/test/gtest-extra.cc
+++ b/test/gtest-extra.cc
@@ -104,7 +104,7 @@
 #endif  // FMT_USE_FILE_DESCRIPTORS
 
 std::string format_system_error(int error_code, fmt::StringRef message) {
-  fmt::MemoryWriter out;
+  fmt::internal::MemoryBuffer<char> out;
   fmt::format_system_error(out, error_code, message);
-  return out.str();
+  return to_string(out);
 }
diff --git a/test/ostream-test.cc b/test/ostream-test.cc
index eea803d..761820b 100644
--- a/test/ostream-test.cc
+++ b/test/ostream-test.cc
@@ -59,17 +59,17 @@
 }
 
 struct TestArgFormatter : fmt::ArgFormatter<char> {
-  TestArgFormatter(fmt::writer &w, fmt::context &ctx, fmt::format_specs &s)
-    : fmt::ArgFormatter<char>(w, ctx, s) {}
+  TestArgFormatter(fmt::buffer &buf, fmt::context &ctx, fmt::format_specs &s)
+    : fmt::ArgFormatter<char>(buf, ctx, s) {}
 };
 
 TEST(OStreamTest, CustomArg) {
-  fmt::MemoryWriter writer;
+  fmt::internal::MemoryBuffer<char> buffer;
   fmt::context ctx("}", fmt::args());
   fmt::format_specs spec;
-  TestArgFormatter af(writer, ctx, spec);
+  TestArgFormatter af(buffer, ctx, spec);
   visit(af, fmt::internal::make_arg<fmt::context>(TestEnum()));
-  EXPECT_EQ("TestEnum", writer.str());
+  EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size()));
 }
 
 TEST(OStreamTest, Format) {
@@ -121,9 +121,10 @@
 
 TEST(OStreamTest, WriteToOStream) {
   std::ostringstream os;
-  fmt::MemoryWriter w;
-  w.write("foo");
-  fmt::internal::write(os, w);
+  fmt::internal::MemoryBuffer<char> buffer;
+  const char *foo = "foo";
+  buffer.append(foo, foo + std::strlen(foo));
+  fmt::internal::write(os, buffer);
   EXPECT_EQ("foo", os.str());
 }
 
@@ -133,16 +134,10 @@
   if (max_size <= fmt::internal::to_unsigned(max_streamsize))
     return;
 
-  class TestWriter : public fmt::basic_writer<char> {
-   private:
-    struct TestBuffer : fmt::basic_buffer<char> {
-      explicit TestBuffer(std::size_t size) { size_ = size; }
-      void grow(std::size_t) {}
-    } buffer_;
-   public:
-    explicit TestWriter(std::size_t size)
-      : fmt::basic_writer<char>(buffer_), buffer_(size) {}
-  } w(max_size);
+  struct TestBuffer : fmt::basic_buffer<char> {
+    explicit TestBuffer(std::size_t size) { size_ = size; }
+    void grow(std::size_t) {}
+  } buffer(max_size);
 
   struct MockStreamBuf : std::streambuf {
     MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
@@ -150,11 +145,11 @@
       const void *v = s;
       return xsputn(v, n);
     }
-  } buffer;
+  } streambuf;
 
   struct TestOStream : std::ostream {
     explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {}
-  } os(buffer);
+  } os(streambuf);
 
   testing::InSequence sequence;
   const char *data = 0;
@@ -163,10 +158,10 @@
     typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize;
     UStreamSize n = std::min<UStreamSize>(
           size, fmt::internal::to_unsigned(max_streamsize));
-    EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n)))
+    EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
         .WillOnce(testing::Return(max_streamsize));
     data += n;
     size -= static_cast<std::size_t>(n);
   } while (size != 0);
-  fmt::internal::write(os, w);
+  fmt::internal::write(os, buffer);
 }
diff --git a/test/util-test.cc b/test/util-test.cc
index 84ba407..9466c37 100644
--- a/test/util-test.cc
+++ b/test/util-test.cc
@@ -67,9 +67,10 @@
 struct Test {};
 
 template <typename Char>
-void format_value(fmt::basic_writer<Char> &w, Test,
+void format_value(fmt::basic_buffer<Char> &b, Test,
                   fmt::basic_context<Char> &) {
-  w.write("test");
+  const Char *test = "test";
+  b.append(test, test + std::strlen(test));
 }
 
 template <typename Context, typename T>
@@ -416,7 +417,7 @@
   bool called;
 };
 
-void format_value(fmt::writer &, const Test &, CustomContext &ctx) {
+void format_value(fmt::buffer &, const Test &, CustomContext &ctx) {
   ctx.called = true;
 }
 
@@ -424,8 +425,8 @@
   ::Test t;
   fmt::internal::value<CustomContext> arg(t);
   CustomContext ctx = {false};
-  fmt::MemoryWriter w;
-  arg.custom.format(w, &t, &ctx);
+  fmt::internal::MemoryBuffer<char> buffer;
+  arg.custom.format(buffer, &t, &ctx);
   EXPECT_TRUE(ctx.called);
 }
 
@@ -568,10 +569,10 @@
   EXPECT_CALL(visitor, visit(_)).WillOnce(
         testing::Invoke([&](fmt::internal::CustomValue<char> custom) {
     EXPECT_EQ(&test, custom.value);
-    fmt::MemoryWriter w;
+    fmt::internal::MemoryBuffer<char> buffer;
     fmt::context ctx("}", fmt::args());
-    custom.format(w, &test, &ctx);
-    EXPECT_EQ("test", w.str());
+    custom.format(buffer, &test, &ctx);
+    EXPECT_EQ("test", std::string(buffer.data(), buffer.size()));
     return Visitor::Result();
   }));
   fmt::visit(visitor, make_arg<fmt::context>(test));
@@ -689,7 +690,7 @@
 #endif  // _WIN32
 
 typedef void (*FormatErrorMessage)(
-        fmt::writer &out, int error_code, StringRef message);
+        fmt::buffer &out, int error_code, StringRef message);
 
 template <typename Error>
 void check_throw_error(int error_code, FormatErrorMessage format) {
@@ -699,20 +700,21 @@
   } catch (const fmt::SystemError &e) {
     error = e;
   }
-  fmt::MemoryWriter message;
+  fmt::internal::MemoryBuffer<char> message;
   format(message, error_code, "test error");
-  EXPECT_EQ(message.str(), error.what());
+  EXPECT_EQ(to_string(message), error.what());
   EXPECT_EQ(error_code, error.error_code());
 }
 
 TEST(UtilTest, FormatSystemError) {
-  fmt::MemoryWriter message;
+  fmt::internal::MemoryBuffer<char> message;
   fmt::format_system_error(message, EDOM, "test");
-  EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str());
+  EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)),
+            to_string(message));
   message.clear();
   fmt::format_system_error(
         message, EDOM, fmt::StringRef(0, std::numeric_limits<size_t>::max()));
-  EXPECT_EQ(fmt::format("error {}", EDOM), message.str());
+  EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message));
 }
 
 TEST(UtilTest, SystemError) {
@@ -723,10 +725,11 @@
 }
 
 TEST(UtilTest, ReportSystemError) {
-  fmt::MemoryWriter out;
+  fmt::internal::MemoryBuffer<char> out;
   fmt::format_system_error(out, EDOM, "test error");
-  out.write('\n');
-  EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), out.str());
+  out.push_back('\n');
+  EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"),
+               to_string(out));
 }
 
 #ifdef _WIN32