Commit 2b415b7a authored by ToolsDevler's avatar ToolsDevler Committed by Victor Zverovich

Restructure printf_arg_formatter to make it customizable

parent 5d755d0a
...@@ -197,9 +197,7 @@ using internal::printf; // For printing into memory_buffer. ...@@ -197,9 +197,7 @@ using internal::printf; // For printing into memory_buffer.
template <typename Range> class printf_arg_formatter; template <typename Range> class printf_arg_formatter;
template <typename OutputIt, typename Char, template <typename OutputIt, typename Char>
typename ArgFormatter =
printf_arg_formatter<back_insert_range<internal::buffer<Char>>>>
class basic_printf_context; class basic_printf_context;
/** /**
...@@ -212,12 +210,12 @@ class printf_arg_formatter ...@@ -212,12 +210,12 @@ class printf_arg_formatter
: public internal::function< : public internal::function<
typename internal::arg_formatter_base<Range>::iterator>, typename internal::arg_formatter_base<Range>::iterator>,
public internal::arg_formatter_base<Range> { public internal::arg_formatter_base<Range> {
public:
typedef decltype(internal::declval<Range>().begin()) iterator;
private: private:
typedef typename Range::value_type char_type; typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base; typedef internal::arg_formatter_base<Range> base;
typedef basic_printf_context<iterator, char_type, printf_arg_formatter> typedef basic_printf_context<iterator, char_type> context_type;
context_type;
context_type& context_; context_type& context_;
...@@ -328,7 +326,7 @@ template <typename T> struct printf_formatter { ...@@ -328,7 +326,7 @@ template <typename T> struct printf_formatter {
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template <typename OutputIt, typename Char, typename ArgFormatter> template <typename OutputIt, typename Char>
class basic_printf_context { class basic_printf_context {
public: public:
/** The character type for the output. */ /** The character type for the output. */
...@@ -379,11 +377,12 @@ class basic_printf_context { ...@@ -379,11 +377,12 @@ class basic_printf_context {
} }
/** Formats stored arguments and writes the output to the range. */ /** Formats stored arguments and writes the output to the range. */
template<typename ArgFormatter = printf_arg_formatter<back_insert_range<internal::buffer<Char>>>>
OutputIt format(); OutputIt format();
}; };
template <typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char>
void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec, void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& spec,
const Char*& it, const Char*& it,
const Char* end) { const Char* end) {
for (; it != end; ++it) { for (; it != end; ++it) {
...@@ -409,9 +408,9 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec, ...@@ -409,9 +408,9 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs& spec,
} }
} }
template <typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char>
typename basic_printf_context<OutputIt, Char, AF>::format_arg typename basic_printf_context<OutputIt, Char>::format_arg
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) { basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
if (arg_index == std::numeric_limits<unsigned>::max()) if (arg_index == std::numeric_limits<unsigned>::max())
arg_index = parse_ctx_.next_arg_id(); arg_index = parse_ctx_.next_arg_id();
else else
...@@ -419,8 +418,8 @@ basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) { ...@@ -419,8 +418,8 @@ basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
return internal::get_arg(*this, arg_index); return internal::get_arg(*this, arg_index);
} }
template <typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char>
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header( unsigned basic_printf_context<OutputIt, Char>::parse_header(
const Char*& it, const Char* end, format_specs& spec) { const Char*& it, const Char* end, format_specs& spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max(); unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it; char_type c = *it;
...@@ -457,8 +456,9 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header( ...@@ -457,8 +456,9 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
return arg_index; return arg_index;
} }
template <typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char>
OutputIt basic_printf_context<OutputIt, Char, AF>::format() { template <typename ArgFormatter>
OutputIt basic_printf_context<OutputIt, Char>::format() {
auto out = this->out(); auto out = this->out();
const Char* start = parse_ctx_.begin(); const Char* start = parse_ctx_.begin();
const Char* end = parse_ctx_.end(); const Char* end = parse_ctx_.end();
...@@ -567,7 +567,7 @@ OutputIt basic_printf_context<OutputIt, Char, AF>::format() { ...@@ -567,7 +567,7 @@ OutputIt basic_printf_context<OutputIt, Char, AF>::format() {
start = it; start = it;
// Format argument. // Format argument.
visit_format_arg(AF(out, spec, *this), arg); visit_format_arg(ArgFormatter(out, spec, *this), arg);
} }
return std::copy(start, it, out); return std::copy(start, it, out);
} }
...@@ -712,6 +712,19 @@ inline int vfprintf( ...@@ -712,6 +712,19 @@ inline int vfprintf(
return static_cast<int>(buffer.size()); return static_cast<int>(buffer.size());
} }
/** Formats arguments and writes the output to the range. */
template <typename ArgFormatter, typename Char,
typename Context = basic_printf_context<
typename ArgFormatter::iterator, Char>>
typename ArgFormatter::iterator vprintf(internal::buffer<Char>& out,
basic_string_view<Char> format_str,
basic_format_args<Context> args) {
typename ArgFormatter::iterator iter(out);
Context(iter, format_str, args).template format<ArgFormatter>();
return iter;
}
/** /**
\rst \rst
Prints formatted data to the stream *os*. Prints formatted data to the stream *os*.
......
...@@ -554,3 +554,51 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) { ...@@ -554,3 +554,51 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) {
fmt::make_wprintf_args(42, L"something"))); fmt::make_wprintf_args(42, L"something")));
#endif #endif
} }
typedef fmt::printf_arg_formatter<
fmt::back_insert_range<fmt::internal::buffer<char>>> formatter_t;
typedef fmt::basic_printf_context<formatter_t::iterator, char> context_t;
// A custom printf argument formatter that doesn't print `-` for floating-point
// values rounded to 0.
class custom_printf_arg_formatter : public formatter_t {
public:
using formatter_t::iterator;
custom_printf_arg_formatter(formatter_t::iterator iter, formatter_t::format_specs& spec, context_t& ctx)
: formatter_t(iter, spec, ctx) {}
using formatter_t::operator();
#if FMT_MSC_VER > 0 && FMT_MSC_VER <= 1804
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
iterator operator()(T value) {
#else
iterator operator()(double value) {
#endif
// Comparing a float to 0.0 is safe.
if (round(value * pow(10, spec()->precision)) == 0.0) value = 0;
return formatter_t::operator()(value);
}
};
typedef fmt::basic_format_args<context_t> format_args_t;
std::string custom_vformat(fmt::string_view format_str, format_args_t args) {
fmt::memory_buffer buffer;
fmt::vprintf<custom_printf_arg_formatter>(buffer, format_str, args);
return std::string(buffer.data(), buffer.size());
}
template <typename... Args>
std::string custom_format(const char* format_str, const Args&... args) {
auto va = fmt::make_printf_args (args...);
return custom_vformat(format_str, va);
}
TEST(CustomFormatterTest, Format) {
EXPECT_EQ("0.00", custom_format("%.2f", -.00001));
EXPECT_EQ("0.00", custom_format("%.2f", .00001));
EXPECT_EQ("1.00", custom_format("%.2f", 1.00001));
EXPECT_EQ("-1.00", custom_format("%.2f", -1.00001));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment