diff --git a/include/sec21/memory.h b/include/sec21/memory.h index 1105eb1..dd7ae6a 100644 --- a/include/sec21/memory.h +++ b/include/sec21/memory.h @@ -68,9 +68,14 @@ namespace sec21 } } // namespace sec21 +#if __cpp_lib_constexpr_charconv >= 202207L template <> -struct std::formatter +class std::formatter { + bool human_readable{false}; + std::size_t precision{0}; + + public: constexpr auto parse(std::format_parse_context& ctx) { auto pos = ctx.begin(); @@ -78,10 +83,15 @@ struct std::formatter if (*pos == 'h' or *pos == 'H') { human_readable = true; } +#ifndef WIN32 if (*pos == '.') { + //! \todo some issues with MSVC compiler + // maybe should work if proposal 'std::from_chars should work with std::string_view' is approved + // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2007r0.html pos = std::from_chars(++pos, ctx.end(), precision).ptr; --pos; } +#endif ++pos; } return pos; @@ -90,25 +100,21 @@ struct std::formatter auto format(sec21::memory const& obj, std::format_context& ctx) const { constexpr auto units = std::array{"B", "kB", "MB", "GB", "TB", "PB"}; + auto value = static_cast(obj.bytes); + auto unit = units[0]; if (human_readable) { constexpr auto factor = 1000; //! \todo constexpr auto factorIEC = 1024; - auto value = static_cast(obj.bytes); - auto unit = units[0]; - for (decltype(units.size()) i = 0; i < units.size(); ++i) { if (obj.bytes >= std::pow(factor, i)) { value = static_cast(obj.bytes) / std::pow(factor, i); unit = units[i]; } } - return std::format_to(ctx.out(), "{:.{}f}{}", value, precision, unit); } - return std::format_to(ctx.out(), "{}{}", obj.bytes, units[0]); + return std::format_to(ctx.out(), "{:.{}f}{}", value, precision, unit); } - - bool human_readable{false}; - std::size_t precision{2}; }; +#endif \ No newline at end of file diff --git a/tests/memory.cpp b/tests/memory.cpp index d0d25ac..42b5e93 100644 --- a/tests/memory.cpp +++ b/tests/memory.cpp @@ -20,7 +20,7 @@ TEST_CASE("memory class", "[sec21]") } SECTION("test safety check of subtraction operator") { - REQUIRE_THROWS([] { auto result = memory{2} - memory{10}; }()); + REQUIRE_THROWS([] { [[maybe_unused]] auto result = memory{2} - memory{10}; }()); // REQUIRE_THROWS([] { auto result = memory{2} - std::byte{10}; }()); } SECTION("multiplication") @@ -28,24 +28,35 @@ TEST_CASE("memory class", "[sec21]") REQUIRE(memory{2} * memory{1} == 2_B); REQUIRE(4_kiB * std::byte{2} == memory{8192}); } +#if __cpp_lib_constexpr_charconv >= 202207L SECTION("test formatter") { SECTION("default") { REQUIRE(std::format("{}", memory{1024}) == "1024B"); } SECTION("format output to a human readable format") { - REQUIRE(std::format("{:h}", memory{1_kiB}) == "1.02kB"); - REQUIRE(std::format("{:h}", memory{1_MiB}) == "1.05MB"); - REQUIRE(std::format("{:h}", memory{1_GiB}) == "1.07GB"); - REQUIRE(std::format("{:h}", memory{1_TiB}) == "1.10TB"); - REQUIRE(std::format("{:h}", memory{1_PiB}) == "1.13PB"); + REQUIRE(std::format("{:h}", memory{1_kiB}) == "1kB"); + REQUIRE(std::format("{:h}", memory{1_MiB}) == "1MB"); + REQUIRE(std::format("{:h}", memory{1_GiB}) == "1GB"); + REQUIRE(std::format("{:h}", memory{1_TiB}) == "1TB"); + REQUIRE(std::format("{:h}", memory{1_PiB}) == "1PB"); } +#ifndef WIN32 SECTION("human readable format with precision") { REQUIRE(std::format("{:.0h}", memory{1024 * 1024}) == "1MB"); REQUIRE(std::format("{:.1h}", memory{1024 * 1024}) == "1.0MB"); + REQUIRE(std::format("{:.2h}", memory{1024 * 1024}) == "1.05MB"); REQUIRE(std::format("{:.4h}", memory{1024 * 1024}) == "1.0486MB"); - REQUIRE(std::format("{:.h}", memory{1024 * 1024}) == "1.05MB"); + REQUIRE(std::format("{:.h}", memory{1024 * 1024}) == "1MB"); } + SECTION("format with precision") + { + REQUIRE(std::format("{:.0}", memory{1}) == "1B"); + REQUIRE(std::format("{:.1}", memory{1}) == "1.0B"); + REQUIRE(std::format("{:.4}", memory{1}) == "1.0000B"); + } +#endif } +#endif }