mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Make argument formatter customizable
This commit is contained in:
@ -371,7 +371,13 @@ class BasicWriter;
|
|||||||
typedef BasicWriter<char> Writer;
|
typedef BasicWriter<char> Writer;
|
||||||
typedef BasicWriter<wchar_t> WWriter;
|
typedef BasicWriter<wchar_t> WWriter;
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
|
class BasicArgFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharType,
|
||||||
|
typename ArgFormatter = internal::BasicArgFormatter<CharType> >
|
||||||
class BasicFormatter;
|
class BasicFormatter;
|
||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
@ -1885,7 +1891,7 @@ class PrintfFormatter : private FormatterBase {
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
/** This template formats data and writes the output to a writer. */
|
/** This template formats data and writes the output to a writer. */
|
||||||
template <typename CharType>
|
template <typename CharType, typename ArgFormatter>
|
||||||
class BasicFormatter : private internal::FormatterBase {
|
class BasicFormatter : private internal::FormatterBase {
|
||||||
public:
|
public:
|
||||||
/** The character type for the output. */
|
/** The character type for the output. */
|
||||||
@ -3475,9 +3481,9 @@ void check_sign(const Char *&s, const Arg &arg) {
|
|||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char, typename AF>
|
||||||
inline internal::Arg BasicFormatter<Char>::get_arg(
|
inline internal::Arg BasicFormatter<Char, AF>::get_arg(
|
||||||
BasicStringRef<Char> arg_name, const char *&error) {
|
BasicStringRef<Char> arg_name, const char *&error) {
|
||||||
if (check_no_auto_index(error)) {
|
if (check_no_auto_index(error)) {
|
||||||
map_.init(args());
|
map_.init(args());
|
||||||
const internal::Arg *arg = map_.find(arg_name);
|
const internal::Arg *arg = map_.find(arg_name);
|
||||||
@ -3488,8 +3494,8 @@ inline internal::Arg BasicFormatter<Char>::get_arg(
|
|||||||
return internal::Arg();
|
return internal::Arg();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char, typename AF>
|
||||||
inline internal::Arg BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s) {
|
||||||
const char *error = 0;
|
const char *error = 0;
|
||||||
internal::Arg arg = *s < '0' || *s > '9' ?
|
internal::Arg arg = *s < '0' || *s > '9' ?
|
||||||
next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error);
|
next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error);
|
||||||
@ -3500,8 +3506,8 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char, typename AF>
|
||||||
inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) {
|
inline internal::Arg BasicFormatter<Char, AF>::parse_arg_name(const Char *&s) {
|
||||||
assert(internal::is_name_start(*s));
|
assert(internal::is_name_start(*s));
|
||||||
const Char *start = s;
|
const Char *start = s;
|
||||||
Char c;
|
Char c;
|
||||||
@ -3515,8 +3521,8 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char, typename ArgFormatter>
|
||||||
const Char *BasicFormatter<Char>::format(
|
const Char *BasicFormatter<Char, ArgFormatter>::format(
|
||||||
const Char *&format_str, const internal::Arg &arg) {
|
const Char *&format_str, const internal::Arg &arg) {
|
||||||
using internal::Arg;
|
using internal::Arg;
|
||||||
const Char *s = format_str;
|
const Char *s = format_str;
|
||||||
@ -3681,12 +3687,12 @@ const Char *BasicFormatter<Char>::format(
|
|||||||
FMT_THROW(FormatError("missing '}' in format string"));
|
FMT_THROW(FormatError("missing '}' in format string"));
|
||||||
|
|
||||||
// Format argument.
|
// Format argument.
|
||||||
internal::BasicArgFormatter<Char>(*this, spec, s - 1).visit(arg);
|
ArgFormatter(*this, spec, s - 1).visit(arg);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char, typename AF>
|
||||||
void BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
|
void BasicFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
|
||||||
const Char *s = format_str.c_str();
|
const Char *s = format_str.c_str();
|
||||||
const Char *start = s;
|
const Char *start = s;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
|
@ -1658,3 +1658,36 @@ std::ostream &operator<<(std::ostream &os, EmptyTest) {
|
|||||||
TEST(FormatTest, EmptyCustomOutput) {
|
TEST(FormatTest, EmptyCustomOutput) {
|
||||||
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
|
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CustomArgFormatter :
|
||||||
|
public fmt::internal::ArgFormatterBase<CustomArgFormatter, char> {
|
||||||
|
public:
|
||||||
|
typedef fmt::internal::ArgFormatterBase<CustomArgFormatter, char> Base;
|
||||||
|
|
||||||
|
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
|
||||||
|
fmt::FormatSpec &s, const char *)
|
||||||
|
: fmt::internal::ArgFormatterBase<CustomArgFormatter, char>(f.writer(), s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_int(int value) {
|
||||||
|
fmt::FormatSpec &spec = this->spec();
|
||||||
|
if (spec.type() == 'x')
|
||||||
|
visit_uint(value); // convert to unsigned and format
|
||||||
|
else
|
||||||
|
Base::visit_int(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string custom_format(const char *format_str, fmt::ArgList args) {
|
||||||
|
fmt::MemoryWriter writer;
|
||||||
|
fmt::BasicFormatter<char, CustomArgFormatter> formatter(args, writer);
|
||||||
|
formatter.format(format_str);
|
||||||
|
return writer.str();
|
||||||
|
}
|
||||||
|
FMT_VARIADIC(std::string, custom_format, const char *)
|
||||||
|
|
||||||
|
TEST(FormatTest, CustomArgFormatter) {
|
||||||
|
int x = -0xbeef;
|
||||||
|
EXPECT_EQ(fmt::format("{:x}", static_cast<unsigned>(x)),
|
||||||
|
custom_format("{:x}", x));
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user