From 5adeb648f74c1771164c0686d6e0fc584cf36d9e Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Wed, 2 Jul 2025 04:00:06 +0100 Subject: move everything from util to core --- nihil.core/parse_size.ccm | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 nihil.core/parse_size.ccm (limited to 'nihil.core/parse_size.ccm') diff --git a/nihil.core/parse_size.ccm b/nihil.core/parse_size.ccm new file mode 100644 index 0000000..5f80755 --- /dev/null +++ b/nihil.core/parse_size.ccm @@ -0,0 +1,90 @@ +// This source code is released into the public domain. +export module nihil.core:parse_size; + +import nihil.std; + +import :ctype; +import :errc; +import :error; +import :monad; + +namespace nihil { + +export template +auto get_multiplier(Char c) -> std::expected +{ + auto ret = std::uint64_t{1}; + + // clang-format off + switch (c) { + case 'p': case 'P': ret *= 1024; // NOLINT + case 't': case 'T': ret *= 1024; // NOLINT + case 'g': case 'G': ret *= 1024; // NOLINT + case 'm': case 'M': ret *= 1024; // NOLINT + case 'k': case 'K': ret *= 1024; // NOLINT + return ret; + + default: + return error(errc::invalid_unit); + } + // clang-format on +} + +// 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 error(errc::empty_string); + + auto ret = T{0}; + + for (auto c : num_str) { + if (ret > (std::numeric_limits::max() / 10)) + co_return error(std::errc::result_out_of_range); + ret *= 10; + + auto digit = static_cast(c - '0'); + if ((std::numeric_limits::max() - digit) < ret) + co_return 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 error(errc::invalid_unit); + + auto mult = co_await get_multiplier(mchar); + + if (std::cmp_greater(ret, std::numeric_limits::max() / mult)) + co_return error(std::errc::result_out_of_range); + + co_return ret *mult; +} + +export template +[[nodiscard]] auto parse_size(char const *s) +{ + return parse_size(std::string_view(s)); +} + +export template +[[nodiscard]] auto parse_size(wchar_t const *s) +{ + return parse_size(std::wstring_view(s)); +} + +} // namespace nihil -- cgit v1.2.3