Skip to content

Commit a93ee71

Browse files
committed
unconditional charconv
1 parent f175b37 commit a93ee71

File tree

1 file changed

+31
-160
lines changed

1 file changed

+31
-160
lines changed

sources/libcore/string.cpp

Lines changed: 31 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
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

Comments
 (0)