Merge branch 'cxx17-string-toculong'

Fixes for C++17 version of wxString::ToCULong().

See #24022.
This commit is contained in:
Vadim Zeitlin
2023-11-03 00:51:04 +01:00
2 changed files with 73 additions and 18 deletions
+59 -18
View File
@@ -1577,18 +1577,29 @@ bool wxString::ToDouble(double *pVal) const
// to if the compiler claims to support C++17, but it doesn't hurt to check).
#ifdef __cpp_lib_to_chars
bool wxString::ToCLong(long *pVal, int base) const
namespace
{
wxCHECK_MSG( pVal, false, "null output pointer" );
const wxScopedCharBuffer& buf = utf8_str();
auto start = buf.data();
const auto end = start + buf.length();
// Helper of ToCLong() and ToCULong() taking care of prefix and base-related
// stuff: because from_chars() doesn't skip leading whitespace and doesn't
// recognize base==0 nor "0x" prefix even if base 16 is explicitly specified,
// we need to skip the leading space and prefix indicating the base to use if
// it's present and adjust "base" itself instead.
//
// Return false if base is already specified but is incompatible with the
// prefix used.
bool SkipOptPrefixAndSetBase(int& base, const char*& start, const char* end)
{
// Start by skipping whitespace.
while ( wxSafeIsspace(*start) )
++start;
// from_chars() doesn't recognize base==0 and doesn't recognize "0x" prefix
// even if base 16 is explicitly specified, so adjust the input to use the
// form it supports.
if ( buf.length() > 1 && *start == '0' )
// Also skip optional "+" which std::from_chars() doesn't accept neither.
if ( *start == '+' )
++start;
// Then check for the base prefix.
if ( end - start > 1 && *start == '0' )
{
++start;
if ( *start == 'x' || *start == 'X' )
@@ -1609,6 +1620,22 @@ bool wxString::ToCLong(long *pVal, int base) const
if ( base == 0 )
base = 10;
return true;
}
} // anonymous namespace
bool wxString::ToCLong(long *pVal, int base) const
{
wxCHECK_MSG( pVal, false, "null output pointer" );
const wxScopedCharBuffer& buf = utf8_str();
auto start = buf.data();
const auto end = start + buf.length();
if ( !SkipOptPrefixAndSetBase(base, start, end) )
return false;
const auto res = std::from_chars(start, end, *pVal, base);
return res.ec == std::errc{} && res.ptr == end;
@@ -1616,20 +1643,34 @@ bool wxString::ToCLong(long *pVal, int base) const
bool wxString::ToCULong(unsigned long *pVal, int base) const
{
// We intentionally don't use std::from_chars() here because this function
// is supposed to be compatible with strtoul() and so _succeed_ for "-1",
// for example, instead of returning an error as from_chars() (much more
// logically) does.
wxCHECK_MSG( pVal, false, "null output pointer" );
long l;
if ( !ToCLong(&l, base) )
const wxScopedCharBuffer& buf = utf8_str();
auto start = buf.data();
const auto end = start + buf.length();
if ( !SkipOptPrefixAndSetBase(base, start, end) )
return false;
*pVal = static_cast<unsigned long>(l);
// Extra complication: for compatibility reasons, this function does accept
// "-1" as valid input (as strtoul() does!), but from_chars() doesn't, for
// unsigned values, so check for this separately.
if ( *start == '-' )
{
long l;
const auto res = std::from_chars(start, end, l, base);
return true;
if ( res.ec != std::errc{} || res.ptr != end )
return false;
*pVal = static_cast<unsigned long>(l);
return true;
}
const auto res = std::from_chars(start, end, *pVal, base);
return res.ec == std::errc{} && res.ptr == end;
}
bool wxString::ToCDouble(double *pVal) const
+14
View File
@@ -580,6 +580,9 @@ static const struct ToLongData
{ wxT("-1"), -1, Number_Signed | Number_Long },
// this is surprising but consistent with strtoul() behaviour
{ wxT("-1"), (TestValue_t)ULONG_MAX, Number_Unsigned | Number_Long },
// a couple of edge cases
{ wxT(" +1"), 1, Number_Ok },
{ wxT(" -1"), (TestValue_t)ULONG_MAX, Number_Unsigned | Number_Long },
// this must overflow, even with 64 bit long
{ wxT("922337203685477580711"), 0, Number_Invalid },
@@ -607,6 +610,17 @@ static const struct ToLongData
{ wxT("0x11"), 17, Number_Ok, 0 },
{ wxT("0x11"), 0, Number_Invalid, 8 },
{ wxT("0x11"), 17, Number_Ok, 16 },
{
#if SIZEOF_LONG == 4
wxT("0xffffffff"),
#elif SIZEOF_LONG == 8
wxT("0xffffffffffffffff"),
#else
#error "Unknown sizeof(long)"
#endif
(TestValue_t)ULONG_MAX, Number_Unsigned, 0
},
};
wxGCC_WARNING_RESTORE(missing-field-initializers)