guanaqo 1.0.0-alpha.25
Utilities for scientific software
Loading...
Searching...
No Matches
from_chars-wrapper.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @ingroup strings
5/// Portable wrapper around std::from_chars for integers and floats.
6
7#include <charconv>
8#include <stdexcept>
9#include <system_error>
10
11#if __cpp_lib_to_chars
12
13#define GUANAQO_USE_FROM_CHARS_INT 1
14#if defined(__clang__) // Clang
15#pragma message("Using std::stod as a fallback to replace std::from_chars")
16#define GUANAQO_USE_FROM_CHARS_FLOAT 0
17#elif defined(_MSC_VER) // MSVC
18#if _MSC_VER >= 1924
19#define GUANAQO_USE_FROM_CHARS_FLOAT 1
20#else
21#pragma message("Using std::stod as a fallback to replace std::from_chars")
22#define GUANAQO_USE_FROM_CHARS_FLOAT 0
23#endif
24#elif defined(__GNUC__) // GCC
25#if __GNUC__ >= 11
26#define GUANAQO_USE_FROM_CHARS_FLOAT 1
27#else
28#pragma message("Using std::stod as a fallback to replace std::from_chars")
29#define GUANAQO_USE_FROM_CHARS_FLOAT 0
30#endif
31#else // Unknown
32#pragma message("Unknown compiler: not using std::from_chars for floats")
33#define GUANAQO_USE_FROM_CHARS_FLOAT 0
34#endif
35
36#else // __cpp_lib_to_chars
37#define GUANAQO_USE_FROM_CHARS_INT 0
38#define GUANAQO_USE_FROM_CHARS_FLOAT 0
39#endif
40
41namespace guanaqo {
42
43/// @ingroup strings
44template <class T>
45 requires(
46#if GUANAQO_USE_FROM_CHARS_FLOAT
47 std::floating_point<T> ||
48#endif
49 false) // NOLINT(readability-simplify-boolean-expr)
50std::from_chars_result
51from_chars(const char *first, const char *last, T &value,
52 std::chars_format fmt = std::chars_format::general) {
53 return std::from_chars(first, last, value, fmt);
54}
55
56/// @ingroup strings
57template <class T>
58 requires(
59#if GUANAQO_USE_FROM_CHARS_INT
60 std::integral<T> ||
61#endif
62 false) // NOLINT(readability-simplify-boolean-expr)
63std::from_chars_result from_chars(const char *first, const char *last, T &value,
64 int base = 10) {
65 return std::from_chars(first, last, value, base);
66}
67
68/// @ingroup strings
69template <class T, class... Args>
70 requires(
71#if !GUANAQO_USE_FROM_CHARS_FLOAT
72 std::floating_point<T> ||
73#endif
74 false) // NOLINT(readability-simplify-boolean-expr)
75std::from_chars_result from_chars(
76 const char *first, const char *last, T &value,
77 [[maybe_unused]] std::chars_format fmt = std::chars_format::general) {
78 size_t end_index = 0;
79 try {
80 if constexpr (std::is_same_v<T, float>)
81 value = std::stof(std::string(first, last), &end_index);
82 else if constexpr (std::is_same_v<T, double>)
83 value = std::stod(std::string(first, last), &end_index);
84 else if constexpr (std::is_same_v<T, long double>)
85 value = std::stold(std::string(first, last), &end_index);
86 else
87 static_assert(std::is_same_v<T, void>); // false
88 } catch (std::invalid_argument &e) {
89 return {
90 .ptr = first,
91 .ec = std::errc::invalid_argument,
92 };
93 } catch (std::out_of_range &e) {
94 return {
95 .ptr = first + end_index,
96 .ec = std::errc::result_out_of_range,
97 };
98 }
99 return {
100 .ptr = first + end_index,
101 .ec = std::errc(),
102 };
103}
104
105/// @ingroup strings
106template <class T, class... Args>
107 requires(
108#if !GUANAQO_USE_FROM_CHARS_INT
109 std::integral<T> ||
110#endif
111 false) // NOLINT(readability-simplify-boolean-expr)
112std::from_chars_result from_chars(const char *first, const char *last, T &value,
113 int base = 10) {
114 size_t end_index = 0;
115 try {
116 if constexpr (std::is_same_v<T, signed char>)
117 value = static_cast<signed char>(
118 std::stoi(std::string(first, last), &end_index, base));
119 else if constexpr (std::is_same_v<T, short>)
120 value = static_cast<short>(
121 std::stoi(std::string(first, last), &end_index, base));
122 else if constexpr (std::is_same_v<T, int>)
123 value = std::stoi(std::string(first, last), &end_index, base);
124 else if constexpr (std::is_same_v<T, long>)
125 value = std::stol(std::string(first, last), &end_index, base);
126 else if constexpr (std::is_same_v<T, long long>)
127 value = std::stoll(std::string(first, last), &end_index, base);
128 else if constexpr (std::is_same_v<T, unsigned char>)
129 value = static_cast<unsigned char>(
130 std::stoul(std::string(first, last), &end_index, base));
131 else if constexpr (std::is_same_v<T, unsigned short>)
132 value = static_cast<unsigned short>(
133 std::stoul(std::string(first, last), &end_index, base));
134 else if constexpr (std::is_same_v<T, unsigned int>)
135 value = static_cast<unsigned int>(
136 std::stoul(std::string(first, last), &end_index, base));
137 else if constexpr (std::is_same_v<T, unsigned long>)
138 value = std::stoul(std::string(first, last), &end_index, base);
139 else if constexpr (std::is_same_v<T, unsigned long long>)
140 value = std::stoull(std::string(first, last), &end_index, base);
141 else
142 static_assert(std::is_same_v<T, void>); // false
143 } catch (std::invalid_argument &e) {
144 return {
145 .ptr = first,
146 .ec = std::errc::invalid_argument,
147 };
148 } catch (std::out_of_range &e) {
149 return {
150 .ptr = first + end_index,
151 .ec = std::errc::result_out_of_range,
152 };
153 }
154 return {
155 .ptr = first + end_index,
156 .ec = std::errc(),
157 };
158}
159
160} // namespace guanaqo
std::from_chars_result from_chars(const char *first, const char *last, T &value, std::chars_format fmt=std::chars_format::general)