From: Joel Rosdahl Date: Tue, 21 Feb 2023 20:34:18 +0000 (+0100) Subject: refactor: Move Util::parse_size to util X-Git-Tag: v4.8~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66c9c76151497638f1be2bb05ccc2d58d075fc2d;p=thirdparty%2Fccache.git refactor: Move Util::parse_size to util --- diff --git a/src/Config.cpp b/src/Config.cpp index 1e5547737..bf79acea8 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1037,7 +1037,7 @@ Config::set_item(const std::string& key, break; case ConfigItem::max_size: - m_max_size = Util::parse_size(value); + m_max_size = util::value_or_throw(util::parse_size(value)); break; case ConfigItem::msvc_dep_prefix: diff --git a/src/Util.cpp b/src/Util.cpp index c9cf3cbb6..6ba1b3431 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -980,47 +980,6 @@ parse_duration(std::string_view duration) } } -uint64_t -parse_size(const std::string& value) -{ - errno = 0; - - char* p; - double result = strtod(value.c_str(), &p); - if (errno != 0 || result < 0 || p == value.c_str() || value.empty()) { - throw core::Error(FMT("invalid size: \"{}\"", value)); - } - - while (isspace(*p)) { - ++p; - } - - if (*p != '\0') { - unsigned multiplier = *(p + 1) == 'i' ? 1024 : 1000; - switch (*p) { - case 'T': - result *= multiplier; - [[fallthrough]]; - case 'G': - result *= multiplier; - [[fallthrough]]; - case 'M': - result *= multiplier; - [[fallthrough]]; - case 'K': - case 'k': - result *= multiplier; - break; - default: - throw core::Error(FMT("invalid size: \"{}\"", value)); - } - } else { - // Default suffix: G. - result *= 1000 * 1000 * 1000; - } - return static_cast(result); -} - #ifndef _WIN32 std::string read_link(const std::string& path) diff --git a/src/Util.hpp b/src/Util.hpp index 7f7be73e2..d1a4796fc 100644 --- a/src/Util.hpp +++ b/src/Util.hpp @@ -277,11 +277,6 @@ std::string normalize_concrete_absolute_path(const std::string& path); // into seconds. Throws `core::Error` on error. uint64_t parse_duration(std::string_view duration); -// Parse a "size value", i.e. a string that can end in k, M, G, T (10-based -// suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility, K -// is also recognized as a synonym of k. Throws `core::Error` on parse error. -uint64_t parse_size(const std::string& value); - #ifndef _WIN32 // Like readlink(2) but returns the string (or the empty string on failure). std::string read_link(const std::string& path); diff --git a/src/core/mainoptions.cpp b/src/core/mainoptions.cpp index 40db41dcc..1fba40db7 100644 --- a/src/core/mainoptions.cpp +++ b/src/core/mainoptions.cpp @@ -485,7 +485,7 @@ process_main_options(int argc, const char* const* argv) break; case TRIM_MAX_SIZE: - trim_max_size = Util::parse_size(arg); + trim_max_size = util::value_or_throw(util::parse_size(arg)); break; case TRIM_METHOD: @@ -657,7 +657,7 @@ process_main_options(int argc, const char* const* argv) } case 'M': { // --max-size - uint64_t size = Util::parse_size(arg); + uint64_t size = util::value_or_throw(util::parse_size(arg)); config.set_value_in_file(config.config_path(), "max_size", arg); if (size == 0) { PRINT_RAW(stdout, "Unset cache size limit\n"); diff --git a/src/util/string.cpp b/src/util/string.cpp index 914f1f740..4ad3decda 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -114,6 +114,48 @@ parse_signed(std::string_view value, } } +nonstd::expected +parse_size(const std::string& value) +{ + errno = 0; + + char* p; + double result = strtod(value.c_str(), &p); + if (errno != 0 || result < 0 || p == value.c_str() || value.empty()) { + return nonstd::make_unexpected(FMT("invalid size: \"{}\"", value)); + } + + while (isspace(*p)) { + ++p; + } + + if (*p != '\0') { + unsigned multiplier = *(p + 1) == 'i' ? 1024 : 1000; + switch (*p) { + case 'T': + result *= multiplier; + [[fallthrough]]; + case 'G': + result *= multiplier; + [[fallthrough]]; + case 'M': + result *= multiplier; + [[fallthrough]]; + case 'K': + case 'k': + result *= multiplier; + break; + default: + return nonstd::make_unexpected(FMT("invalid size: \"{}\"", value)); + } + } else { + // Default suffix: G. + result *= 1000 * 1000 * 1000; + } + + return static_cast(result); +} + nonstd::expected parse_umask(std::string_view value) { diff --git a/src/util/string.hpp b/src/util/string.hpp index 5154915df..7df40aada 100644 --- a/src/util/string.hpp +++ b/src/util/string.hpp @@ -77,6 +77,11 @@ parse_signed(std::string_view value, std::optional max_value = std::nullopt, std::string_view description = "integer"); +// Parse a "size value", i.e. a string that can end in k, M, G, T (10-based +// suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility, K +// is also recognized as a synonym of k. +nonstd::expected parse_size(const std::string& value); + // Parse `value` (an octal integer). nonstd::expected parse_umask(std::string_view value); diff --git a/unittest/test_Util.cpp b/unittest/test_Util.cpp index 9c54e0b4c..fd02076b7 100644 --- a/unittest/test_Util.cpp +++ b/unittest/test_Util.cpp @@ -601,33 +601,6 @@ TEST_CASE("Util::parse_duration") "invalid suffix (supported: d (day) and s (second)): \"2\""); } -TEST_CASE("Util::parse_size") -{ - CHECK(Util::parse_size("0") == 0); - CHECK(Util::parse_size("42") // Default suffix: G - == static_cast(42) * 1000 * 1000 * 1000); - CHECK(Util::parse_size("78k") == 78 * 1000); - CHECK(Util::parse_size("78K") == 78 * 1000); - CHECK(Util::parse_size("1.1 M") == (int64_t(1.1 * 1000 * 1000))); - CHECK(Util::parse_size("438.55M") == (int64_t(438.55 * 1000 * 1000))); - CHECK(Util::parse_size("1 G") == 1 * 1000 * 1000 * 1000); - CHECK(Util::parse_size("2T") - == static_cast(2) * 1000 * 1000 * 1000 * 1000); - CHECK(Util::parse_size("78 Ki") == 78 * 1024); - CHECK(Util::parse_size("1.1Mi") == (int64_t(1.1 * 1024 * 1024))); - CHECK(Util::parse_size("438.55 Mi") == (int64_t(438.55 * 1024 * 1024))); - CHECK(Util::parse_size("1Gi") == 1 * 1024 * 1024 * 1024); - CHECK(Util::parse_size("2 Ti") - == static_cast(2) * 1024 * 1024 * 1024 * 1024); - - CHECK(Util::parse_size("9MB") == 9 * 1000 * 1000); - CHECK(Util::parse_size("9MiB") == 9 * 1024 * 1024); - - CHECK_THROWS_WITH(Util::parse_size(""), "invalid size: \"\""); - CHECK_THROWS_WITH(Util::parse_size("x"), "invalid size: \"x\""); - CHECK_THROWS_WITH(Util::parse_size("10x"), "invalid size: \"10x\""); -} - TEST_CASE("Util::remove_extension") { CHECK(Util::remove_extension("") == ""); diff --git a/unittest/test_util_string.cpp b/unittest/test_util_string.cpp index 26fcab246..12746d080 100644 --- a/unittest/test_util_string.cpp +++ b/unittest/test_util_string.cpp @@ -183,6 +183,33 @@ TEST_CASE("util::parse_signed") == "banana must be between 1 and 2"); } +TEST_CASE("util::parse_size") +{ + CHECK(*util::parse_size("0") == 0); + CHECK(*util::parse_size("42") // Default suffix: G + == static_cast(42) * 1000 * 1000 * 1000); + CHECK(*util::parse_size("78k") == 78 * 1000); + CHECK(*util::parse_size("78K") == 78 * 1000); + CHECK(*util::parse_size("1.1 M") == (int64_t(1.1 * 1000 * 1000))); + CHECK(*util::parse_size("438.55M") == (int64_t(438.55 * 1000 * 1000))); + CHECK(*util::parse_size("1 G") == 1 * 1000 * 1000 * 1000); + CHECK(*util::parse_size("2T") + == static_cast(2) * 1000 * 1000 * 1000 * 1000); + CHECK(*util::parse_size("78 Ki") == 78 * 1024); + CHECK(*util::parse_size("1.1Mi") == (int64_t(1.1 * 1024 * 1024))); + CHECK(*util::parse_size("438.55 Mi") == (int64_t(438.55 * 1024 * 1024))); + CHECK(*util::parse_size("1Gi") == 1 * 1024 * 1024 * 1024); + CHECK(*util::parse_size("2 Ti") + == static_cast(2) * 1024 * 1024 * 1024 * 1024); + + CHECK(*util::parse_size("9MB") == 9 * 1000 * 1000); + CHECK(*util::parse_size("9MiB") == 9 * 1024 * 1024); + + CHECK(util::parse_size("").error() == "invalid size: \"\""); + CHECK(util::parse_size("x").error() == "invalid size: \"x\""); + CHECK(util::parse_size("10x").error() == "invalid size: \"10x\""); +} + TEST_CASE("util::parse_umask") { CHECK(util::parse_umask("1") == 1U);