8 changes: 2 additions & 6 deletions libc/src/stdio/printf_core/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#include "src/__support/arg_list.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/string/memory_utils/memset_implementations.h"

#include <stddef.h>

Expand Down Expand Up @@ -49,7 +48,7 @@ class Parser {
// TypeDesc objects, which store the size as well as minimal type information.
// This is necessary because some systems separate the floating point and
// integer values in va_args.
TypeDesc desc_arr[DESC_ARR_LEN];
TypeDesc desc_arr[DESC_ARR_LEN] = {{0, Integer}};;

// TODO: Look into object stores for optimization.

Expand All @@ -58,10 +57,7 @@ class Parser {
public:
#ifndef LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE
Parser(const char *__restrict new_str, internal::ArgList &args)
: str(new_str), args_cur(args), args_start(args) {
inline_memset(reinterpret_cast<char *>(desc_arr), 0,
DESC_ARR_LEN * sizeof(TypeDesc));
}
: str(new_str), args_cur(args), args_start(args) {}
#else
Parser(const char *__restrict new_str, internal::ArgList &args)
: str(new_str), args_cur(args) {}
Expand Down
5 changes: 3 additions & 2 deletions libc/src/stdio/printf_core/printf_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ int printf_main(Writer *writer, const char *__restrict str,
Parser parser(str, args);
int result = 0;
for (FormatSection cur_section = parser.get_next_section();
cur_section.raw_len > 0; cur_section = parser.get_next_section()) {
!cur_section.raw_string.empty();
cur_section = parser.get_next_section()) {
if (cur_section.has_conv)
result = convert(writer, cur_section);
else
result = writer->write(cur_section.raw_string, cur_section.raw_len);
result = writer->write(cur_section.raw_string);

if (result < 0)
return result;
Expand Down
5 changes: 2 additions & 3 deletions libc/src/stdio/printf_core/ptr_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PTR_CONVERTER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PTR_CONVERTER_H

#include "src/__support/CPP/string_view.h"
#include "src/stdio/printf_core/converter_utils.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/int_converter.h"
Expand All @@ -19,9 +20,7 @@ namespace printf_core {

int inline convert_pointer(Writer *writer, const FormatSection &to_conv) {
if (to_conv.conv_val_ptr == (void *)(nullptr)) {
const char ZERO_STR[] = "(nullptr)";
// subtract 1 from sizeof to remove the null byte at the end.
RET_IF_RESULT_NEGATIVE(writer->write(ZERO_STR, sizeof(ZERO_STR) - 1));
RET_IF_RESULT_NEGATIVE(writer->write("(nullptr)"));
} else {
FormatSection hex_conv;
hex_conv.has_conv = true;
Expand Down
40 changes: 21 additions & 19 deletions libc/src/stdio/printf_core/string_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRING_CONVERTER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRING_CONVERTER_H

#include "src/__support/CPP/string_view.h"
#include "src/stdio/printf_core/converter_utils.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/writer.h"
Expand All @@ -19,33 +20,34 @@ namespace __llvm_libc {
namespace printf_core {

int inline convert_string(Writer *writer, const FormatSection &to_conv) {
int string_len = 0;
size_t string_len = 0;

for (char *cur_str = reinterpret_cast<char *>(to_conv.conv_val_ptr);
cur_str[string_len]; ++string_len) {
;
}

if (to_conv.precision >= 0 && to_conv.precision < string_len)
if (to_conv.precision >= 0 &&
static_cast<size_t>(to_conv.precision) < string_len)
string_len = to_conv.precision;

if (to_conv.min_width > string_len) {
if ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) ==
FormatFlags::LEFT_JUSTIFIED) {
RET_IF_RESULT_NEGATIVE(writer->write(
reinterpret_cast<const char *>(to_conv.conv_val_ptr), string_len));
RET_IF_RESULT_NEGATIVE(
writer->write_chars(' ', to_conv.min_width - string_len));

} else {
RET_IF_RESULT_NEGATIVE(
writer->write_chars(' ', to_conv.min_width - string_len));
RET_IF_RESULT_NEGATIVE(writer->write(
reinterpret_cast<const char *>(to_conv.conv_val_ptr), string_len));
}
} else {
RET_IF_RESULT_NEGATIVE(writer->write(
reinterpret_cast<const char *>(to_conv.conv_val_ptr), string_len));
size_t padding_spaces = to_conv.min_width > static_cast<int>(string_len)
? to_conv.min_width - string_len
: 0;

// If the padding is on the left side, write the spaces first.
if (padding_spaces > 0 &&
(to_conv.flags & FormatFlags::LEFT_JUSTIFIED) == 0) {
RET_IF_RESULT_NEGATIVE(writer->write(' ', to_conv.min_width - string_len));
}

RET_IF_RESULT_NEGATIVE(writer->write(
{reinterpret_cast<const char *>(to_conv.conv_val_ptr), string_len}));

// If the padding is on the right side, write the spaces last.
if (padding_spaces > 0 &&
(to_conv.flags & FormatFlags::LEFT_JUSTIFIED) != 0) {
RET_IF_RESULT_NEGATIVE(writer->write(' ', to_conv.min_width - string_len));
}
return WRITE_OK;
}
Expand Down
44 changes: 39 additions & 5 deletions libc/src/stdio/printf_core/string_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,62 @@
//===----------------------------------------------------------------------===//

#include "src/stdio/printf_core/string_writer.h"
#include "src/__support/CPP/string_view.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/string/memory_utils/memcpy_implementations.h"
#include "src/string/memory_utils/memset_implementations.h"
#include <stddef.h>

namespace __llvm_libc {
namespace printf_core {

void StringWriter::write(const char *__restrict to_write, size_t len) {
void StringWriter::write(cpp::string_view new_string) {
size_t len = new_string.size();
if (len > available_capacity)
len = available_capacity;

if (len > 0) {
inline_memcpy(cur_buffer, to_write, len);
inline_memcpy(cur_buffer, new_string.data(), len);
cur_buffer += len;
available_capacity -= len;
}
}

int write_to_string(void *raw_pointer, const char *__restrict to_write,
size_t len) {
void StringWriter::write(char new_char, size_t len) {
if (len > available_capacity)
len = available_capacity;

if (len > 0) {
inline_memset(cur_buffer, new_char, len);
cur_buffer += len;
available_capacity -= len;
}
}

void StringWriter::write(char new_char) {
if (1 > available_capacity)
return;

cur_buffer[0] = new_char;
++cur_buffer;
available_capacity -= 1;
}

int StringWriter::write_str(void *raw_pointer, cpp::string_view new_string) {
StringWriter *string_writer = reinterpret_cast<StringWriter *>(raw_pointer);
string_writer->write(new_string);
return WRITE_OK;
}

int StringWriter::write_chars(void *raw_pointer, char new_char, size_t len) {
StringWriter *string_writer = reinterpret_cast<StringWriter *>(raw_pointer);
string_writer->write(new_char, len);
return WRITE_OK;
}

int StringWriter::write_char(void *raw_pointer, char new_char) {
StringWriter *string_writer = reinterpret_cast<StringWriter *>(raw_pointer);
string_writer->write(to_write, len);
string_writer->write(new_char);
return WRITE_OK;
}

Expand Down
16 changes: 10 additions & 6 deletions libc/src/stdio/printf_core/string_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRING_WRITER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRING_WRITER_H

#include "src/__support/CPP/string_view.h"
#include "src/string/memory_utils/memcpy_implementations.h"
#include <stddef.h>

Expand All @@ -26,18 +27,21 @@ class StringWriter {
StringWriter(char *__restrict buffer, size_t max_len = ~size_t(0))
: cur_buffer(buffer), available_capacity(max_len) {}

void write(const char *__restrict to_write, size_t len);
void write(cpp::string_view new_string);
void write(char new_char, size_t len);
void write(char new_char);

// Terminate should only be called if the original max length passed to
// snprintf was greater than 0. It writes a null byte to the end of the
// cur_buffer, regardless of available_capacity.
void terminate() { *cur_buffer = '\0'; }
};

// write_to_string treats raw_pointer as a StringWriter and calls its write
// function.
int write_to_string(void *raw_pointer, const char *__restrict to_write,
size_t len);
// These write functions take a StringWriter as a void* in raw_pointer, and
// call the appropriate write function on it.
static int write_str(void *raw_pointer, cpp::string_view new_string);
static int write_chars(void *raw_pointer, char new_char, size_t len);
static int write_char(void *raw_pointer, char new_char);
};

} // namespace printf_core
} // namespace __llvm_libc
Expand Down
4 changes: 3 additions & 1 deletion libc/src/stdio/printf_core/vfprintf_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ int vfprintf_internal(::FILE *__restrict stream, const char *__restrict format,
internal::ArgList &args) {
FileWriter file_writer(stream);
printf_core::Writer writer(reinterpret_cast<void *>(&file_writer),
printf_core::write_to_file);
printf_core::FileWriter::write_str,
printf_core::FileWriter::write_chars,
printf_core::FileWriter::write_char);
return printf_core::printf_main(&writer, format, args);
}

Expand Down
26 changes: 11 additions & 15 deletions libc/src/stdio/printf_core/writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,25 @@
//===----------------------------------------------------------------------===//

#include "writer.h"
#include "src/string/memory_utils/memset_implementations.h"
#include "src/__support/CPP/string_view.h"
#include <stddef.h>

namespace __llvm_libc {
namespace printf_core {

int Writer::write(const char *new_string, size_t length) {
int Writer::write(cpp::string_view new_string) {
chars_written += new_string.size();
return str_write(output, new_string);
}

int Writer::write(char new_char, size_t length) {
chars_written += length;
return raw_write(output, new_string, length);
return chars_write(output, new_char, length);
}

int Writer::write_chars(char new_char, size_t length) {
constexpr size_t BUFF_SIZE = 8;
char buff[BUFF_SIZE];
int result;
inline_memset(buff, new_char, BUFF_SIZE);
while (length > BUFF_SIZE) {
result = write(buff, BUFF_SIZE);
if (result < 0)
return result;
length -= BUFF_SIZE;
}
return write(buff, length);
int Writer::write(char new_char) {
chars_written += 1;
return char_write(output, new_char);
}

} // namespace printf_core
Expand Down
39 changes: 25 additions & 14 deletions libc/src/stdio/printf_core/writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITER_H

#include "src/__support/CPP/string_view.h"
#include <stddef.h>

namespace __llvm_libc {
namespace printf_core {

using WriteFunc = int (*)(void *, const char *__restrict, size_t);
using WriteStrFunc = int (*)(void *, cpp::string_view);
using WriteCharsFunc = int (*)(void *, char, size_t);
using WriteCharFunc = int (*)(void *, char);

class Writer final {
// output is a pointer to the string or file that the writer is meant to write
Expand All @@ -25,23 +28,31 @@ class Writer final {
// length, will copy the number of bytes equal to the length from the char*
// onto the end of output. It should return a positive number or zero on
// success, or a negative number on failure.
WriteFunc raw_write;
WriteStrFunc str_write;
WriteCharsFunc chars_write;
WriteCharFunc char_write;

int chars_written = 0;

public:
Writer(void *init_output, WriteFunc init_raw_write)
: output(init_output), raw_write(init_raw_write) {}

// write will copy length bytes from new_string into output using
// raw_write. It increments chars_written by length always. It returns the
// result of raw_write.
int write(const char *new_string, size_t length);

// write_chars will copy length copies of new_char into output using the write
// function and a statically sized buffer. This is primarily used for padding.
// If write returns a negative value, this will return early with that value.
int write_chars(char new_char, size_t length);
Writer(void *init_output, WriteStrFunc init_str_write,
WriteCharsFunc init_chars_write, WriteCharFunc init_char_write)
: output(init_output), str_write(init_str_write),
chars_write(init_chars_write), char_write(init_char_write) {}

// write will copy new_string into output using str_write. It increments
// chars_written by the length of new_string. It returns the result of
// str_write.
int write(cpp::string_view new_string);

// this version of write will copy length copies of new_char into output using
// chars_write. This is primarily used for padding. It returns the result of
// chars_write.
int write(char new_char, size_t len);

// this version of write will copy just new_char into output. This is often
// used for negative signs. It returns the result of chars_write.
int write(char new_char);

int get_chars_written() { return chars_written; }
};
Expand Down
4 changes: 3 additions & 1 deletion libc/src/stdio/snprintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ LLVM_LIBC_FUNCTION(int, snprintf,
va_end(vlist);
printf_core::StringWriter str_writer(buffer, (buffsz > 0 ? buffsz - 1 : 0));
printf_core::Writer writer(reinterpret_cast<void *>(&str_writer),
printf_core::write_to_string);
printf_core::StringWriter::write_str,
printf_core::StringWriter::write_chars,
printf_core::StringWriter::write_char);

int ret_val = printf_core::printf_main(&writer, format, args);
if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer.
Expand Down
4 changes: 3 additions & 1 deletion libc/src/stdio/sprintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ LLVM_LIBC_FUNCTION(int, sprintf,
va_end(vlist);
printf_core::StringWriter str_writer(buffer);
printf_core::Writer writer(reinterpret_cast<void *>(&str_writer),
printf_core::write_to_string);
printf_core::StringWriter::write_str,
printf_core::StringWriter::write_chars,
printf_core::StringWriter::write_char);

int ret_val = printf_core::printf_main(&writer, format, args);
str_writer.terminate();
Expand Down
2 changes: 2 additions & 0 deletions libc/test/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_libc_unittest(
DEPENDS
libc.src.stdio.printf_core.parser
libc.src.stdio.printf_core.core_structs
libc.src.__support.CPP.string_view
libc.src.__support.arg_list
)

Expand All @@ -21,6 +22,7 @@ add_libc_unittest(
DEPENDS
libc.src.stdio.printf_core.writer
libc.src.stdio.printf_core.string_writer
libc.src.__support.CPP.string_view
)

add_libc_unittest(
Expand Down
30 changes: 6 additions & 24 deletions libc/test/src/stdio/printf_core/converter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ class LlvmLibcPrintfConverterTest : public __llvm_libc::testing::Test {
__llvm_libc::printf_core::StringWriter(str);
__llvm_libc::printf_core::Writer writer = __llvm_libc::printf_core::Writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
__llvm_libc::printf_core::StringWriter::write_str,
__llvm_libc::printf_core::StringWriter::write_chars,
__llvm_libc::printf_core::StringWriter::write_char);
};

TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) {
__llvm_libc::printf_core::FormatSection raw_section;
raw_section.has_conv = false;
raw_section.raw_string = "abc";
raw_section.raw_len = 3;

__llvm_libc::printf_core::convert(&writer, raw_section);

Expand Down Expand Up @@ -196,17 +197,10 @@ TEST_F(LlvmLibcPrintfConverterTest, IntConversionSimple) {
ASSERT_EQ(writer.get_chars_written(), 5);
}

TEST(LlvmLibcPrintfConverterTest, HexConversion) {
char str[20];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);

TEST_F(LlvmLibcPrintfConverterTest, HexConversion) {
__llvm_libc::printf_core::FormatSection section;
section.has_conv = true;
section.raw_string = "%#018x";
section.raw_len = 6;
section.conv_name = 'x';
section.flags = static_cast<__llvm_libc::printf_core::FormatFlags>(
__llvm_libc::printf_core::FormatFlags::ALTERNATE_FORM |
Expand All @@ -220,17 +214,11 @@ TEST(LlvmLibcPrintfConverterTest, HexConversion) {
ASSERT_EQ(writer.get_chars_written(), 18);
}

TEST(LlvmLibcPrintfConverterTest, PointerConversion) {
char str[20];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
TEST_F(LlvmLibcPrintfConverterTest, PointerConversion) {

__llvm_libc::printf_core::FormatSection section;
section.has_conv = true;
section.raw_string = "%p";
section.raw_len = 2;
section.conv_name = 'p';
section.conv_val_ptr = (void *)(0x123456ab);
__llvm_libc::printf_core::convert(&writer, section);
Expand All @@ -240,17 +228,11 @@ TEST(LlvmLibcPrintfConverterTest, PointerConversion) {
ASSERT_EQ(writer.get_chars_written(), 10);
}

TEST(LlvmLibcPrintfConverterTest, OctConversion) {
char str[20];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
TEST_F(LlvmLibcPrintfConverterTest, OctConversion) {

__llvm_libc::printf_core::FormatSection section;
section.has_conv = true;
section.raw_string = "%o";
section.raw_len = 2;
section.conv_name = 'o';
section.conv_val_raw = 01234;
__llvm_libc::printf_core::convert(&writer, section);
Expand Down
139 changes: 72 additions & 67 deletions libc/test/src/stdio/printf_core/parser_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/arg_list.h"
#include "src/stdio/printf_core/parser.h"

Expand All @@ -15,6 +16,8 @@
#include "utils/UnitTest/PrintfMatcher.h"
#include "utils/UnitTest/Test.h"

using __llvm_libc::cpp::string_view;

void init(const char *__restrict str, ...) {
va_list vlist;
va_start(vlist, str);
Expand All @@ -33,7 +36,8 @@ void evaluate(__llvm_libc::printf_core::FormatSection *format_arr,

__llvm_libc::printf_core::Parser parser(str, v);

for (auto cur_section = parser.get_next_section(); cur_section.raw_len > 0;
for (auto cur_section = parser.get_next_section();
!cur_section.raw_string.empty();
cur_section = parser.get_next_section()) {
*format_arr = cur_section;
++format_arr;
Expand All @@ -49,8 +53,8 @@ TEST(LlvmLibcPrintfParserTest, EvalRaw) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = false;
expected.raw_len = 4;
expected.raw_string = str;

expected.raw_string = {str, 4};

ASSERT_FORMAT_EQ(expected, format_arr[0]);
// TODO: add checks that the format_arr after the last one has length 0
Expand All @@ -63,21 +67,21 @@ TEST(LlvmLibcPrintfParserTest, EvalSimple) {

__llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
expected0.has_conv = false;
expected0.raw_len = 5;
expected0.raw_string = str;

expected0.raw_string = {str, 5};

ASSERT_FORMAT_EQ(expected0, format_arr[0]);

expected1.has_conv = true;
expected1.raw_len = 2;
expected1.raw_string = str + 5;

expected1.raw_string = {str + 5, 2};
expected1.conv_name = '%';

ASSERT_FORMAT_EQ(expected1, format_arr[1]);

expected2.has_conv = false;
expected2.raw_len = 5;
expected2.raw_string = str + 7;

expected2.raw_string = {str + 7, 5};

ASSERT_FORMAT_EQ(expected2, format_arr[2]);
}
Expand All @@ -90,8 +94,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArg) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 2;
expected.raw_string = str;

expected.raw_string = {str, 2};
expected.conv_val_raw = arg1;
expected.conv_name = 'd';

Expand All @@ -106,8 +110,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithFlags) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 7;
expected.raw_string = str;

expected.raw_string = {str, 7};
expected.flags = static_cast<__llvm_libc::printf_core::FormatFlags>(
__llvm_libc::printf_core::FormatFlags::FORCE_SIGN |
__llvm_libc::printf_core::FormatFlags::LEFT_JUSTIFIED |
Expand All @@ -128,8 +132,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithWidth) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 4;
expected.raw_string = str;

expected.raw_string = {str, 4};
expected.min_width = 12;
expected.conv_val_raw = arg1;
expected.conv_name = 'd';
Expand All @@ -145,8 +149,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithPrecision) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 5;
expected.raw_string = str;

expected.raw_string = {str, 5};
expected.precision = 34;
expected.conv_val_raw = arg1;
expected.conv_name = 'd';
Expand All @@ -162,8 +166,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithTrivialPrecision) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 3;
expected.raw_string = str;

expected.raw_string = {str, 3};
expected.precision = 0;
expected.conv_val_raw = arg1;
expected.conv_name = 'd';
Expand All @@ -179,8 +183,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithShortLengthModifier) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 3;
expected.raw_string = str;

expected.raw_string = {str, 3};
expected.length_modifier = __llvm_libc::printf_core::LengthModifier::h;
expected.conv_val_raw = arg1;
expected.conv_name = 'd';
Expand All @@ -196,8 +200,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithLongLengthModifier) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 4;
expected.raw_string = str;

expected.raw_string = {str, 4};
expected.length_modifier = __llvm_libc::printf_core::LengthModifier::ll;
expected.conv_val_raw = arg1;
expected.conv_name = 'd';
Expand All @@ -213,8 +217,8 @@ TEST(LlvmLibcPrintfParserTest, EvalOneArgWithAllOptions) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 11;
expected.raw_string = str;

expected.raw_string = {str, 11};
expected.flags = static_cast<__llvm_libc::printf_core::FormatFlags>(
__llvm_libc::printf_core::FormatFlags::LEFT_JUSTIFIED |
__llvm_libc::printf_core::FormatFlags::LEADING_ZEROES |
Expand All @@ -238,24 +242,24 @@ TEST(LlvmLibcPrintfParserTest, EvalThreeArgs) {

__llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
expected0.has_conv = true;
expected0.raw_len = 2;
expected0.raw_string = str;

expected0.raw_string = {str, 2};
expected0.conv_val_raw = arg1;
expected0.conv_name = 'd';

ASSERT_FORMAT_EQ(expected0, format_arr[0]);

expected1.has_conv = true;
expected1.raw_len = 2;
expected1.raw_string = str + 2;

expected1.raw_string = {str + 2, 2};
expected1.conv_val_raw = __llvm_libc::cpp::bit_cast<uint64_t>(arg2);
expected1.conv_name = 'f';

ASSERT_FORMAT_EQ(expected1, format_arr[1]);

expected2.has_conv = true;
expected2.raw_len = 2;
expected2.raw_string = str + 4;

expected2.raw_string = {str + 4, 2};
expected2.conv_val_ptr = const_cast<char *>(arg3);
expected2.conv_name = 's';

Expand All @@ -272,8 +276,8 @@ TEST(LlvmLibcPrintfParserTest, IndexModeOneArg) {

__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 4;
expected.raw_string = str;

expected.raw_string = {str, 4};
expected.conv_val_raw = arg1;
expected.conv_name = 'd';

Expand All @@ -290,24 +294,24 @@ TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsSequential) {

__llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
expected0.has_conv = true;
expected0.raw_len = 4;
expected0.raw_string = str;

expected0.raw_string = {str, 4};
expected0.conv_val_raw = arg1;
expected0.conv_name = 'd';

ASSERT_FORMAT_EQ(expected0, format_arr[0]);

expected1.has_conv = true;
expected1.raw_len = 4;
expected1.raw_string = str + 4;

expected1.raw_string = {str + 4, 4};
expected1.conv_val_raw = __llvm_libc::cpp::bit_cast<uint64_t>(arg2);
expected1.conv_name = 'f';

ASSERT_FORMAT_EQ(expected1, format_arr[1]);

expected2.has_conv = true;
expected2.raw_len = 4;
expected2.raw_string = str + 8;

expected2.raw_string = {str + 8, 4};
expected2.conv_val_ptr = const_cast<char *>(arg3);
expected2.conv_name = 's';

Expand All @@ -324,24 +328,24 @@ TEST(LlvmLibcPrintfParserTest, IndexModeThreeArgsReverse) {

__llvm_libc::printf_core::FormatSection expected0, expected1, expected2;
expected0.has_conv = true;
expected0.raw_len = 4;
expected0.raw_string = str;

expected0.raw_string = {str, 4};
expected0.conv_val_raw = arg1;
expected0.conv_name = 'd';

ASSERT_FORMAT_EQ(expected0, format_arr[0]);

expected1.has_conv = true;
expected1.raw_len = 4;
expected1.raw_string = str + 4;

expected1.raw_string = {str + 4, 4};
expected1.conv_val_raw = __llvm_libc::cpp::bit_cast<uint64_t>(arg2);
expected1.conv_name = 'f';

ASSERT_FORMAT_EQ(expected1, format_arr[1]);

expected2.has_conv = true;
expected2.raw_len = 4;
expected2.raw_string = str + 8;

expected2.raw_string = {str + 8, 4};
expected2.conv_val_ptr = const_cast<char *>(arg3);
expected2.conv_name = 's';

Expand All @@ -358,8 +362,9 @@ TEST(LlvmLibcPrintfParserTest, IndexModeTenArgsRandom) {
for (size_t i = 0; i < 10; ++i) {
__llvm_libc::printf_core::FormatSection expected;
expected.has_conv = true;
expected.raw_len = 4 + (i >= 9 ? 1 : 0);
expected.raw_string = str + (4 * i);

expected.raw_string = {str + (4 * i),
static_cast<size_t>(4 + (i >= 9 ? 1 : 0))};
expected.conv_val_raw = i + 1;
expected.conv_name = 'd';
EXPECT_FORMAT_EQ(expected, format_arr[i]);
Expand All @@ -380,42 +385,42 @@ TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
expected9;

expected0.has_conv = false;
expected0.raw_len = 12;
expected0.raw_string = str;

expected0.raw_string = {str, 12};

EXPECT_FORMAT_EQ(expected0, format_arr[0]);

expected1.has_conv = true;
expected1.raw_len = 6;
expected1.raw_string = str + 12;

expected1.raw_string = {str + 12, 6};
expected1.length_modifier = __llvm_libc::printf_core::LengthModifier::ll;
expected1.conv_val_raw = arg3;
expected1.conv_name = 'u';

EXPECT_FORMAT_EQ(expected1, format_arr[1]);

expected2.has_conv = false;
expected2.raw_len = 1;
expected2.raw_string = str + 18;

expected2.raw_string = {str + 18, 1};

EXPECT_FORMAT_EQ(expected2, format_arr[2]);

expected3.has_conv = true;
expected3.raw_len = 2;
expected3.raw_string = str + 19;

expected3.raw_string = {str + 19, 2};
expected3.conv_name = '%';

EXPECT_FORMAT_EQ(expected3, format_arr[3]);

expected4.has_conv = false;
expected4.raw_len = 1;
expected4.raw_string = str + 21;

expected4.raw_string = {str + 21, 1};

EXPECT_FORMAT_EQ(expected4, format_arr[4]);

expected5.has_conv = true;
expected5.raw_len = 8;
expected5.raw_string = str + 22;

expected5.raw_string = {str + 22, 8};
expected5.flags = __llvm_libc::printf_core::FormatFlags::SPACE_PREFIX;
expected5.min_width = arg4;
expected5.conv_val_raw = __llvm_libc::cpp::bit_cast<uint64_t>(arg2);
Expand All @@ -424,14 +429,14 @@ TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
EXPECT_FORMAT_EQ(expected5, format_arr[5]);

expected6.has_conv = false;
expected6.raw_len = 1;
expected6.raw_string = str + 30;

expected6.raw_string = {str + 30, 1};

EXPECT_FORMAT_EQ(expected6, format_arr[6]);

expected7.has_conv = true;
expected7.raw_len = 9;
expected7.raw_string = str + 31;

expected7.raw_string = {str + 31, 9};
expected7.flags = __llvm_libc::printf_core::FormatFlags::SPACE_PREFIX;
expected7.precision = arg4;
expected7.conv_val_raw = __llvm_libc::cpp::bit_cast<uint64_t>(arg2);
Expand All @@ -440,14 +445,14 @@ TEST(LlvmLibcPrintfParserTest, IndexModeComplexParsing) {
EXPECT_FORMAT_EQ(expected7, format_arr[7]);

expected8.has_conv = false;
expected8.raw_len = 1;
expected8.raw_string = str + 40;

expected8.raw_string = {str + 40, 1};

EXPECT_FORMAT_EQ(expected8, format_arr[8]);

expected9.has_conv = true;
expected9.raw_len = 7;
expected9.raw_string = str + 41;

expected9.raw_string = {str + 41, 7};
expected9.min_width = 1;
expected9.precision = 1;
expected9.conv_val_raw = arg1;
Expand Down
124 changes: 61 additions & 63 deletions libc/test/src/stdio/printf_core/string_writer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,34 @@
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/string_view.h"
#include "src/stdio/printf_core/string_writer.h"
#include "src/stdio/printf_core/writer.h"

#include "utils/UnitTest/Test.h"

using __llvm_libc::cpp::string_view;

__llvm_libc::printf_core::Writer get_writer(void *str_writer) {
return __llvm_libc::printf_core::Writer(
str_writer, __llvm_libc::printf_core::StringWriter::write_str,
__llvm_libc::printf_core::StringWriter::write_chars,
__llvm_libc::printf_core::StringWriter::write_char);
}

TEST(LlvmLibcPrintfStringWriterTest, Constructor) {
char str[10];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
}

TEST(LlvmLibcPrintfStringWriterTest, Write) {
char str[4] = {'D', 'E', 'F', 'G'};
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write("abc", 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write({"abc", 3});

EXPECT_EQ(str[3], 'G');
// This null terminates the string. The writer has no indication when the
Expand All @@ -42,12 +50,11 @@ TEST(LlvmLibcPrintfStringWriterTest, Write) {
TEST(LlvmLibcPrintfStringWriterTest, WriteMultipleTimes) {
char str[10];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write("abc", 3);
writer.write("DEF", 3);
writer.write("1234", 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write({"abc", 3});
writer.write({"DEF", 3});
writer.write({"1234", 3});

str_writer.terminate();

Expand All @@ -58,10 +65,9 @@ TEST(LlvmLibcPrintfStringWriterTest, WriteMultipleTimes) {
TEST(LlvmLibcPrintfStringWriterTest, WriteChars) {
char str[4] = {'D', 'E', 'F', 'G'};
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write_chars('a', 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write('a', 3);

EXPECT_EQ(str[3], 'G');
str_writer.terminate();
Expand All @@ -73,12 +79,11 @@ TEST(LlvmLibcPrintfStringWriterTest, WriteChars) {
TEST(LlvmLibcPrintfStringWriterTest, WriteCharsMultipleTimes) {
char str[10];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write_chars('a', 3);
writer.write_chars('D', 3);
writer.write_chars('1', 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write('a', 3);
writer.write('D', 3);
writer.write('1', 3);

str_writer.terminate();

Expand All @@ -89,10 +94,9 @@ TEST(LlvmLibcPrintfStringWriterTest, WriteCharsMultipleTimes) {
TEST(LlvmLibcPrintfStringWriterTest, WriteManyChars) {
char str[100];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write_chars('Z', 99);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write('Z', 99);

str_writer.terminate();

Expand All @@ -113,13 +117,12 @@ TEST(LlvmLibcPrintfStringWriterTest, WriteManyChars) {
TEST(LlvmLibcPrintfStringWriterTest, MixedWrites) {
char str[13];
__llvm_libc::printf_core::StringWriter str_writer(str);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write_chars('a', 3);
writer.write("DEF", 3);
writer.write_chars('1', 3);
writer.write("456", 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});

str_writer.terminate();

Expand All @@ -130,10 +133,9 @@ TEST(LlvmLibcPrintfStringWriterTest, MixedWrites) {
TEST(LlvmLibcPrintfStringWriterTest, WriteWithMaxLength) {
char str[11];
__llvm_libc::printf_core::StringWriter str_writer(str, 10);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write("abcDEF123456", 12);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write({"abcDEF123456", 12});

str_writer.terminate();

Expand All @@ -144,11 +146,10 @@ TEST(LlvmLibcPrintfStringWriterTest, WriteWithMaxLength) {
TEST(LlvmLibcPrintfStringWriterTest, WriteCharsWithMaxLength) {
char str[11];
__llvm_libc::printf_core::StringWriter str_writer(str, 10);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));

writer.write_chars('1', 15);
writer.write('1', 15);

str_writer.terminate();

Expand All @@ -159,13 +160,12 @@ TEST(LlvmLibcPrintfStringWriterTest, WriteCharsWithMaxLength) {
TEST(LlvmLibcPrintfStringWriterTest, MixedWriteWithMaxLength) {
char str[11];
__llvm_libc::printf_core::StringWriter str_writer(str, 10);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write_chars('a', 3);
writer.write("DEF", 3);
writer.write_chars('1', 3);
writer.write("456", 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});

str_writer.terminate();

Expand All @@ -176,15 +176,14 @@ TEST(LlvmLibcPrintfStringWriterTest, MixedWriteWithMaxLength) {
TEST(LlvmLibcPrintfStringWriterTest, StringWithMaxLengthOne) {
char str[1];
__llvm_libc::printf_core::StringWriter str_writer(str, 0);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
// This is because the max length should be at most 1 less than the size of
// the buffer it's writing to.
writer.write_chars('a', 3);
writer.write("DEF", 3);
writer.write_chars('1', 3);
writer.write("456", 3);
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});

str_writer.terminate();

Expand All @@ -194,13 +193,12 @@ TEST(LlvmLibcPrintfStringWriterTest, StringWithMaxLengthOne) {

TEST(LlvmLibcPrintfStringWriterTest, NullStringWithZeroMaxLength) {
__llvm_libc::printf_core::StringWriter str_writer(nullptr, 0);
__llvm_libc::printf_core::Writer writer(
reinterpret_cast<void *>(&str_writer),
__llvm_libc::printf_core::write_to_string);
writer.write_chars('a', 3);
writer.write("DEF", 3);
writer.write_chars('1', 3);
writer.write("456", 3);
__llvm_libc::printf_core::Writer writer =
get_writer(reinterpret_cast<void *>(&str_writer));
writer.write('a', 3);
writer.write({"DEF", 3});
writer.write('1', 3);
writer.write({"456", 3});

ASSERT_EQ(writer.get_chars_written(), 12);
}
2 changes: 1 addition & 1 deletion libc/utils/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ target_link_libraries(LibcPrintfHelpers LibcUnitTest)
add_dependencies(
LibcPrintfHelpers
LibcUnitTest
libc.src.__support.CPP.uint128
libc.src.__support.FPUtil.fputil #FPBits
libc.src.stdio.printf_core.core_structs
libc.utils.UnitTest.string_utils
)
11 changes: 7 additions & 4 deletions libc/utils/UnitTest/PrintfMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include "PrintfMatcher.h"

#include "src/__support/CPP/UInt128.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/stdio/printf_core/core_structs.h"

#include "utils/UnitTest/StringUtils.h"
Expand Down Expand Up @@ -37,8 +37,8 @@ namespace {
break

void display(testutils::StreamWrapper &stream, FormatSection form) {
stream << "Raw String (len " << form.raw_len << "): \"";
for (size_t i = 0; i < form.raw_len; ++i) {
stream << "Raw String (len " << form.raw_string.size() << "): \"";
for (size_t i = 0; i < form.raw_string.size(); ++i) {
stream << form.raw_string[i];
}
stream << "\"";
Expand Down Expand Up @@ -72,7 +72,10 @@ void display(testutils::StreamWrapper &stream, FormatSection form) {
reinterpret_cast<uintptr_t>(form.conv_val_ptr))
<< "\n";
else if (form.conv_name != '%')
stream << "\tvalue: " << int_to_hex<UInt128>(form.conv_val_raw) << "\n";
stream << "\tvalue: "
<< int_to_hex<fputil::FPBits<long double>::UIntType>(
form.conv_val_raw)
<< "\n";
}
}
} // anonymous namespace
Expand Down