mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-27 20:40:06 +00:00
Initial support for custom formatters
This commit is contained in:
parent
5f8af5ef1d
commit
6ced4230f4
63
format.h
63
format.h
@ -1021,8 +1021,11 @@ template<>
|
|||||||
struct Not<false> { enum { value = 1 }; };
|
struct Not<false> { enum { value = 1 }; };
|
||||||
|
|
||||||
// Makes an Arg object from any type.
|
// Makes an Arg object from any type.
|
||||||
template <typename Char>
|
template <typename Formatter>
|
||||||
class MakeValue : public Arg {
|
class MakeValue : public Arg {
|
||||||
|
public:
|
||||||
|
typedef typename Formatter::Char Char;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The following two methods are private to disallow formatting of
|
// The following two methods are private to disallow formatting of
|
||||||
// arbitrary pointers. If you want to output a pointer cast it to
|
// arbitrary pointers. If you want to output a pointer cast it to
|
||||||
@ -1060,7 +1063,7 @@ class MakeValue : public Arg {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
static void format_custom_arg(
|
static void format_custom_arg(
|
||||||
void *formatter, const void *arg, void *format_str_ptr) {
|
void *formatter, const void *arg, void *format_str_ptr) {
|
||||||
format(*static_cast<BasicFormatter<Char>*>(formatter),
|
format(*static_cast<Formatter*>(formatter),
|
||||||
*static_cast<const Char**>(format_str_ptr),
|
*static_cast<const Char**>(format_str_ptr),
|
||||||
*static_cast<const T*>(arg));
|
*static_cast<const T*>(arg));
|
||||||
}
|
}
|
||||||
@ -1166,7 +1169,7 @@ class MakeValue : public Arg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Additional template param `Char_` is needed here because make_type always
|
// Additional template param `Char_` is needed here because make_type always
|
||||||
// uses MakeValue<char>.
|
// uses char.
|
||||||
template <typename Char_>
|
template <typename Char_>
|
||||||
MakeValue(const NamedArg<Char_> &value) { pointer = &value; }
|
MakeValue(const NamedArg<Char_> &value) { pointer = &value; }
|
||||||
|
|
||||||
@ -1178,10 +1181,12 @@ template <typename Char>
|
|||||||
struct NamedArg : Arg {
|
struct NamedArg : Arg {
|
||||||
BasicStringRef<Char> name;
|
BasicStringRef<Char> name;
|
||||||
|
|
||||||
|
typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
NamedArg(BasicStringRef<Char> argname, const T &value)
|
NamedArg(BasicStringRef<Char> argname, const T &value)
|
||||||
: Arg(MakeValue<Char>(value)), name(argname) {
|
: Arg(MakeValue(value)), name(argname) {
|
||||||
type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value));
|
type = static_cast<Arg::Type>(MakeValue::type(value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1455,8 +1460,11 @@ class PrintfFormatter : private FormatterBase {
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
// A formatter.
|
// A formatter.
|
||||||
template <typename Char>
|
template <typename CharType>
|
||||||
class BasicFormatter : private internal::FormatterBase {
|
class BasicFormatter : private internal::FormatterBase {
|
||||||
|
public:
|
||||||
|
typedef CharType Char;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BasicWriter<Char> &writer_;
|
BasicWriter<Char> &writer_;
|
||||||
internal::ArgMap<Char> map_;
|
internal::ArgMap<Char> map_;
|
||||||
@ -1730,7 +1738,9 @@ namespace internal {
|
|||||||
inline uint64_t make_type() { return 0; }
|
inline uint64_t make_type() { return 0; }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline uint64_t make_type(const T &arg) { return MakeValue<char>::type(arg); }
|
inline uint64_t make_type(const T &arg) {
|
||||||
|
return MakeValue< BasicFormatter<char> >::type(arg);
|
||||||
|
}
|
||||||
|
|
||||||
template <unsigned N>
|
template <unsigned N>
|
||||||
struct ArgArray {
|
struct ArgArray {
|
||||||
@ -1754,7 +1764,8 @@ inline void do_set_types(Arg *) {}
|
|||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
|
inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
|
||||||
args->type = static_cast<Arg::Type>(MakeValue<T>::type(arg));
|
args->type = static_cast<Arg::Type>(
|
||||||
|
MakeValue< BasicFormatter<char> >::type(arg));
|
||||||
do_set_types(args + 1, tail...);
|
do_set_types(args + 1, tail...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1770,24 +1781,24 @@ inline void set_types(Value *, const Args & ...) {
|
|||||||
// Do nothing as types are passed separately from values.
|
// Do nothing as types are passed separately from values.
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Value>
|
template <typename Formatter, typename Value>
|
||||||
inline void store_args(Value *) {}
|
inline void store_args(Value *) {}
|
||||||
|
|
||||||
template <typename Char, typename Arg, typename T, typename... Args>
|
template <typename Formatter, typename Arg, typename T, typename... Args>
|
||||||
inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
|
inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
|
||||||
// Assign only the Value subobject of Arg and don't overwrite type (if any)
|
// Assign only the Value subobject of Arg and don't overwrite type (if any)
|
||||||
// that is assigned by set_types.
|
// that is assigned by set_types.
|
||||||
Value &value = *args;
|
Value &value = *args;
|
||||||
value = MakeValue<Char>(arg);
|
value = MakeValue<Formatter>(arg);
|
||||||
store_args<Char>(args + 1, tail...);
|
store_args<Formatter>(args + 1, tail...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename... Args>
|
template <typename Formatter, typename... Args>
|
||||||
ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
|
ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
|
||||||
const Args & ... args) {
|
const Args & ... args) {
|
||||||
if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
|
if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
|
||||||
set_types(array, args...);
|
set_types(array, args...);
|
||||||
store_args<Char>(array, args...);
|
store_args<Formatter>(array, args...);
|
||||||
return ArgList(make_type(args...), array);
|
return ArgList(make_type(args...), array);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -1847,8 +1858,10 @@ class FormatBuf : public std::basic_streambuf<Char> {
|
|||||||
# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
|
# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
|
||||||
# define FMT_MAKE_ARG_TYPE(n) T##n
|
# define FMT_MAKE_ARG_TYPE(n) T##n
|
||||||
# define FMT_MAKE_ARG(n) const T##n &v##n
|
# define FMT_MAKE_ARG(n) const T##n &v##n
|
||||||
# define FMT_ASSIGN_char(n) arr[n] = fmt::internal::MakeValue<char>(v##n)
|
# define FMT_ASSIGN_char(n) \
|
||||||
# define FMT_ASSIGN_wchar_t(n) arr[n] = fmt::internal::MakeValue<wchar_t>(v##n)
|
arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<char> >(v##n)
|
||||||
|
# define FMT_ASSIGN_wchar_t(n) \
|
||||||
|
arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter<wchar_t> >(v##n)
|
||||||
|
|
||||||
#if FMT_USE_VARIADIC_TEMPLATES
|
#if FMT_USE_VARIADIC_TEMPLATES
|
||||||
// Defines a variadic function returning void.
|
// Defines a variadic function returning void.
|
||||||
@ -1856,7 +1869,8 @@ class FormatBuf : public std::basic_streambuf<Char> {
|
|||||||
template <typename... Args> \
|
template <typename... Args> \
|
||||||
void func(arg_type arg0, const Args & ... args) { \
|
void func(arg_type arg0, const Args & ... args) { \
|
||||||
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
|
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
|
||||||
func(arg0, fmt::internal::make_arg_list<Char>(array, args...)); \
|
func(arg0, fmt::internal::make_arg_list< \
|
||||||
|
fmt::BasicFormatter<Char> >(array, args...)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines a variadic constructor.
|
// Defines a variadic constructor.
|
||||||
@ -1864,12 +1878,14 @@ class FormatBuf : public std::basic_streambuf<Char> {
|
|||||||
template <typename... Args> \
|
template <typename... Args> \
|
||||||
ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
|
ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
|
||||||
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
|
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
|
||||||
func(arg0, arg1, fmt::internal::make_arg_list<Char>(array, args...)); \
|
func(arg0, arg1, fmt::internal::make_arg_list< \
|
||||||
|
fmt::BasicFormatter<Char> >(array, args...)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
# define FMT_MAKE_REF(n) fmt::internal::MakeValue<Char>(v##n)
|
# define FMT_MAKE_REF(n) \
|
||||||
|
fmt::internal::MakeValue< fmt::BasicFormatter<Char> >(v##n)
|
||||||
# define FMT_MAKE_REF2(n) v##n
|
# define FMT_MAKE_REF2(n) v##n
|
||||||
|
|
||||||
// Defines a wrapper for a function taking one argument of type arg_type
|
// Defines a wrapper for a function taking one argument of type arg_type
|
||||||
@ -2735,9 +2751,9 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
|
|||||||
output << value;
|
output << value;
|
||||||
|
|
||||||
BasicStringRef<Char> str(&buffer[0], format_buf.size());
|
BasicStringRef<Char> str(&buffer[0], format_buf.size());
|
||||||
internal::Arg arg = internal::MakeValue<Char>(str);
|
typedef internal::MakeValue< BasicFormatter<Char> > MakeValue;
|
||||||
arg.type = static_cast<internal::Arg::Type>(
|
internal::Arg arg = MakeValue(str);
|
||||||
internal::MakeValue<Char>::type(str));
|
arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str));
|
||||||
format_str = f.format(format_str, arg);
|
format_str = f.format(format_str, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3062,7 +3078,8 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
|
|||||||
const Args & ... args) { \
|
const Args & ... args) { \
|
||||||
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
|
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
|
||||||
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
|
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
|
||||||
fmt::internal::make_arg_list<Char>(array, args...)); \
|
fmt::internal::make_arg_list< \
|
||||||
|
fmt::BasicFormatter<Char> >(array, args...)); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Defines a wrapper for a function taking __VA_ARGS__ arguments
|
// Defines a wrapper for a function taking __VA_ARGS__ arguments
|
||||||
|
@ -69,9 +69,9 @@ std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os, Test) {
|
|||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
Arg make_arg(const T &value) {
|
Arg make_arg(const T &value) {
|
||||||
Arg arg = fmt::internal::MakeValue<Char>(value);
|
typedef fmt::internal::MakeValue< fmt::BasicFormatter<Char> > MakeValue;
|
||||||
arg.type = static_cast<Arg::Type>(
|
Arg arg = MakeValue(value);
|
||||||
fmt::internal::MakeValue<Char>::type(value));
|
arg.type = static_cast<Arg::Type>(MakeValue::type(value));
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -575,6 +575,23 @@ TEST(UtilTest, ArgList) {
|
|||||||
EXPECT_EQ(Arg::NONE, args[1].type);
|
EXPECT_EQ(Arg::NONE, args[1].type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CustomFormatter {
|
||||||
|
typedef char Char;
|
||||||
|
};
|
||||||
|
|
||||||
|
void format(CustomFormatter &, const char *&s, const Test &) {
|
||||||
|
s = "custom_format";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UtilTest, MakeValueWithCustomFormatter) {
|
||||||
|
::Test t;
|
||||||
|
Arg arg = fmt::internal::MakeValue<CustomFormatter>(t);
|
||||||
|
CustomFormatter formatter;
|
||||||
|
const char *s = "";
|
||||||
|
arg.custom.format(&formatter, &t, &s);
|
||||||
|
EXPECT_STREQ("custom_format", s);
|
||||||
|
}
|
||||||
|
|
||||||
struct Result {
|
struct Result {
|
||||||
Arg arg;
|
Arg arg;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user