/* * This source code is released into the public domain. */ module; #include #include #include #include #include #include #include #include export module nihil.util:parse_size; import nihil.core; import nihil.error; import nihil.monad; import :ctype; namespace nihil { template auto get_multiplier(Char c) -> std::expected { auto ret = std::uint64_t{1}; switch (c) { case 'p': case 'P': ret *= 1024; case 't': case 'T': ret *= 1024; case 'g': case 'G': ret *= 1024; case 'm': case 'M': ret *= 1024; case 'k': case 'K': ret *= 1024; return ret; default: return std::unexpected(error(errc::invalid_unit)); } } /* * Parse a string containing a human-formatted size, such as "1024" * or "4g". Parsing is always done in the "C" locale and does not * recognise thousands separators or negative numbers. */ export template [[nodiscard]] auto parse_size(std::basic_string_view str) -> std::expected { // Extract the numeric part of the string. auto it = std::ranges::find_if_not(str, is_c_digit); auto num_str = std::basic_string_view( std::ranges::begin(str), it); if (num_str.empty()) co_return std::unexpected(error(errc::empty_string)); auto ret = T{0}; for (auto c : num_str) { if (ret > (std::numeric_limits::max() / 10)) co_return std::unexpected(error( std::errc::result_out_of_range)); ret *= 10; auto digit = static_cast(c - '0'); if ((std::numeric_limits::max() - digit) < ret) co_return std::unexpected(error( std::errc::result_out_of_range)); ret += digit; } if (it == str.end()) // No multiplier. co_return ret; auto mchar = *it++; if (it != str.end()) // Multiplier is more than one character. co_return std::unexpected(error(errc::invalid_unit)); auto mult = co_await get_multiplier(mchar); if (std::cmp_greater(ret, std::numeric_limits::max() / mult)) co_return std::unexpected(error( std::errc::result_out_of_range)); co_return ret * mult; } export template [[nodiscard]] inline auto parse_size(char const *s) { return parse_size(std::string_view(s)); } export template [[nodiscard]] inline auto parse_size(wchar_t const *s) { return parse_size(std::wstring_view(s)); } }