From: Joel Rosdahl Date: Mon, 27 Jul 2020 18:03:06 +0000 (+0200) Subject: C++-ify parse_size_with_suffix X-Git-Tag: v4.0~283 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=aa705c0422ec7fdd57cb28ff19c901a193917d0d;p=thirdparty%2Fccache.git C++-ify parse_size_with_suffix --- diff --git a/src/Config.cpp b/src/Config.cpp index f58ecc640..9a708e7dc 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -212,16 +212,6 @@ parse_double(const std::string& value) return result; } -uint64_t -parse_cache_size(const std::string& value) -{ - uint64_t result; - if (!parse_size_with_suffix(value.c_str(), &result)) { - throw Error(fmt::format("invalid size: \"{}\"", value)); - } - return result; -} - std::string format_cache_size(uint64_t value) { @@ -762,7 +752,7 @@ Config::set_item(const std::string& key, break; case ConfigItem::max_size: - m_max_size = parse_cache_size(value); + m_max_size = Util::parse_size(value); break; case ConfigItem::path: diff --git a/src/Util.cpp b/src/Util.cpp index b8b92f89a..61b9506ed 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -737,6 +737,47 @@ parse_int(const std::string& value) return result; } +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 Error(fmt::format("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 Error(fmt::format("invalid size: \"{}\"", value)); + } + } else { + // Default suffix: G. + result *= 1000 * 1000 * 1000; + } + return static_cast(result); +} + uint32_t parse_uint32(const std::string& value) { diff --git a/src/Util.hpp b/src/Util.hpp index b2cd2844d..ca10f4bae 100644 --- a/src/Util.hpp +++ b/src/Util.hpp @@ -274,6 +274,11 @@ uint32_t parse_duration(const std::string& duration); // Throws `Error` on error. int parse_int(const std::string& value); +// 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 `Error` on parse error. +uint64_t parse_size(const std::string& value); + // Parse a string into an unsigned 32-bit integer. // // Throws `Error` on error. diff --git a/src/ccache.cpp b/src/ccache.cpp index dfdc5ecd5..0b727c7ac 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -2329,10 +2329,7 @@ handle_main_options(int argc, const char* const* argv) } case 'M': { // --max-size - uint64_t size; - if (!parse_size_with_suffix(optarg, &size)) { - fatal("invalid size: %s", optarg); - } + uint64_t size = Util::parse_size(optarg); Config::set_value_in_file( ctx.config.primary_config_path(), "max_size", optarg); if (size == 0) { diff --git a/src/legacy_util.cpp b/src/legacy_util.cpp index 00c97e302..e007a7049 100644 --- a/src/legacy_util.cpp +++ b/src/legacy_util.cpp @@ -342,51 +342,6 @@ reformat(char** ptr, const char* format, ...) } } -// 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. -bool -parse_size_with_suffix(const char* str, uint64_t* size) -{ - errno = 0; - - char* p; - double x = strtod(str, &p); - if (errno != 0 || x < 0 || p == str || *str == '\0') { - return false; - } - - while (isspace(*p)) { - ++p; - } - - if (*p != '\0') { - unsigned multiplier = *(p + 1) == 'i' ? 1024 : 1000; - switch (*p) { - case 'T': - x *= multiplier; - // Fallthrough. - case 'G': - x *= multiplier; - // Fallthrough. - case 'M': - x *= multiplier; - // Fallthrough. - case 'K': - case 'k': - x *= multiplier; - break; - default: - return false; - } - } else { - // Default suffix: G. - x *= 1000 * 1000 * 1000; - } - *size = (uint64_t)x; - return true; -} - #if !defined(_WIN32) && !defined(HAVE_LOCALTIME_R) // localtime_r replacement. (Mingw-w64 has an inline localtime_r which is not // detected by AC_CHECK_FUNCS.) diff --git a/src/legacy_util.hpp b/src/legacy_util.hpp index 16049292d..4310c0684 100644 --- a/src/legacy_util.hpp +++ b/src/legacy_util.hpp @@ -36,7 +36,6 @@ char* x_strdup(const char* s); char* x_strndup(const char* s, size_t n); void x_setenv(const char* name, const char* value); void x_unsetenv(const char* name); -bool parse_size_with_suffix(const char* str, uint64_t* size); #ifndef HAVE_LOCALTIME_R struct tm* localtime_r(const time_t* timep, struct tm* result); #endif diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 5f919d94f..16aae0edd 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -17,7 +17,6 @@ set( test_argprocessing.cpp test_compopt.cpp test_hashutil.cpp - test_legacy_util.cpp test_logging.cpp) if(INODE_CACHE_SUPPORTED) diff --git a/unittest/test_Util.cpp b/unittest/test_Util.cpp index 844cd6253..eaa6965cd 100644 --- a/unittest/test_Util.cpp +++ b/unittest/test_Util.cpp @@ -568,6 +568,30 @@ TEST_CASE("Util::parse_int") } } +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_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::parse_uint32") { CHECK(Util::parse_uint32("0") == 0); diff --git a/unittest/test_legacy_util.cpp b/unittest/test_legacy_util.cpp deleted file mode 100644 index 0630cbfaf..000000000 --- a/unittest/test_legacy_util.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2010-2020 Joel Rosdahl and other contributors -// -// See doc/AUTHORS.adoc for a complete list of contributors. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 3 of the License, or (at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -// more details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the Free Software Foundation, Inc., 51 -// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -#include "../src/legacy_util.hpp" - -#include "third_party/doctest.h" - -#define CHECK_STR_EQ_FREE2(a, b) \ - do { \ - CHECK(strcmp((a), (b)) == 0); \ - free(b); \ - } while (false) - -TEST_SUITE_BEGIN("legacy_util"); - -TEST_CASE("parse_size_with_suffix") -{ - uint64_t size; - size_t i; - struct - { - const char* size; - int64_t expected; - } sizes[] = { - {"0", 0}, - {"42", (int64_t)42 * 1000 * 1000 * 1000}, // Default suffix: G - - {"78k", 78 * 1000}, - {"78K", 78 * 1000}, - {"1.1 M", (int64_t)(1.1 * 1000 * 1000)}, - {"438.55M", (int64_t)(438.55 * 1000 * 1000)}, - {"1 G", 1 * 1000 * 1000 * 1000}, - {"2T", (int64_t)2 * 1000 * 1000 * 1000 * 1000}, - - {"78 Ki", 78 * 1024}, - {"1.1Mi", (int64_t)(1.1 * 1024 * 1024)}, - {"438.55 Mi", (int64_t)(438.55 * 1024 * 1024)}, - {"1Gi", 1 * 1024 * 1024 * 1024}, - {"2 Ti", (int64_t)2 * 1024 * 1024 * 1024 * 1024}, - }; - - for (i = 0; i < ARRAY_SIZE(sizes); ++i) { - CHECK(parse_size_with_suffix(sizes[i].size, &size)); - CHECK(size == sizes[i].expected); - } -} - -TEST_SUITE_END();