Reduce symbol sizes and simplify iterator use

This commit is contained in:
Victor Zverovich 2020-07-09 08:41:05 -07:00
parent c5adfc51c5
commit b998e0f30b
10 changed files with 53 additions and 44 deletions

View File

@ -608,8 +608,7 @@ template <typename CompiledFormat, typename... Args,
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer;
using context = buffer_context<Char>;
detail::buffer<Char>& base = buffer;
detail::cf::vformat_to<context>(std::back_inserter(base), cf,
detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf,
make_format_args<context>(args...));
return to_string(buffer);
}

View File

@ -722,6 +722,17 @@ class container_buffer : public buffer<typename Container::value_type> {
: buffer<typename Container::value_type>(c.size()), container_(c) {}
};
// An output iterator that appends to the buffer.
// It is used to reduce symbol sizes for the common case.
template <typename T>
class buffer_appender : public std::back_insert_iterator<buffer<T>> {
public:
explicit buffer_appender(buffer<T>& buf)
: std::back_insert_iterator<buffer<T>>(buf) {}
buffer_appender(std::back_insert_iterator<buffer<T>> it)
: std::back_insert_iterator<buffer<T>>(it) {}
};
// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
inline Container& get_container(std::back_insert_iterator<Container> it) {
@ -1356,13 +1367,13 @@ template <typename OutputIt, typename Char> class basic_format_context {
template <typename Char>
using buffer_context =
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>;
basic_format_context<detail::buffer_appender<Char>, Char>;
using format_context = buffer_context<char>;
using wformat_context = buffer_context<wchar_t>;
// Workaround a bug in gcc: https://stackoverflow.com/q/62767544/471164.
// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
#define FMT_BUFFER_CONTEXT(Char) \
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>
basic_format_context<detail::buffer_appender<Char>, Char>
/**
\rst
@ -1772,7 +1783,7 @@ std::basic_string<Char> vformat(
FMT_API std::string vformat(string_view format_str, format_args args);
template <typename Char>
typename FMT_BUFFER_CONTEXT(Char)::iterator vformat_to(
buffer_appender<Char> vformat_to(
buffer<Char>& buf, basic_string_view<Char> format_str,
basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args);

View File

@ -1296,6 +1296,19 @@ FMT_FUNC const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
return next;
}
struct stringifier {
template <typename T> FMT_INLINE std::string operator()(T value) const {
return to_string(value);
}
std::string operator()(basic_format_arg<format_context>::handle h) const {
memory_buffer buf;
format_parse_context parse_ctx({});
format_context format_ctx(buffer_appender<char>(buf), {}, {});
h.format(parse_ctx, format_ctx);
return to_string(buf);
}
};
} // namespace detail
template <> struct formatter<detail::bigint> {
@ -1384,20 +1397,6 @@ FMT_FUNC void report_system_error(int error_code,
report_error(format_system_error, error_code, message);
}
struct stringifier {
template <typename T> FMT_INLINE std::string operator()(T value) const {
return to_string(value);
}
std::string operator()(basic_format_arg<format_context>::handle h) const {
memory_buffer buf;
detail::buffer<char>& base = buf;
format_parse_context parse_ctx({});
format_context format_ctx(std::back_inserter(base), {}, {});
h.format(parse_ctx, format_ctx);
return to_string(buf);
}
};
FMT_FUNC std::string detail::vformat(string_view format_str, format_args args) {
if (format_str.size() == 2 && equal2(format_str.data(), "{}")) {
auto arg = args.get(0);

View File

@ -371,6 +371,11 @@ reserve(std::back_insert_iterator<Container> it, size_t n) {
return make_checked(get_data(c) + size, n);
}
template <typename T>
inline checked_ptr<T> reserve(buffer_appender<T> it, size_t n) {
return reserve(std::back_insert_iterator<buffer<T>>(it), n);
}
template <typename Iterator> inline Iterator& reserve(Iterator& it, size_t) {
return it;
}
@ -2933,7 +2938,7 @@ class arg_formatter : public arg_formatter_base<OutputIt, Char> {
template <typename OutputIt, typename Char>
using arg_formatter FMT_DEPRECATED_ALIAS =
detail::arg_formatter<OutputIt, Char>;
detail::arg_formatter<OutputIt, Char>;
/**
An error returned by an operating system or a language runtime,
@ -3445,11 +3450,11 @@ std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
}
template <typename Char>
typename buffer_context<Char>::iterator detail::vformat_to(
detail::buffer_appender<Char> detail::vformat_to(
detail::buffer<Char>& buf, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
using af = arg_formatter<typename buffer_context<Char>::iterator, Char>;
return vformat_to<af>(std::back_inserter(buf), to_string_view(format_str),
return vformat_to<af>(buffer_appender<Char>(buf), to_string_view(format_str),
args);
}

View File

@ -21,7 +21,7 @@ typename buffer_context<Char>::iterator vformat_to(
basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
using af = arg_formatter<typename buffer_context<Char>::iterator, Char>;
return vformat_to<af>(std::back_inserter(buf), to_string_view(format_str),
return vformat_to<af>(buffer_appender<Char>(buf), to_string_view(format_str),
args, detail::locale_ref(loc));
}

View File

@ -53,10 +53,7 @@ template <typename Char> struct formatter<test_struct, Char> {
return ctx.begin();
}
typedef std::back_insert_iterator<buffer<Char>> iterator;
auto format(test_struct, basic_format_context<iterator, char>& ctx)
-> decltype(ctx.out()) {
auto format(test_struct, format_context& ctx) -> decltype(ctx.out()) {
const Char* test = "test";
return std::copy_n(test, std::strlen(test), ctx.out());
}
@ -377,9 +374,9 @@ struct check_custom {
test_buffer() : fmt::detail::buffer<char>(data, 0, 10) {}
void grow(size_t) {}
} buffer;
fmt::detail::buffer<char>& base = buffer;
fmt::format_parse_context parse_ctx("");
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
fmt::format_context ctx{
fmt::detail::buffer_appender<char>(buffer), fmt::format_args()};
h.format(parse_ctx, ctx);
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
return test_result();
@ -388,8 +385,8 @@ struct check_custom {
TEST(ArgTest, CustomArg) {
test_struct test;
typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
visitor;
using visitor =
mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>;
testing::StrictMock<visitor> v;
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
fmt::visit_format_arg(v, make_arg<fmt::format_context>(test));

View File

@ -39,10 +39,9 @@ class custom_arg_formatter
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
fmt::detail::buffer<char>& base = buffer;
// Pass custom argument formatter as a template arg to vwrite.
fmt::vformat_to<custom_arg_formatter>(std::back_inserter(base), format_str,
args);
fmt::vformat_to<custom_arg_formatter>(
fmt::detail::buffer_appender<char>(buffer), format_str, args);
return std::string(buffer.data(), buffer.size());
}

View File

@ -38,9 +38,9 @@ namespace std {
template<class Out, class charT> class basic_format_context;
using format_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::detail::buffer<char>>, char>;
/* unspecified */ fmt::detail::buffer_appender<char>, char>;
using wformat_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::detail::buffer<wchar_t>>, wchar_t>;
/* unspecified */ fmt::detail::buffer_appender<wchar_t>, wchar_t>;
template<class T, class charT = char> struct formatter {
formatter() = delete;
@ -714,7 +714,7 @@ string vformat(string_view fmt, format_args args) {
fmt::detail::buffer<char>& buf = mbuf;
using af = detail::arg_formatter<fmt::format_context::iterator, char>;
detail::format_handler<af, char, format_context>
h(std::back_inserter(buf), fmt, args, {});
h(fmt::detail::buffer_appender<char>(buf), fmt, args, {});
fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h);
return to_string(mbuf);
}

View File

@ -1844,10 +1844,9 @@ class mock_arg_formatter
};
static void custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
fmt::detail::buffer<char>& base = buffer;
fmt::vformat_to<mock_arg_formatter>(std::back_inserter(base), format_str,
args);
fmt::memory_buffer buf;
fmt::vformat_to<mock_arg_formatter>(fmt::detail::buffer_appender<char>(buf),
format_str, args);
}
template <typename... Args>

View File

@ -75,8 +75,8 @@ struct test_arg_formatter
TEST(OStreamTest, CustomArg) {
fmt::memory_buffer buffer;
fmt::detail::buffer<char>& base = buffer;
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
fmt::format_context ctx(
fmt::detail::buffer_appender<char>{buffer}, fmt::format_args());
fmt::format_specs spec;
test_arg_formatter af(ctx, spec);
fmt::visit_format_arg(