From eefd42f93fc2c551ede678d6163926b174f79e32 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 16 Aug 2021 18:44:42 -0300 Subject: [PATCH] Add fmtlib::fmt backport of C++20 std::format Because I'm tired of waiting for std::format. --- .gitmodules | 3 + external/CMakeLists.txt | 1 + external/fmt | 1 + src/blockchain_db/lmdb/db_lmdb.cpp | 3 +- src/common/CMakeLists.txt | 1 + src/daemon/rpc_command_executor.cpp | 139 ++++++++++++---------------- src/gen_multisig/gen_multisig.cpp | 6 +- 7 files changed, 68 insertions(+), 86 deletions(-) create mode 160000 external/fmt diff --git a/.gitmodules b/.gitmodules index 1be8f2c69..0b167c4f1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,6 @@ [submodule "external/ghc-filesystem"] path = external/ghc-filesystem url = https://github.com/gulrak/filesystem.git +[submodule "external/fmt"] + path = external/fmt + url = https://github.com/fmtlib/fmt.git diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index ea982713a..007b8dcc9 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -83,6 +83,7 @@ endif() add_subdirectory(db_drivers) add_subdirectory(easylogging++ easyloggingpp) add_subdirectory(randomx EXCLUDE_FROM_ALL) +add_subdirectory(fmt) # uSockets doesn't really have a proper build system (just a very simple Makefile) so build it # ourselves. diff --git a/external/fmt b/external/fmt new file mode 160000 index 000000000..d141cdbeb --- /dev/null +++ b/external/fmt @@ -0,0 +1 @@ +Subproject commit d141cdbeb0fb422a3fb7173b285fd38e0d1772dc diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 9f9c63498..001ea938a 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -28,7 +28,6 @@ #include "db_lmdb.h" -#include #include #include #include @@ -712,7 +711,7 @@ bool BlockchainLMDB::need_resize(uint64_t threshold_size) const MDEBUG("Space remaining: " << mei.me_mapsize - size_used); MDEBUG("Size threshold: " << threshold_size); float resize_percent = RESIZE_PERCENT; - MDEBUG(boost::format("Percent used: %.04f Percent threshold: %.04f") % (100.*size_used/mei.me_mapsize) % (100.*resize_percent)); + MDEBUG("Percent used: " << 100.*size_used/mei.me_mapsize << " Percent threshold: " << 100.*resize_percent); if (threshold_size > 0) { diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 55ce18535..ef8717f57 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -66,6 +66,7 @@ target_link_libraries(common cncrypto oxenmq::oxenmq filesystem + fmt::fmt PRIVATE libunbound OpenSSL::SSL diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 984831db4..e9e4f4ec7 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -40,8 +40,9 @@ #include "cryptonote_core/service_node_rules.h" #include "cryptonote_basic/hardfork.h" #include "checkpoints/checkpoints.h" -#include +#include #include +#include #include "common/oxen_integration_test_hooks.h" @@ -111,19 +112,6 @@ namespace { return input_line_result::yes; } - const char *get_address_type_name(epee::net_utils::address_type address_type) - { - switch (address_type) - { - default: - case epee::net_utils::address_type::invalid: return "invalid"; - case epee::net_utils::address_type::ipv4: return "IPv4"; - case epee::net_utils::address_type::ipv6: return "IPv6"; - case epee::net_utils::address_type::i2p: return "I2P"; - case epee::net_utils::address_type::tor: return "Tor"; - } - } - void print_peer(std::string const & prefix, GET_PEER_LIST::peer const & peer, bool pruned_only, bool publicrpc_only) { if (pruned_only && peer.pruning_seed == 0) @@ -139,7 +127,7 @@ namespace { std::string addr_str = peer.host + ":" + std::to_string(peer.port); std::string rpc_port = peer.rpc_port ? std::to_string(peer.rpc_port) : "-"; std::string pruning_seed = epee::string_tools::to_string_hex(peer.pruning_seed); - tools::msg_writer() << boost::format("%-10s %-25s %-25s %-5s %-4s %s") % prefix % id_str % addr_str % rpc_port % pruning_seed % elapsed; + tools::msg_writer() << fmt::format("{:<10} {:<25} {:<25} {:<5} %{:-4} {}", prefix, id_str, addr_str, rpc_port, pruning_seed, elapsed); } void print_block_header(block_header_response const & header) @@ -174,11 +162,11 @@ namespace { if (dt < 90s) s = std::to_string(dt.count()) + (abbreviate ? "sec" : dt == 1s ? " second" : " seconds"); else if (dt < 90min) - s = (boost::format(abbreviate ? "%.1fmin" : "%.1f minutes") % ((float)dt.count()/60)).str(); + s = fmt::format("{:.1f}{:s}", ((float)dt.count()/60), abbreviate ? "min" : " minutes"); else if (dt < 36h) - s = (boost::format(abbreviate ? "%.1fhr" : "%.1f hours") % ((float)dt.count()/3600)).str(); + s = fmt::format("{:.1f}{:s}", ((float)dt.count()/3600), abbreviate ? "hr" : " hours"); else - s = (boost::format("%.1f days") % ((float)dt.count()/(86400))).str(); + s = fmt::format("{:.1f} days", ((float)dt.count()/86400)); if (abbreviate) { if (ago < 0s) return s + " (in fut.)"; @@ -407,15 +395,15 @@ bool rpc_command_executor::show_difficulty() { static std::string get_mining_speed(uint64_t hr) { - if (hr>1e9) return (boost::format("%.2f GH/s") % (hr/1e9)).str(); - if (hr>1e6) return (boost::format("%.2f MH/s") % (hr/1e6)).str(); - if (hr>1e3) return (boost::format("%.2f kH/s") % (hr/1e3)).str(); - return (boost::format("%.0f H/s") % hr).str(); + if (hr >= 1e9) return fmt::format("{:.2f} GH/s", hr*1e-9); + if (hr >= 1e6) return fmt::format("{:.2f} MH/s", hr*1e-6); + if (hr >= 1e3) return fmt::format("{:.2f} kH/s", hr*1e-3); + return fmt::format("{:d} H/s", hr); } -static std::ostream& print_fork_extra_info(std::ostream& o, uint64_t t, uint64_t now, uint64_t block_time) +static std::ostream& print_fork_extra_info(std::ostream& o, uint64_t t, uint64_t now, std::chrono::seconds block_time) { - uint64_t blocks_per_day = 86400 / block_time; + double blocks_per_day = 24h / block_time; if (t == now) return o << " (forking now)"; @@ -428,8 +416,8 @@ static std::ostream& print_fork_extra_info(std::ostream& o, uint64_t t, uint64_t if (dblocks <= 30) return o << dblocks << " blocks)"; if (dblocks <= blocks_per_day / 2) - return o << boost::format("%.1f hours)") % (dblocks / (float)blocks_per_day * 24); - return o << boost::format("%.1f days)") % (dblocks / (float)blocks_per_day); + return o << fmt::format("{:.1f} hours)", dblocks / blocks_per_day * 24); + return o << fmt::format("{:.1f} days)", dblocks / blocks_per_day); } static float get_sync_percentage(uint64_t height, uint64_t target_height) @@ -440,10 +428,6 @@ static float get_sync_percentage(uint64_t height, uint64_t target_height) return 99.9f; // to avoid 100% when not fully synced return pc; } -static float get_sync_percentage(const GET_INFO::response &ires) -{ - return get_sync_percentage(ires.height, ires.target_height); -} bool rpc_command_executor::show_status() { GET_INFO::response ires{}; @@ -505,7 +489,7 @@ bool rpc_command_executor::show_status() { std::ostringstream str; str << "Height: " << ires.height; if (ires.height != net_height) - str << "/" << net_height << " (" << boost::format("%.1f") % get_sync_percentage(ires) << "%)"; + str << fmt::format("/{} ({:.1f}%)", net_height, get_sync_percentage(ires.height, net_height)); if (ires.testnet) str << " ON TESTNET"; else if (ires.devnet) str << " ON DEVNET"; @@ -516,8 +500,10 @@ bool rpc_command_executor::show_status() { if (ires.was_bootstrap_ever_used && *ires.was_bootstrap_ever_used && ires.bootstrap_daemon_address) { str << ", bootstrap " << *ires.bootstrap_daemon_address; - if (ires.untrusted) - str << boost::format(", local height: %llu (%.1f%%)") % *ires.height_without_bootstrap % get_sync_percentage(*ires.height_without_bootstrap, net_height); + if (ires.untrusted) { + auto hwb = *ires.height_without_bootstrap; + str << fmt::format(", local height: {} ({:.1f}%)", hwb, get_sync_percentage(hwb, net_height)); + } else str << " was used"; } @@ -533,7 +519,7 @@ bool rpc_command_executor::show_status() { str << ", v" << (ires.version.empty() ? "?.?.?" : ires.version); str << "(net v" << +hfres.version << ')'; if (hfres.earliest_height) - print_fork_extra_info(str, *hfres.earliest_height, net_height, ires.target); + print_fork_extra_info(str, *hfres.earliest_height, net_height, 1s * ires.target); std::time_t now = std::time(nullptr); @@ -637,42 +623,33 @@ bool rpc_command_executor::print_connections() { if (!invoke({}, res, "Failed to retrieve connection info")) return false; - tools::msg_writer() << std::setw(30) << std::left << "Remote Host" - << std::setw(8) << "Type" - << std::setw(20) << "Peer id" - << std::setw(20) << "Support Flags" - << std::setw(30) << "Recv/Sent (inactive,sec)" - << std::setw(25) << "State" - << std::setw(20) << "Livetime(sec)" - << std::setw(12) << "Down (kB/s)" - << std::setw(14) << "Down(now)" - << std::setw(10) << "Up (kB/s)" - << std::setw(13) << "Up(now)" - << std::endl; + constexpr auto hdr_fmt = "{:<30}{:<8}{:<20}{:<30}{:<25}{:<20}{:<12s}{:<14s}{:<10s}{:<13s}"sv; + constexpr auto row_fmt = "{:<30}{:<8}{:<20}{:<30}{:<25}{:<20}{:<12.1f}{:<14.1f}{:<10.1f}{:<13.1f}{}{}"sv; + tools::msg_writer() << fmt::format(hdr_fmt, + "Remote Host", "Type", "Peer id", "Recv/Sent (inactive,sec)", "State", "Livetime(sec)", + "Down (kB/sec)", "Down(now)", "Up (kB/s)", "Up(now)"); for (auto & info : res.connections) { std::string address = info.incoming ? "INC " : "OUT "; - address += info.ip + ":" + info.port; - //std::string in_out = info.incoming ? "INC " : "OUT "; - tools::msg_writer() - //<< std::setw(30) << std::left << in_out - << std::setw(30) << std::left << address - << std::setw(8) << (get_address_type_name((epee::net_utils::address_type)info.address_type)) - << std::setw(20) << info.peer_id - << std::setw(20) << info.support_flags - << std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(tools::to_seconds(info.recv_idle_time)) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(tools::to_seconds(info.send_idle_time)) + ")" - << std::setw(25) << info.state - << std::setw(20) << std::to_string(tools::to_seconds(info.live_time)) - << std::setw(12) << info.avg_download - << std::setw(14) << info.current_download - << std::setw(10) << info.avg_upload - << std::setw(13) << info.current_upload - - << std::left << (info.localhost ? "[LOCALHOST]" : "") - << std::left << (info.local_ip ? "[LAN]" : ""); - //tools::msg_writer() << boost::format("%-25s peer_id: %-25s %s") % address % info.peer_id % in_out; - + address += info.ip; + address += ':'; + address += info.port; + tools::msg_writer() << fmt::format(row_fmt, + address, + info.address_type, + info.peer_id, + fmt::format("{}({}/{})", info.recv_count, + tools::friendly_duration(info.recv_idle_time), + tools::friendly_duration(info.send_idle_time)), + info.state, + tools::friendly_duration(info.live_time), + info.avg_upload / 1000., + info.current_download / 1000., + info.avg_upload / 1000., + info.current_upload / 1000., + info.localhost ? "[LOCALHOST]" : "", + info.local_ip ? "[LAN]" : ""); } return true; @@ -691,24 +668,24 @@ bool rpc_command_executor::print_net_stats() uint64_t average = seconds > 0 ? net_stats_res.total_bytes_in / seconds : 0; uint64_t limit = limit_res.limit_down * 1024; // convert to bytes, as limits are always kB/s double percent = (double)average / (double)limit * 100.0; - tools::success_msg_writer() << boost::format("Received %u bytes (%s) in %u packets, average %s/s = %.2f%% of the limit of %s/s") - % net_stats_res.total_bytes_in - % tools::get_human_readable_bytes(net_stats_res.total_bytes_in) - % net_stats_res.total_packets_in - % tools::get_human_readable_bytes(average) - % percent - % tools::get_human_readable_bytes(limit); + tools::success_msg_writer() << fmt::format("Received {} bytes ({}) in {} packets, average {}/s = {:.2f}% of the limit of {}/s", + net_stats_res.total_bytes_in, + tools::get_human_readable_bytes(net_stats_res.total_bytes_in), + net_stats_res.total_packets_in, + tools::get_human_readable_bytes(average), + percent, + tools::get_human_readable_bytes(limit)); average = seconds > 0 ? net_stats_res.total_bytes_out / seconds : 0; limit = limit_res.limit_up * 1024; percent = (double)average / (double)limit * 100.0; - tools::success_msg_writer() << boost::format("Sent %u bytes (%s) in %u packets, average %s/s = %.2f%% of the limit of %s/s") - % net_stats_res.total_bytes_out - % tools::get_human_readable_bytes(net_stats_res.total_bytes_out) - % net_stats_res.total_packets_out - % tools::get_human_readable_bytes(average) - % percent - % tools::get_human_readable_bytes(limit); + tools::success_msg_writer() << fmt::format("Sent {} bytes ({}) in {} packets, average {}/s = {:.2f}% of the limit of {}/s", + net_stats_res.total_bytes_out, + tools::get_human_readable_bytes(net_stats_res.total_bytes_out), + net_stats_res.total_packets_out, + tools::get_human_readable_bytes(average), + percent, + tools::get_human_readable_bytes(limit)); return true; } @@ -1043,7 +1020,7 @@ bool rpc_command_executor::print_transaction_pool_stats() { else { uint64_t backlog = (res.pool_stats.bytes_total + full_reward_zone - 1) / full_reward_zone; - backlog_message = (boost::format("estimated %u block (%u minutes) backlog") % backlog % (backlog * TARGET_BLOCK_TIME / 1min)).str(); + backlog_message = fmt::format("estimated {} block ({} minutes) backlog", backlog, (backlog * TARGET_BLOCK_TIME / 1min)); } tools::msg_writer() << n_transactions << " tx(es), " << res.pool_stats.bytes_total << " bytes total (min " << res.pool_stats.bytes_min << ", max " << res.pool_stats.bytes_max << ", avg " << avg_bytes << ", median " << res.pool_stats.bytes_med << ")" << std::endl diff --git a/src/gen_multisig/gen_multisig.cpp b/src/gen_multisig/gen_multisig.cpp index 7b4d41fc0..daf2076bc 100644 --- a/src/gen_multisig/gen_multisig.cpp +++ b/src/gen_multisig/gen_multisig.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "crypto/crypto.h" // for crypto::secret_key definition #include "common/i18n.h" #include "common/command_line.h" @@ -78,7 +78,7 @@ namespace static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path& basename, network_type nettype, bool create_address_file) { - tools::msg_writer() << (boost::format(genms::tr("Generating %u %u/%u multisig wallets")) % total % threshold % total).str(); + tools::msg_writer() << fmt::format(genms::tr("Generating {:d} {:d}/{:d} multisig wallets"), total, threshold, total); const auto pwd_container = tools::password_container::prompt(true, "Enter password for new multisig wallets"); @@ -227,7 +227,7 @@ int main(int argc, char* argv[]) } if (threshold <= 1 || threshold > total) { - tools::fail_msg_writer() << (boost::format(genms::tr("Error: expected N > 1 and N <= M, but got N==%u and M==%d")) % threshold % total).str(); + tools::fail_msg_writer() << fmt::format(genms::tr("Error: expected N > 1 and N <= M, but got N=={:d} and M=={:d}"), threshold, total); return 1; } fs::path basename;