blob: c95ac50c1b1ee2bd2412a1fde7f80eb842eb994d (
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
/*
* This source code is released into the public domain.
*/
module;
#include <algorithm>
#include <coroutine>
#include <cstdint>
#include <expected>
#include <ranges>
#include <string>
#include <system_error>
#include <utility>
export module nihil.util:parse_size;
import nihil.core;
import nihil.error;
import nihil.monad;
import :ctype;
namespace nihil {
template<typename Char>
auto get_multiplier(Char c) -> std::expected<std::uint64_t, error>
{
auto ret = std::uint64_t{1};
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 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<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 std::unexpected(error(errc::empty_string));
auto ret = T{0};
for (auto c : num_str) {
if (ret > (std::numeric_limits<T>::max() / 10))
co_return std::unexpected(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 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<T>::max() / mult))
co_return std::unexpected(error(
std::errc::result_out_of_range));
co_return ret * mult;
}
export template<typename T>
[[nodiscard]] inline auto parse_size(char const *s)
{
return parse_size<T>(std::string_view(s));
}
export template<typename T>
[[nodiscard]] inline auto parse_size(wchar_t const *s)
{
return parse_size<T>(std::wstring_view(s));
}
}
|