2019-09-23 20:25:54 +00:00
|
|
|
#pragma once
|
|
|
|
|
2019-09-24 09:21:28 +00:00
|
|
|
#include <fmt/format.h>
|
2022-02-05 20:19:55 +00:00
|
|
|
#include <glibmm/ustring.h>
|
2019-09-23 20:25:54 +00:00
|
|
|
|
2019-09-24 09:21:28 +00:00
|
|
|
class pow_format {
|
2022-04-06 06:37:19 +00:00
|
|
|
public:
|
2024-02-06 15:03:30 +00:00
|
|
|
pow_format(long long val, std::string&& unit, bool binary = false, bool skip_decimal = false)
|
|
|
|
: val_(val), unit_(unit), binary_(binary), skip_decimal_(skip_decimal){};
|
2019-09-23 20:25:54 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
long long val_;
|
|
|
|
std::string unit_;
|
|
|
|
bool binary_;
|
2024-02-06 15:03:30 +00:00
|
|
|
bool skip_decimal_;
|
2019-09-24 09:21:28 +00:00
|
|
|
};
|
2019-09-23 20:25:54 +00:00
|
|
|
|
2019-09-24 09:21:28 +00:00
|
|
|
namespace fmt {
|
2022-04-06 06:37:19 +00:00
|
|
|
template <>
|
|
|
|
struct formatter<pow_format> {
|
|
|
|
char spec = 0;
|
|
|
|
int width = 0;
|
2019-09-24 09:21:28 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
template <typename ParseContext>
|
|
|
|
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
|
|
auto it = ctx.begin(), end = ctx.end();
|
|
|
|
if (it != end && *it == ':') ++it;
|
|
|
|
if (it && (*it == '>' || *it == '<' || *it == '=')) {
|
|
|
|
spec = *it;
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
if (it == end || *it == '}') return it;
|
|
|
|
if ('0' <= *it && *it <= '9') {
|
|
|
|
// We ignore it for now, but keep it for compatibility with
|
|
|
|
// existing configs where the format for pow_format'ed numbers was
|
|
|
|
// 'string' and specifications such as {:>9} were valid.
|
|
|
|
// The rationale for ignoring it is that the only reason to specify
|
|
|
|
// an alignment and a with is to get a fixed width bar, and ">" is
|
|
|
|
// sufficient in this implementation.
|
2021-06-30 02:29:12 +00:00
|
|
|
#if FMT_VERSION < 80000
|
2022-04-06 06:37:19 +00:00
|
|
|
width = parse_nonnegative_int(it, end, ctx);
|
2021-06-30 02:29:12 +00:00
|
|
|
#else
|
2022-04-06 06:37:19 +00:00
|
|
|
width = detail::parse_nonnegative_int(it, end, -1);
|
2021-06-30 02:29:12 +00:00
|
|
|
#endif
|
2022-04-06 06:37:19 +00:00
|
|
|
}
|
|
|
|
return it;
|
|
|
|
}
|
2019-09-24 09:21:28 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
template <class FormatContext>
|
|
|
|
auto format(const pow_format& s, FormatContext& ctx) -> decltype(ctx.out()) {
|
|
|
|
const char* units[] = {"", "k", "M", "G", "T", "P", nullptr};
|
2019-09-24 09:21:28 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
auto base = s.binary_ ? 1024ull : 1000ll;
|
2024-02-06 15:03:30 +00:00
|
|
|
auto div = 1ll;
|
2022-04-06 06:37:19 +00:00
|
|
|
auto fraction = (double)s.val_;
|
2019-09-24 09:21:28 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
int pow;
|
|
|
|
for (pow = 0; units[pow + 1] != nullptr && fraction / base >= 1; ++pow) {
|
|
|
|
fraction /= base;
|
2024-02-06 15:03:30 +00:00
|
|
|
div *= base;
|
2022-04-06 06:37:19 +00:00
|
|
|
}
|
2022-02-05 20:19:55 +00:00
|
|
|
|
2024-02-06 15:03:30 +00:00
|
|
|
auto fixed_precision = (s.skip_decimal_ && ((s.val_%div) == 0)) ? 0 : 1;
|
|
|
|
auto number_width = 3 + fixed_precision // coeff in {:.{fixed_precision}f} format
|
|
|
|
+ (fixed_precision != 0)// float dot
|
|
|
|
+ s.binary_; // potential digit before the decimal point
|
|
|
|
auto max_width = number_width + 1 // prefix from units array
|
|
|
|
+ s.binary_ // for the 'i' in GiB.
|
2022-04-06 06:37:19 +00:00
|
|
|
+ s.unit_.length();
|
2022-02-05 20:19:55 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
const char* format;
|
|
|
|
std::string string;
|
|
|
|
switch (spec) {
|
|
|
|
case '>':
|
2023-01-16 21:24:55 +00:00
|
|
|
return fmt::format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), max_width);
|
2022-04-06 06:37:19 +00:00
|
|
|
case '<':
|
2023-01-16 21:24:55 +00:00
|
|
|
return fmt::format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width);
|
2022-04-06 06:37:19 +00:00
|
|
|
case '=':
|
2024-02-06 15:03:30 +00:00
|
|
|
format = "{coefficient:<{number_width}.{fixed_precision}f}{padding}{prefix}{unit}";
|
2022-04-06 06:37:19 +00:00
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
default:
|
2024-02-06 15:03:30 +00:00
|
|
|
format = "{coefficient:.{fixed_precision}f}{prefix}{unit}";
|
2022-04-06 06:37:19 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-01-16 21:24:55 +00:00
|
|
|
return fmt::format_to(
|
|
|
|
ctx.out(), fmt::runtime(format), fmt::arg("coefficient", fraction),
|
2024-02-06 15:03:30 +00:00
|
|
|
fmt::arg("fixed_precision", fixed_precision),
|
2022-07-21 20:37:43 +00:00
|
|
|
fmt::arg("number_width", number_width),
|
2022-04-06 06:37:19 +00:00
|
|
|
fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")),
|
|
|
|
fmt::arg("unit", s.unit_),
|
|
|
|
fmt::arg("padding", pow ? ""
|
|
|
|
: s.binary_ ? " "
|
|
|
|
: " "));
|
|
|
|
}
|
|
|
|
};
|
2019-09-24 09:21:28 +00:00
|
|
|
|
2022-04-06 06:37:19 +00:00
|
|
|
// Glib ustirng support
|
|
|
|
template <>
|
|
|
|
struct formatter<Glib::ustring> : formatter<std::string> {
|
|
|
|
template <typename FormatContext>
|
|
|
|
auto format(const Glib::ustring& value, FormatContext& ctx) {
|
2023-08-15 18:57:07 +00:00
|
|
|
return formatter<std::string>::format(static_cast<std::string>(value), ctx);
|
2022-04-06 06:37:19 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace fmt
|