/src/Fast-DDS/src/cpp/utils/UnitsParser.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | /* |
16 | | * UnitsParser.cpp |
17 | | * |
18 | | */ |
19 | | |
20 | | #include <utils/UnitsParser.hpp> |
21 | | |
22 | | #include <algorithm> |
23 | | #include <cctype> |
24 | | #include <cstdint> |
25 | | #include <limits> |
26 | | #include <map> |
27 | | #include <regex> |
28 | | #include <set> |
29 | | #include <stdexcept> |
30 | | #include <string> |
31 | | |
32 | | namespace eprosima { |
33 | | namespace fastdds { |
34 | | namespace dds { |
35 | | namespace utils { |
36 | | |
37 | | void to_uppercase( |
38 | | std::string& st) noexcept |
39 | 19.2k | { |
40 | | // These lambda has been taken from the notes in https://en.cppreference.com/w/cpp/string/byte/toupper |
41 | | // Note how the argument passed is unsigned char to avoid undefined behavior |
42 | 19.2k | auto my_toupper = [](unsigned char c) |
43 | 7.51M | { |
44 | 7.51M | return static_cast<char>(std::toupper(c)); |
45 | 7.51M | }; |
46 | 19.2k | std::transform(st.begin(), st.end(), st.begin(), my_toupper); |
47 | 19.2k | } |
48 | | |
49 | | uint32_t parse_value_and_units( |
50 | | std::string& value, |
51 | | std::string units) |
52 | 20.4k | { |
53 | 20.4k | static const std::map<std::string, std::uint32_t> magnitudes = { |
54 | 20.4k | {"", 1}, |
55 | 20.4k | {"B", 1}, |
56 | 20.4k | {"KB", 1000}, |
57 | 20.4k | {"MB", 1000 * 1000}, |
58 | 20.4k | {"GB", 1000 * 1000 * 1000}, |
59 | 20.4k | {"KIB", 1024}, |
60 | 20.4k | {"MIB", 1024 * 1024}, |
61 | 20.4k | {"GIB", 1024 * 1024 * 1024}, |
62 | 20.4k | }; |
63 | | |
64 | 20.4k | uint64_t num = 0; |
65 | 20.4k | try |
66 | 20.4k | { |
67 | 20.4k | num = std::stoull(value); |
68 | 20.4k | } |
69 | 20.4k | catch (std::out_of_range&) |
70 | 20.4k | { |
71 | 1.22k | throw std::invalid_argument("Failed to parse value from string." \ |
72 | 1.22k | " The number is too large to be converted to bytes (Max: (2^32)-1 Bytes)."); |
73 | 1.22k | } |
74 | | |
75 | 19.2k | to_uppercase(units); |
76 | | |
77 | 19.2k | uint32_t magnitude = 0; |
78 | 19.2k | try |
79 | 19.2k | { |
80 | 19.2k | magnitude = magnitudes.at(units); |
81 | 19.2k | } |
82 | 19.2k | catch (std::out_of_range&) |
83 | 19.2k | { |
84 | 10.0k | throw std::invalid_argument( |
85 | 10.0k | "The units are not in the expected format. Use: {B, KB, MG, GB, KIB, MIB, GIB}."); |
86 | 10.0k | } |
87 | | |
88 | | // Check whether the product of number * magnitude overflows |
89 | 9.16k | if (num > std::numeric_limits<std::uint32_t>::max() / magnitude) |
90 | 3.40k | { |
91 | 3.40k | throw std::invalid_argument("The number is too large to be converted to bytes (Max: (2^32)-1 Bytes)."); |
92 | 3.40k | } |
93 | | |
94 | | // The explicit cast to uint32_t is safe since the number has already been checked to fit. |
95 | | // The product is also safe since the possible overflow has also been checked. |
96 | 5.76k | const std::uint32_t bytes = static_cast<std::uint32_t>(num) * magnitude; |
97 | | |
98 | 5.76k | return bytes; |
99 | 9.16k | } |
100 | | |
101 | | } /* namespace utils */ |
102 | | } /* namespace dds */ |
103 | | } /* namespace fastdds */ |
104 | | } /* namespace eprosima */ |