Hello,
Thanks a lot for awesome format library!
Could you please help me for format custom type.
I have a structure
struct Stat {
size_t min = 0;
size_t max = 0;
size_t avg = 0;
size_t count = 0;
};
class Perf {
Stat get(Event event) const {...}
};
I wrote custom formatter for my Perf class, but I'd like to support different formatting strings.
For example to format my perf as text of like json.
Could you please tell me or point to an example how to do that?
Thank you in advance!
namespace fmt {
template <> struct formatter<kg::Perf> {
template <typename ParseContext> constexpr auto parse(ParseContext &ctx) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const kg::Perf &perf, FormatContext &ctx) {
auto oit =
format_to(ctx.begin(),
"\n{:-<63}\n {: <21} {: >9} {: >9} {: >9} {: >9} \n{:-<63}\n",
"", "Event", "min(ns)", "max(ns)", "avg(ns)", "N", "");
for (auto e : kg::Perf::events) {
auto stat = perf.get(e);
oit = format_to(oit, " {: <21} {: >8} {: >8} {: >8} {: >8} \n",
kg::Perf::to_string(e), stat.min, stat.max, stat.avg,
stat.count);
}
return oit;
}
};
Could you please tell me or point to an example how to do that?
You need to parse your format specifiers such as the output type in the parse function, for example:
template <> struct fmt::formatter<kg::Perf> {
// Output type:
// 't' or 0: text
// 'j': json
char type = 0;
template <typename ParseContext> constexpr auto parse(ParseContext &ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
if (*it == 't' || *it == 'j')
type = *it++;
return it;
}
template <typename FormatContext>
auto format(const kg::Perf &perf, FormatContext &ctx) {
auto it = ctx.begin();
if (!type || type == 't') {
// Format as text.
it = format_to(it,
"\n{:-<63}\n {: <21} {: >9} {: >9} {: >9} {: >9} \n{:-<63}\n",
"", "Event", "min(ns)", "max(ns)", "avg(ns)", "N", "");
// ...
} else {
// Format as json.
// ...
}
return it;
}
};
Then you'll be able to use the specifiers with any of the format functions:
fmt::print("{}\n", kg::Perf()); // print as text
fmt::print("{:j}\n", kg::Perf()); // print as json
@vitaut , thanks a lot!
It might be great to have this sample in documentation!
It might be great to have this sample in documentation!
Yeah, it's on my TODO list.
Hi, I was about to open a similar issue and this one pops out. This is great example, but does this allow things like format("{1:t} {0:j}", foo, bar) and format("{a:t}", arg("a", foo)) ?
I assume that there is a base formatter class that have parse(ctx) to parse everything up to ":" and handle the positional arg or named arg in a standard way, then we can write custom formatter to parse the rest of ctx as in this example.
Could you please write an example? @vitaut
Also, is it possible to implement compile time switch if constexpr (type == "t") in format(...) with the current design, when the fmt string is compile-time string_view?
does this allow things like
format("{1:t} {0:j}", foo, bar)andformat("{a:t}", arg("a", foo))?
Yes. You don't need to do anything special for named arguments.
is it possible to implement compile time switch
if constexpr (type == "t")informat(...)with the current design, when the fmt string is compile-time string_view?
I don't think compile-time switch will work because you need to be able to parse at runtime as well, but you can make your parse method constexpr and then the compile-time checks will automatically apply to it.
Got it. Thank you very much!