Files
scylladb/utils/pretty_printers.hh
Kefu Chai c40da20092 utils/pretty_printers: stop using undocumented fmt api
format_parse_context::on_error() is an undocumented API in fmt v9
and in fmt v10, see

- https://fmt.dev/9.1.0/api.html#_CPPv4I0EN3fmt16basic_format_argE
- https://fmt.dev/10.0.0/api.html#_CPPv4I0EN3fmt26basic_format_parse_contextE

despite that this API was once used in its document for fmt v10.0.0, see
https://fmt.dev/10.0.0/api.html#formatting-user-defined-types. it's
still, well, undocumented.

so, to have better compatibility, let's use the documented API in place
of undocumented one. please note, `throw_format_error()` was still
not a public API before 10.1.0, so before that release we have to
throw `fmt::format_error` explicitly. so we cannot use it yet during
the transitional period.

because the class of `fmt::format_error` is defined in `fmt/format.h`,
we need to include this header for using it.

Refs #13245

Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>

Closes scylladb/scylladb#16212
2023-11-29 12:49:04 +02:00

90 lines
2.6 KiB
C++

/*
* Copyright (C) 2023-present ScyllaDB
*/
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <chrono>
#include <fmt/format.h>
namespace utils {
class pretty_printed_data_size {
uint64_t _size;
public:
pretty_printed_data_size(uint64_t size) : _size(size) {}
friend fmt::formatter<pretty_printed_data_size>;
};
class pretty_printed_throughput {
uint64_t _size;
std::chrono::duration<float> _duration;
public:
pretty_printed_throughput(uint64_t size, std::chrono::duration<float> dur) : _size(size), _duration(std::move(dur)) {}
friend fmt::formatter<pretty_printed_throughput>;
};
}
// print data_size using IEC or SI binary prefix annotation with optional "B"
// or " bytes" unit postfix.
//
// usage:
// fmt::print("{}", 10'024); // prints "10kB", using SI and add the "B" unit
// // postfix by default
// fmt::print("{:i}", 42); // prints "42 bytes"
// fmt::print("{:ib}", 10'024); // prints "10Ki", IEC unit is used, without
// // the " bytes" or "B" unit
// fmt::print("{:s}", 10); // prints "10 bytes", SI unit is used
// fmt::print("{:sb}", 10'000); // prints "10k", SI unit is used, without
// // the unit postfix
template <>
struct fmt::formatter<utils::pretty_printed_data_size> {
enum class prefix_type {
SI,
IEC,
};
prefix_type _prefix = prefix_type::SI;
bool _bytes = true;
constexpr auto parse(format_parse_context& ctx) {
auto it = ctx.begin();
auto end = ctx.end();
if (it != end) {
if (*it == 's') {
_prefix = prefix_type::SI;
++it;
} else if (*it == 'i') {
_prefix = prefix_type::IEC;
++it;
}
if (*it == 'b') {
_bytes = false;
++it;
}
}
if (it != end && *it != '}') {
throw fmt::format_error("invalid format specifier");
}
return it;
}
template <typename FormatContext>
auto format(utils::pretty_printed_data_size, FormatContext& ctx) const -> decltype(ctx.out());
};
template <>
struct fmt::formatter<utils::pretty_printed_throughput>
: private fmt::formatter<utils::pretty_printed_data_size> {
using size_formatter = fmt::formatter<utils::pretty_printed_data_size>;
public:
using size_formatter::parse;
template <typename FormatContext>
auto format(const utils::pretty_printed_throughput&, FormatContext& ctx) const -> decltype(ctx.out());
};