[libc-commits] [libc] [libc] Update printf_core::Writer to template on character type. (PR #220669)
Alex Strelnikov via libc-commits
libc-commits at lists.llvm.org
Thu Sep 3 07:48:59 PDT 2026
https://github.com/strel-12 updated https://github.com/llvm/llvm-project/pull/220669
>From 0f2bdc1743bf41b739d64b8998bcd9775444bea8 Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Wed, 2 Sep 2026 16:26:21 +0000
Subject: [PATCH 1/2] Update printf_core::Writer to template on character type.
---
libc/src/__support/printf_core/CMakeLists.txt | 45 ++-
.../__support/printf_core/char_converter.h | 4 +-
libc/src/__support/printf_core/converter.h | 18 +-
.../__support/printf_core/fixed_converter.h | 4 +-
.../printf_core/float_dec_converter.h | 55 ++-
.../printf_core/float_dec_converter_limited.h | 36 +-
.../printf_core/float_hex_converter.h | 4 +-
.../printf_core/float_inf_nan_converter.h | 4 +-
.../src/__support/printf_core/int_converter.h | 4 +-
.../__support/printf_core/make_file_writer.h | 120 +++++++
.../printf_core/make_resizing_writer.h | 63 ++++
.../printf_core/make_stderr_writer.h | 56 +++
.../{write_modes.def => overflow_modes.def} | 9 +-
libc/src/__support/printf_core/printf_main.h | 9 +-
.../src/__support/printf_core/ptr_converter.h | 4 +-
.../printf_core/strerror_converter.h | 4 +-
.../__support/printf_core/string_converter.h | 12 +-
.../printf_core/vasprintf_internal.h | 37 +-
.../__support/printf_core/vfprintf_internal.h | 67 +---
.../printf_core/write_int_converter.h | 4 +-
libc/src/__support/printf_core/writer.h | 327 ++++++++++--------
libc/src/err/report.cpp | 17 +-
libc/src/stdio/snprintf.cpp | 8 +-
libc/src/stdio/sprintf.cpp | 6 +-
libc/src/stdio/vsnprintf.cpp | 8 +-
libc/src/stdio/vsprintf.cpp | 6 +-
libc/src/stdlib/str_from_util.h | 4 +-
libc/src/stdlib/strfromd.cpp | 8 +-
libc/src/stdlib/strfromf.cpp | 8 +-
libc/src/stdlib/strfroml.cpp | 8 +-
libc/src/time/asctime_utils.h | 5 +-
libc/src/time/strftime.cpp | 8 +-
.../time/strftime_core/composite_converter.h | 32 +-
libc/src/time/strftime_core/converter.h | 6 +-
libc/src/time/strftime_core/num_converter.h | 8 +-
libc/src/time/strftime_core/str_converter.h | 6 +-
libc/src/time/strftime_core/strftime_main.h | 4 +-
.../__support/printf_core/converter_test.cpp | 10 +-
.../src/__support/printf_core/writer_test.cpp | 117 +++----
39 files changed, 695 insertions(+), 460 deletions(-)
create mode 100644 libc/src/__support/printf_core/make_file_writer.h
create mode 100644 libc/src/__support/printf_core/make_resizing_writer.h
create mode 100644 libc/src/__support/printf_core/make_stderr_writer.h
rename libc/src/__support/printf_core/{write_modes.def => overflow_modes.def} (66%)
diff --git a/libc/src/__support/printf_core/CMakeLists.txt b/libc/src/__support/printf_core/CMakeLists.txt
index 3617bb7ac1ea2..12826b55d98c9 100644
--- a/libc/src/__support/printf_core/CMakeLists.txt
+++ b/libc/src/__support/printf_core/CMakeLists.txt
@@ -118,6 +118,30 @@ add_header_library(
libc.src.string.memory_utils.inline_memset
)
+add_header_library(
+ make_resizing_writer
+ HDRS
+ make_resizing_writer.h
+ DEPENDS
+ .writer
+ libc.hdr.func.malloc
+ libc.hdr.func.free
+ libc.hdr.func.realloc
+ libc.src.__support.CPP.string_view
+ libc.src.__support.printf_core.writer
+)
+
+add_header_library(
+ make_stderr_writer
+ HDRS
+ make_stderr_writer.h
+ DEPENDS
+ .writer
+ libc.src.__support.CPP.string_view
+ libc.src.__support.OSUtil.io
+ libc.src.__support.macros.config
+)
+
add_header_library(
converter
HDRS
@@ -179,12 +203,10 @@ add_header_library(
vasprintf_internal.h
DEPENDS
libc.hdr.func.malloc
- libc.hdr.func.free
- libc.hdr.func.realloc
libc.src.__support.arg_list
libc.src.__support.error_or
+ libc.src.__support.printf_core.make_resizing_writer
libc.src.__support.printf_core.printf_main
- libc.src.__support.printf_core.writer
)
add_header_library(
@@ -202,15 +224,28 @@ if(NOT (TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD)
return()
endif()
+add_header_library(
+ make_file_writer
+ HDRS
+ make_file_writer.h
+ DEPENDS
+ .writer
+ libc.src.__support.CPP.string_view
+ libc.src.__support.File.file
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+ ${use_system_file}
+)
+
add_header_library(
vfprintf_internal
HDRS
vfprintf_internal.h
DEPENDS
+ .make_file_writer
+ .printf_main
libc.src.__support.File.file
libc.src.__support.error_or
libc.src.__support.arg_list
- libc.src.__support.printf_core.printf_main
- libc.src.__support.printf_core.writer
${use_system_file}
)
diff --git a/libc/src/__support/printf_core/char_converter.h b/libc/src/__support/printf_core/char_converter.h
index 59f3e22f7ce50..7bad28d18d1be 100644
--- a/libc/src/__support/printf_core/char_converter.h
+++ b/libc/src/__support/printf_core/char_converter.h
@@ -26,8 +26,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-template <WriteMode write_mode>
-LIBC_INLINE int convert_char(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_char(Writer<mode> *writer,
const FormatSection &to_conv) {
char buffer[MB_LEN_MAX];
diff --git a/libc/src/__support/printf_core/converter.h b/libc/src/__support/printf_core/converter.h
index 67d0ee3d42b61..05ef6829b3a5e 100644
--- a/libc/src/__support/printf_core/converter.h
+++ b/libc/src/__support/printf_core/converter.h
@@ -29,8 +29,8 @@ namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
-LIBC_PRINTF_MODULE((template <WriteMode write_mode>
- int convert_float(Writer<write_mode> *writer,
+LIBC_PRINTF_MODULE((template <OverflowMode mode>
+ int convert_float(Writer<mode> *writer,
const FormatSection &to_conv)),
{
switch (to_conv.conv_name) {
@@ -52,18 +52,18 @@ LIBC_PRINTF_MODULE((template <WriteMode write_mode>
#endif // not LIBC_COPT_PRINTF_DISABLE_FLOAT
#ifdef LIBC_PRINTF_DEFINE_MODULES
-#define HANDLE_WRITE_MODE(MODE) \
- template int convert_float<WriteMode::MODE>( \
- Writer<WriteMode::MODE> * writer, const FormatSection &to_conv);
-#include "src/__support/printf_core/write_modes.def"
-#undef HANDLE_WRITE_MODE
+#define HANDLE_OVERFLOW_MODE(MODE) \
+ template int convert_float<OverflowMode::MODE>( \
+ Writer<OverflowMode::MODE> * writer, const FormatSection &to_conv);
+#include "src/__support/printf_core/overflow_modes.def"
+#undef HANDLE_OVERFLOW_MODE
#endif // LIBC_PRINTF_DEFINE_MODULES
// convert will call a conversion function to convert the FormatSection into
// its string representation, and then that will write the result to the
// writer.
-template <WriteMode write_mode>
-int convert(Writer<write_mode> *writer, const FormatSection &to_conv) {
+template <OverflowMode mode>
+int convert(Writer<mode> *writer, const FormatSection &to_conv) {
if (!to_conv.has_conv)
return writer->write(to_conv.raw_string);
diff --git a/libc/src/__support/printf_core/fixed_converter.h b/libc/src/__support/printf_core/fixed_converter.h
index 76b2d0d63644f..04994a7729bc8 100644
--- a/libc/src/__support/printf_core/fixed_converter.h
+++ b/libc/src/__support/printf_core/fixed_converter.h
@@ -63,8 +63,8 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) {
} \
} while (false)
-template <WriteMode write_mode>
-LIBC_INLINE int convert_fixed(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_fixed(Writer<mode> *writer,
const FormatSection &to_conv) {
// Long accum should be the largest type, so we can store all the smaller
// numbers in things sized for it.
diff --git a/libc/src/__support/printf_core/float_dec_converter.h b/libc/src/__support/printf_core/float_dec_converter.h
index b678cd29cdb81..89ea766e72f0a 100644
--- a/libc/src/__support/printf_core/float_dec_converter.h
+++ b/libc/src/__support/printf_core/float_dec_converter.h
@@ -99,7 +99,7 @@ zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa,
return has_trailing_zeros;
}
-template <WriteMode write_mode> class PaddingWriter {
+template <OverflowMode mode> class PaddingWriter {
bool left_justified = false;
bool leading_zeroes = false;
char sign_char = 0;
@@ -113,7 +113,7 @@ template <WriteMode write_mode> class PaddingWriter {
sign_char(init_sign_char),
min_width(to_conv.min_width > 0 ? to_conv.min_width : 0) {}
- LIBC_INLINE int write_left_padding(Writer<write_mode> *writer,
+ LIBC_INLINE int write_left_padding(Writer<mode> *writer,
size_t total_digits) {
// The pattern is (spaces) (sign) (zeroes), but only one of spaces and
// zeroes can be written, and only if the padding amount is positive.
@@ -137,7 +137,7 @@ template <WriteMode write_mode> class PaddingWriter {
return 0;
}
- LIBC_INLINE int write_right_padding(Writer<write_mode> *writer,
+ LIBC_INLINE int write_right_padding(Writer<mode> *writer,
size_t total_digits) {
// If and only if the conversion is left justified, there may be trailing
// spaces.
@@ -163,7 +163,7 @@ template <WriteMode write_mode> class PaddingWriter {
This FloatWriter class does the buffering and counting, and writes to the
output when necessary.
*/
-template <WriteMode write_mode> class FloatWriter {
+template <OverflowMode mode> class FloatWriter {
char block_buffer[BLOCK_SIZE]; // The buffer that holds a block.
size_t buffered_digits = 0; // The number of digits held in the buffer.
bool has_written = false; // True once any digits have been output.
@@ -172,8 +172,8 @@ template <WriteMode write_mode> class FloatWriter {
size_t digits_before_decimal = 0; // The # of digits to write before the '.'
size_t total_digits_written = 0; // The # of digits that have been output.
bool has_decimal_point; // True if the number has a decimal point.
- Writer<write_mode> *writer; // Writes to the final output.
- PaddingWriter<write_mode>
+ Writer<mode> *writer; // Writes to the final output.
+ PaddingWriter<mode>
padding_writer; // Handles prefixes/padding, uses total_digits.
LIBC_INLINE int flush_buffer(bool round_up_max_blocks = false) {
@@ -255,9 +255,9 @@ template <WriteMode write_mode> class FloatWriter {
#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE
public:
- LIBC_INLINE FloatWriter(Writer<write_mode> *init_writer,
+ LIBC_INLINE FloatWriter(Writer<mode> *init_writer,
bool init_has_decimal_point,
- const PaddingWriter<write_mode> &init_padding_writer)
+ const PaddingWriter<mode> &init_padding_writer)
: has_decimal_point(init_has_decimal_point), writer(init_writer),
padding_writer(init_padding_writer) {}
@@ -480,23 +480,16 @@ template <WriteMode write_mode> class FloatWriter {
};
// Class-template auto deduction helpers, add more if needed.
-FloatWriter(Writer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>, bool,
- const PaddingWriter<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>)
- -> FloatWriter<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>;
-FloatWriter(Writer<WriteMode::RESIZE_AND_FILL_BUFF>, bool,
- const PaddingWriter<WriteMode::RESIZE_AND_FILL_BUFF>)
- -> FloatWriter<WriteMode::RESIZE_AND_FILL_BUFF>;
-FloatWriter(Writer<WriteMode::FLUSH_TO_STREAM>, bool,
- const PaddingWriter<WriteMode::FLUSH_TO_STREAM>)
- -> FloatWriter<WriteMode::FLUSH_TO_STREAM>;
+template <OverflowMode mode>
+FloatWriter(Writer<mode>, bool, const PaddingWriter<mode>) -> FloatWriter<mode>;
// This implementation is based on the Ryu Printf algorithm by Ulf Adams:
// Ulf Adams. 2019. Ryƫ revisited: printf floating point conversion.
// Proc. ACM Program. Lang. 3, OOPSLA, Article 169 (October 2019), 23 pages.
// https://doi.org/10.1145/3360595
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_decimal_typed(Writer<write_mode> *writer,
+LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
@@ -523,7 +516,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer<write_mode> *writer,
// ignored.
bool nonzero = false;
- PaddingWriter<write_mode> padding_writer(to_conv, sign_char);
+ PaddingWriter<mode> padding_writer(to_conv, sign_char);
FloatWriter float_writer(writer, has_decimal_point, padding_writer);
FloatToString<T> float_converter(float_bits.get_val());
@@ -604,9 +597,9 @@ LIBC_INLINE int convert_float_decimal_typed(Writer<write_mode> *writer,
return WRITE_OK;
}
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_dec_exp_typed(Writer<write_mode> *writer,
+LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
@@ -628,7 +621,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer<write_mode> *writer,
bool has_decimal_point =
(precision > 0) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0);
- PaddingWriter<write_mode> padding_writer(to_conv, sign_char);
+ PaddingWriter<mode> padding_writer(to_conv, sign_char);
FloatWriter float_writer(writer, has_decimal_point, padding_writer);
FloatToString<T> float_converter(float_bits.get_val());
@@ -765,9 +758,9 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer<write_mode> *writer,
return WRITE_OK;
}
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_dec_auto_typed(Writer<write_mode> *writer,
+LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
@@ -1133,8 +1126,8 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<write_mode> *writer,
// TODO: unify the float converters to remove the duplicated checks for inf/nan.
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_decimal(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_decimal(Writer<mode> *writer,
const FormatSection &to_conv) {
#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128)
if (to_conv.length_modifier == LengthModifier::Q) {
@@ -1169,8 +1162,8 @@ LIBC_INLINE int convert_float_decimal(Writer<write_mode> *writer,
return convert_inf_nan(writer, to_conv);
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_dec_exp(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_dec_exp(Writer<mode> *writer,
const FormatSection &to_conv) {
#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128)
if (to_conv.length_modifier == LengthModifier::Q) {
@@ -1205,8 +1198,8 @@ LIBC_INLINE int convert_float_dec_exp(Writer<write_mode> *writer,
return convert_inf_nan(writer, to_conv);
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_dec_auto(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_dec_auto(Writer<mode> *writer,
const FormatSection &to_conv) {
#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128)
if (to_conv.length_modifier == LengthModifier::Q) {
diff --git a/libc/src/__support/printf_core/float_dec_converter_limited.h b/libc/src/__support/printf_core/float_dec_converter_limited.h
index 2e34004ce92ca..7aa886db37a3d 100644
--- a/libc/src/__support/printf_core/float_dec_converter_limited.h
+++ b/libc/src/__support/printf_core/float_dec_converter_limited.h
@@ -374,8 +374,8 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) {
return output;
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_inner(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_inner(Writer<mode> *writer,
const FormatSection &to_conv,
int32_t fraction_len, int exponent,
AnyFloatStorageType mantissa, Sign sign,
@@ -618,10 +618,10 @@ LIBC_INLINE int convert_float_inner(Writer<write_mode> *writer,
return WRITE_OK;
}
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE int
-convert_float_typed(Writer<write_mode> *writer, const FormatSection &to_conv,
+convert_float_typed(Writer<mode> *writer, const FormatSection &to_conv,
fputil::FPBits<T> float_bits, ConversionType ctype) {
return convert_float_inner(writer, to_conv, float_bits.FRACTION_LEN,
float_bits.get_explicit_exponent(),
@@ -629,8 +629,8 @@ convert_float_typed(Writer<write_mode> *writer, const FormatSection &to_conv,
float_bits.sign(), ctype);
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_outer(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_outer(Writer<mode> *writer,
const FormatSection &to_conv,
ConversionType ctype) {
#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128)
@@ -666,44 +666,44 @@ LIBC_INLINE int convert_float_outer(Writer<write_mode> *writer,
return convert_inf_nan(writer, to_conv);
}
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_decimal_typed(Writer<write_mode> *writer,
+LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::F);
}
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_dec_exp_typed(Writer<write_mode> *writer,
+LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::E);
}
-template <typename T, WriteMode write_mode,
+template <typename T, OverflowMode mode,
cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
-LIBC_INLINE int convert_float_dec_auto_typed(Writer<write_mode> *writer,
+LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer,
const FormatSection &to_conv,
fputil::FPBits<T> float_bits) {
return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::G);
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_decimal(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_decimal(Writer<mode> *writer,
const FormatSection &to_conv) {
return convert_float_outer(writer, to_conv, ConversionType::F);
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_dec_exp(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_dec_exp(Writer<mode> *writer,
const FormatSection &to_conv) {
return convert_float_outer(writer, to_conv, ConversionType::E);
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_dec_auto(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_dec_auto(Writer<mode> *writer,
const FormatSection &to_conv) {
return convert_float_outer(writer, to_conv, ConversionType::G);
}
diff --git a/libc/src/__support/printf_core/float_hex_converter.h b/libc/src/__support/printf_core/float_hex_converter.h
index 640db7be2c0f4..15f3d9f05a127 100644
--- a/libc/src/__support/printf_core/float_hex_converter.h
+++ b/libc/src/__support/printf_core/float_hex_converter.h
@@ -47,8 +47,8 @@ get_float_hex_exp_fp_bits_properties(AnyFloatStorageType float_raw) {
};
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer,
const FormatSection &to_conv) {
#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128)
static constexpr uint32_t MAX_POSSIBLE_FRACTION_LEN =
diff --git a/libc/src/__support/printf_core/float_inf_nan_converter.h b/libc/src/__support/printf_core/float_inf_nan_converter.h
index 81769ae4b4913..40740c701d99f 100644
--- a/libc/src/__support/printf_core/float_inf_nan_converter.h
+++ b/libc/src/__support/printf_core/float_inf_nan_converter.h
@@ -38,8 +38,8 @@ get_inf_nan_fp_bits_properties(AnyFloatStorageType float_raw) {
};
}
-template <WriteMode write_mode>
-LIBC_INLINE int convert_inf_nan(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_inf_nan(Writer<mode> *writer,
const FormatSection &to_conv) {
// All of the letters will be defined relative to variable a, which will be
// the appropriate case based on the case of the conversion.
diff --git a/libc/src/__support/printf_core/int_converter.h b/libc/src/__support/printf_core/int_converter.h
index c40c742e41c35..786d9ff2268ff 100644
--- a/libc/src/__support/printf_core/int_converter.h
+++ b/libc/src/__support/printf_core/int_converter.h
@@ -61,8 +61,8 @@ num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) {
} // namespace details
-template <WriteMode write_mode>
-LIBC_INLINE int convert_int(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_int(Writer<mode> *writer,
const FormatSection &to_conv) {
static constexpr size_t BITS_IN_BYTE = 8;
static constexpr size_t BITS_IN_NUM = sizeof(uintmax_t) * BITS_IN_BYTE;
diff --git a/libc/src/__support/printf_core/make_file_writer.h b/libc/src/__support/printf_core/make_file_writer.h
new file mode 100644
index 0000000000000..e0639581ee5e0
--- /dev/null
+++ b/libc/src/__support/printf_core/make_file_writer.h
@@ -0,0 +1,120 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation helpers for Writer<OverflowMode::FLUSH_TO_FILE, CharT>.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_FILE_WRITER_H
+#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_FILE_WRITER_H
+
+#include "hdr/types/FILE.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/File/file.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/printf_core/writer.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace printf_core {
+
+template <typename CharT>
+LIBC_INLINE Writer<Mode<OverflowMode::FLUSH_TO_FILE>::value, CharT>
+make_file_writer(CharT *buffer, size_t buffer_len, ::FILE *fp) {
+ return Writer(buffer, buffer_len,
+ make_overflow_writer<OverflowMode::FLUSH_TO_FILE, CharT>(fp));
+}
+
+} // namespace printf_core
+
+namespace internal {
+#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
+LIBC_INLINE int ferror_unlocked(FILE *f) {
+ return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked();
+}
+
+LIBC_INLINE void flockfile(FILE *f) {
+ reinterpret_cast<LIBC_NAMESPACE::File *>(f)->lock();
+}
+
+LIBC_INLINE void funlockfile(FILE *f) {
+ reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock();
+}
+
+LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
+ size_t nmemb, FILE *f) {
+ return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->write_unlocked(
+ ptr, size * nmemb);
+}
+#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
+LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror_unlocked(f); }
+
+LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(f); }
+
+LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); }
+
+LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
+ size_t nmemb, ::FILE *f) {
+ // Need to use system errno in this case, as system write will set this errno
+ // which we need to propagate back into our code. fwrite only modifies errno
+ // if there was an error, and errno may have previously been nonzero. Only
+ // return errno if there was an error.
+ size_t members_written = ::fwrite_unlocked(ptr, size, nmemb, f);
+ return {members_written, members_written == nmemb ? 0 : errno};
+}
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+} // namespace internal
+
+namespace printf_core {
+
+LIBC_INLINE int write_to_file_unlocked(cpp::string_view str,
+ ::FILE *target_file) {
+ if (str.size() == 0)
+ return WRITE_OK;
+
+ auto write_result = internal::fwrite_unlocked(str.data(), sizeof(char),
+ str.size(), 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 != str.size() ||
+ internal::ferror_unlocked(target_file))
+ return FILE_WRITE_ERROR;
+
+ return WRITE_OK;
+}
+
+// Handles overflow by flushing the current contents of `wb` and `new_str` to
+// the `FILE` pointed to by `fp`.
+template <typename CharT>
+LIBC_INLINE int
+overflow_write_flush_to_file(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str, void *fp) {
+ ::FILE *target_file = reinterpret_cast<::FILE *>(fp);
+ int retval;
+
+ retval = write_to_file_unlocked({wb.buff, wb.buff_cur}, target_file);
+ if (retval < 0)
+ return retval;
+ wb.buff_cur = 0;
+
+ retval = write_to_file_unlocked(new_str, target_file);
+ if (retval < 0)
+ return retval;
+
+ return WRITE_OK;
+}
+
+} // namespace printf_core
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_FILE_WRITER_H
diff --git a/libc/src/__support/printf_core/make_resizing_writer.h b/libc/src/__support/printf_core/make_resizing_writer.h
new file mode 100644
index 0000000000000..31dcd0d510d81
--- /dev/null
+++ b/libc/src/__support/printf_core/make_resizing_writer.h
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation helpers for Writer<OverflowMode::RESIZE_BUFFER, CharT>.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_RESIZING_WRITER_H
+#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_RESIZING_WRITER_H
+
+#include "hdr/func/free.h"
+#include "hdr/func/malloc.h"
+#include "hdr/func/realloc.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/printf_core/writer.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace printf_core {
+
+template <typename CharT>
+LIBC_INLINE Writer<Mode<OverflowMode::RESIZE_BUFFER>::value, CharT>
+make_resizing_writer(CharT *buffer, size_t buffer_len, bool buffer_on_stack) {
+ return Writer(buffer, buffer_len,
+ make_overflow_writer<OverflowMode::RESIZE_BUFFER, CharT>(
+ buffer_on_stack ? buffer : nullptr));
+}
+
+// Handles overflow by resizing `wb` to have enough capacity for `new_str`, and
+// then copying the `new_str` contents into the buffer.
+template <typename CharT>
+LIBC_INLINE int
+overflow_write_resize_buffer(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str,
+ void *initial_stack_buffer) {
+ size_t new_size = new_str.size() + wb.buff_cur;
+ const bool is_on_stack = (wb.buff == initial_stack_buffer);
+ char *new_buff = static_cast<char *>(
+ is_on_stack ? malloc(new_size + 1)
+ : realloc(wb.buff, new_size + 1)); // +1 for null
+ if (new_buff == nullptr) {
+ if (!is_on_stack)
+ free(wb.buff);
+ return ALLOCATION_ERROR;
+ }
+ if (is_on_stack)
+ 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());
+ wb.buff_cur = new_size;
+ wb.buff_len = new_size;
+ return WRITE_OK;
+}
+
+} // namespace printf_core
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_RESIZING_WRITER_H
diff --git a/libc/src/__support/printf_core/make_stderr_writer.h b/libc/src/__support/printf_core/make_stderr_writer.h
new file mode 100644
index 0000000000000..0d2322ed0c74d
--- /dev/null
+++ b/libc/src/__support/printf_core/make_stderr_writer.h
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation helpers for Writer<OverflowMode::FLUSH_TO_STDERR, CharT>.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_STDERR_WRITER_H
+#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_STDERR_WRITER_H
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/io.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/printf_core/writer.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace printf_core {
+
+template <typename CharT>
+LIBC_INLINE Writer<Mode<OverflowMode::FLUSH_TO_STDERR>::value, CharT>
+make_stderr_writer(CharT *buffer, size_t buffer_len) {
+ return Writer(
+ buffer, buffer_len,
+ make_overflow_writer<OverflowMode::FLUSH_TO_STDERR, CharT>(nullptr));
+}
+
+LIBC_INLINE void flush_to_stderr(WriteBuffer<char> &wb) {
+ if (wb.buff_cur == 0)
+ return;
+
+ write_to_stderr({wb.buff, wb.buff_cur});
+ wb.buff_cur = 0;
+}
+
+// Handles overflow by flushing the current contents of `wb` and `new_str` to
+// stderr.
+template <typename CharT>
+LIBC_INLINE int
+overflow_write_flush_to_stderr(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str, void *) {
+ flush_to_stderr(wb);
+ if (new_str.size() > 0)
+ write_to_stderr(new_str);
+ return WRITE_OK;
+}
+
+} // namespace printf_core
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_STDERR_WRITER_H
diff --git a/libc/src/__support/printf_core/write_modes.def b/libc/src/__support/printf_core/overflow_modes.def
similarity index 66%
rename from libc/src/__support/printf_core/write_modes.def
rename to libc/src/__support/printf_core/overflow_modes.def
index fdce4d0241f99..a18301e4ebf66 100644
--- a/libc/src/__support/printf_core/write_modes.def
+++ b/libc/src/__support/printf_core/overflow_modes.def
@@ -6,7 +6,8 @@
//
//===----------------------------------------------------------------------===//
-HANDLE_WRITE_MODE(FILL_BUFF_AND_DROP_OVERFLOW)
-HANDLE_WRITE_MODE(FLUSH_TO_STREAM)
-HANDLE_WRITE_MODE(RESIZE_AND_FILL_BUFF)
-HANDLE_WRITE_MODE(RUNTIME_DISPATCH)
+HANDLE_OVERFLOW_MODE(DROP_OVERFLOW)
+HANDLE_OVERFLOW_MODE(FLUSH_TO_FILE)
+HANDLE_OVERFLOW_MODE(FLUSH_TO_STDERR)
+HANDLE_OVERFLOW_MODE(RESIZE_BUFFER)
+HANDLE_OVERFLOW_MODE(RUNTIME_DISPATCH)
diff --git a/libc/src/__support/printf_core/printf_main.h b/libc/src/__support/printf_core/printf_main.h
index b08e05be25303..9800c33460602 100644
--- a/libc/src/__support/printf_core/printf_main.h
+++ b/libc/src/__support/printf_core/printf_main.h
@@ -22,8 +22,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-template <WriteMode write_mode>
-ErrorOr<size_t> printf_main_modular(Writer<write_mode> *writer,
+template <OverflowMode mode>
+ErrorOr<size_t> printf_main_modular(Writer<mode> *writer,
const char *__restrict str,
internal::ArgList &args) {
Parser<internal::ArgList> parser(str, args);
@@ -42,9 +42,8 @@ ErrorOr<size_t> printf_main_modular(Writer<write_mode> *writer,
return writer->get_chars_written();
}
-template <WriteMode write_mode>
-ErrorOr<size_t> printf_main(Writer<write_mode> *writer,
- const char *__restrict str,
+template <OverflowMode mode>
+ErrorOr<size_t> printf_main(Writer<mode> *writer, const char *__restrict str,
internal::ArgList &args) {
#ifdef LIBC_COPT_PRINTF_MODULAR
LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float");
diff --git a/libc/src/__support/printf_core/ptr_converter.h b/libc/src/__support/printf_core/ptr_converter.h
index 692933a63f38b..6415439bbb2a5 100644
--- a/libc/src/__support/printf_core/ptr_converter.h
+++ b/libc/src/__support/printf_core/ptr_converter.h
@@ -18,8 +18,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-template <WriteMode write_mode>
-LIBC_INLINE int convert_pointer(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_pointer(Writer<mode> *writer,
const FormatSection &to_conv) {
FormatSection new_conv = to_conv;
diff --git a/libc/src/__support/printf_core/strerror_converter.h b/libc/src/__support/printf_core/strerror_converter.h
index ec02a9a52f99a..4e4e61295b533 100644
--- a/libc/src/__support/printf_core/strerror_converter.h
+++ b/libc/src/__support/printf_core/strerror_converter.h
@@ -19,8 +19,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-template <WriteMode write_mode>
-LIBC_INLINE int convert_strerror(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_strerror(Writer<mode> *writer,
const FormatSection &to_conv) {
FormatSection new_conv = to_conv;
const int error_num = static_cast<int>(to_conv.conv_val_raw);
diff --git a/libc/src/__support/printf_core/string_converter.h b/libc/src/__support/printf_core/string_converter.h
index 4cd1d52a2bab5..5352bd8306ba6 100644
--- a/libc/src/__support/printf_core/string_converter.h
+++ b/libc/src/__support/printf_core/string_converter.h
@@ -27,8 +27,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-template <WriteMode write_mode>
-LIBC_INLINE int char_writer(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int char_writer(Writer<mode> *writer,
const FormatSection &to_conv) {
const char *str_ptr = reinterpret_cast<const char *>(to_conv.conv_val_ptr);
size_t string_len = 0;
@@ -66,8 +66,8 @@ LIBC_INLINE int char_writer(Writer<write_mode> *writer,
}
#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE
-template <WriteMode write_mode>
-LIBC_INLINE int wchar_writer(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int wchar_writer(Writer<mode> *writer,
const FormatSection &to_conv) {
size_t string_len = 0;
const char32_t *wstr_ptr =
@@ -121,8 +121,8 @@ LIBC_INLINE int wchar_writer(Writer<write_mode> *writer,
}
#endif // LIBC_COPT_PRINTF_DISABLE_WIDE
-template <WriteMode write_mode>
-LIBC_INLINE int convert_string(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_string(Writer<mode> *writer,
const FormatSection &to_conv) {
int ret = 0;
if (to_conv.length_modifier == LengthModifier::l) {
diff --git a/libc/src/__support/printf_core/vasprintf_internal.h b/libc/src/__support/printf_core/vasprintf_internal.h
index 969da6ebc46bb..5396161c74115 100644
--- a/libc/src/__support/printf_core/vasprintf_internal.h
+++ b/libc/src/__support/printf_core/vasprintf_internal.h
@@ -9,39 +9,16 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_VASPRINTF_INTERNAL_H
#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_VASPRINTF_INTERNAL_H
-#include "hdr/func/free.h"
#include "hdr/func/malloc.h"
-#include "hdr/func/realloc.h"
#include "src/__support/arg_list.h"
#include "src/__support/error_or.h"
#include "src/__support/printf_core/core_structs.h"
+#include "src/__support/printf_core/make_resizing_writer.h"
#include "src/__support/printf_core/printf_main.h"
-#include "src/__support/printf_core/writer.h"
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-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 *>(
- isBuffOnStack ? malloc(new_size + 1)
- : realloc(wb->buff, new_size + 1)); // +1 for null
- if (new_buff == nullptr) {
- if (wb->buff != wb->init_buff)
- free(wb->buff);
- return ALLOCATION_ERROR;
- }
- 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());
- wb->buff_cur = new_size;
- wb->buff_len = new_size;
- return printf_core::WRITE_OK;
-}
-
constexpr size_t DEFAULT_BUFFER_SIZE = 200;
template <bool use_modular = false>
@@ -49,9 +26,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::ResizingBuffer wb(init_buff_on_stack, DEFAULT_BUFFER_SIZE,
- resize_overflow_hook);
- printf_core::Writer writer(wb);
+ Writer writer = make_resizing_writer(init_buff_on_stack, DEFAULT_BUFFER_SIZE,
+ /* buffer_on_stack = */ true);
auto ret_val = [&] {
if constexpr (use_modular)
@@ -63,13 +39,14 @@ LIBC_INLINE ErrorOr<size_t> vasprintf_internal(char **ret,
*ret = nullptr;
return ret_val;
}
- if (wb.buff == init_buff_on_stack) {
+ char *final_buff = writer.get_write_buffer().buff;
+ if (final_buff == init_buff_on_stack) {
*ret = static_cast<char *>(malloc(ret_val.value() + 1));
if (ret == nullptr)
return Error(ALLOCATION_ERROR);
- inline_memcpy(*ret, wb.buff, ret_val.value());
+ inline_memcpy(*ret, final_buff, ret_val.value());
} else {
- *ret = wb.buff;
+ *ret = final_buff;
}
(*ret)[ret_val.value()] = '\0';
return ret_val;
diff --git a/libc/src/__support/printf_core/vfprintf_internal.h b/libc/src/__support/printf_core/vfprintf_internal.h
index 6a62e966f7ff6..1f2ea5960f4c4 100644
--- a/libc/src/__support/printf_core/vfprintf_internal.h
+++ b/libc/src/__support/printf_core/vfprintf_internal.h
@@ -15,87 +15,28 @@
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
#include "src/__support/macros/config.h"
#include "src/__support/printf_core/core_structs.h"
+#include "src/__support/printf_core/make_file_writer.h"
#include "src/__support/printf_core/printf_main.h"
-#include "src/__support/printf_core/writer.h"
#include "hdr/types/FILE.h"
namespace LIBC_NAMESPACE_DECL {
-
-namespace internal {
-#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
-LIBC_INLINE int ferror_unlocked(FILE *f) {
- return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked();
-}
-
-LIBC_INLINE void flockfile(FILE *f) {
- reinterpret_cast<LIBC_NAMESPACE::File *>(f)->lock();
-}
-
-LIBC_INLINE void funlockfile(FILE *f) {
- reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock();
-}
-
-LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
- size_t nmemb, FILE *f) {
- return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->write_unlocked(
- ptr, size * nmemb);
-}
-#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
-LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror_unlocked(f); }
-
-LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(f); }
-
-LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); }
-
-LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
- size_t nmemb, ::FILE *f) {
- // Need to use system errno in this case, as system write will set this errno
- // which we need to propagate back into our code. fwrite only modifies errno
- // if there was an error, and errno may have previously been nonzero. Only
- // return errno if there was an error.
- size_t members_written = ::fwrite_unlocked(ptr, size, nmemb, f);
- return {members_written, members_written == nmemb ? 0 : errno};
-}
-#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
-} // namespace internal
-
namespace printf_core {
-LIBC_INLINE int file_write_hook(cpp::string_view new_str, 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);
- // 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() ||
- internal::ferror_unlocked(target_file))
- return FILE_WRITE_ERROR;
-
- return WRITE_OK;
-}
-
LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE *__restrict stream,
const char *__restrict format,
internal::ArgList &args) {
constexpr size_t BUFF_SIZE = 1024;
char buffer[BUFF_SIZE];
- printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &file_write_hook,
- reinterpret_cast<void *>(stream));
- Writer writer(wb);
+ Writer writer = make_file_writer(buffer, BUFF_SIZE, stream);
internal::flockfile(stream);
auto retval = printf_main(&writer, format, args);
if (!retval.has_value()) {
internal::funlockfile(stream);
return retval;
}
- int flushval = wb.flush_to_stream();
+ WriteBuffer<char> &wb = writer.get_write_buffer();
+ int flushval = write_to_file_unlocked({wb.buff, wb.buff_cur}, stream);
if (flushval != WRITE_OK)
retval = Error(-flushval);
internal::funlockfile(stream);
diff --git a/libc/src/__support/printf_core/write_int_converter.h b/libc/src/__support/printf_core/write_int_converter.h
index 906af324d10b4..882963c1c44e2 100644
--- a/libc/src/__support/printf_core/write_int_converter.h
+++ b/libc/src/__support/printf_core/write_int_converter.h
@@ -19,8 +19,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-template <WriteMode write_mode>
-LIBC_INLINE int convert_write_int(Writer<write_mode> *writer,
+template <OverflowMode mode>
+LIBC_INLINE int convert_write_int(Writer<mode> *writer,
const FormatSection &to_conv) {
#ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS
diff --git a/libc/src/__support/printf_core/writer.h b/libc/src/__support/printf_core/writer.h
index e7d3fe530d7b0..31f1557ab09e4 100644
--- a/libc/src/__support/printf_core/writer.h
+++ b/libc/src/__support/printf_core/writer.h
@@ -21,206 +21,242 @@
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
-#define HANDLE_WRITE_MODE(MODE) MODE,
-enum class WriteMode {
-#include "src/__support/printf_core/write_modes.def"
+#define HANDLE_OVERFLOW_MODE(MODE) MODE,
+enum class OverflowMode {
+#include "src/__support/printf_core/overflow_modes.def"
};
-#undef HANDLE_WRITE_MODE
+#undef HANDLE_OVERFLOW_MODE
// Helper to omit the template argument if we are using runtime dispatch and
// avoid multiple copies of the converter functions.
-template <WriteMode write_mode> struct Mode {
+template <OverflowMode mode> struct Mode {
#ifdef LIBC_COPT_PRINTF_RUNTIME_DISPATCH
- static constexpr WriteMode value = WriteMode::RUNTIME_DISPATCH;
+ static constexpr OverflowMode value = OverflowMode::RUNTIME_DISPATCH;
#else
- static constexpr WriteMode value = write_mode;
+ static constexpr OverflowMode value = mode;
#endif
};
-template <WriteMode write_mode> class Writer;
-
-template <WriteMode write_mode> struct WriteBuffer {
- char *buff;
+template <typename CharT> struct WriteBuffer {
+ CharT *buff;
size_t buff_len;
size_t buff_cur = 0;
- // The current writing mode in case the user wants runtime dispatch of the
- // stream writer with function pointers.
- [[maybe_unused]] WriteMode write_mode_;
-
-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;
+// Function type for handling the slow path in `Writer` when the `WriteBuffer`
+// may not have enough remaining capacity for the new content.
+template <typename CharT>
+using OverflowWriteFn = int (*)(WriteBuffer<CharT> & /* wb */,
+ cpp::basic_string_view<CharT> /* new_str */,
+ void * /* state */);
+
+// Handles overflow by filling any remaining space in `wb` with the start of
+// `new_str`, and dropping any excess bytes.
+template <typename CharT>
+LIBC_INLINE int
+overflow_write_drop_overflow(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str, void *) {
+ if (wb.buff_cur < wb.buff_len) {
+ size_t chars_to_write = wb.buff_len - wb.buff_cur;
+ if (chars_to_write > new_str.size())
+ chars_to_write = new_str.size();
+ inline_memcpy(wb.buff + wb.buff_cur, new_str.data(),
+ chars_to_write * sizeof(CharT));
+ wb.buff_cur += chars_to_write;
}
+ return WRITE_OK;
+}
+
+// Defined in make_file_writer.h
+template <typename CharT>
+int overflow_write_flush_to_file(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str,
+ void *fp);
+
+// Defined in make_stderr_writer.h
+template <typename CharT>
+int overflow_write_flush_to_stderr(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str,
+ void *);
+
+// Defined in make_resizing_writer.h
+template <typename CharT>
+int overflow_write_resize_buffer(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str,
+ void *initial_stack_buffer);
+
+// Trait type helper mapping `OverflowMode` to the corresponding function.
+template <OverflowMode mode, typename CharT> struct OverflowModeToWriteFn {};
+
+template <typename CharT>
+struct OverflowModeToWriteFn<OverflowMode::DROP_OVERFLOW, CharT> {
+ static constexpr OverflowWriteFn<CharT> value =
+ overflow_write_drop_overflow<CharT>;
};
-// 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 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);
- if (retval < 0)
- return retval;
- }
- if (new_str.size() > 0) {
- int retval = stream_writer(new_str, output_target);
- if (retval < 0)
- return retval;
- }
- buff_cur = 0;
- return WRITE_OK;
+template <typename CharT>
+struct OverflowModeToWriteFn<OverflowMode::FLUSH_TO_FILE, CharT> {
+ static constexpr OverflowWriteFn<CharT> value =
+ overflow_write_flush_to_file<CharT>;
+};
+
+template <typename CharT>
+struct OverflowModeToWriteFn<OverflowMode::FLUSH_TO_STDERR, CharT> {
+ static constexpr OverflowWriteFn<CharT> value =
+ overflow_write_flush_to_stderr<CharT>;
+};
+
+template <typename CharT>
+struct OverflowModeToWriteFn<OverflowMode::RESIZE_BUFFER, CharT> {
+ static constexpr OverflowWriteFn<CharT> value =
+ overflow_write_resize_buffer<CharT>;
+};
+
+// Helper template used by `Writer` to dispatch to the appropriate
+// `OverflowWriteFn`.
+template <OverflowMode mode, typename CharT> struct OverflowWriter;
+
+template <typename CharT>
+struct OverflowWriter<OverflowMode::DROP_OVERFLOW, CharT> {
+ LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *) {}
+
+ LIBC_INLINE int write(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str) {
+ return overflow_write_drop_overflow<CharT>(wb, new_str, nullptr);
+ }
+};
+
+template <typename CharT>
+struct OverflowWriter<OverflowMode::FLUSH_TO_FILE, CharT> {
+ void *file;
+
+ LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *file) : file(file) {}
+
+ LIBC_INLINE int write(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str) {
+ return overflow_write_flush_to_file(wb, new_str, file);
}
+};
+
+template <typename CharT>
+struct OverflowWriter<OverflowMode::FLUSH_TO_STDERR, CharT> {
+ LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *) {}
- LIBC_INLINE int flush_to_stream() { return flush_to_stream({}); }
+ LIBC_INLINE int write(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str) {
+ return overflow_write_flush_to_stderr(wb, new_str, nullptr);
+ }
};
-// 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.
-
- 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 <typename CharT>
+struct OverflowWriter<OverflowMode::RESIZE_BUFFER, CharT> {
+ void *initial_stack_buffer;
+
+ LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *initial_stack_buffer)
+ : initial_stack_buffer(initial_stack_buffer) {}
+
+ LIBC_INLINE int write(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str) {
+ return overflow_write_resize_buffer(wb, new_str, initial_stack_buffer);
}
};
-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 <typename CharT>
+struct OverflowWriter<OverflowMode::RUNTIME_DISPATCH, CharT> {
+ OverflowWriteFn<CharT> runtime_fn;
+ void *state;
-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);
-}
+ LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT> runtime_fn, void *state)
+ : runtime_fn(runtime_fn), state(state) {}
+
+ LIBC_INLINE int write(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str) {
+ return runtime_fn(wb, new_str, state);
+ }
+};
-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);
+// Constructs an `OverflowWriter` that dispatches according to
+// `LIBC_COPT_PRINTF_RUNTIME_DISPATCH`.
+template <OverflowMode mode, typename CharT>
+LIBC_INLINE OverflowWriter<Mode<mode>::value, CharT>
+make_overflow_writer(void *state) {
+ return OverflowWriter<Mode<mode>::value, CharT>(
+ OverflowModeToWriteFn<mode, CharT>::value, state);
}
-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);
+// Fills the `dest` buffer with `count` copies of `value`.
+template <typename CharT>
+LIBC_INLINE void fill_buffer(CharT *dest, CharT value, size_t count) {
+ if constexpr (sizeof(CharT) == sizeof(unsigned char)) {
+ inline_memset(dest, static_cast<unsigned char>(value), count);
+ } else {
+ for (size_t i = 0; i < count; ++i)
+ dest[i] = value;
+ }
}
-template <WriteMode write_mode> class Writer final {
- WriteBuffer<write_mode> &wb;
+template <OverflowMode mode, typename CharT = char> class Writer final {
+ WriteBuffer<CharT> wb;
size_t chars_written = 0;
+ OverflowWriter<mode, CharT> overflow_writer;
- LIBC_INLINE int pad(char new_char, size_t length) {
+ LIBC_INLINE int pad(CharT 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;
// ASSERT: length > buff_space
if (buff_space > 0) {
- inline_memset(wb.buff + wb.buff_cur, new_char, buff_space);
+ fill_buffer(wb.buff + wb.buff_cur, new_char, buff_space);
wb.buff_cur += buff_space;
written = buff_space;
}
// Next, overflow write the rest of length using the mini_buff.
constexpr size_t MINI_BUFF_SIZE = 64;
- char 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);
+ CharT mini_buff[MINI_BUFF_SIZE];
+ fill_buffer(mini_buff, new_char, MINI_BUFF_SIZE);
+ cpp::basic_string_view<CharT> mb_string_view(mini_buff, MINI_BUFF_SIZE);
while (written + MINI_BUFF_SIZE < length) {
- int result = wb.overflow_write(mb_string_view);
+ int result = overflow_writer.write(wb, mb_string_view);
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);
+ cpp::basic_string_view<CharT> mb_substr =
+ mb_string_view.substr(0, length - written);
+ return overflow_writer.write(wb, mb_substr);
}
public:
- LIBC_INLINE Writer(WriteBuffer<write_mode> &wb) : wb(wb) {}
+ // Prefer using the factory functions in make_*_writer.h or
+ // `make_drop_overflow_writer` below, instead of directly calling this
+ // constructor.
+ LIBC_INLINE Writer(CharT *buffer, size_t buffer_len,
+ OverflowWriter<mode, CharT> overflow_writer)
+ : wb{.buff = buffer, .buff_len = buffer_len},
+ overflow_writer(overflow_writer) {}
// Takes a string, copies it into the buffer if there is space, else passes it
// to the overflow mechanism to be handled separately.
- LIBC_INLINE int write(cpp::string_view new_string) {
+ LIBC_INLINE int write(cpp::basic_string_view<CharT> new_string) {
chars_written += new_string.size();
if (LIBC_LIKELY(wb.buff_cur + new_string.size() <= wb.buff_len)) {
inline_memcpy(wb.buff + wb.buff_cur, new_string.data(),
- new_string.size());
+ new_string.size() * sizeof(CharT));
wb.buff_cur += new_string.size();
return WRITE_OK;
}
- return wb.overflow_write(new_string);
+ return overflow_writer.write(wb, new_string);
}
// 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(CharT 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);
+ fill_buffer(wb.buff + wb.buff_cur, new_char, length);
wb.buff_cur += length;
return WRITE_OK;
}
@@ -229,27 +265,32 @@ 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(CharT 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 overflow_writer.write(wb, {&new_char, 1});
}
LIBC_INLINE size_t get_chars_written() { return chars_written; }
+
+ LIBC_INLINE WriteBuffer<CharT> &get_write_buffer() { return wb; }
};
-// Class-template auto deduction helpers.
-Writer(WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>)
- -> Writer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>;
-Writer(WriteBuffer<WriteMode::RESIZE_AND_FILL_BUFF>)
- -> Writer<WriteMode::RESIZE_AND_FILL_BUFF>;
-Writer(WriteBuffer<WriteMode::FLUSH_TO_STREAM>)
- -> Writer<WriteMode::FLUSH_TO_STREAM>;
+// Class-template auto deduction helper.
+template <OverflowMode mode, typename CharT>
+Writer(CharT *, size_t, OverflowWriter<mode, CharT>) -> Writer<mode, CharT>;
+
+template <typename CharT>
+LIBC_INLINE Writer<Mode<OverflowMode::DROP_OVERFLOW>::value, CharT>
+make_drop_overflow_writer(CharT *buffer, size_t buffer_len) {
+ return Writer(
+ buffer, buffer_len,
+ make_overflow_writer<OverflowMode::DROP_OVERFLOW, CharT>(nullptr));
+}
} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/err/report.cpp b/libc/src/err/report.cpp
index e3ca01a9cbd5c..9c02b0ea8abdf 100644
--- a/libc/src/err/report.cpp
+++ b/libc/src/err/report.cpp
@@ -20,8 +20,8 @@
#include "src/__support/arg_list.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/__support/printf_core/make_stderr_writer.h"
#include "src/__support/printf_core/printf_main.h"
-#include "src/__support/printf_core/writer.h"
#ifdef LIBC_FULL_BUILD
#include "src/errno/program_invocation_short_name.h"
@@ -41,14 +41,9 @@ void report(bool show_err, int err_num, const char *fmt,
if (!progname)
progname = "";
char buffer[1024];
- printf_core::FlushingBuffer wb(
- buffer, sizeof(buffer),
- [](cpp::string_view str, [[maybe_unused]] void *raw_stream) -> int {
- write_to_stderr(str);
- return static_cast<int>(str.size());
- },
- nullptr);
- printf_core::Writer writer(wb);
+ printf_core::Writer writer =
+ printf_core::make_stderr_writer(buffer, sizeof(buffer));
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write(progname);
if (fmt != nullptr || show_err)
@@ -56,7 +51,7 @@ void report(bool show_err, int err_num, const char *fmt,
if (fmt != nullptr) {
if (!printf_core::printf_main(&writer, fmt, args)) {
- wb.flush_to_stream();
+ printf_core::flush_to_stderr(wb);
return;
}
if (show_err)
@@ -67,7 +62,7 @@ void report(bool show_err, int err_num, const char *fmt,
writer.write(get_error_string(err_num));
writer.write("\n");
- wb.flush_to_stream();
+ printf_core::flush_to_stderr(wb);
}
} // namespace err_reporting
diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp
index ec1364ca6efc2..cf500c044f9ac 100644
--- a/libc/src/stdio/snprintf.cpp
+++ b/libc/src/stdio/snprintf.cpp
@@ -31,8 +31,8 @@ LLVM_LIBC_FUNCTION(int, snprintf,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffsz > 0 ? buffsz - 1 : 0));
#ifdef LIBC_COPT_PRINTF_MODULAR
LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float");
@@ -44,8 +44,10 @@ LLVM_LIBC_FUNCTION(int, snprintf,
libc_errno = printf_core::internal_error_to_errno(ret_val.error());
return -1;
}
- if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
+ if (buffsz > 0) { // if the buffsz is 0 the buffer may be a null pointer.
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
+ }
if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
libc_errno =
diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp
index 702ea5d43c69a..bbb452b286167 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::DropOverflowBuffer wb(buffer,
- cpp::numeric_limits<size_t>::max());
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, cpp::numeric_limits<size_t>::max());
#ifdef LIBC_COPT_PRINTF_MODULAR
LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float");
@@ -45,6 +44,7 @@ LLVM_LIBC_FUNCTION(int, sprintf,
libc_errno = printf_core::internal_error_to_errno(ret_val.error());
return -1;
}
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp
index b25daed931fce..5174152669f38 100644
--- a/libc/src/stdio/vsnprintf.cpp
+++ b/libc/src/stdio/vsnprintf.cpp
@@ -28,8 +28,8 @@ 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::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffsz > 0 ? buffsz - 1 : 0));
#ifdef LIBC_COPT_PRINTF_MODULAR
LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float");
@@ -41,8 +41,10 @@ LLVM_LIBC_FUNCTION(int, vsnprintf,
libc_errno = printf_core::internal_error_to_errno(ret_val.error());
return -1;
}
- if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
+ if (buffsz > 0) { // if the buffsz is 0 the buffer may be a null pointer.
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
+ }
if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
libc_errno =
diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp
index f1af2f6143ad2..2a82045060cf3 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::DropOverflowBuffer wb(buffer,
- cpp::numeric_limits<size_t>::max());
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, cpp::numeric_limits<size_t>::max());
#ifdef LIBC_COPT_PRINTF_MODULAR
LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float");
@@ -42,6 +41,7 @@ LLVM_LIBC_FUNCTION(int, vsprintf,
libc_errno = printf_core::internal_error_to_errno(ret_val.error());
return -1;
}
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) {
diff --git a/libc/src/stdlib/str_from_util.h b/libc/src/stdlib/str_from_util.h
index 8cd147580f719..205adcff17094 100644
--- a/libc/src/stdlib/str_from_util.h
+++ b/libc/src/stdlib/str_from_util.h
@@ -104,8 +104,8 @@ printf_core::FormatSection parse_format_string(const char *__restrict format,
return section;
}
-template <typename T, printf_core::WriteMode write_mode>
-int strfromfloat_convert(printf_core::Writer<write_mode> *writer,
+template <typename T, printf_core::OverflowMode overflow_mode>
+int strfromfloat_convert(printf_core::Writer<overflow_mode> *writer,
const printf_core::FormatSection §ion) {
if (!section.has_conv)
return writer->write(section.raw_string);
diff --git a/libc/src/stdlib/strfromd.cpp b/libc/src/stdlib/strfromd.cpp
index dbf46b7c0534b..8983a0f5787d8 100644
--- a/libc/src/stdlib/strfromd.cpp
+++ b/libc/src/stdlib/strfromd.cpp
@@ -22,8 +22,8 @@ LLVM_LIBC_FUNCTION(int, strfromd,
printf_core::FormatSection section =
internal::parse_format_string(format, fp);
- printf_core::DropOverflowBuffer wb(s, (n > 0 ? n - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer =
+ printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
int result = 0;
if (section.has_conv)
@@ -34,8 +34,10 @@ LLVM_LIBC_FUNCTION(int, strfromd,
if (result < 0)
return result;
- if (n > 0)
+ if (n > 0) {
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
+ }
if (writer.get_chars_written() >
static_cast<size_t>(cpp::numeric_limits<int>::max())) {
diff --git a/libc/src/stdlib/strfromf.cpp b/libc/src/stdlib/strfromf.cpp
index d1ea47d55a250..417372d576af6 100644
--- a/libc/src/stdlib/strfromf.cpp
+++ b/libc/src/stdlib/strfromf.cpp
@@ -22,8 +22,8 @@ LLVM_LIBC_FUNCTION(int, strfromf,
printf_core::FormatSection section =
internal::parse_format_string(format, fp);
- printf_core::DropOverflowBuffer wb(s, (n > 0 ? n - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer =
+ printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
int result = 0;
if (section.has_conv)
@@ -34,8 +34,10 @@ LLVM_LIBC_FUNCTION(int, strfromf,
if (result < 0)
return result;
- if (n > 0)
+ if (n > 0) {
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
+ }
if (writer.get_chars_written() >
static_cast<size_t>(cpp::numeric_limits<int>::max())) {
diff --git a/libc/src/stdlib/strfroml.cpp b/libc/src/stdlib/strfroml.cpp
index c23c12fc91c27..2f32db0966b60 100644
--- a/libc/src/stdlib/strfroml.cpp
+++ b/libc/src/stdlib/strfroml.cpp
@@ -27,8 +27,8 @@ LLVM_LIBC_FUNCTION(int, strfroml,
// the length modifier has to be set to LengthModifier::L
section.length_modifier = printf_core::LengthModifier::L;
- printf_core::DropOverflowBuffer wb(s, (n > 0 ? n - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer =
+ printf_core::make_drop_overflow_writer(s, (n > 0 ? n - 1 : 0));
int result = 0;
if (section.has_conv)
@@ -39,8 +39,10 @@ LLVM_LIBC_FUNCTION(int, strfroml,
if (result < 0)
return result;
- if (n > 0)
+ if (n > 0) {
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
+ }
if (writer.get_chars_written() >
static_cast<size_t>(cpp::numeric_limits<int>::max())) {
diff --git a/libc/src/time/asctime_utils.h b/libc/src/time/asctime_utils.h
index f81965a6a2045..95df9de4682cf 100644
--- a/libc/src/time/asctime_utils.h
+++ b/libc/src/time/asctime_utils.h
@@ -38,9 +38,8 @@ LIBC_INLINE ErrorOr<char *> asctime(const tm *timeptr, char *buffer,
timeptr->tm_mon > (time_constants::MONTHS_PER_YEAR - 1))
return cpp::unexpected(EINVAL);
- printf_core::DropOverflowBuffer wb(buffer,
- buffer_length > 0 ? buffer_length - 1 : 0);
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffer_length > 0 ? buffer_length - 1 : 0));
auto res = strftime_core::strftime_main(&writer, "%a %b %e %T %Y\n", timeptr);
if (!res.has_value())
diff --git a/libc/src/time/strftime.cpp b/libc/src/time/strftime.cpp
index 5522a2c1d2e4b..a6a202455d0d2 100644
--- a/libc/src/time/strftime.cpp
+++ b/libc/src/time/strftime.cpp
@@ -25,11 +25,13 @@ LLVM_LIBC_FUNCTION(size_t, strftime,
LIBC_CRASH_ON_NULLPTR(format);
LIBC_CRASH_ON_NULLPTR(timeptr);
- printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffsz > 0 ? buffsz - 1 : 0));
auto ret = strftime_core::strftime_main(&writer, format, timeptr);
- if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
+ if (buffsz > 0) { // if the buffsz is 0 the buffer may be a null pointer.
+ const printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
wb.buff[wb.buff_cur] = '\0';
+ }
return (!ret.has_value() || ret.value() >= buffsz) ? 0 : ret.value();
}
diff --git a/libc/src/time/strftime_core/composite_converter.h b/libc/src/time/strftime_core/composite_converter.h
index ec279615806e9..fdc52828a49e1 100644
--- a/libc/src/time/strftime_core/composite_converter.h
+++ b/libc/src/time/strftime_core/composite_converter.h
@@ -44,8 +44,8 @@ get_specific_int_format(const tm *timeptr, const FormatSection &base_to_conv,
return result;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_date_us(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_date_us(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv,
const tm *timeptr) {
// format is %m/%d/%y (month/day/year)
@@ -67,8 +67,8 @@ LIBC_INLINE int convert_date_us(printf_core::Writer<write_mode> *writer,
return WRITE_OK;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_date_iso(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_date_iso(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv,
const tm *timeptr) {
// format is "%Y-%m-%d" (year-month-day)
@@ -90,8 +90,8 @@ LIBC_INLINE int convert_date_iso(printf_core::Writer<write_mode> *writer,
return WRITE_OK;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_time_am_pm(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_time_am_pm(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv,
const tm *timeptr) {
// format is "%I:%M:%S %p" (hour:minute:second AM/PM)
@@ -118,8 +118,8 @@ LIBC_INLINE int convert_time_am_pm(printf_core::Writer<write_mode> *writer,
return WRITE_OK;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_time_minute(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_time_minute(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv,
const tm *timeptr) {
// format is "%H:%M" (hour:minute)
@@ -138,8 +138,8 @@ LIBC_INLINE int convert_time_minute(printf_core::Writer<write_mode> *writer,
return WRITE_OK;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_time_second(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_time_second(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv,
const tm *timeptr) {
// format is "%H:%M:%S" (hour:minute:second)
@@ -161,10 +161,10 @@ LIBC_INLINE int convert_time_second(printf_core::Writer<write_mode> *writer,
return WRITE_OK;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_full_date_time(printf_core::Writer<write_mode> *writer,
- const FormatSection &to_conv,
- const tm *timeptr) {
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int
+convert_full_date_time(printf_core::Writer<overflow_mode> *writer,
+ const FormatSection &to_conv, const tm *timeptr) {
const time_utils::TMReader time_reader(timeptr);
// format is "%a %b %e %T %Y" (weekday month mday [time] year)
// we only pad the first conversion, and we assume all the other values are in
@@ -200,8 +200,8 @@ LIBC_INLINE int convert_full_date_time(printf_core::Writer<write_mode> *writer,
return WRITE_OK;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_composite(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_composite(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv,
const tm *timeptr) {
switch (to_conv.conv_name) {
diff --git a/libc/src/time/strftime_core/converter.h b/libc/src/time/strftime_core/converter.h
index b6203ae8b72d0..3e6bab6df2b60 100644
--- a/libc/src/time/strftime_core/converter.h
+++ b/libc/src/time/strftime_core/converter.h
@@ -27,14 +27,14 @@ namespace strftime_core {
/// Converts a format section and writes it to the writer.
///
-/// \tparam write_mode The write mode for the writer.
+/// \tparam overflow_mode The write overflow mode for the writer.
/// \param writer The writer to write the output to.
/// \param to_conv The format section to convert.
/// \param timeptr Pointer to the tm structure.
/// \return Number of characters written on success, or a negative error code on
/// failure.
-template <printf_core::WriteMode write_mode>
-int convert(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+int convert(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv, const tm *timeptr) {
// TODO: Implement the locale support.
// Currently locale flags are ignored, as described by the posix standard for
diff --git a/libc/src/time/strftime_core/num_converter.h b/libc/src/time/strftime_core/num_converter.h
index 6bcc166fecf93..65c3406a73ea2 100644
--- a/libc/src/time/strftime_core/num_converter.h
+++ b/libc/src/time/strftime_core/num_converter.h
@@ -31,8 +31,8 @@ struct IntFormatSection {
char padding_char = '0';
};
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int write_padded_int(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int write_padded_int(printf_core::Writer<overflow_mode> *writer,
const IntFormatSection &num_info) {
DecFmt d(num_info.num);
@@ -193,8 +193,8 @@ get_int_format(const FormatSection &to_conv, const tm *timeptr) {
return result;
}
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_int(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_int(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv, const tm *timeptr) {
auto num_info_or = get_int_format(to_conv, timeptr);
if (!num_info_or)
diff --git a/libc/src/time/strftime_core/str_converter.h b/libc/src/time/strftime_core/str_converter.h
index 4a636679c4a18..8941abac35d5d 100644
--- a/libc/src/time/strftime_core/str_converter.h
+++ b/libc/src/time/strftime_core/str_converter.h
@@ -35,13 +35,13 @@ unwrap_opt(cpp::optional<cpp::string_view> str_opt) {
/// Converts string-based format specifiers (like %a, %Z) and writes to writer.
///
-/// \tparam write_mode The write mode for the writer.
+/// \tparam overflow_mode The write overflow mode for the writer.
/// \param writer The writer to write the output to.
/// \param to_conv The format section to convert.
/// \param timeptr Pointer to the tm structure.
/// \return WRITE_OK on success, or negative value on error.
-template <printf_core::WriteMode write_mode>
-LIBC_INLINE int convert_str(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+LIBC_INLINE int convert_str(printf_core::Writer<overflow_mode> *writer,
const FormatSection &to_conv, const tm *timeptr) {
cpp::string_view str;
cpp::optional<cpp::string_view> str_opt;
diff --git a/libc/src/time/strftime_core/strftime_main.h b/libc/src/time/strftime_core/strftime_main.h
index 4f958fb5bb294..75a734f176918 100644
--- a/libc/src/time/strftime_core/strftime_main.h
+++ b/libc/src/time/strftime_core/strftime_main.h
@@ -20,8 +20,8 @@
namespace LIBC_NAMESPACE_DECL {
namespace strftime_core {
-template <printf_core::WriteMode write_mode>
-ErrorOr<size_t> strftime_main(printf_core::Writer<write_mode> *writer,
+template <printf_core::OverflowMode overflow_mode>
+ErrorOr<size_t> strftime_main(printf_core::Writer<overflow_mode> *writer,
const char *__restrict str, const tm *timeptr) {
Parser parser(str);
int result = 0;
diff --git a/libc/test/src/__support/printf_core/converter_test.cpp b/libc/test/src/__support/printf_core/converter_test.cpp
index 36037ab2ed4b0..a09873c128eab 100644
--- a/libc/test/src/__support/printf_core/converter_test.cpp
+++ b/libc/test/src/__support/printf_core/converter_test.cpp
@@ -14,14 +14,16 @@
class LlvmLibcPrintfConverterTest : public LIBC_NAMESPACE::testing::Test {
protected:
- LlvmLibcPrintfConverterTest() : wb(str, sizeof(str) - 1), writer(wb) {}
+ LlvmLibcPrintfConverterTest()
+ : writer(LIBC_NAMESPACE::printf_core::make_drop_overflow_writer(
+ str, sizeof(str) - 1)),
+ wb(writer.get_write_buffer()) {}
char str[60];
- 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>
+ LIBC_NAMESPACE::printf_core::OverflowMode::DROP_OVERFLOW>::value>
writer;
+ LIBC_NAMESPACE::printf_core::WriteBuffer<char> &wb;
};
TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) {
diff --git a/libc/test/src/__support/printf_core/writer_test.cpp b/libc/test/src/__support/printf_core/writer_test.cpp
index b1873d729bb3f..5d34cdae1a18d 100644
--- a/libc/test/src/__support/printf_core/writer_test.cpp
+++ b/libc/test/src/__support/printf_core/writer_test.cpp
@@ -15,22 +15,23 @@
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;
+using LIBC_NAMESPACE::printf_core::make_drop_overflow_writer;
+using LIBC_NAMESPACE::printf_core::OverflowMode;
+using LIBC_NAMESPACE::printf_core::OverflowWriter;
+using LIBC_NAMESPACE::printf_core::WRITE_OK;
+using LIBC_NAMESPACE::printf_core::WriteBuffer;
using LIBC_NAMESPACE::printf_core::Writer;
TEST(LlvmLibcPrintfWriterTest, Constructor) {
char str[10];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
- (void)writer;
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ EXPECT_EQ(writer.get_write_buffer().buff, str);
}
TEST(LlvmLibcPrintfWriterTest, Write) {
char str[4] = {'D', 'E', 'F', 'G'};
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write({"abc", 3});
EXPECT_EQ(str[3], 'G');
@@ -45,8 +46,8 @@ TEST(LlvmLibcPrintfWriterTest, Write) {
TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) {
char str[10];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write({"abc", 3});
writer.write({"DEF", 3});
writer.write({"1234", 3});
@@ -59,8 +60,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) {
TEST(LlvmLibcPrintfWriterTest, WriteChars) {
char str[4] = {'D', 'E', 'F', 'G'};
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('a', 3);
EXPECT_EQ(str[3], 'G');
@@ -72,8 +73,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteChars) {
TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) {
char str[10];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('a', 3);
writer.write('D', 3);
writer.write('1', 3);
@@ -86,8 +87,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) {
TEST(LlvmLibcPrintfWriterTest, WriteManyChars) {
char str[100];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('Z', 99);
wb.buff[wb.buff_cur] = '\0';
@@ -108,8 +109,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteManyChars) {
TEST(LlvmLibcPrintfWriterTest, MixedWrites) {
char str[13];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -123,8 +124,8 @@ TEST(LlvmLibcPrintfWriterTest, MixedWrites) {
TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) {
char str[11];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write({"abcDEF123456", 12});
wb.buff[wb.buff_cur] = '\0';
@@ -135,8 +136,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) {
TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) {
char str[11];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('1', 15);
wb.buff[wb.buff_cur] = '\0';
@@ -147,9 +148,8 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) {
TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) {
char str[11];
- DropOverflowBuffer wb(str, sizeof(str) - 1);
-
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, sizeof(str) - 1);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -165,9 +165,8 @@ 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.
- DropOverflowBuffer wb(str, 0);
-
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer(str, 0);
+ WriteBuffer<char> &wb = writer.get_write_buffer();
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -180,9 +179,7 @@ TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) {
}
TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) {
- DropOverflowBuffer wb(nullptr, 0);
-
- Writer writer(wb);
+ Writer writer = make_drop_overflow_writer<char>(nullptr, 0);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
@@ -196,10 +193,9 @@ struct OutBuff {
size_t cur_pos = 0;
};
-int copy_to_out(string_view new_str, void *raw_out_buff) {
- if (new_str.size() == 0) {
- return 0;
- }
+void copy_to_out(string_view new_str, void *raw_out_buff) {
+ if (new_str.size() == 0)
+ return;
OutBuff *out_buff = reinterpret_cast<OutBuff *>(raw_out_buff);
@@ -207,7 +203,21 @@ int copy_to_out(string_view new_str, void *raw_out_buff) {
new_str.data(), new_str.size());
out_buff->cur_pos += new_str.size();
- return 0;
+}
+
+int overflow_write_copy_to_out(WriteBuffer<char> &wb, string_view new_str,
+ void *raw_out_buff) {
+ copy_to_out({wb.buff, wb.buff_cur}, raw_out_buff);
+ wb.buff_cur = 0;
+ copy_to_out(new_str, raw_out_buff);
+ return WRITE_OK;
+}
+
+Writer<OverflowMode::RUNTIME_DISPATCH>
+make_test_writer(char *buffer, size_t buffer_length, OutBuff *out_buff) {
+ return Writer(buffer, buffer_length,
+ OverflowWriter<OverflowMode::RUNTIME_DISPATCH, char>(
+ overflow_write_copy_to_out, out_buff));
}
TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) {
@@ -216,12 +226,11 @@ TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- FlushingBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out,
- reinterpret_cast<void *>(&out_buff));
- Writer writer(wb);
+ Writer writer = make_test_writer(wb_buff, sizeof(wb_buff) - 1, &out_buff);
writer.write({"abcDEF123456", 12});
- wb.flush_to_stream();
+ WriteBuffer<char> &wb = writer.get_write_buffer();
+ copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("abcDEF123456", str);
@@ -234,12 +243,11 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- FlushingBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out,
- reinterpret_cast<void *>(&out_buff));
- Writer writer(wb);
+ Writer writer = make_test_writer(wb_buff, sizeof(wb_buff) - 1, &out_buff);
writer.write('1', 15);
- wb.flush_to_stream();
+ WriteBuffer<char> &wb = writer.get_write_buffer();
+ copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("111111111111111", str);
@@ -252,15 +260,14 @@ TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- FlushingBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out,
- reinterpret_cast<void *>(&out_buff));
- Writer writer(wb);
+ Writer writer = make_test_writer(wb_buff, sizeof(wb_buff) - 1, &out_buff);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});
- wb.flush_to_stream();
+ WriteBuffer<char> &wb = writer.get_write_buffer();
+ copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("aaaDEF111456", str);
@@ -273,16 +280,14 @@ TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[1];
- FlushingBuffer wb(wb_buff, 0, ©_to_out,
- reinterpret_cast<void *>(&out_buff));
-
- Writer writer(wb);
+ Writer writer = make_test_writer(wb_buff, 0, &out_buff);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});
- wb.flush_to_stream();
+ WriteBuffer<char> &wb = writer.get_write_buffer();
+ copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("aaaDEF111456", str);
@@ -294,16 +299,12 @@ TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
- FlushingBuffer wb(nullptr, 0, ©_to_out,
- reinterpret_cast<void *>(&out_buff));
-
- Writer writer(wb);
+ Writer writer = make_test_writer(nullptr, 0, &out_buff);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});
- wb.flush_to_stream();
str[out_buff.cur_pos] = '\0';
ASSERT_EQ(writer.get_chars_written(), size_t{12});
>From 447413c8acc46e5553797b7acd704f7ab0db0dcb Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Thu, 3 Sep 2026 14:48:33 +0000
Subject: [PATCH 2/2] Rework down to two overflow modes, drop and callback only
---
libc/src/__support/printf_core/CMakeLists.txt | 45 +----
.../__support/printf_core/make_file_writer.h | 120 -------------
.../printf_core/make_resizing_writer.h | 63 -------
.../printf_core/make_stderr_writer.h | 56 ------
.../__support/printf_core/overflow_modes.def | 5 +-
.../printf_core/vasprintf_internal.h | 31 +++-
.../__support/printf_core/vfprintf_internal.h | 68 +++++++-
libc/src/__support/printf_core/writer.h | 160 +++++++-----------
libc/src/err/report.cpp | 17 +-
libc/src/stdio/baremetal/vfprintf_internal.h | 11 +-
libc/src/stdio/snprintf_modular.cpp | 5 +-
libc/src/stdio/sprintf_modular.cpp | 6 +-
libc/src/stdio/vsnprintf_modular.cpp | 5 +-
libc/src/stdio/vsprintf_modular.cpp | 6 +-
libc/src/time/strftime_l.cpp | 5 +-
.../src/__support/printf_core/writer_test.cpp | 55 +++---
16 files changed, 215 insertions(+), 443 deletions(-)
delete mode 100644 libc/src/__support/printf_core/make_file_writer.h
delete mode 100644 libc/src/__support/printf_core/make_resizing_writer.h
delete mode 100644 libc/src/__support/printf_core/make_stderr_writer.h
diff --git a/libc/src/__support/printf_core/CMakeLists.txt b/libc/src/__support/printf_core/CMakeLists.txt
index 12826b55d98c9..3617bb7ac1ea2 100644
--- a/libc/src/__support/printf_core/CMakeLists.txt
+++ b/libc/src/__support/printf_core/CMakeLists.txt
@@ -118,30 +118,6 @@ add_header_library(
libc.src.string.memory_utils.inline_memset
)
-add_header_library(
- make_resizing_writer
- HDRS
- make_resizing_writer.h
- DEPENDS
- .writer
- libc.hdr.func.malloc
- libc.hdr.func.free
- libc.hdr.func.realloc
- libc.src.__support.CPP.string_view
- libc.src.__support.printf_core.writer
-)
-
-add_header_library(
- make_stderr_writer
- HDRS
- make_stderr_writer.h
- DEPENDS
- .writer
- libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.io
- libc.src.__support.macros.config
-)
-
add_header_library(
converter
HDRS
@@ -203,10 +179,12 @@ add_header_library(
vasprintf_internal.h
DEPENDS
libc.hdr.func.malloc
+ libc.hdr.func.free
+ libc.hdr.func.realloc
libc.src.__support.arg_list
libc.src.__support.error_or
- libc.src.__support.printf_core.make_resizing_writer
libc.src.__support.printf_core.printf_main
+ libc.src.__support.printf_core.writer
)
add_header_library(
@@ -224,28 +202,15 @@ if(NOT (TARGET libc.src.__support.File.file) AND LLVM_LIBC_FULL_BUILD)
return()
endif()
-add_header_library(
- make_file_writer
- HDRS
- make_file_writer.h
- DEPENDS
- .writer
- libc.src.__support.CPP.string_view
- libc.src.__support.File.file
- libc.src.__support.macros.attributes
- libc.src.__support.macros.config
- ${use_system_file}
-)
-
add_header_library(
vfprintf_internal
HDRS
vfprintf_internal.h
DEPENDS
- .make_file_writer
- .printf_main
libc.src.__support.File.file
libc.src.__support.error_or
libc.src.__support.arg_list
+ libc.src.__support.printf_core.printf_main
+ libc.src.__support.printf_core.writer
${use_system_file}
)
diff --git a/libc/src/__support/printf_core/make_file_writer.h b/libc/src/__support/printf_core/make_file_writer.h
deleted file mode 100644
index e0639581ee5e0..0000000000000
--- a/libc/src/__support/printf_core/make_file_writer.h
+++ /dev/null
@@ -1,120 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Implementation helpers for Writer<OverflowMode::FLUSH_TO_FILE, CharT>.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_FILE_WRITER_H
-#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_FILE_WRITER_H
-
-#include "hdr/types/FILE.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/File/file.h"
-#include "src/__support/macros/attributes.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/printf_core/writer.h"
-
-namespace LIBC_NAMESPACE_DECL {
-namespace printf_core {
-
-template <typename CharT>
-LIBC_INLINE Writer<Mode<OverflowMode::FLUSH_TO_FILE>::value, CharT>
-make_file_writer(CharT *buffer, size_t buffer_len, ::FILE *fp) {
- return Writer(buffer, buffer_len,
- make_overflow_writer<OverflowMode::FLUSH_TO_FILE, CharT>(fp));
-}
-
-} // namespace printf_core
-
-namespace internal {
-#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
-LIBC_INLINE int ferror_unlocked(FILE *f) {
- return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked();
-}
-
-LIBC_INLINE void flockfile(FILE *f) {
- reinterpret_cast<LIBC_NAMESPACE::File *>(f)->lock();
-}
-
-LIBC_INLINE void funlockfile(FILE *f) {
- reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock();
-}
-
-LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
- size_t nmemb, FILE *f) {
- return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->write_unlocked(
- ptr, size * nmemb);
-}
-#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
-LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror_unlocked(f); }
-
-LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(f); }
-
-LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); }
-
-LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
- size_t nmemb, ::FILE *f) {
- // Need to use system errno in this case, as system write will set this errno
- // which we need to propagate back into our code. fwrite only modifies errno
- // if there was an error, and errno may have previously been nonzero. Only
- // return errno if there was an error.
- size_t members_written = ::fwrite_unlocked(ptr, size, nmemb, f);
- return {members_written, members_written == nmemb ? 0 : errno};
-}
-#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
-} // namespace internal
-
-namespace printf_core {
-
-LIBC_INLINE int write_to_file_unlocked(cpp::string_view str,
- ::FILE *target_file) {
- if (str.size() == 0)
- return WRITE_OK;
-
- auto write_result = internal::fwrite_unlocked(str.data(), sizeof(char),
- str.size(), 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 != str.size() ||
- internal::ferror_unlocked(target_file))
- return FILE_WRITE_ERROR;
-
- return WRITE_OK;
-}
-
-// Handles overflow by flushing the current contents of `wb` and `new_str` to
-// the `FILE` pointed to by `fp`.
-template <typename CharT>
-LIBC_INLINE int
-overflow_write_flush_to_file(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str, void *fp) {
- ::FILE *target_file = reinterpret_cast<::FILE *>(fp);
- int retval;
-
- retval = write_to_file_unlocked({wb.buff, wb.buff_cur}, target_file);
- if (retval < 0)
- return retval;
- wb.buff_cur = 0;
-
- retval = write_to_file_unlocked(new_str, target_file);
- if (retval < 0)
- return retval;
-
- return WRITE_OK;
-}
-
-} // namespace printf_core
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_FILE_WRITER_H
diff --git a/libc/src/__support/printf_core/make_resizing_writer.h b/libc/src/__support/printf_core/make_resizing_writer.h
deleted file mode 100644
index 31dcd0d510d81..0000000000000
--- a/libc/src/__support/printf_core/make_resizing_writer.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Implementation helpers for Writer<OverflowMode::RESIZE_BUFFER, CharT>.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_RESIZING_WRITER_H
-#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_RESIZING_WRITER_H
-
-#include "hdr/func/free.h"
-#include "hdr/func/malloc.h"
-#include "hdr/func/realloc.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/printf_core/writer.h"
-
-namespace LIBC_NAMESPACE_DECL {
-namespace printf_core {
-
-template <typename CharT>
-LIBC_INLINE Writer<Mode<OverflowMode::RESIZE_BUFFER>::value, CharT>
-make_resizing_writer(CharT *buffer, size_t buffer_len, bool buffer_on_stack) {
- return Writer(buffer, buffer_len,
- make_overflow_writer<OverflowMode::RESIZE_BUFFER, CharT>(
- buffer_on_stack ? buffer : nullptr));
-}
-
-// Handles overflow by resizing `wb` to have enough capacity for `new_str`, and
-// then copying the `new_str` contents into the buffer.
-template <typename CharT>
-LIBC_INLINE int
-overflow_write_resize_buffer(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str,
- void *initial_stack_buffer) {
- size_t new_size = new_str.size() + wb.buff_cur;
- const bool is_on_stack = (wb.buff == initial_stack_buffer);
- char *new_buff = static_cast<char *>(
- is_on_stack ? malloc(new_size + 1)
- : realloc(wb.buff, new_size + 1)); // +1 for null
- if (new_buff == nullptr) {
- if (!is_on_stack)
- free(wb.buff);
- return ALLOCATION_ERROR;
- }
- if (is_on_stack)
- 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());
- wb.buff_cur = new_size;
- wb.buff_len = new_size;
- return WRITE_OK;
-}
-
-} // namespace printf_core
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_RESIZING_WRITER_H
diff --git a/libc/src/__support/printf_core/make_stderr_writer.h b/libc/src/__support/printf_core/make_stderr_writer.h
deleted file mode 100644
index 0d2322ed0c74d..0000000000000
--- a/libc/src/__support/printf_core/make_stderr_writer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Implementation helpers for Writer<OverflowMode::FLUSH_TO_STDERR, CharT>.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_STDERR_WRITER_H
-#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_STDERR_WRITER_H
-
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/io.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/printf_core/writer.h"
-
-namespace LIBC_NAMESPACE_DECL {
-namespace printf_core {
-
-template <typename CharT>
-LIBC_INLINE Writer<Mode<OverflowMode::FLUSH_TO_STDERR>::value, CharT>
-make_stderr_writer(CharT *buffer, size_t buffer_len) {
- return Writer(
- buffer, buffer_len,
- make_overflow_writer<OverflowMode::FLUSH_TO_STDERR, CharT>(nullptr));
-}
-
-LIBC_INLINE void flush_to_stderr(WriteBuffer<char> &wb) {
- if (wb.buff_cur == 0)
- return;
-
- write_to_stderr({wb.buff, wb.buff_cur});
- wb.buff_cur = 0;
-}
-
-// Handles overflow by flushing the current contents of `wb` and `new_str` to
-// stderr.
-template <typename CharT>
-LIBC_INLINE int
-overflow_write_flush_to_stderr(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str, void *) {
- flush_to_stderr(wb);
- if (new_str.size() > 0)
- write_to_stderr(new_str);
- return WRITE_OK;
-}
-
-} // namespace printf_core
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_MAKE_STDERR_WRITER_H
diff --git a/libc/src/__support/printf_core/overflow_modes.def b/libc/src/__support/printf_core/overflow_modes.def
index a18301e4ebf66..8fc1e620ed75d 100644
--- a/libc/src/__support/printf_core/overflow_modes.def
+++ b/libc/src/__support/printf_core/overflow_modes.def
@@ -7,7 +7,4 @@
//===----------------------------------------------------------------------===//
HANDLE_OVERFLOW_MODE(DROP_OVERFLOW)
-HANDLE_OVERFLOW_MODE(FLUSH_TO_FILE)
-HANDLE_OVERFLOW_MODE(FLUSH_TO_STDERR)
-HANDLE_OVERFLOW_MODE(RESIZE_BUFFER)
-HANDLE_OVERFLOW_MODE(RUNTIME_DISPATCH)
+HANDLE_OVERFLOW_MODE(CALLBACK)
diff --git a/libc/src/__support/printf_core/vasprintf_internal.h b/libc/src/__support/printf_core/vasprintf_internal.h
index 5396161c74115..5421336bc339d 100644
--- a/libc/src/__support/printf_core/vasprintf_internal.h
+++ b/libc/src/__support/printf_core/vasprintf_internal.h
@@ -9,16 +9,40 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_VASPRINTF_INTERNAL_H
#define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_VASPRINTF_INTERNAL_H
+#include "hdr/func/free.h"
#include "hdr/func/malloc.h"
+#include "hdr/func/realloc.h"
#include "src/__support/arg_list.h"
#include "src/__support/error_or.h"
#include "src/__support/printf_core/core_structs.h"
-#include "src/__support/printf_core/make_resizing_writer.h"
#include "src/__support/printf_core/printf_main.h"
+#include "src/__support/printf_core/writer.h"
namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
+LIBC_INLINE int overflow_write_resize_buffer(WriteBuffer<char> &wb,
+ cpp::string_view new_str,
+ void *initial_stack_buffer) {
+ size_t new_size = new_str.size() + wb.buff_cur;
+ const bool is_buff_on_stack = (wb.buff == initial_stack_buffer);
+ char *new_buff = static_cast<char *>(
+ is_buff_on_stack ? malloc(new_size + 1)
+ : realloc(wb.buff, new_size + 1)); // +1 for null
+ if (new_buff == nullptr) {
+ if (!is_buff_on_stack)
+ free(wb.buff);
+ return ALLOCATION_ERROR;
+ }
+ if (is_buff_on_stack)
+ 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());
+ wb.buff_cur = new_size;
+ wb.buff_len = new_size;
+ return printf_core::WRITE_OK;
+}
+
constexpr size_t DEFAULT_BUFFER_SIZE = 200;
template <bool use_modular = false>
@@ -26,8 +50,9 @@ LIBC_INLINE ErrorOr<size_t> vasprintf_internal(char **ret,
const char *__restrict format,
internal::ArgList args) {
char init_buff_on_stack[DEFAULT_BUFFER_SIZE];
- Writer writer = make_resizing_writer(init_buff_on_stack, DEFAULT_BUFFER_SIZE,
- /* buffer_on_stack = */ true);
+ printf_core::Writer writer = printf_core::make_writer(
+ init_buff_on_stack, DEFAULT_BUFFER_SIZE, &overflow_write_resize_buffer,
+ init_buff_on_stack);
auto ret_val = [&] {
if constexpr (use_modular)
diff --git a/libc/src/__support/printf_core/vfprintf_internal.h b/libc/src/__support/printf_core/vfprintf_internal.h
index 1f2ea5960f4c4..523eea30787cc 100644
--- a/libc/src/__support/printf_core/vfprintf_internal.h
+++ b/libc/src/__support/printf_core/vfprintf_internal.h
@@ -15,28 +15,88 @@
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
#include "src/__support/macros/config.h"
#include "src/__support/printf_core/core_structs.h"
-#include "src/__support/printf_core/make_file_writer.h"
#include "src/__support/printf_core/printf_main.h"
+#include "src/__support/printf_core/writer.h"
#include "hdr/types/FILE.h"
namespace LIBC_NAMESPACE_DECL {
+
+namespace internal {
+#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
+LIBC_INLINE int ferror_unlocked(FILE *f) {
+ return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->error_unlocked();
+}
+
+LIBC_INLINE void flockfile(FILE *f) {
+ reinterpret_cast<LIBC_NAMESPACE::File *>(f)->lock();
+}
+
+LIBC_INLINE void funlockfile(FILE *f) {
+ reinterpret_cast<LIBC_NAMESPACE::File *>(f)->unlock();
+}
+
+LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
+ size_t nmemb, FILE *f) {
+ return reinterpret_cast<LIBC_NAMESPACE::File *>(f)->write_unlocked(
+ ptr, size * nmemb);
+}
+#else // defined(LIBC_COPT_STDIO_USE_SYSTEM_FILE)
+LIBC_INLINE int ferror_unlocked(::FILE *f) { return ::ferror_unlocked(f); }
+
+LIBC_INLINE void flockfile(::FILE *f) { ::flockfile(f); }
+
+LIBC_INLINE void funlockfile(::FILE *f) { ::funlockfile(f); }
+
+LIBC_INLINE FileIOResult fwrite_unlocked(const void *ptr, size_t size,
+ size_t nmemb, ::FILE *f) {
+ // Need to use system errno in this case, as system write will set this errno
+ // which we need to propagate back into our code. fwrite only modifies errno
+ // if there was an error, and errno may have previously been nonzero. Only
+ // return errno if there was an error.
+ size_t members_written = ::fwrite_unlocked(ptr, size, nmemb, f);
+ return {members_written, members_written == nmemb ? 0 : errno};
+}
+#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE
+} // namespace internal
+
namespace printf_core {
+LIBC_INLINE int file_write_hook(cpp::string_view new_str, 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);
+ // 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() ||
+ internal::ferror_unlocked(target_file))
+ return FILE_WRITE_ERROR;
+
+ return WRITE_OK;
+}
+
LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE *__restrict stream,
const char *__restrict format,
internal::ArgList &args) {
constexpr size_t BUFF_SIZE = 1024;
char buffer[BUFF_SIZE];
- Writer writer = make_file_writer(buffer, BUFF_SIZE, stream);
+ Writer writer =
+ make_writer(buffer, BUFF_SIZE,
+ &overflow_write_flush_to_sink<char, file_write_hook>, stream);
internal::flockfile(stream);
auto retval = printf_main(&writer, format, args);
if (!retval.has_value()) {
internal::funlockfile(stream);
return retval;
}
- WriteBuffer<char> &wb = writer.get_write_buffer();
- int flushval = write_to_file_unlocked({wb.buff, wb.buff_cur}, stream);
+ int flushval =
+ writer.get_write_buffer().flush_to_sink<file_write_hook>(stream);
if (flushval != WRITE_OK)
retval = Error(-flushval);
internal::funlockfile(stream);
diff --git a/libc/src/__support/printf_core/writer.h b/libc/src/__support/printf_core/writer.h
index 31f1557ab09e4..031c48b3a353d 100644
--- a/libc/src/__support/printf_core/writer.h
+++ b/libc/src/__support/printf_core/writer.h
@@ -31,27 +31,47 @@ enum class OverflowMode {
// avoid multiple copies of the converter functions.
template <OverflowMode mode> struct Mode {
#ifdef LIBC_COPT_PRINTF_RUNTIME_DISPATCH
- static constexpr OverflowMode value = OverflowMode::RUNTIME_DISPATCH;
+ static constexpr OverflowMode value = OverflowMode::CALLBACK;
#else
static constexpr OverflowMode value = mode;
#endif
};
+// Function type for an optionally stateful write sink to be used in a
+// `Writer` "overflow write" callback.
+//
+// Should not be expected to handle an empty string input.
+template <typename CharT>
+using WriteSink = int (*)(cpp::basic_string_view<CharT> /* str */,
+ void * /* state */);
+
template <typename CharT> struct WriteBuffer {
CharT *buff;
size_t buff_len;
size_t buff_cur = 0;
+
+ // Flushes the current contents of the buffer to `write_sink`, if non-empty.
+ template <WriteSink<CharT> write_sink>
+ LIBC_INLINE int flush_to_sink(void *sink_state = nullptr) {
+ if (buff_cur == 0)
+ return WRITE_OK;
+
+ int retval = write_sink({buff, buff_cur}, sink_state);
+ if (retval >= 0)
+ buff_cur = 0;
+ return retval;
+ }
};
-// Function type for handling the slow path in `Writer` when the `WriteBuffer`
-// may not have enough remaining capacity for the new content.
+// Function type for handling the "overflow write" slow path in `Writer` when
+// the `WriteBuffer` may not have enough remaining capacity for the new content.
template <typename CharT>
using OverflowWriteFn = int (*)(WriteBuffer<CharT> & /* wb */,
cpp::basic_string_view<CharT> /* new_str */,
void * /* state */);
// Handles overflow by filling any remaining space in `wb` with the start of
-// `new_str`, and dropping any excess bytes.
+// `new_str`, and dropping any excess characters.
template <typename CharT>
LIBC_INLINE int
overflow_write_drop_overflow(WriteBuffer<CharT> &wb,
@@ -67,50 +87,22 @@ overflow_write_drop_overflow(WriteBuffer<CharT> &wb,
return WRITE_OK;
}
-// Defined in make_file_writer.h
-template <typename CharT>
-int overflow_write_flush_to_file(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str,
- void *fp);
-
-// Defined in make_stderr_writer.h
-template <typename CharT>
-int overflow_write_flush_to_stderr(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str,
- void *);
-
-// Defined in make_resizing_writer.h
-template <typename CharT>
-int overflow_write_resize_buffer(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str,
- void *initial_stack_buffer);
-
-// Trait type helper mapping `OverflowMode` to the corresponding function.
-template <OverflowMode mode, typename CharT> struct OverflowModeToWriteFn {};
-
-template <typename CharT>
-struct OverflowModeToWriteFn<OverflowMode::DROP_OVERFLOW, CharT> {
- static constexpr OverflowWriteFn<CharT> value =
- overflow_write_drop_overflow<CharT>;
-};
-
-template <typename CharT>
-struct OverflowModeToWriteFn<OverflowMode::FLUSH_TO_FILE, CharT> {
- static constexpr OverflowWriteFn<CharT> value =
- overflow_write_flush_to_file<CharT>;
-};
-
-template <typename CharT>
-struct OverflowModeToWriteFn<OverflowMode::FLUSH_TO_STDERR, CharT> {
- static constexpr OverflowWriteFn<CharT> value =
- overflow_write_flush_to_stderr<CharT>;
-};
-
-template <typename CharT>
-struct OverflowModeToWriteFn<OverflowMode::RESIZE_BUFFER, CharT> {
- static constexpr OverflowWriteFn<CharT> value =
- overflow_write_resize_buffer<CharT>;
-};
+// Flushes the current contents of `wb` to `write_sink`, followed by `new_str`.
+template <typename CharT, WriteSink<CharT> write_sink>
+LIBC_INLINE int
+overflow_write_flush_to_sink(WriteBuffer<CharT> &wb,
+ cpp::basic_string_view<CharT> new_str,
+ void *sink_state) {
+ int retval = wb.template flush_to_sink<write_sink>(sink_state);
+ if (retval < 0)
+ return retval;
+ if (new_str.size() > 0) {
+ retval = write_sink(new_str, sink_state);
+ if (retval < 0)
+ return retval;
+ }
+ return WRITE_OK;
+}
// Helper template used by `Writer` to dispatch to the appropriate
// `OverflowWriteFn`.
@@ -126,43 +118,7 @@ struct OverflowWriter<OverflowMode::DROP_OVERFLOW, CharT> {
}
};
-template <typename CharT>
-struct OverflowWriter<OverflowMode::FLUSH_TO_FILE, CharT> {
- void *file;
-
- LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *file) : file(file) {}
-
- LIBC_INLINE int write(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str) {
- return overflow_write_flush_to_file(wb, new_str, file);
- }
-};
-
-template <typename CharT>
-struct OverflowWriter<OverflowMode::FLUSH_TO_STDERR, CharT> {
- LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *) {}
-
- LIBC_INLINE int write(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str) {
- return overflow_write_flush_to_stderr(wb, new_str, nullptr);
- }
-};
-
-template <typename CharT>
-struct OverflowWriter<OverflowMode::RESIZE_BUFFER, CharT> {
- void *initial_stack_buffer;
-
- LIBC_INLINE OverflowWriter(OverflowWriteFn<CharT>, void *initial_stack_buffer)
- : initial_stack_buffer(initial_stack_buffer) {}
-
- LIBC_INLINE int write(WriteBuffer<CharT> &wb,
- cpp::basic_string_view<CharT> new_str) {
- return overflow_write_resize_buffer(wb, new_str, initial_stack_buffer);
- }
-};
-
-template <typename CharT>
-struct OverflowWriter<OverflowMode::RUNTIME_DISPATCH, CharT> {
+template <typename CharT> struct OverflowWriter<OverflowMode::CALLBACK, CharT> {
OverflowWriteFn<CharT> runtime_fn;
void *state;
@@ -175,15 +131,6 @@ struct OverflowWriter<OverflowMode::RUNTIME_DISPATCH, CharT> {
}
};
-// Constructs an `OverflowWriter` that dispatches according to
-// `LIBC_COPT_PRINTF_RUNTIME_DISPATCH`.
-template <OverflowMode mode, typename CharT>
-LIBC_INLINE OverflowWriter<Mode<mode>::value, CharT>
-make_overflow_writer(void *state) {
- return OverflowWriter<Mode<mode>::value, CharT>(
- OverflowModeToWriteFn<mode, CharT>::value, state);
-}
-
// Fills the `dest` buffer with `count` copies of `value`.
template <typename CharT>
LIBC_INLINE void fill_buffer(CharT *dest, CharT value, size_t count) {
@@ -227,15 +174,21 @@ template <OverflowMode mode, typename CharT = char> class Writer final {
return overflow_writer.write(wb, mb_substr);
}
-public:
- // Prefer using the factory functions in make_*_writer.h or
- // `make_drop_overflow_writer` below, instead of directly calling this
- // constructor.
LIBC_INLINE Writer(CharT *buffer, size_t buffer_len,
OverflowWriter<mode, CharT> overflow_writer)
: wb{.buff = buffer, .buff_len = buffer_len},
overflow_writer(overflow_writer) {}
+public:
+ template <typename CharType>
+ friend Writer<Mode<OverflowMode::DROP_OVERFLOW>::value, CharType>
+ make_drop_overflow_writer(CharType *buffer, size_t buffer_len);
+
+ template <typename CharType>
+ friend Writer<Mode<OverflowMode::CALLBACK>::value, CharType>
+ make_writer(CharType *buffer, size_t buffer_len,
+ OverflowWriteFn<CharType> callback, void *callback_state);
+
// Takes a string, copies it into the buffer if there is space, else passes it
// to the overflow mechanism to be handled separately.
LIBC_INLINE int write(cpp::basic_string_view<CharT> new_string) {
@@ -287,9 +240,18 @@ Writer(CharT *, size_t, OverflowWriter<mode, CharT>) -> Writer<mode, CharT>;
template <typename CharT>
LIBC_INLINE Writer<Mode<OverflowMode::DROP_OVERFLOW>::value, CharT>
make_drop_overflow_writer(CharT *buffer, size_t buffer_len) {
+ return Writer(buffer, buffer_len,
+ OverflowWriter<Mode<OverflowMode::DROP_OVERFLOW>::value, CharT>(
+ overflow_write_drop_overflow<CharT>, nullptr));
+}
+
+template <typename CharT>
+LIBC_INLINE Writer<OverflowMode::CALLBACK, CharT>
+make_writer(CharT *buffer, size_t buffer_len, OverflowWriteFn<CharT> callback,
+ void *callback_state = nullptr) {
return Writer(
buffer, buffer_len,
- make_overflow_writer<OverflowMode::DROP_OVERFLOW, CharT>(nullptr));
+ OverflowWriter<OverflowMode::CALLBACK, CharT>(callback, callback_state));
}
} // namespace printf_core
diff --git a/libc/src/err/report.cpp b/libc/src/err/report.cpp
index 9c02b0ea8abdf..3b35043201100 100644
--- a/libc/src/err/report.cpp
+++ b/libc/src/err/report.cpp
@@ -20,8 +20,8 @@
#include "src/__support/arg_list.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/printf_core/make_stderr_writer.h"
#include "src/__support/printf_core/printf_main.h"
+#include "src/__support/printf_core/writer.h"
#ifdef LIBC_FULL_BUILD
#include "src/errno/program_invocation_short_name.h"
@@ -35,15 +35,20 @@ extern "C" char *program_invocation_short_name;
namespace LIBC_NAMESPACE_DECL {
namespace err_reporting {
+LIBC_INLINE int stderr_write_hook(cpp::string_view str, void *) {
+ write_to_stderr(str);
+ return printf_core::WRITE_OK;
+}
+
void report(bool show_err, int err_num, const char *fmt,
internal::ArgList &args) {
const char *progname = PROGRAM_INVOCATION_SHORT_NAME;
if (!progname)
progname = "";
char buffer[1024];
- printf_core::Writer writer =
- printf_core::make_stderr_writer(buffer, sizeof(buffer));
- printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
+ printf_core::Writer writer = printf_core::make_writer(
+ buffer, sizeof(buffer),
+ &printf_core::overflow_write_flush_to_sink<char, stderr_write_hook>);
writer.write(progname);
if (fmt != nullptr || show_err)
@@ -51,7 +56,7 @@ void report(bool show_err, int err_num, const char *fmt,
if (fmt != nullptr) {
if (!printf_core::printf_main(&writer, fmt, args)) {
- printf_core::flush_to_stderr(wb);
+ writer.get_write_buffer().flush_to_sink<stderr_write_hook>();
return;
}
if (show_err)
@@ -62,7 +67,7 @@ void report(bool show_err, int err_num, const char *fmt,
writer.write(get_error_string(err_num));
writer.write("\n");
- printf_core::flush_to_stderr(wb);
+ writer.get_write_buffer().flush_to_sink<stderr_write_hook>();
}
} // namespace err_reporting
diff --git a/libc/src/stdio/baremetal/vfprintf_internal.h b/libc/src/stdio/baremetal/vfprintf_internal.h
index c86c40a7cca0c..715124df7a3b3 100644
--- a/libc/src/stdio/baremetal/vfprintf_internal.h
+++ b/libc/src/stdio/baremetal/vfprintf_internal.h
@@ -45,9 +45,11 @@ LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
static constexpr size_t BUFF_SIZE = 1024;
char buffer[BUFF_SIZE];
- printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &internal::write_hook,
- stream);
- printf_core::Writer writer(wb);
+ // TODO:
+ printf_core::Writer writer = print_core::make_writer(
+ buffer, BUFF_SIZE,
+ &printf_core::overflow_write_flush_to_sink<char, internal::write_hook>,
+ stream);
auto retval = [&] {
if constexpr (use_modular)
@@ -60,7 +62,8 @@ LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream,
return -1;
}
- int flushval = wb.flush_to_stream();
+ int flushval =
+ writer.get_write_buffer().flush_to_sink<internal::write_hook>(stream);
if (flushval != printf_core::WRITE_OK) {
libc_errno = printf_core::internal_error_to_errno(-flushval);
return -1;
diff --git a/libc/src/stdio/snprintf_modular.cpp b/libc/src/stdio/snprintf_modular.cpp
index 86afdb9c5828e..485bf6b41693c 100644
--- a/libc/src/stdio/snprintf_modular.cpp
+++ b/libc/src/stdio/snprintf_modular.cpp
@@ -31,8 +31,9 @@ LLVM_LIBC_FUNCTION(int, __snprintf_modular,
// and pointer semantics, as well as handling
// destruction automatically.
va_end(vlist);
- printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
auto ret_val = printf_core::printf_main_modular(&writer, format, args);
if (!ret_val.has_value()) {
diff --git a/libc/src/stdio/sprintf_modular.cpp b/libc/src/stdio/sprintf_modular.cpp
index 9003e2440d535..ce2a3b6a257df 100644
--- a/libc/src/stdio/sprintf_modular.cpp
+++ b/libc/src/stdio/sprintf_modular.cpp
@@ -31,9 +31,9 @@ LLVM_LIBC_FUNCTION(int, __sprintf_modular,
// destruction automatically.
va_end(vlist);
- printf_core::DropOverflowBuffer wb(buffer,
- cpp::numeric_limits<size_t>::max());
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, cpp::numeric_limits<size_t>::max());
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
auto ret_val = printf_core::printf_main_modular(&writer, format, args);
if (!ret_val.has_value()) {
diff --git a/libc/src/stdio/vsnprintf_modular.cpp b/libc/src/stdio/vsnprintf_modular.cpp
index 96f020839c3cc..366f5af8c9884 100644
--- a/libc/src/stdio/vsnprintf_modular.cpp
+++ b/libc/src/stdio/vsnprintf_modular.cpp
@@ -28,8 +28,9 @@ LLVM_LIBC_FUNCTION(int, __vsnprintf_modular,
internal::ArgList args(vlist); // This holder class allows for easier copying
// and pointer semantics, as well as handling
// destruction automatically.
- printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
auto ret_val = printf_core::printf_main_modular(&writer, format, args);
if (!ret_val.has_value()) {
diff --git a/libc/src/stdio/vsprintf_modular.cpp b/libc/src/stdio/vsprintf_modular.cpp
index 34deab1bfe412..40af67f313c43 100644
--- a/libc/src/stdio/vsprintf_modular.cpp
+++ b/libc/src/stdio/vsprintf_modular.cpp
@@ -28,9 +28,9 @@ LLVM_LIBC_FUNCTION(int, __vsprintf_modular,
// and pointer semantics, as well as handling
// destruction automatically.
- printf_core::DropOverflowBuffer wb(buffer,
- cpp::numeric_limits<size_t>::max());
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, cpp::numeric_limits<size_t>::max());
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
auto ret_val = printf_core::printf_main_modular(&writer, format, args);
if (!ret_val.has_value()) {
diff --git a/libc/src/time/strftime_l.cpp b/libc/src/time/strftime_l.cpp
index faf3883c476b2..db72ca747c6fb 100644
--- a/libc/src/time/strftime_l.cpp
+++ b/libc/src/time/strftime_l.cpp
@@ -28,8 +28,9 @@ LLVM_LIBC_FUNCTION(size_t, strftime_l,
LIBC_CRASH_ON_NULLPTR(format);
LIBC_CRASH_ON_NULLPTR(timeptr);
- printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0));
- printf_core::Writer writer(wb);
+ printf_core::Writer writer = printf_core::make_drop_overflow_writer(
+ buffer, (buffsz > 0 ? buffsz - 1 : 0));
+ printf_core::WriteBuffer<char> &wb = writer.get_write_buffer();
auto ret = strftime_core::strftime_main(&writer, format, timeptr);
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
wb.buff[wb.buff_cur] = '\0';
diff --git a/libc/test/src/__support/printf_core/writer_test.cpp b/libc/test/src/__support/printf_core/writer_test.cpp
index 5d34cdae1a18d..5fc226bdeff62 100644
--- a/libc/test/src/__support/printf_core/writer_test.cpp
+++ b/libc/test/src/__support/printf_core/writer_test.cpp
@@ -16,8 +16,9 @@ namespace {
using LIBC_NAMESPACE::cpp::string_view;
using LIBC_NAMESPACE::printf_core::make_drop_overflow_writer;
+using LIBC_NAMESPACE::printf_core::make_writer;
+using LIBC_NAMESPACE::printf_core::overflow_write_flush_to_sink;
using LIBC_NAMESPACE::printf_core::OverflowMode;
-using LIBC_NAMESPACE::printf_core::OverflowWriter;
using LIBC_NAMESPACE::printf_core::WRITE_OK;
using LIBC_NAMESPACE::printf_core::WriteBuffer;
using LIBC_NAMESPACE::printf_core::Writer;
@@ -193,44 +194,28 @@ struct OutBuff {
size_t cur_pos = 0;
};
-void copy_to_out(string_view new_str, void *raw_out_buff) {
- if (new_str.size() == 0)
- return;
-
+int copy_to_out(string_view new_str, void *raw_out_buff) {
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());
out_buff->cur_pos += new_str.size();
-}
-
-int overflow_write_copy_to_out(WriteBuffer<char> &wb, string_view new_str,
- void *raw_out_buff) {
- copy_to_out({wb.buff, wb.buff_cur}, raw_out_buff);
- wb.buff_cur = 0;
- copy_to_out(new_str, raw_out_buff);
return WRITE_OK;
}
-Writer<OverflowMode::RUNTIME_DISPATCH>
-make_test_writer(char *buffer, size_t buffer_length, OutBuff *out_buff) {
- return Writer(buffer, buffer_length,
- OverflowWriter<OverflowMode::RUNTIME_DISPATCH, char>(
- overflow_write_copy_to_out, out_buff));
-}
-
TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) {
char str[16];
OutBuff out_buff = {str, 0};
char wb_buff[8];
- Writer writer = make_test_writer(wb_buff, sizeof(wb_buff) - 1, &out_buff);
+ Writer writer =
+ make_writer(wb_buff, sizeof(wb_buff) - 1,
+ &overflow_write_flush_to_sink<char, copy_to_out>, &out_buff);
writer.write({"abcDEF123456", 12});
- WriteBuffer<char> &wb = writer.get_write_buffer();
- copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
+ writer.get_write_buffer().flush_to_sink<copy_to_out>(&out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("abcDEF123456", str);
@@ -243,11 +228,12 @@ TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- Writer writer = make_test_writer(wb_buff, sizeof(wb_buff) - 1, &out_buff);
+ Writer writer =
+ make_writer(wb_buff, sizeof(wb_buff) - 1,
+ &overflow_write_flush_to_sink<char, copy_to_out>, &out_buff);
writer.write('1', 15);
- WriteBuffer<char> &wb = writer.get_write_buffer();
- copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
+ writer.get_write_buffer().flush_to_sink<copy_to_out>(&out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("111111111111111", str);
@@ -260,14 +246,15 @@ TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[8];
- Writer writer = make_test_writer(wb_buff, sizeof(wb_buff) - 1, &out_buff);
+ Writer writer =
+ make_writer(wb_buff, sizeof(wb_buff) - 1,
+ &overflow_write_flush_to_sink<char, copy_to_out>, &out_buff);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});
- WriteBuffer<char> &wb = writer.get_write_buffer();
- copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
+ writer.get_write_buffer().flush_to_sink<copy_to_out>(&out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("aaaDEF111456", str);
@@ -280,14 +267,15 @@ TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) {
OutBuff out_buff = {str, 0};
char wb_buff[1];
- Writer writer = make_test_writer(wb_buff, 0, &out_buff);
+ Writer writer =
+ make_writer(wb_buff, sizeof(wb_buff) - 1,
+ &overflow_write_flush_to_sink<char, copy_to_out>, &out_buff);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});
- WriteBuffer<char> &wb = writer.get_write_buffer();
- copy_to_out({wb.buff, wb.buff_cur}, &out_buff);
+ writer.get_write_buffer().flush_to_sink<copy_to_out>(&out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_STREQ("aaaDEF111456", str);
@@ -299,12 +287,15 @@ TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) {
OutBuff out_buff = {str, 0};
- Writer writer = make_test_writer(nullptr, 0, &out_buff);
+ Writer writer =
+ make_writer(static_cast<char *>(nullptr), 0,
+ &overflow_write_flush_to_sink<char, copy_to_out>, &out_buff);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});
+ writer.get_write_buffer().flush_to_sink<copy_to_out>(&out_buff);
str[out_buff.cur_pos] = '\0';
ASSERT_EQ(writer.get_chars_written(), size_t{12});
More information about the libc-commits
mailing list