CCF
Loading...
Searching...
No Matches
unit_strings.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/ds/logger.h"
6#include "ccf/ds/nonstd.h"
7
8#include <charconv>
9#include <cmath>
10#include <nlohmann/json.hpp>
11#include <string>
12
13namespace ccf::ds
14{
15 // Inspired by CLI11's AsNumberWithUnit
17 {
18 public:
19 template <class F, typename T>
20 static size_t convert(
21 const std::string_view& input,
22 std::map<std::string_view, T>& mapping,
23 F&& f) // NOLINT(cppcoreguidelines-missing-std-forward)
24 {
25 if (input.empty())
26 {
27 throw std::logic_error("Cannot convert empty unit string");
28 }
29
30 const auto* unit_begin = input.end();
31 while (unit_begin > input.begin() && std::isalpha(*(unit_begin - 1)))
32 {
33 unit_begin--;
34 }
35
36 auto unit = std::string(unit_begin, input.end());
37 ccf::nonstd::to_lower(unit);
38 auto value = std::string(input.begin(), unit_begin);
39
40 size_t ret = 0;
41 auto res =
42 std::from_chars(value.data(), value.data() + value.size(), ret);
43 if (res.ec != std::errc())
44 {
45 throw std::logic_error(fmt::format(
46 "Could not convert value from size string \"{}\": {}",
47 value,
48 res.ec));
49 }
50
51 if (unit.empty())
52 {
53 return ret;
54 }
55
56 auto factor = mapping.find(unit);
57 if (factor == mapping.end())
58 {
59 // Return list of allowed units
60 std::string allowed_units_str;
61 for (auto it = mapping.begin(); it != mapping.end(); ++it)
62 {
63 allowed_units_str += it->first;
64 if (std::next(it) != mapping.end())
65 {
66 allowed_units_str += ", ";
67 }
68 }
69 throw std::logic_error(fmt::format(
70 "Unit {} is invalid. Allowed: {}", unit, allowed_units_str));
71 }
72
73 return f(ret, factor->second);
74 }
75 };
76
77 static size_t convert_size_string(const std::string_view& input)
78 {
79 std::map<std::string_view, size_t> size_suffix_to_power = {
80 {"b", 0}, {"kb", 1}, {"mb", 2}, {"gb", 3}, {"tb", 4}, {"pb", 5}};
81
83 input, size_suffix_to_power, [](size_t value, size_t power) {
84 return value * std::pow(1024, power);
85 });
86 }
87
88 static size_t convert_time_string(const std::string_view& input)
89 {
90 std::map<std::string_view, std::pair<size_t, size_t>> size_suffix_to_power =
91 {{"", {1, 0}},
92 {"us", {1, 0}},
93 {"ms", {1, 3}},
94 {"s", {1, 6}},
95 {"min", {60, 6}},
96 {"h", {36, 8}}};
97
99 input,
100 size_suffix_to_power,
101 [](size_t value, const std::pair<size_t, size_t>& factors) {
102 return value * factors.first * std::pow(10, factors.second);
103 });
104 }
105
107 {
108 std::string str;
109
110 UnitString() = default;
111 UnitString(const std::string_view& str_) : str(str_) {}
112
113 bool operator==(const UnitString&) const = default;
114 };
115
116 inline void to_json(nlohmann::json& j, const UnitString& s)
117 {
118 j = s.str;
119 }
120
122 {
123 size_t value = 0;
124
125 SizeString() = default;
126 SizeString(const std::string_view& str_) :
127 UnitString(str_),
128 value(convert_size_string(str_))
129 {}
130
131 SizeString(const char* str_) :
132 UnitString(str_),
133 value(convert_size_string(str_))
134 {}
135
136 operator size_t() const
137 {
138 return value;
139 }
140
141 [[nodiscard]] size_t count_bytes() const
142 {
143 return value;
144 }
145 };
146
147 inline void from_json(const nlohmann::json& j, SizeString& s)
148 {
149 s = j.get<std::string_view>();
150 }
151
152 inline std::string schema_name(
153 [[maybe_unused]] const SizeString* size_string_type)
154 {
155 return "TimeString";
156 }
157
158 inline void fill_json_schema(
159 nlohmann::json& schema, [[maybe_unused]] const SizeString* size_string_type)
160 {
161 schema["type"] = "string";
162 schema["pattern"] = "^[0-9]+(B|KB|MB|GB|TB|PB)?$";
163 }
164
166 {
167 std::chrono::microseconds value = {};
168
169 TimeString() = default;
170 TimeString(const std::string_view& str_) :
171 UnitString(str_),
172 value(convert_time_string(str_))
173 {}
174
175 operator std::chrono::microseconds() const
176 {
177 return value;
178 }
179
180 operator std::chrono::milliseconds() const
181 {
182 return std::chrono::duration_cast<std::chrono::milliseconds>(
183 std::chrono::microseconds(*this));
184 }
185
186 operator std::chrono::seconds() const
187 {
188 return std::chrono::duration_cast<std::chrono::seconds>(
189 std::chrono::microseconds(*this));
190 }
191
192 [[nodiscard]] size_t count_ms() const
193 {
194 return std::chrono::milliseconds(*this).count();
195 }
196
197 [[nodiscard]] size_t count_s() const
198 {
199 return std::chrono::seconds(*this).count();
200 }
201 };
202
203 inline void from_json(const nlohmann::json& j, TimeString& s)
204 {
205 s = j.get<std::string_view>();
206 }
207
208 inline std::string schema_name(
209 [[maybe_unused]] const TimeString* time_string_type)
210 {
211 return "TimeString";
212 }
213
214 inline void fill_json_schema(
215 nlohmann::json& schema, [[maybe_unused]] const TimeString* time_string_type)
216 {
217 schema["type"] = "string";
218 schema["pattern"] = "^[0-9]+(us|ms|s|min|h)?$";
219 }
220}
221
222FMT_BEGIN_NAMESPACE
223template <>
224struct formatter<ccf::ds::SizeString>
225{
226 template <typename ParseContext>
227 constexpr auto parse(ParseContext& ctx)
228 {
229 return ctx.begin();
230 }
231
232 template <typename FormatContext>
233 auto format(const ccf::ds::SizeString& v, FormatContext& ctx) const
234 {
235 std::stringstream ss;
236 ss << v.str;
237 return format_to(ctx.out(), "{}", ss.str());
238 }
239};
240FMT_END_NAMESPACE
Definition unit_strings.h:17
static size_t convert(const std::string_view &input, std::map< std::string_view, T > &mapping, F &&f)
Definition unit_strings.h:20
Definition contiguous_set.h:12
void fill_json_schema(nlohmann::json &schema, const SizeString *size_string_type)
Definition unit_strings.h:158
std::string schema_name(const SizeString *size_string_type)
Definition unit_strings.h:152
void from_json(const nlohmann::json &j, SizeString &s)
Definition unit_strings.h:147
void to_json(nlohmann::json &j, const UnitString &s)
Definition unit_strings.h:116
Definition app_interface.h:14
Definition unit_strings.h:122
size_t value
Definition unit_strings.h:123
SizeString(const char *str_)
Definition unit_strings.h:131
SizeString(const std::string_view &str_)
Definition unit_strings.h:126
size_t count_bytes() const
Definition unit_strings.h:141
Definition unit_strings.h:166
size_t count_s() const
Definition unit_strings.h:197
std::chrono::microseconds value
Definition unit_strings.h:167
TimeString(const std::string_view &str_)
Definition unit_strings.h:170
size_t count_ms() const
Definition unit_strings.h:192
Definition unit_strings.h:107
UnitString(const std::string_view &str_)
Definition unit_strings.h:111
bool operator==(const UnitString &) const =default
std::string str
Definition unit_strings.h:108
auto format(const ccf::ds::SizeString &v, FormatContext &ctx) const
Definition unit_strings.h:233
constexpr auto parse(ParseContext &ctx)
Definition unit_strings.h:227