Skip to content

Commit

Permalink
eliminate one case where basic_print_context would copy a string into…
Browse files Browse the repository at this point in the history
… a fmt::basic_memory_buffer character by character instead of using fmt::basic_memory_buffer::append
  • Loading branch information
rimathia committed Nov 8, 2020
1 parent 038057e commit d566465
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
40 changes: 37 additions & 3 deletions include/fmt/printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,40 @@ template <typename T> struct printf_formatter {
}
};

namespace detail {
template <typename, typename = void>
struct has_container_append : std::false_type {};

template <typename OutputIt>
struct has_container_append<
OutputIt,
void_t<decltype(
get_container(std::declval<OutputIt>())
.append(std::declval<
const typename OutputIt::container_type::value_type*>(),
std::declval<const typename OutputIt::container_type::
value_type*>()))>> : std::true_type {};

template <typename OutputIt>
enable_if_t<has_container_append<OutputIt>::value, OutputIt>
container_aware_copy(const typename OutputIt::container_type::value_type* first,
const typename OutputIt::container_type::value_type* last,
OutputIt out) {
detail::get_container(out).append(first, last);
return out;
}

static_assert(has_container_append<buffer_appender<char>>::value,
"has_container_append doesn't work");

template <typename OutputIt, typename Char>
enable_if_t<!has_container_append<OutputIt>::value, OutputIt>
container_aware_copy(const Char* first, const Char* last, OutputIt out) {
return std::copy(first, last, out);
}

} // namespace detail

/**
This template formats data and writes the output through an output iterator.
*/
Expand Down Expand Up @@ -477,11 +511,11 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
char_type c = *it++;
if (c != '%') continue;
if (it != end && *it == c) {
out = std::copy(start, it, out);
out = container_aware_copy(start, it, out);
start = ++it;
continue;
}
out = std::copy(start, it - 1, out);
out = container_aware_copy(start, it - 1, out);

format_specs specs;
specs.align = align::right;
Expand Down Expand Up @@ -593,7 +627,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
// Format argument.
out = visit_format_arg(ArgFormatter(out, specs, *this), arg);
}
return std::copy(start, it, out);
return container_aware_copy(start, it, out);
}

template <typename Char>
Expand Down
22 changes: 19 additions & 3 deletions test/printf-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,26 @@ TEST(PrintfTest, PrintfDetermineOutputSize) {
const auto format_arg = "Hello";
const auto expected_size = fmt::sprintf(format_string, format_arg).size();

EXPECT_EQ((truncated_printf_context(
EXPECT_EQ(expected_size,
(truncated_printf_context(
fmt::detail::truncating_iterator<backit>(it, 0), format_string,
fmt::make_format_args<truncated_printf_context>(format_arg))
.format()
.count()),
expected_size);
.count()));
}

TEST(PrintfTest, PrintfAppendToBuffer) {
using backit = std::back_insert_iterator<fmt::basic_memory_buffer<char>>;
using context = fmt::basic_printf_context<backit, char>;

const auto format_string = "%s";
const char* format_arg = "Hello";
fmt::basic_memory_buffer<char> buffer;
context(std::back_inserter(buffer), format_string,
fmt::make_format_args<context>(format_arg))
.format();

std::string result(std::begin(buffer), std::end(buffer));

EXPECT_EQ(std::string("Hello"), result);
}

0 comments on commit d566465

Please sign in to comment.