diff --git a/raft/raft.hh b/raft/raft.hh index 452f0142d0..0884f6f292 100644 --- a/raft/raft.hh +++ b/raft/raft.hh @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include @@ -814,6 +815,16 @@ public: } // namespace raft +#if FMT_VERSION < 100000 +// fmt v10 introduced formatter for std::exception +template T> +struct fmt::formatter : fmt::formatter { + auto format(const T& e, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", e.what()); + } +}; +#endif + template <> struct fmt::formatter : fmt::formatter { auto format(const raft::server_address&, fmt::format_context& ctx) const -> decltype(ctx.out()); diff --git a/test/raft/generator.hh b/test/raft/generator.hh index 5127b03106..cbfc2ebae0 100644 --- a/test/raft/generator.hh +++ b/test/raft/generator.hh @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include "utils/chunked_vector.hh" @@ -469,10 +471,6 @@ struct either_of { either_of(Op o) : op(std::move(o)) { static_assert(Executable>); } - - friend std::ostream& operator<<(std::ostream& os, const either_of& e) { - return os << e.op; - } }; } // namespace operation @@ -827,20 +825,34 @@ stagger_gen stagger( } // namespace generator -namespace operation { +template +struct fmt::formatter> : fmt::formatter { + auto format(operation::either_of& e, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", e.op); + } +}; template -std::ostream& operator<<(std::ostream& os, const exceptional_result& r) { - try { - std::rethrow_exception(r.eptr); - } catch (const std::exception& e) { - return os << format("exceptional{{i:{}, ex:{}}}", r.op, e); +struct fmt::formatter> : fmt::formatter { + auto format(const operation::exceptional_result& r, fmt::format_context& ctx) const { + try { + std::rethrow_exception(r.eptr); + } catch (const std::exception& e) { + return fmt::format_to(ctx.out(), "exceptional{{i:{}, ex:{}}}", r.op, e); + } } -} +}; template -std::ostream& operator<<(std::ostream& os, const completion& c) { - return os << format("c{{r:{}, t:{}, tid:{}}}", c.result, c.time, c.thread); -} +struct fmt::formatter> : fmt::formatter { + auto format(const operation::completion& c, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "c{{r:{}, t:{}, tid:{}}}", c.result, c.time, c.thread); + } +}; -} // namespace operation +template +struct fmt::formatter> : fmt::formatter { + auto format(const operation::invocable& op, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", static_cast(op)); + } +}; diff --git a/test/raft/randomized_nemesis_test.cc b/test/raft/randomized_nemesis_test.cc index f67c93be01..90cb4b01eb 100644 --- a/test/raft/randomized_nemesis_test.cc +++ b/test/raft/randomized_nemesis_test.cc @@ -36,18 +36,27 @@ namespace std { -std::ostream& operator<<(std::ostream& os, const std::monostate&) { - return os << ""; -} - +// fmt::formatter requires that the none of Ts... has +// fallback formatter, so we cannot use it before ditching operator<< of +// all element types. template std::ostream& operator<<(std::ostream& os, const std::variant& v) { - std::visit([&os] (auto& arg) { os << arg; }, v); + std::visit([&os] (auto& arg) { fmt::print(os, "{}", arg); }, v); return os; } } // namespace std +#if FMT_VERSION < 100000 +// fmt v10 introduced formatter for std::exception +template <> +struct fmt::formatter : fmt::formatter { + auto format(const seastar::timed_out_error& e, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "{}", e.what()); + } +}; +#endif + using namespace seastar; using namespace std::chrono_literals; @@ -2589,9 +2598,12 @@ struct raft_call { co_return res; } +}; - friend std::ostream& operator<<(std::ostream& os, const raft_call& c) { - return os << format("raft_call{{input:{},timeout:{}}}", c.input, c.timeout); +template +struct fmt::formatter> : fmt::formatter { + auto format(const raft_call& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "raft_call{{input:{}, timeout:{}}}", r.input, r.timeout); } }; @@ -2624,9 +2636,12 @@ struct raft_read { co_return result_type{read_id, std::move(res)}; } +}; - friend std::ostream& operator<<(std::ostream& os, const raft_read& r) { - return os << format("raft_read{{id:{}, timeout:{}}}", r.read_id, r.timeout); +template +struct fmt::formatter> : fmt::formatter { + auto format(const raft_read& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "raft_read{{id:{}, timeout:{}}}", r.read_id, r.timeout); } }; @@ -2696,8 +2711,13 @@ public: co_return std::monostate{}; } - friend std::ostream& operator<<(std::ostream& os, const network_majority_grudge& p) { - return os << format("network_majority_grudge{{duration:{}}}", p._duration); + friend fmt::formatter; +}; + +template +struct fmt::formatter> : fmt::formatter { + auto format(const network_majority_grudge& p, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "network_majority_grudge{{duration:{}}}", p._duration); } }; @@ -2822,9 +2842,12 @@ struct reconfiguration { return execute_reconfigure(s, ctx, std::move(nodes), members_end, voters_end); } } +}; - friend std::ostream& operator<<(std::ostream& os, const reconfiguration& r) { - return os << format("reconfiguration{{timeout:{}}}", r.timeout); +template +struct fmt::formatter>: fmt::formatter { + auto format(const reconfiguration& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "reconfiguration{{timeout:{}}}", r.timeout); } }; @@ -2863,22 +2886,23 @@ struct stop_crash { co_return result_type{}; } - friend std::ostream& operator<<(std::ostream& os, const stop_crash& c) { - return os << format("stop_crash{{delay:{}}}", c.restart_delay); - } - friend std::ostream& operator<<(std::ostream& os, const result_type&) { return os << ""; } }; -namespace operation { +template +struct fmt::formatter>: fmt::formatter { + auto format(const stop_crash& c, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "stop_crash{{delay:{}}}", c.restart_delay); + } +}; -std::ostream& operator<<(std::ostream& os, const thread_id& tid) { - return os << format("thread_id{{{}}}", tid.id); -} - -} // namespace operation +template <> struct fmt::formatter: fmt::formatter { + auto format(const operation::thread_id& tid, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "thread_id{{{}}}", tid.id); + } +}; // An immutable sequence of integers. class append_seq { @@ -2961,11 +2985,7 @@ public: return {{_seq, _end - 1, digest_remove(_digest, (*_seq)[_end - 1])}, (*_seq)[_end - 1]}; } - friend std::ostream& operator<<(std::ostream& os, const append_seq& s) { - // TODO: don't copy the elements - std::vector v{s._seq->begin(), s._seq->begin() + s._end}; - return os << format("seq({} _end {})", v, s._end); - } + friend fmt::formatter; private: append_seq(lw_shared_ptr> seq, size_t end, elem_t d) @@ -2987,6 +3007,15 @@ struct AppendReg { static thread_local const state_t init; }; +template <> struct fmt::formatter : fmt::formatter { + auto format(const append_seq& s, fmt::format_context& ctx) const { + // TODO: don't copy the elements + std::vector v{s._seq->begin(), s._seq->begin() + s._end}; + return fmt::format_to(ctx.out(), "seq({} _end {})", v, s._end); + } +}; + + thread_local const AppendReg::state_t AppendReg::init{{0}}; namespace ser { @@ -3177,13 +3206,17 @@ private: } }; -std::ostream& operator<<(std::ostream& os, const AppendReg::append& a) { - return os << format("append{{{}}}", a.x); -} +template <> struct fmt::formatter : fmt::formatter { + auto format(const AppendReg::append& a, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "append{{{}}}", a.x); + } +}; -std::ostream& operator<<(std::ostream& os, const AppendReg::ret& r) { - return os << format("ret{{{}, {}}}", r.x, r.prev); -} +template <> struct fmt::formatter : fmt::formatter { + auto format(const AppendReg::ret& r, fmt::format_context& ctx) const { + return fmt::format_to(ctx.out(), "ret{{{}, {}}}", r.x, r.prev); + } +}; SEASTAR_TEST_CASE(basic_generator_test) { using op_type = operation::invocable