11#include < algorithm>
22#include < cctype> // std::isspace
33#include < cerrno>
4+ #include < charconv> // to_chars, from_chars
45#include < cstdio>
56#include < cstdlib>
67#include < cstring>
78#include < vector>
89
9- // charconv (with FP) is available since:
10- // GCC 11
11- // Visual Studio 2017 version 15.8
12- #if (defined(_MSC_VER) && _MSC_VER >= 1915) || (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 11)
13- #define GCHL_USE_CHARCONV
14- #endif
15-
16- #ifdef GCHL_USE_CHARCONV
17- #include < charconv> // to_chars, from_chars
18- #endif
19-
2010#include < cage-core/macros.h>
2111#include < cage-core/string.h>
2212
@@ -58,89 +48,6 @@ namespace cage
5848 {
5949 namespace
6050 {
61- #if not defined(GCHL_USE_CHARCONV)
62-
63- template <class T >
64- void genericScan (const char *s, T &value)
65- {
66- errno = 0 ;
67- char *e = nullptr ;
68- if (std::numeric_limits<T>::is_signed)
69- {
70- sint64 v = std::strtoll (s, &e, 10 );
71- value = (T)v;
72- if (v < std::numeric_limits<T>::min () || v > std::numeric_limits<T>::max ())
73- e = nullptr ;
74- }
75- else
76- {
77- uint64 v = std::strtoull (s, &e, 10 );
78- value = (T)v;
79- if (*s == ' -' || v < std::numeric_limits<T>::min () || v > std::numeric_limits<T>::max ())
80- e = nullptr ;
81- }
82- if (!*s || !e || *e != 0 || std::isspace (*s) || errno != 0 )
83- {
84- CAGE_LOG_THROW (Stringizer () + " input string: " + s);
85- CAGE_THROW_ERROR (Exception, " fromString failed" );
86- }
87- }
88-
89- template <>
90- void genericScan<sint64>(const char *s, sint64 &value)
91- {
92- errno = 0 ;
93- char *e = nullptr ;
94- value = std::strtoll (s, &e, 10 );
95- if (!*s || !e || *e != 0 || std::isspace (*s) || errno != 0 )
96- {
97- CAGE_LOG_THROW (Stringizer () + " input string: " + s);
98- CAGE_THROW_ERROR (Exception, " fromString failed" );
99- }
100- }
101-
102- template <>
103- void genericScan<uint64>(const char *s, uint64 &value)
104- {
105- errno = 0 ;
106- char *e = nullptr ;
107- value = std::strtoull (s, &e, 10 );
108- if (!*s || !e || *s == ' -' || *e != 0 || std::isspace (*s) || errno != 0 )
109- {
110- CAGE_LOG_THROW (Stringizer () + " input string: " + s);
111- CAGE_THROW_ERROR (Exception, " fromString failed" );
112- }
113- }
114-
115- template <>
116- void genericScan<double >(const char *s, double &value)
117- {
118- errno = 0 ;
119- char *e = nullptr ;
120- double v = std::strtod (s, &e);
121- if (!*s || !e || *e != 0 || std::isspace (*s) || errno != 0 )
122- {
123- CAGE_LOG_THROW (Stringizer () + " input string: " + s);
124- CAGE_THROW_ERROR (Exception, " fromString failed" );
125- }
126- value = v;
127- }
128-
129- template <>
130- void genericScan<float >(const char *s, float &value)
131- {
132- double v;
133- genericScan (s, v);
134- if (v < std::numeric_limits<float >::lowest () || v > std::numeric_limits<float >::max ())
135- {
136- CAGE_LOG_THROW (Stringizer () + " input string: " + s);
137- CAGE_THROW_ERROR (Exception, " fromString failed" );
138- }
139- value = (float )v;
140- }
141-
142- #endif // GCHL_USE_CHARCONV
143-
14451 bool isOrdered (const char *data, uint32 current)
14552 {
14653 // use adjacent_find to test that there are no duplicates
@@ -241,61 +148,27 @@ namespace cage
241148 }
242149 }
243150
244- #if not defined(GCHL_USE_CHARCONV)
245-
246- #define GCHL_GENERATE (TYPE, SPEC ) \
247- uint32 toString (char *s, uint32, TYPE value) \
151+ #define GCHL_FROMSTRING (TYPE ) \
152+ void fromString (const char *s, uint32 n, TYPE &value) \
153+ { \
154+ const auto [p, ec] = std::from_chars (s, s + n, value); \
155+ if (p != s + n || ec != std::errc ()) \
248156 { \
249- sint32 ret = std::sprintf (s, CAGE_STRINGIZE (SPEC), value); \
250- if (ret < 0 ) \
251- CAGE_THROW_ERROR (Exception, " toString failed" ); \
252- s[ret] = 0 ; \
253- return ret; \
157+ CAGE_LOG_THROW (Stringizer () + " input string: " + s); \
158+ CAGE_THROW_ERROR (Exception, " failed conversion of string to " CAGE_STRINGIZE (TYPE)); \
254159 } \
255- void fromString (const char *s, uint32, TYPE &value) \
256- { \
257- return genericScan (s, value); \
258- }
259- GCHL_GENERATE (sint8, % hhd);
260- GCHL_GENERATE (sint16, % hd);
261- GCHL_GENERATE (sint32, % d);
262- GCHL_GENERATE (uint8, % hhu);
263- GCHL_GENERATE (uint16, % hu);
264- GCHL_GENERATE (uint32, % u);
265- #ifdef CAGE_SYSTEM_WINDOWS
266- GCHL_GENERATE (sint64, % lld);
267- GCHL_GENERATE (uint64, % llu);
268- #else
269- GCHL_GENERATE (sint64, % ld);
270- GCHL_GENERATE (uint64, % lu);
271- #endif
272- GCHL_GENERATE (float , % f);
273- GCHL_GENERATE (double , % .16lg);
274- #undef GCHL_GENERATE
275-
276- #else // GCHL_USE_CHARCONV
277-
278- #define GCHL_FROMSTRING (TYPE ) \
279- void fromString (const char *s, uint32 n, TYPE &value) \
280- { \
281- const auto [p, ec] = std::from_chars (s, s + n, value); \
282- if (p != s + n || ec != std::errc ()) \
283- { \
284- CAGE_LOG_THROW (Stringizer () + " input string: " + s); \
285- CAGE_THROW_ERROR (Exception, " failed conversion of string to " CAGE_STRINGIZE (TYPE)); \
286- } \
287- }
160+ }
288161
289- #define GCHL_GENERATE (TYPE ) \
290- uint32 toString (char *s, uint32 n, TYPE value) \
291- { \
292- const auto [p, ec] = std::to_chars (s, s + n, value); \
293- if (ec != std::errc ()) \
294- CAGE_THROW_ERROR (Exception, " failed conversion of " CAGE_STRINGIZE (TYPE) " to string" ); \
295- *p = 0 ; \
296- return numeric_cast<uint32>(p - s); \
297- } \
298- GCHL_FROMSTRING (TYPE)
162+ #define GCHL_GENERATE (TYPE ) \
163+ uint32 toString (char *s, uint32 n, TYPE value) \
164+ { \
165+ const auto [p, ec] = std::to_chars (s, s + n, value); \
166+ if (ec != std::errc ()) \
167+ CAGE_THROW_ERROR (Exception, " failed conversion of " CAGE_STRINGIZE (TYPE) " to string" ); \
168+ *p = 0 ; \
169+ return numeric_cast<uint32>(p - s); \
170+ } \
171+ GCHL_FROMSTRING (TYPE)
299172
300173 GCHL_GENERATE (sint8);
301174 GCHL_GENERATE (sint16);
@@ -305,24 +178,22 @@ namespace cage
305178 GCHL_GENERATE (uint16);
306179 GCHL_GENERATE (uint32);
307180 GCHL_GENERATE (uint64);
308- #undef GCHL_GENERATE
181+ #undef GCHL_GENERATE
309182
310- #define GCHL_GENERATE (TYPE ) \
311- uint32 toString (char *s, uint32 n, TYPE value) \
312- { \
313- const auto [p, ec] = std::to_chars (s, s + n, value, std::chars_format::fixed); \
314- if (ec != std::errc ()) \
315- CAGE_THROW_ERROR (Exception, " failed conversion of " CAGE_STRINGIZE (TYPE) " to string" ); \
316- *p = 0 ; \
317- return numeric_cast<uint32>(p - s); \
318- } \
319- GCHL_FROMSTRING (TYPE)
183+ #define GCHL_GENERATE (TYPE ) \
184+ uint32 toString (char *s, uint32 n, TYPE value) \
185+ { \
186+ const auto [p, ec] = std::to_chars (s, s + n, value, std::chars_format::fixed); \
187+ if (ec != std::errc ()) \
188+ CAGE_THROW_ERROR (Exception, " failed conversion of " CAGE_STRINGIZE (TYPE) " to string" ); \
189+ *p = 0 ; \
190+ return numeric_cast<uint32>(p - s); \
191+ } \
192+ GCHL_FROMSTRING (TYPE)
320193
321194 GCHL_GENERATE (float );
322195 GCHL_GENERATE (double );
323- #undef GCHL_GENERATE
324-
325- #endif // GCHL_USE_CHARCONV
196+ #undef GCHL_GENERATE
326197
327198 uint32 toString (char *s, uint32 n, bool value)
328199 {
0 commit comments