blob: 5f80755a80868ca03567591207a35bd6167865aa (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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 <typename Char>
auto get_multiplier(Char c) -> std::expected<std::uint64_t, error>
{
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 <typename T, typename Char>
[[nodiscard]]
auto parse_size(std::basic_string_view<Char> str) -> std::expected<T, error>
{
// 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<Char>(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<T>::max() / 10))
co_return error(std::errc::result_out_of_range);
ret *= 10;
auto digit = static_cast<T>(c - '0');
if ((std::numeric_limits<T>::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<T>::max() / mult))
co_return error(std::errc::result_out_of_range);
co_return ret *mult;
}
export template <typename T>
[[nodiscard]] auto parse_size(char const *s)
{
return parse_size<T>(std::string_view(s));
}
export template <typename T>
[[nodiscard]] auto parse_size(wchar_t const *s)
{
return parse_size<T>(std::wstring_view(s));
}
} // namespace nihil
|