https://github.com/vonosmas created 
https://github.com/llvm/llvm-project/pull/170959

This change doesn't yet modify
Writer::write(string_view) public API, which
has a lot of uses through printf_core.

For wide-char write functions (like swprintf) we'd
need to templatize WriteBuffer and Writer to
support wide characrters. We'd need to either
support helper cpp::string_view class to support
wide-character strings, or replace them with pure
pointer/size pairs.

The latter option seems to be a more
straightforward one, given that majority of printf_core operates on buffers 
anyway
(and only constructs string_views right
before invoking the buffer), and we don't
have a use case internal wide-character
string-views.

>From 008397fc8a6aa17b27aecd965c3fc2be433708c0 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <[email protected]>
Date: Fri, 21 Nov 2025 19:45:34 +0000
Subject: [PATCH 1/2] [libc] Refactor static polymorphism in WriteBuffer (NFC).

There are three flavors of WriteBuffer currently, all of which
could be passed into printf_core::Writer class. It's a tricky
class, since it chooses a flavor-specific logic either based
on runtime dispatch (to save code size and prevent
generating three versions of the entirety of printf_core),
or based on template arguments (to avoid dealing with
function pointers in codegen for FILL_BUFF_AND_DROP_OVERFLOW path.

Refactor this somewhat convoluted logic to have three
concrete subclasses inheriting from the templated base
class, and use static polymorphism with reinterpret_cast
to implement dispatching above. Now we can actually
have flavor-specific fields, constructors, and methods
(e.g. "flush_to_stream" is now a method of FlushingBuffer),
and the code on the user side is cleaner: the complexity
of enabling/disabling runtime-dispatch and using proper
template arguments is now localized in writer.h.

This code will need to be further templatized to support
buffers of type wchar_t to implement swprintf() and
friends. This change would make it (ever so slightly) easier.
---
 libc/src/__support/RPC/rpc_server.h           |  12 +-
 libc/src/stdio/baremetal/printf.cpp           |   8 +-
 libc/src/stdio/baremetal/vprintf.cpp          |   8 +-
 .../stdio/printf_core/vasprintf_internal.h    |  10 +-
 .../src/stdio/printf_core/vfprintf_internal.h |   6 +-
 libc/src/stdio/printf_core/writer.h           | 154 +++++++++++-------
 libc/src/stdio/snprintf.cpp                   |   4 +-
 libc/src/stdio/sprintf.cpp                    |   5 +-
 libc/src/stdio/vsnprintf.cpp                  |   4 +-
 libc/src/stdio/vsprintf.cpp                   |   5 +-
 libc/src/stdlib/strfromd.cpp                  |   4 +-
 libc/src/stdlib/strfromf.cpp                  |   4 +-
 libc/src/stdlib/strfroml.cpp                  |   4 +-
 libc/src/time/strftime.cpp                    |   4 +-
 libc/src/time/strftime_l.cpp                  |   4 +-
 .../src/stdio/printf_core/converter_test.cpp  |  16 +-
 .../src/stdio/printf_core/writer_test.cpp     |  64 ++++----
 17 files changed, 162 insertions(+), 154 deletions(-)

diff --git a/libc/src/__support/RPC/rpc_server.h 
b/libc/src/__support/RPC/rpc_server.h
index abd604ae48146..98dc40ecd0a89 100644
--- a/libc/src/__support/RPC/rpc_server.h
+++ b/libc/src/__support/RPC/rpc_server.h
@@ -169,9 +169,7 @@ LIBC_INLINE static void handle_printf(rpc::Server::Port 
&port,
     if (!format[lane])
       continue;
 
-    printf_core::WriteBuffer<
-        printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
-        wb(nullptr, 0);
+    printf_core::DropOverflowBuffer wb(nullptr, 0);
     printf_core::Writer writer(wb);
 
     internal::DummyArgList<packed> printf_args;
@@ -198,9 +196,7 @@ LIBC_INLINE static void handle_printf(rpc::Server::Port 
&port,
     if (!format[lane])
       continue;
 
-    printf_core::WriteBuffer<
-        printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
-        wb(nullptr, 0);
+    printf_core::DropOverflowBuffer wb(nullptr, 0);
     printf_core::Writer writer(wb);
 
     internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
@@ -262,9 +258,7 @@ LIBC_INLINE static void handle_printf(rpc::Server::Port 
&port,
       continue;
 
     char *buffer = temp_storage.alloc(buffer_size[lane]);
-    printf_core::WriteBuffer<
-        printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
-        wb(buffer, buffer_size[lane]);
+    printf_core::DropOverflowBuffer wb(buffer, buffer_size[lane]);
     printf_core::Writer writer(wb);
 
     internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
diff --git a/libc/src/stdio/baremetal/printf.cpp 
b/libc/src/stdio/baremetal/printf.cpp
index 5a9b19ff20471..2fa9cf7c9f3cd 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -41,9 +41,9 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict 
format, ...)) {
   static constexpr size_t BUFF_SIZE = 1024;
   char buffer[BUFF_SIZE];
 
-  printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
-      buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
-  printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
+  printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &stdout_write_hook,
+                                 nullptr);
+  printf_core::Writer writer(wb);
 
   auto retval = printf_core::printf_main(&writer, format, args);
   if (!retval.has_value()) {
@@ -51,7 +51,7 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict 
format, ...)) {
     return -1;
   }
 
-  int flushval = wb.overflow_write("");
+  int flushval = wb.flush_to_stream();
   if (flushval != printf_core::WRITE_OK) {
     libc_errno = printf_core::internal_error_to_errno(-flushval);
     return -1;
diff --git a/libc/src/stdio/baremetal/vprintf.cpp 
b/libc/src/stdio/baremetal/vprintf.cpp
index c172b368d15f3..d89f26cd72b0a 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -39,9 +39,9 @@ LLVM_LIBC_FUNCTION(int, vprintf,
   static constexpr size_t BUFF_SIZE = 1024;
   char buffer[BUFF_SIZE];
 
-  printf_core::WriteBuffer<printf_core::WriteMode::FLUSH_TO_STREAM> wb(
-      buffer, BUFF_SIZE, &stdout_write_hook, nullptr);
-  printf_core::Writer<printf_core::WriteMode::FLUSH_TO_STREAM> writer(wb);
+  printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &stdout_write_hook,
+                                 nullptr);
+  printf_core::Writer writer(wb);
 
   auto retval = printf_core::printf_main(&writer, format, args);
   if (!retval.has_value()) {
@@ -49,7 +49,7 @@ LLVM_LIBC_FUNCTION(int, vprintf,
     return -1;
   }
 
-  int flushval = wb.overflow_write("");
+  int flushval = wb.flush_to_stream();
   if (flushval != printf_core::WRITE_OK) {
     libc_errno = printf_core::internal_error_to_errno(-flushval);
     return -1;
diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h 
b/libc/src/stdio/printf_core/vasprintf_internal.h
index 41df17b67f35b..db6b95d49aaca 100644
--- a/libc/src/stdio/printf_core/vasprintf_internal.h
+++ b/libc/src/stdio/printf_core/vasprintf_internal.h
@@ -18,10 +18,8 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace printf_core {
 
-LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, void *target) {
-  WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value> *wb =
-      reinterpret_cast<
-          WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value> *>(target);
+LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str,
+                                     ResizingBuffer *wb) {
   size_t new_size = new_str.size() + wb->buff_cur;
   const bool isBuffOnStack = (wb->buff == wb->init_buff);
   char *new_buff = static_cast<char *>(
@@ -47,8 +45,8 @@ LIBC_INLINE ErrorOr<size_t> vasprintf_internal(char **ret,
                                                const char *__restrict format,
                                                internal::ArgList args) {
   char init_buff_on_stack[DEFAULT_BUFFER_SIZE];
-  printf_core::WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value> wb(
-      init_buff_on_stack, DEFAULT_BUFFER_SIZE, resize_overflow_hook);
+  printf_core::ResizingBuffer wb(init_buff_on_stack, DEFAULT_BUFFER_SIZE,
+                                 resize_overflow_hook);
   printf_core::Writer writer(wb);
 
   auto ret_val = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h 
b/libc/src/stdio/printf_core/vfprintf_internal.h
index c47a03d741f98..321b0693ad339 100644
--- a/libc/src/stdio/printf_core/vfprintf_internal.h
+++ b/libc/src/stdio/printf_core/vfprintf_internal.h
@@ -86,8 +86,8 @@ LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE 
*__restrict stream,
                                               internal::ArgList &args) {
   constexpr size_t BUFF_SIZE = 1024;
   char buffer[BUFF_SIZE];
-  printf_core::WriteBuffer<Mode<WriteMode::FLUSH_TO_STREAM>::value> wb(
-      buffer, BUFF_SIZE, &file_write_hook, reinterpret_cast<void *>(stream));
+  printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &file_write_hook,
+                                 reinterpret_cast<void *>(stream));
   Writer writer(wb);
   internal::flockfile(stream);
   auto retval = printf_main(&writer, format, args);
@@ -95,7 +95,7 @@ LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE 
*__restrict stream,
     internal::funlockfile(stream);
     return retval;
   }
-  int flushval = wb.overflow_write("");
+  int flushval = wb.flush_to_stream();
   if (flushval != WRITE_OK)
     retval = Error(-flushval);
   internal::funlockfile(stream);
diff --git a/libc/src/stdio/printf_core/writer.h 
b/libc/src/stdio/printf_core/writer.h
index 9de108ece510f..cb45b105597d1 100644
--- a/libc/src/stdio/printf_core/writer.h
+++ b/libc/src/stdio/printf_core/writer.h
@@ -38,36 +38,65 @@ template <WriteMode write_mode> struct Mode {
 #endif
 };
 
+template <WriteMode write_mode> class Writer;
+
 template <WriteMode write_mode> struct WriteBuffer {
-  using StreamWriter = int (*)(cpp::string_view, void *);
   char *buff;
-  const char *init_buff; // for checking when resize.
   size_t buff_len;
   size_t buff_cur = 0;
-
-  // The stream writer will be called when the buffer is full. It will be 
passed
-  // string_views to write to the stream.
-  const StreamWriter stream_writer;
-  void *output_target;
-
   // The current writing mode in case the user wants runtime dispatch of the
   // stream writer with function pointers.
   [[maybe_unused]] WriteMode write_mode_;
 
-  LIBC_INLINE WriteBuffer(char *buff, size_t buff_len, StreamWriter hook,
-                          void *target)
-      : buff(buff), init_buff(buff), buff_len(buff_len), stream_writer(hook),
-        output_target(target), write_mode_(WriteMode::FLUSH_TO_STREAM) {}
+protected:
+  LIBC_INLINE WriteBuffer(char *buff, size_t buff_len, WriteMode mode)
+      : buff(buff), buff_len(buff_len), write_mode_(mode) {}
+
+private:
+  friend class Writer<write_mode>;
+  // The overflow_write method will handle the case when adding new_str to
+  // the buffer would overflow it. Specific actions will depend on the buffer
+  // type / write_mode.
+  LIBC_INLINE int overflow_write(cpp::string_view new_str);
+};
+
+// Buffer variant that discards characters that don't fit into the buffer.
+struct DropOverflowBuffer
+    : public WriteBuffer<Mode<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value> {
+  LIBC_INLINE DropOverflowBuffer(char *buff, size_t buff_len)
+      : WriteBuffer<Mode<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>(
+            buff, buff_len, WriteMode::FILL_BUFF_AND_DROP_OVERFLOW) {}
+
+  LIBC_INLINE int fill_remaining_to_buff(cpp::string_view new_str) {
+    if (buff_cur < buff_len) {
+      size_t bytes_to_write = buff_len - buff_cur;
+      if (bytes_to_write > new_str.size()) {
+        bytes_to_write = new_str.size();
+      }
+      inline_memcpy(buff + buff_cur, new_str.data(), bytes_to_write);
+      buff_cur += bytes_to_write;
+    }
+    return WRITE_OK;
+  }
+};
 
-  LIBC_INLINE WriteBuffer(char *buff, size_t buff_len)
-      : buff(buff), init_buff(buff), buff_len(buff_len), 
stream_writer(nullptr),
-        output_target(nullptr),
-        write_mode_(WriteMode::FILL_BUFF_AND_DROP_OVERFLOW) {}
+// Buffer variant that flushes to stream when it gets full.
+struct FlushingBuffer
+    : public WriteBuffer<Mode<WriteMode::FLUSH_TO_STREAM>::value> {
+  // The stream writer will be called when the buffer is full. It will be 
passed
+  // string_views to write to the stream.
+  using StreamWriter = int (*)(cpp::string_view, void *);
+  const StreamWriter stream_writer;
+  void *output_target;
 
-  LIBC_INLINE WriteBuffer(char *buff, size_t buff_len, StreamWriter hook)
-      : buff(buff), init_buff(buff), buff_len(buff_len), stream_writer(hook),
-        output_target(this), write_mode_(WriteMode::RESIZE_AND_FILL_BUFF) {}
+  LIBC_INLINE FlushingBuffer(char *buff, size_t buff_len, StreamWriter hook,
+                             void *target)
+      : WriteBuffer<Mode<WriteMode::FLUSH_TO_STREAM>::value>(
+            buff, buff_len, WriteMode::FLUSH_TO_STREAM),
+        stream_writer(hook), output_target(target) {}
 
+  // Flushes the entire current buffer to stream, followed by the new_str (if
+  // non-empty).
   LIBC_INLINE int flush_to_stream(cpp::string_view new_str) {
     if (buff_cur > 0) {
       int retval = stream_writer({buff, buff_cur}, output_target);
@@ -83,48 +112,61 @@ template <WriteMode write_mode> struct WriteBuffer {
     return WRITE_OK;
   }
 
-  LIBC_INLINE int fill_remaining_to_buff(cpp::string_view new_str) {
-    if (buff_cur < buff_len) {
-      size_t bytes_to_write = buff_len - buff_cur;
-      if (bytes_to_write > new_str.size()) {
-        bytes_to_write = new_str.size();
-      }
-      inline_memcpy(buff + buff_cur, new_str.data(), bytes_to_write);
-      buff_cur += bytes_to_write;
-    }
-    return WRITE_OK;
-  }
+  LIBC_INLINE int flush_to_stream() { return flush_to_stream({}); }
+};
 
-  LIBC_INLINE int resize_and_write(cpp::string_view new_str) {
-    return stream_writer(new_str, output_target);
-  }
+// Buffer variant that calls a resizing callback when it gets full.
+struct ResizingBuffer
+    : public WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value> {
+  using ResizeWriter = int (*)(cpp::string_view, ResizingBuffer *);
+  const ResizeWriter resize_writer;
+  const char *init_buff; // for checking when resize.
 
-  // The overflow_write method is intended to be called to write the contents 
of
-  // the buffer and new_str to the stream_writer if it exists. If a resizing
-  // hook is provided, it will resize the buffer and write the contents. If
-  // neither a stream_writer nor a resizing hook is provided, it will fill the
-  // remaining space in the buffer with new_str and drop the overflow. Calling
-  // this with an empty string will flush the buffer if relevant.
-
-  LIBC_INLINE int overflow_write(cpp::string_view new_str) {
-    if constexpr (write_mode == WriteMode::RUNTIME_DISPATCH) {
-      if (write_mode_ == WriteMode::FILL_BUFF_AND_DROP_OVERFLOW)
-        return fill_remaining_to_buff(new_str);
-      else if (write_mode_ == WriteMode::FLUSH_TO_STREAM)
-        return flush_to_stream(new_str);
-      else if (write_mode_ == WriteMode::RESIZE_AND_FILL_BUFF)
-        return resize_and_write(new_str);
-    } else if constexpr (write_mode == WriteMode::FILL_BUFF_AND_DROP_OVERFLOW) 
{
-      return fill_remaining_to_buff(new_str);
-    } else if constexpr (write_mode == WriteMode::FLUSH_TO_STREAM) {
-      return flush_to_stream(new_str);
-    } else if constexpr (write_mode == WriteMode::RESIZE_AND_FILL_BUFF) {
-      return resize_and_write(new_str);
-    }
-    __builtin_unreachable();
+  LIBC_INLINE ResizingBuffer(char *buff, size_t buff_len, ResizeWriter hook)
+      : WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value>(
+            buff, buff_len, WriteMode::RESIZE_AND_FILL_BUFF),
+        resize_writer(hook), init_buff(buff) {}
+
+  // Invokes the callback that is supposed to resize the buffer and make
+  // it large enough to fit the new_str addition.
+  LIBC_INLINE int resize_and_write(cpp::string_view new_str) {
+    return resize_writer(new_str, this);
   }
 };
 
+template <>
+LIBC_INLINE int WriteBuffer<WriteMode::RUNTIME_DISPATCH>::overflow_write(
+    cpp::string_view new_str) {
+  if (write_mode_ == WriteMode::FILL_BUFF_AND_DROP_OVERFLOW)
+    return reinterpret_cast<DropOverflowBuffer 
*>(this)->fill_remaining_to_buff(
+        new_str);
+  else if (write_mode_ == WriteMode::FLUSH_TO_STREAM)
+    return reinterpret_cast<FlushingBuffer *>(this)->flush_to_stream(new_str);
+  else if (write_mode_ == WriteMode::RESIZE_AND_FILL_BUFF)
+    return reinterpret_cast<ResizingBuffer *>(this)->resize_and_write(new_str);
+  __builtin_unreachable();
+}
+
+template <>
+LIBC_INLINE int
+WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::overflow_write(
+    cpp::string_view new_str) {
+  return reinterpret_cast<DropOverflowBuffer *>(this)->fill_remaining_to_buff(
+      new_str);
+}
+
+template <>
+LIBC_INLINE int WriteBuffer<WriteMode::FLUSH_TO_STREAM>::overflow_write(
+    cpp::string_view new_str) {
+  return reinterpret_cast<FlushingBuffer *>(this)->flush_to_stream(new_str);
+}
+
+template <>
+LIBC_INLINE int WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF>::overflow_write(
+    cpp::string_view new_str) {
+  return reinterpret_cast<ResizingBuffer *>(this)->resize_and_write(new_str);
+}
+
 template <WriteMode write_mode> class Writer final {
   WriteBuffer<write_mode> &wb;
   size_t chars_written = 0;
diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp
index d95195f6f485f..8364e8d59b278 100644
--- a/libc/src/stdio/snprintf.cpp
+++ b/libc/src/stdio/snprintf.cpp
@@ -31,9 +31,7 @@ LLVM_LIBC_FUNCTION(int, snprintf,
                                  // and pointer semantics, as well as handling
                                  // destruction automatically.
   va_end(vlist);
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+  printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
   printf_core::Writer writer(wb);
 
   auto ret_val = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp
index 2a9b6ea7c5e50..d340096bb6d2b 100644
--- a/libc/src/stdio/sprintf.cpp
+++ b/libc/src/stdio/sprintf.cpp
@@ -31,9 +31,8 @@ LLVM_LIBC_FUNCTION(int, sprintf,
                                  // destruction automatically.
   va_end(vlist);
 
-  printf_core::WriteBuffer<
-      printf_core::Mode<printf_core::WriteMode::RESIZE_AND_FILL_BUFF>::value>
-      wb(buffer, cpp::numeric_limits<size_t>::max());
+  printf_core::DropOverflowBuffer wb(buffer,
+                                     cpp::numeric_limits<size_t>::max());
   printf_core::Writer writer(wb);
 
   auto ret_val = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp
index 5d936360c0857..b65343dfefc75 100644
--- a/libc/src/stdio/vsnprintf.cpp
+++ b/libc/src/stdio/vsnprintf.cpp
@@ -28,9 +28,7 @@ LLVM_LIBC_FUNCTION(int, vsnprintf,
   internal::ArgList args(vlist); // This holder class allows for easier copying
                                  // and pointer semantics, as well as handling
                                  // destruction automatically.
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+  printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
   printf_core::Writer writer(wb);
 
   auto ret_val = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp
index f9cf8118534f6..8affb88d2b807 100644
--- a/libc/src/stdio/vsprintf.cpp
+++ b/libc/src/stdio/vsprintf.cpp
@@ -28,9 +28,8 @@ LLVM_LIBC_FUNCTION(int, vsprintf,
                                  // and pointer semantics, as well as handling
                                  // destruction automatically.
 
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(buffer, cpp::numeric_limits<size_t>::max());
+  printf_core::DropOverflowBuffer wb(buffer,
+                                     cpp::numeric_limits<size_t>::max());
   printf_core::Writer writer(wb);
 
   auto ret_val = printf_core::printf_main(&writer, format, args);
diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp
index 71e257f08645b..5409a57c722d4 100644
--- a/libc/src/stdlib/strfromd.cpp
+++ b/libc/src/stdlib/strfromd.cpp
@@ -22,9 +22,7 @@ LLVM_LIBC_FUNCTION(int, strfromd,
 
   printf_core::FormatSection section =
       internal::parse_format_string(format, fp);
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(s, (n > 0 ? n - 1 : 0));
+  printf_core::DropOverflowBuffer wb(s, (n > 0 ? n - 1 : 0));
   printf_core::Writer writer(wb);
 
   int result = 0;
diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp
index 65f242b200f18..e68e50210dd4d 100644
--- a/libc/src/stdlib/strfromf.cpp
+++ b/libc/src/stdlib/strfromf.cpp
@@ -22,9 +22,7 @@ LLVM_LIBC_FUNCTION(int, strfromf,
 
   printf_core::FormatSection section =
       internal::parse_format_string(format, fp);
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(s, (n > 0 ? n - 1 : 0));
+  printf_core::DropOverflowBuffer wb(s, (n > 0 ? n - 1 : 0));
   printf_core::Writer writer(wb);
 
   int result = 0;
diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp
index 31668a0323c93..4be21677f7f13 100644
--- a/libc/src/stdlib/strfroml.cpp
+++ b/libc/src/stdlib/strfroml.cpp
@@ -27,9 +27,7 @@ LLVM_LIBC_FUNCTION(int, strfroml,
   // the length modifier has to be set to LenghtModifier::L
   section.length_modifier = printf_core::LengthModifier::L;
 
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(s, (n > 0 ? n - 1 : 0));
+  printf_core::DropOverflowBuffer wb(s, (n > 0 ? n - 1 : 0));
   printf_core::Writer writer(wb);
 
   int result = 0;
diff --git a/libc/src/time/strftime.cpp b/libc/src/time/strftime.cpp
index ff8c05a0b07da..af0f438d22cab 100644
--- a/libc/src/time/strftime.cpp
+++ b/libc/src/time/strftime.cpp
@@ -19,9 +19,7 @@ namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(size_t, strftime,
                    (char *__restrict buffer, size_t buffsz,
                     const char *__restrict format, const tm *timeptr)) {
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+  printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
   printf_core::Writer writer(wb);
   auto ret = strftime_core::strftime_main(&writer, format, timeptr);
   if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
diff --git a/libc/src/time/strftime_l.cpp b/libc/src/time/strftime_l.cpp
index 2ec90634ea347..7a70d2c5418ee 100644
--- a/libc/src/time/strftime_l.cpp
+++ b/libc/src/time/strftime_l.cpp
@@ -22,9 +22,7 @@ LLVM_LIBC_FUNCTION(size_t, strftime_l,
                    (char *__restrict buffer, size_t buffsz,
                     const char *__restrict format, const tm *timeptr,
                     locale_t)) {
-  printf_core::WriteBuffer<printf_core::Mode<
-      printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>
-      wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
+  printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
   printf_core::Writer writer(wb);
   auto ret = strftime_core::strftime_main(&writer, format, timeptr);
   if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
diff --git a/libc/test/src/stdio/printf_core/converter_test.cpp 
b/libc/test/src/stdio/printf_core/converter_test.cpp
index 2dae2a22c864c..68e2fdac89d47 100644
--- a/libc/test/src/stdio/printf_core/converter_test.cpp
+++ b/libc/test/src/stdio/printf_core/converter_test.cpp
@@ -14,18 +14,14 @@
 
 class LlvmLibcPrintfConverterTest : public LIBC_NAMESPACE::testing::Test {
 protected:
-  // void SetUp() override {}
-  // void TearDown() override {}
+  LlvmLibcPrintfConverterTest() : wb(str, sizeof(str) - 1), writer(wb) {}
 
   char str[60];
-  LIBC_NAMESPACE::printf_core::WriteBuffer<
-      LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
-      wb = LIBC_NAMESPACE::printf_core::WriteBuffer<
-          LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>(
-          str, sizeof(str) - 1);
-  LIBC_NAMESPACE::printf_core::Writer<
-      LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
-      writer = LIBC_NAMESPACE::printf_core::Writer(wb);
+  LIBC_NAMESPACE::printf_core::DropOverflowBuffer wb;
+  LIBC_NAMESPACE::printf_core::Writer<LIBC_NAMESPACE::printf_core::Mode<
+      LIBC_NAMESPACE::printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::
+                                          value>
+      writer;
 };
 
 TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) {
diff --git a/libc/test/src/stdio/printf_core/writer_test.cpp 
b/libc/test/src/stdio/printf_core/writer_test.cpp
index d263cf55aa474..e0128505b2766 100644
--- a/libc/test/src/stdio/printf_core/writer_test.cpp
+++ b/libc/test/src/stdio/printf_core/writer_test.cpp
@@ -15,20 +15,21 @@
 namespace {
 
 using LIBC_NAMESPACE::cpp::string_view;
-using LIBC_NAMESPACE::printf_core::WriteBuffer;
+using LIBC_NAMESPACE::printf_core::DropOverflowBuffer;
+using LIBC_NAMESPACE::printf_core::FlushingBuffer;
 using LIBC_NAMESPACE::printf_core::WriteMode;
 using LIBC_NAMESPACE::printf_core::Writer;
 
 TEST(LlvmLibcPrintfWriterTest, Constructor) {
   char str[10];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   (void)writer;
 }
 
 TEST(LlvmLibcPrintfWriterTest, Write) {
   char str[4] = {'D', 'E', 'F', 'G'};
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write({"abc", 3});
 
@@ -44,7 +45,7 @@ TEST(LlvmLibcPrintfWriterTest, Write) {
 
 TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) {
   char str[10];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write({"abc", 3});
   writer.write({"DEF", 3});
@@ -58,7 +59,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) {
 
 TEST(LlvmLibcPrintfWriterTest, WriteChars) {
   char str[4] = {'D', 'E', 'F', 'G'};
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write('a', 3);
 
@@ -71,7 +72,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteChars) {
 
 TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) {
   char str[10];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write('a', 3);
   writer.write('D', 3);
@@ -85,7 +86,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) {
 
 TEST(LlvmLibcPrintfWriterTest, WriteManyChars) {
   char str[100];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write('Z', 99);
 
@@ -107,7 +108,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteManyChars) {
 
 TEST(LlvmLibcPrintfWriterTest, MixedWrites) {
   char str[13];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write('a', 3);
   writer.write({"DEF", 3});
@@ -122,7 +123,7 @@ TEST(LlvmLibcPrintfWriterTest, MixedWrites) {
 
 TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) {
   char str[11];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write({"abcDEF123456", 12});
 
@@ -134,7 +135,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) {
 
 TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) {
   char str[11];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
   Writer writer(wb);
   writer.write('1', 15);
 
@@ -146,7 +147,7 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) {
 
 TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) {
   char str[11];
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, sizeof(str) - 1);
+  DropOverflowBuffer wb(str, sizeof(str) - 1);
 
   Writer writer(wb);
   writer.write('a', 3);
@@ -164,7 +165,7 @@ TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) {
   char str[1];
   // This is because the max length should be at most 1 less than the size of
   // the buffer it's writing to.
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(str, 0);
+  DropOverflowBuffer wb(str, 0);
 
   Writer writer(wb);
   writer.write('a', 3);
@@ -179,7 +180,7 @@ TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) {
 }
 
 TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) {
-  WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0);
+  DropOverflowBuffer wb(nullptr, 0);
 
   Writer writer(wb);
   writer.write('a', 3);
@@ -215,14 +216,12 @@ TEST(LlvmLibcPrintfWriterTest, 
WriteWithMaxLengthWithCallback) {
   OutBuff out_buff = {str, 0};
 
   char wb_buff[8];
-  WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
-      wb_buff, sizeof(wb_buff), &copy_to_out,
-      reinterpret_cast<void *>(&out_buff));
+  FlushingBuffer wb(wb_buff, sizeof(wb_buff), &copy_to_out,
+                    reinterpret_cast<void *>(&out_buff));
   Writer writer(wb);
   writer.write({"abcDEF123456", 12});
 
-  // Flush the buffer
-  wb.overflow_write("");
+  wb.flush_to_stream();
   str[out_buff.cur_pos] = '\0';
 
   ASSERT_STREQ("abcDEF123456", str);
@@ -235,14 +234,12 @@ TEST(LlvmLibcPrintfWriterTest, 
WriteCharsWithMaxLengthWithCallback) {
   OutBuff out_buff = {str, 0};
 
   char wb_buff[8];
-  WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
-      wb_buff, sizeof(wb_buff), &copy_to_out,
-      reinterpret_cast<void *>(&out_buff));
+  FlushingBuffer wb(wb_buff, sizeof(wb_buff), &copy_to_out,
+                    reinterpret_cast<void *>(&out_buff));
   Writer writer(wb);
   writer.write('1', 15);
 
-  // Flush the buffer
-  wb.overflow_write("");
+  wb.flush_to_stream();
   str[out_buff.cur_pos] = '\0';
 
   ASSERT_STREQ("111111111111111", str);
@@ -255,17 +252,15 @@ TEST(LlvmLibcPrintfWriterTest, 
MixedWriteWithMaxLengthWithCallback) {
   OutBuff out_buff = {str, 0};
 
   char wb_buff[8];
-  WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
-      wb_buff, sizeof(wb_buff), &copy_to_out,
-      reinterpret_cast<void *>(&out_buff));
+  FlushingBuffer wb(wb_buff, sizeof(wb_buff), &copy_to_out,
+                    reinterpret_cast<void *>(&out_buff));
   Writer writer(wb);
   writer.write('a', 3);
   writer.write({"DEF", 3});
   writer.write('1', 3);
   writer.write({"456", 3});
 
-  // Flush the buffer
-  wb.overflow_write("");
+  wb.flush_to_stream();
   str[out_buff.cur_pos] = '\0';
 
   ASSERT_STREQ("aaaDEF111456", str);
@@ -278,8 +273,8 @@ TEST(LlvmLibcPrintfWriterTest, 
ZeroLengthBufferWithCallback) {
   OutBuff out_buff = {str, 0};
 
   char wb_buff[1];
-  WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
-      wb_buff, 0, &copy_to_out, reinterpret_cast<void *>(&out_buff));
+  FlushingBuffer wb(wb_buff, 0, &copy_to_out,
+                    reinterpret_cast<void *>(&out_buff));
 
   Writer writer(wb);
   writer.write('a', 3);
@@ -287,8 +282,7 @@ TEST(LlvmLibcPrintfWriterTest, 
ZeroLengthBufferWithCallback) {
   writer.write('1', 3);
   writer.write({"456", 3});
 
-  // Flush the buffer
-  wb.overflow_write("");
+  wb.flush_to_stream();
   str[out_buff.cur_pos] = '\0';
 
   ASSERT_STREQ("aaaDEF111456", str);
@@ -300,8 +294,8 @@ TEST(LlvmLibcPrintfWriterTest, 
NullStringWithZeroMaxLengthWithCallback) {
 
   OutBuff out_buff = {str, 0};
 
-  WriteBuffer<WriteMode::FLUSH_TO_STREAM> wb(
-      nullptr, 0, &copy_to_out, reinterpret_cast<void *>(&out_buff));
+  FlushingBuffer wb(nullptr, 0, &copy_to_out,
+                    reinterpret_cast<void *>(&out_buff));
 
   Writer writer(wb);
   writer.write('a', 3);
@@ -309,7 +303,7 @@ TEST(LlvmLibcPrintfWriterTest, 
NullStringWithZeroMaxLengthWithCallback) {
   writer.write('1', 3);
   writer.write({"456", 3});
 
-  wb.overflow_write("");
+  wb.flush_to_stream();
   str[out_buff.cur_pos] = '\0';
 
   ASSERT_EQ(writer.get_chars_written(), size_t{12});

>From 43b690df58735c2b0284d946937cba8b512133c8 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <[email protected]>
Date: Sat, 6 Dec 2025 00:18:16 +0000
Subject: [PATCH 2/2] [libc][printf] De-string-viewify writer internals.

This change doesn't yet modify
Writer::write(string_view) public API, which
has a lot of uses through printf_core.

For wide-char write functions (like swprintf) we'd
need to templatize WriteBuffer and Writer to
support wide characrters. We'd need to either
support helper cpp::string_view class to support
wide-character strings, or replace them with pure
pointer/size pairs.

The latter option seems to be a more
straightforward one, given that majority of printf_core operates on buffers 
anyway
(and only constructs string_views right
before invoking the buffer), and we don't
have a use case internal wide-character
string-views.
---
 libc/src/stdio/baremetal/printf.cpp           |   5 +-
 libc/src/stdio/baremetal/vprintf.cpp          |   5 +-
 .../stdio/printf_core/vasprintf_internal.h    |   6 +-
 .../src/stdio/printf_core/vfprintf_internal.h |   9 +-
 libc/src/stdio/printf_core/writer.h           | 105 ++++++++++--------
 .../src/stdio/printf_core/writer_test.cpp     |  12 +-
 6 files changed, 75 insertions(+), 67 deletions(-)

diff --git a/libc/src/stdio/baremetal/printf.cpp 
b/libc/src/stdio/baremetal/printf.cpp
index 2fa9cf7c9f3cd..3329d4fecdad5 100644
--- a/libc/src/stdio/baremetal/printf.cpp
+++ b/libc/src/stdio/baremetal/printf.cpp
@@ -24,8 +24,9 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace {
 
-LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
-  write_to_stdout(new_str);
+LIBC_INLINE int stdout_write_hook(const char *new_str, size_t new_str_len,
+                                  void *) {
+  write_to_stdout({new_str, new_str_len});
   return printf_core::WRITE_OK;
 }
 
diff --git a/libc/src/stdio/baremetal/vprintf.cpp 
b/libc/src/stdio/baremetal/vprintf.cpp
index d89f26cd72b0a..30faa9ad54b8b 100644
--- a/libc/src/stdio/baremetal/vprintf.cpp
+++ b/libc/src/stdio/baremetal/vprintf.cpp
@@ -24,8 +24,9 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace {
 
-LIBC_INLINE int stdout_write_hook(cpp::string_view new_str, void *) {
-  write_to_stdout(new_str);
+LIBC_INLINE int stdout_write_hook(const char *new_str, size_t new_str_len,
+                                  void *) {
+  write_to_stdout({new_str, new_str_len});
   return printf_core::WRITE_OK;
 }
 
diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h 
b/libc/src/stdio/printf_core/vasprintf_internal.h
index db6b95d49aaca..a36e9ca749305 100644
--- a/libc/src/stdio/printf_core/vasprintf_internal.h
+++ b/libc/src/stdio/printf_core/vasprintf_internal.h
@@ -18,9 +18,9 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace printf_core {
 
-LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str,
+LIBC_INLINE int resize_overflow_hook(const char *new_str, size_t new_str_len,
                                      ResizingBuffer *wb) {
-  size_t new_size = new_str.size() + wb->buff_cur;
+  size_t new_size = new_str_len + wb->buff_cur;
   const bool isBuffOnStack = (wb->buff == wb->init_buff);
   char *new_buff = static_cast<char *>(
       isBuffOnStack ? malloc(new_size + 1)
@@ -33,7 +33,7 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str,
   if (isBuffOnStack)
     inline_memcpy(new_buff, wb->buff, wb->buff_cur);
   wb->buff = new_buff;
-  inline_memcpy(wb->buff + wb->buff_cur, new_str.data(), new_str.size());
+  inline_memcpy(wb->buff + wb->buff_cur, new_str, new_str_len);
   wb->buff_cur = new_size;
   wb->buff_len = new_size;
   return printf_core::WRITE_OK;
diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h 
b/libc/src/stdio/printf_core/vfprintf_internal.h
index 321b0693ad339..b2b282fbf7b78 100644
--- a/libc/src/stdio/printf_core/vfprintf_internal.h
+++ b/libc/src/stdio/printf_core/vfprintf_internal.h
@@ -62,19 +62,20 @@ LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, 
size_t size,
 
 namespace printf_core {
 
-LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) {
+LIBC_INLINE int file_write_hook(const char *new_str, size_t new_str_len,
+                                void *fp) {
   ::FILE *target_file = reinterpret_cast<::FILE *>(fp);
   // Write new_str to the target file. The logic preventing a zero-length write
   // is in the writer, so we don't check here.
-  auto write_result = internal::fwrite_unlocked(new_str.data(), sizeof(char),
-                                                new_str.size(), target_file);
+  auto write_result = internal::fwrite_unlocked(new_str, sizeof(char),
+                                                new_str_len, target_file);
   // Propagate actual system error in FileIOResult.
   if (write_result.has_error())
     return -write_result.error;
 
   // In case short write occured or error was not set on FileIOResult for some
   // reason.
-  if (write_result.value != new_str.size() ||
+  if (write_result.value != new_str_len ||
       internal::ferror_unlocked(target_file))
     return FILE_WRITE_ERROR;
 
diff --git a/libc/src/stdio/printf_core/writer.h 
b/libc/src/stdio/printf_core/writer.h
index cb45b105597d1..1eeffee2f5dde 100644
--- a/libc/src/stdio/printf_core/writer.h
+++ b/libc/src/stdio/printf_core/writer.h
@@ -41,7 +41,8 @@ template <WriteMode write_mode> struct Mode {
 template <WriteMode write_mode> class Writer;
 
 template <WriteMode write_mode> struct WriteBuffer {
-  char *buff;
+  using CharType = char;
+  CharType *buff;
   size_t buff_len;
   size_t buff_cur = 0;
   // The current writing mode in case the user wants runtime dispatch of the
@@ -49,7 +50,7 @@ template <WriteMode write_mode> struct WriteBuffer {
   [[maybe_unused]] WriteMode write_mode_;
 
 protected:
-  LIBC_INLINE WriteBuffer(char *buff, size_t buff_len, WriteMode mode)
+  LIBC_INLINE WriteBuffer(CharType *buff, size_t buff_len, WriteMode mode)
       : buff(buff), buff_len(buff_len), write_mode_(mode) {}
 
 private:
@@ -57,24 +58,26 @@ template <WriteMode write_mode> struct WriteBuffer {
   // The overflow_write method will handle the case when adding new_str to
   // the buffer would overflow it. Specific actions will depend on the buffer
   // type / write_mode.
-  LIBC_INLINE int overflow_write(cpp::string_view new_str);
+  LIBC_INLINE int overflow_write(const CharType *new_str, size_t new_str_len);
 };
 
 // Buffer variant that discards characters that don't fit into the buffer.
 struct DropOverflowBuffer
     : public WriteBuffer<Mode<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value> {
-  LIBC_INLINE DropOverflowBuffer(char *buff, size_t buff_len)
+  LIBC_INLINE DropOverflowBuffer(CharType *buff, size_t buff_len)
       : WriteBuffer<Mode<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::value>(
             buff, buff_len, WriteMode::FILL_BUFF_AND_DROP_OVERFLOW) {}
 
-  LIBC_INLINE int fill_remaining_to_buff(cpp::string_view new_str) {
+  LIBC_INLINE int fill_remaining_to_buff(const CharType *new_str,
+                                         size_t new_str_len) {
     if (buff_cur < buff_len) {
-      size_t bytes_to_write = buff_len - buff_cur;
-      if (bytes_to_write > new_str.size()) {
-        bytes_to_write = new_str.size();
+      size_t chars_to_write = buff_len - buff_cur;
+      if (chars_to_write > new_str_len) {
+        chars_to_write = new_str_len;
       }
-      inline_memcpy(buff + buff_cur, new_str.data(), bytes_to_write);
-      buff_cur += bytes_to_write;
+      inline_memcpy(buff + buff_cur, new_str,
+                    chars_to_write * sizeof(CharType));
+      buff_cur += chars_to_write;
     }
     return WRITE_OK;
   }
@@ -84,27 +87,27 @@ struct DropOverflowBuffer
 struct FlushingBuffer
     : public WriteBuffer<Mode<WriteMode::FLUSH_TO_STREAM>::value> {
   // The stream writer will be called when the buffer is full. It will be 
passed
-  // string_views to write to the stream.
-  using StreamWriter = int (*)(cpp::string_view, void *);
+  // buffers to write, and the target provided at construction time.
+  using StreamWriter = int (*)(const CharType *, size_t, void *);
   const StreamWriter stream_writer;
   void *output_target;
 
-  LIBC_INLINE FlushingBuffer(char *buff, size_t buff_len, StreamWriter hook,
+  LIBC_INLINE FlushingBuffer(CharType *buff, size_t buff_len, StreamWriter 
hook,
                              void *target)
       : WriteBuffer<Mode<WriteMode::FLUSH_TO_STREAM>::value>(
             buff, buff_len, WriteMode::FLUSH_TO_STREAM),
         stream_writer(hook), output_target(target) {}
 
-  // Flushes the entire current buffer to stream, followed by the new_str (if
-  // non-empty).
-  LIBC_INLINE int flush_to_stream(cpp::string_view new_str) {
+  // Flushes the entire current buffer to stream, followed by the new_str
+  // buffer.
+  LIBC_INLINE int flush_to_stream(const CharType *new_str, size_t new_str_len) 
{
     if (buff_cur > 0) {
-      int retval = stream_writer({buff, buff_cur}, output_target);
+      int retval = stream_writer(buff, buff_cur, output_target);
       if (retval < 0)
         return retval;
     }
-    if (new_str.size() > 0) {
-      int retval = stream_writer(new_str, output_target);
+    if (new_str_len > 0) {
+      int retval = stream_writer(new_str, new_str_len, output_target);
       if (retval < 0)
         return retval;
     }
@@ -112,66 +115,73 @@ struct FlushingBuffer
     return WRITE_OK;
   }
 
-  LIBC_INLINE int flush_to_stream() { return flush_to_stream({}); }
+  LIBC_INLINE int flush_to_stream() { return flush_to_stream(nullptr, 0); }
 };
 
 // Buffer variant that calls a resizing callback when it gets full.
 struct ResizingBuffer
     : public WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value> {
-  using ResizeWriter = int (*)(cpp::string_view, ResizingBuffer *);
+  using ResizeWriter = int (*)(const CharType *, size_t, ResizingBuffer *);
   const ResizeWriter resize_writer;
-  const char *init_buff; // for checking when resize.
+  const CharType *init_buff; // for checking when resize.
 
-  LIBC_INLINE ResizingBuffer(char *buff, size_t buff_len, ResizeWriter hook)
+  LIBC_INLINE ResizingBuffer(CharType *buff, size_t buff_len, ResizeWriter 
hook)
       : WriteBuffer<Mode<WriteMode::RESIZE_AND_FILL_BUFF>::value>(
             buff, buff_len, WriteMode::RESIZE_AND_FILL_BUFF),
         resize_writer(hook), init_buff(buff) {}
 
   // Invokes the callback that is supposed to resize the buffer and make
   // it large enough to fit the new_str addition.
-  LIBC_INLINE int resize_and_write(cpp::string_view new_str) {
-    return resize_writer(new_str, this);
+  LIBC_INLINE int resize_and_write(const CharType *new_str,
+                                   size_t new_str_len) {
+    return resize_writer(new_str, new_str_len, this);
   }
 };
 
 template <>
 LIBC_INLINE int WriteBuffer<WriteMode::RUNTIME_DISPATCH>::overflow_write(
-    cpp::string_view new_str) {
+    const CharType *new_str, size_t new_str_len) {
   if (write_mode_ == WriteMode::FILL_BUFF_AND_DROP_OVERFLOW)
     return reinterpret_cast<DropOverflowBuffer 
*>(this)->fill_remaining_to_buff(
-        new_str);
+        new_str, new_str_len);
   else if (write_mode_ == WriteMode::FLUSH_TO_STREAM)
-    return reinterpret_cast<FlushingBuffer *>(this)->flush_to_stream(new_str);
+    return reinterpret_cast<FlushingBuffer *>(this)->flush_to_stream(
+        new_str, new_str_len);
   else if (write_mode_ == WriteMode::RESIZE_AND_FILL_BUFF)
-    return reinterpret_cast<ResizingBuffer *>(this)->resize_and_write(new_str);
+    return reinterpret_cast<ResizingBuffer *>(this)->resize_and_write(
+        new_str, new_str_len);
   __builtin_unreachable();
 }
 
 template <>
 LIBC_INLINE int
 WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>::overflow_write(
-    cpp::string_view new_str) {
+    const CharType *new_str, size_t new_str_len) {
   return reinterpret_cast<DropOverflowBuffer *>(this)->fill_remaining_to_buff(
-      new_str);
+      new_str, new_str_len);
 }
 
 template <>
-LIBC_INLINE int WriteBuffer<WriteMode::FLUSH_TO_STREAM>::overflow_write(
-    cpp::string_view new_str) {
-  return reinterpret_cast<FlushingBuffer *>(this)->flush_to_stream(new_str);
+LIBC_INLINE int
+WriteBuffer<WriteMode::FLUSH_TO_STREAM>::overflow_write(const CharType 
*new_str,
+                                                        size_t new_str_len) {
+  return reinterpret_cast<FlushingBuffer *>(this)->flush_to_stream(new_str,
+                                                                   
new_str_len);
 }
 
 template <>
 LIBC_INLINE int WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF>::overflow_write(
-    cpp::string_view new_str) {
-  return reinterpret_cast<ResizingBuffer *>(this)->resize_and_write(new_str);
+    const CharType *new_str, size_t new_str_len) {
+  return reinterpret_cast<ResizingBuffer *>(this)->resize_and_write(
+      new_str, new_str_len);
 }
 
 template <WriteMode write_mode> class Writer final {
+  using CharType = char;
   WriteBuffer<write_mode> &wb;
   size_t chars_written = 0;
 
-  LIBC_INLINE int pad(char new_char, size_t length) {
+  LIBC_INLINE int pad(CharType new_char, size_t length) {
     // First, fill as much of the buffer as possible with the padding char.
     size_t written = 0;
     const size_t buff_space = wb.buff_len - wb.buff_cur;
@@ -184,17 +194,15 @@ template <WriteMode write_mode> class Writer final {
 
     // Next, overflow write the rest of length using the mini_buff.
     constexpr size_t MINI_BUFF_SIZE = 64;
-    char mini_buff[MINI_BUFF_SIZE];
+    CharType mini_buff[MINI_BUFF_SIZE];
     inline_memset(mini_buff, new_char, MINI_BUFF_SIZE);
-    cpp::string_view mb_string_view(mini_buff, MINI_BUFF_SIZE);
     while (written + MINI_BUFF_SIZE < length) {
-      int result = wb.overflow_write(mb_string_view);
+      int result = wb.overflow_write(mini_buff, MINI_BUFF_SIZE);
       if (result != WRITE_OK)
         return result;
       written += MINI_BUFF_SIZE;
     }
-    cpp::string_view mb_substr = mb_string_view.substr(0, length - written);
-    return wb.overflow_write(mb_substr);
+    return wb.overflow_write(mini_buff, length - written);
   }
 
 public:
@@ -202,6 +210,7 @@ template <WriteMode write_mode> class Writer final {
 
   // Takes a string, copies it into the buffer if there is space, else passes 
it
   // to the overflow mechanism to be handled separately.
+  // TODO: Migrate all callers away from string_view to CharType*/size_t pair.
   LIBC_INLINE int write(cpp::string_view new_string) {
     chars_written += new_string.size();
     if (LIBC_LIKELY(wb.buff_cur + new_string.size() <= wb.buff_len)) {
@@ -210,18 +219,17 @@ template <WriteMode write_mode> class Writer final {
       wb.buff_cur += new_string.size();
       return WRITE_OK;
     }
-    return wb.overflow_write(new_string);
+    return wb.overflow_write(new_string.data(), new_string.size());
   }
 
   // Takes a char and a length, memsets the next length characters of the 
buffer
   // if there is space, else calls pad which will loop and call the overflow
   // mechanism on a secondary buffer.
-  LIBC_INLINE int write(char new_char, size_t length) {
+  LIBC_INLINE int write(CharType new_char, size_t length) {
     chars_written += length;
 
     if (LIBC_LIKELY(wb.buff_cur + length <= wb.buff_len)) {
-      inline_memset(wb.buff + wb.buff_cur, static_cast<unsigned 
char>(new_char),
-                    length);
+      inline_memset(wb.buff + wb.buff_cur, new_char, length);
       wb.buff_cur += length;
       return WRITE_OK;
     }
@@ -230,15 +238,14 @@ template <WriteMode write_mode> class Writer final {
 
   // Takes a char, copies it into the buffer if there is space, else passes it
   // to the overflow mechanism to be handled separately.
-  LIBC_INLINE int write(char new_char) {
+  LIBC_INLINE int write(CharType new_char) {
     chars_written += 1;
     if (LIBC_LIKELY(wb.buff_cur + 1 <= wb.buff_len)) {
       wb.buff[wb.buff_cur] = new_char;
       wb.buff_cur += 1;
       return WRITE_OK;
     }
-    cpp::string_view char_string_view(&new_char, 1);
-    return wb.overflow_write(char_string_view);
+    return wb.overflow_write(&new_char, 1);
   }
 
   LIBC_INLINE size_t get_chars_written() { return chars_written; }
diff --git a/libc/test/src/stdio/printf_core/writer_test.cpp 
b/libc/test/src/stdio/printf_core/writer_test.cpp
index e0128505b2766..8f14e38aab922 100644
--- a/libc/test/src/stdio/printf_core/writer_test.cpp
+++ b/libc/test/src/stdio/printf_core/writer_test.cpp
@@ -8,13 +8,11 @@
 
 #include "src/stdio/printf_core/writer.h"
 
-#include "src/__support/CPP/string_view.h"
 #include "src/string/memory_utils/inline_memcpy.h"
 #include "test/UnitTest/Test.h"
 
 namespace {
 
-using LIBC_NAMESPACE::cpp::string_view;
 using LIBC_NAMESPACE::printf_core::DropOverflowBuffer;
 using LIBC_NAMESPACE::printf_core::FlushingBuffer;
 using LIBC_NAMESPACE::printf_core::WriteMode;
@@ -196,17 +194,17 @@ struct OutBuff {
   size_t cur_pos = 0;
 };
 
-int copy_to_out(string_view new_str, void *raw_out_buff) {
-  if (new_str.size() == 0) {
+int copy_to_out(const char *new_str, size_t new_str_len, void *raw_out_buff) {
+  if (new_str_len == 0) {
     return 0;
   }
 
   OutBuff *out_buff = reinterpret_cast<OutBuff *>(raw_out_buff);
 
-  LIBC_NAMESPACE::inline_memcpy(out_buff->out_str + out_buff->cur_pos,
-                                new_str.data(), new_str.size());
+  LIBC_NAMESPACE::inline_memcpy(out_buff->out_str + out_buff->cur_pos, new_str,
+                                new_str_len);
 
-  out_buff->cur_pos += new_str.size();
+  out_buff->cur_pos += new_str_len;
   return 0;
 }
 

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to