guanaqo 1.0.0-alpha.24
Utilities for scientific software
Loading...
Searching...
No Matches
duration-parse.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @ingroup strings
5/// Duration parsing helpers.
6
9#include <chrono>
10#include <string_view>
11
12namespace guanaqo {
13
14/// @addtogroup strings
15/// @{
16
17struct GUANAQO_EXPORT invalid_duration_value : std::invalid_argument {
18 explicit invalid_duration_value(const std::string &arg,
19 std::from_chars_result result)
20 : std::invalid_argument{arg}, result{result} {}
21 std::from_chars_result result;
22};
23
24struct GUANAQO_EXPORT invalid_duration_units : std::invalid_argument {
25 explicit invalid_duration_units(const std::string &arg,
26 std::string_view units)
27 : std::invalid_argument{arg}, units{units} {}
28 /// Points into original argument, beware lifetime issues.
29 std::string_view units;
30};
31
32/// Adds the first duration in the string @p s to the duration @p t.
33template <class Rep, class Period>
34std::string_view parse_single_duration(std::chrono::duration<Rep, Period> &t,
35 std::string_view s) {
36 using Duration = std::remove_cvref_t<decltype(t)>;
37 auto trim = s.find_first_not_of("+0 ");
38 if (trim == std::string_view::npos)
39 return {};
40 s.remove_prefix(trim);
41 const auto *val_end = s.data() + s.size();
42 double value;
43 auto res = from_chars(s.data(), val_end, value);
44 if (res.ec != std::errc())
46 "Invalid value '" + std::string(res.ptr, val_end) + "' for type '" +
47 demangled_typename(typeid(Duration)) +
48 "': " + std::make_error_code(res.ec).message(),
49 res);
50 std::string_view remainder{res.ptr, val_end};
51 auto end = remainder.find_first_of("+-0123456789. ");
52 std::string_view units = remainder.substr(0, end);
53 using std::chrono::duration;
54 auto cast = [](auto t) { return std::chrono::round<Duration>(t); };
55 if (units == "s" || units.empty())
56 t += cast(duration<double, std::ratio<1, 1>>{value});
57 else if (units == "ms")
58 t += cast(duration<double, std::ratio<1, 1'000>>{value});
59 else if (units == "us" || units == "µs")
60 t += cast(duration<double, std::ratio<1, 1'000'000>>{value});
61 else if (units == "ns")
62 t += cast(duration<double, std::ratio<1, 1'000'000'000>>{value});
63 else if (units == "min")
64 t += cast(duration<double, std::ratio<60, 1>>{value});
65 else if (units == "h")
66 t += cast(duration<double, std::ratio<3'600, 1>>{value});
67 else
69 "Invalid units '" + std::string(units) + "' for duration", units);
70 if (end == std::string_view::npos)
71 return {};
72 return remainder.substr(end);
73}
74
75/// Adds the sum of the durations in the string @p s to the duration @p t.
76template <class Rep, class Period>
77void parse_duration(std::chrono::duration<Rep, Period> &t, std::string_view s) {
78 while (!s.empty())
79 s = parse_single_duration(t, s);
80}
81
82/// @}
83
84} // namespace guanaqo
Pretty-print type names.
Portable wrapper around std::from_chars for integers and floats.
std::string demangled_typename(const std::type_info &t)
Get the pretty name of the given type as a string.
std::from_chars_result from_chars(const char *first, const char *last, T &value, std::chars_format fmt=std::chars_format::general)
void parse_duration(std::chrono::duration< Rep, Period > &t, std::string_view s)
Adds the sum of the durations in the string s to the duration t.
std::string_view parse_single_duration(std::chrono::duration< Rep, Period > &t, std::string_view s)
Adds the first duration in the string s to the duration t.
invalid_duration_units(const std::string &arg, std::string_view units)
std::string_view units
Points into original argument, beware lifetime issues.
invalid_duration_value(const std::string &arg, std::from_chars_result result)
std::from_chars_result result