mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-07 08:31:16 +00:00
Add user-defined type support to compilation
This commit is contained in:
parent
8bef1c3b3a
commit
1a83443e6c
@ -408,6 +408,23 @@ template <typename Char, typename T, int N> struct field {
|
|||||||
template <typename Char, typename T, int N>
|
template <typename Char, typename T, int N>
|
||||||
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
||||||
|
|
||||||
|
// A replacement field that refers to argument N and has format specifiers.
|
||||||
|
template <typename Char, typename T, int N> struct spec_field {
|
||||||
|
using char_type = Char;
|
||||||
|
mutable formatter<T, Char> fmt;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
|
const T& arg = get<N>(args...);
|
||||||
|
basic_format_context<OutputIt, Char> ctx(out, {});
|
||||||
|
return fmt.format(arg, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename T, int N>
|
||||||
|
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
|
||||||
|
|
||||||
template <typename L, typename R> struct concat {
|
template <typename L, typename R> struct concat {
|
||||||
L lhs;
|
L lhs;
|
||||||
R rhs;
|
R rhs;
|
||||||
@ -456,6 +473,21 @@ constexpr auto parse_tail(T head, S format_str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Char> struct parse_specs_result {
|
||||||
|
formatter<T, Char> fmt;
|
||||||
|
size_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||||
|
size_t pos) {
|
||||||
|
str.remove_prefix(pos);
|
||||||
|
auto ctx = basic_format_parse_context<Char>(str);
|
||||||
|
auto f = formatter<T, Char>();
|
||||||
|
auto end = f.parse(ctx);
|
||||||
|
return {f, pos + (end - str.data()) + 1};
|
||||||
|
}
|
||||||
|
|
||||||
// Compiles a non-empty format string and returns the compiled representation
|
// Compiles a non-empty format string and returns the compiled representation
|
||||||
// or unknown_format() on unrecognized input.
|
// or unknown_format() on unrecognized input.
|
||||||
template <typename Args, size_t POS, int ID, typename S>
|
template <typename Args, size_t POS, int ID, typename S>
|
||||||
@ -471,6 +503,11 @@ constexpr auto compile_format_string(S format_str) {
|
|||||||
using type = get_type<ID, Args>;
|
using type = get_type<ID, Args>;
|
||||||
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
||||||
format_str);
|
format_str);
|
||||||
|
} else if constexpr (str[POS + 1] == ':') {
|
||||||
|
using type = get_type<ID, Args>;
|
||||||
|
constexpr auto result = parse_specs<type>(str, POS + 2);
|
||||||
|
return parse_tail<Args, result.end, ID + 1>(
|
||||||
|
spec_field<char_type, type, ID>{result.fmt}, format_str);
|
||||||
} else {
|
} else {
|
||||||
return unknown_format();
|
return unknown_format();
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,8 @@ struct formattable {};
|
|||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template <> struct formatter<formattable> : formatter<const char*> {
|
template <> struct formatter<formattable> : formatter<const char*> {
|
||||||
auto format(formattable, format_context& ctx) -> decltype(ctx.out()) {
|
template <typename FormatContext>
|
||||||
|
auto format(formattable, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
return formatter<const char*>::format("foo", ctx);
|
return formatter<const char*>::format("foo", ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -154,6 +155,11 @@ TEST(CompileTest, FormatDefault) {
|
|||||||
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
|
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
|
||||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
|
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
|
||||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
|
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
|
||||||
|
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), formattable()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CompileTest, FormatSpecs) {
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CompileTest, FormatTo) {
|
TEST(CompileTest, FormatTo) {
|
||||||
|
Loading…
Reference in New Issue
Block a user