Use C++17 <charconv> for wxString to/from number conversion
The "new" std::{to,from}_chars() functions are much faster and more
robust than the previously used code, so use them if they are available.
This commit is contained in:
parent
9b1d031a1b
commit
65c048568f
1 changed files with 117 additions and 1 deletions
|
|
@ -1560,7 +1560,119 @@ bool wxString::ToDouble(double *pVal) const
|
|||
);
|
||||
}
|
||||
|
||||
#if wxUSE_XLOCALE
|
||||
// There are several possibilities for implementing the conversion functions
|
||||
// always using "C" locale:
|
||||
//
|
||||
// 1. Preferred one: use C++17 <charconv>, this is the fastest way to do it.
|
||||
// 2. Use <xlocale.h> if it's available.
|
||||
// 3. Use standard locale-dependent C functions and adjust them for the
|
||||
// current locale (slowest and the least robust).
|
||||
|
||||
// Check if C++17 <charconv> is available.
|
||||
#if wxCHECK_CXX_STD(201703L)
|
||||
#include <charconv>
|
||||
#endif
|
||||
|
||||
// Now check if the functions we need are present in it (normally they ought
|
||||
// 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
|
||||
{
|
||||
wxCHECK_MSG( pVal, false, "null output pointer" );
|
||||
|
||||
const wxScopedCharBuffer& buf = utf8_str();
|
||||
auto start = buf.data();
|
||||
const auto end = start + buf.length();
|
||||
|
||||
// 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' )
|
||||
{
|
||||
++start;
|
||||
if ( *start == 'x' || *start == 'X' )
|
||||
{
|
||||
++start;
|
||||
if ( base == 0 )
|
||||
base = 16;
|
||||
else if ( base != 16 )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( base == 0 )
|
||||
base = 8;
|
||||
}
|
||||
}
|
||||
|
||||
if ( base == 0 )
|
||||
base = 10;
|
||||
|
||||
const auto res = std::from_chars(start, end, *pVal, base);
|
||||
|
||||
return res.ec == std::errc{} && res.ptr == end;
|
||||
}
|
||||
|
||||
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) )
|
||||
return false;
|
||||
|
||||
*pVal = static_cast<unsigned long>(l);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxString::ToCDouble(double *pVal) const
|
||||
{
|
||||
wxCHECK_MSG( pVal, false, "null output pointer" );
|
||||
|
||||
const wxScopedCharBuffer& buf = utf8_str();
|
||||
const auto start = buf.data();
|
||||
const auto end = start + buf.length();
|
||||
const auto res = std::from_chars(start, end, *pVal);
|
||||
|
||||
return res.ec == std::errc{} && res.ptr == end;
|
||||
}
|
||||
|
||||
wxString wxString::FromCDouble(double val, int precision)
|
||||
{
|
||||
wxCHECK_MSG( precision >= -1, wxString(), "Invalid negative precision" );
|
||||
|
||||
// 64 digits is more than enough for any double.
|
||||
char buf[64];
|
||||
const auto start = buf;
|
||||
const auto end = buf + sizeof(buf);
|
||||
|
||||
std::to_chars_result res;
|
||||
|
||||
// Note that we must explicitly specify the precision to remain compatible
|
||||
// with the behaviour of sprintf("%g"): by default, the result would be the
|
||||
// shortest string avoiding precision loss, but "%g" is supposed to
|
||||
// truncate, so use its default precision explicitly to achieve this here.
|
||||
if ( precision == -1 )
|
||||
res = std::to_chars(start, end, val, std::chars_format::general, 6);
|
||||
else
|
||||
res = std::to_chars(start, end, val, std::chars_format::fixed, precision);
|
||||
|
||||
if ( res.ec != std::errc{} )
|
||||
return {};
|
||||
|
||||
*res.ptr = '\0';
|
||||
|
||||
return wxString::FromAscii(buf);
|
||||
}
|
||||
|
||||
#elif wxUSE_XLOCALE
|
||||
|
||||
bool wxString::ToCLong(long *pVal, int base) const
|
||||
{
|
||||
|
|
@ -1688,6 +1800,8 @@ wxString wxString::FromDouble(double val, int precision)
|
|||
return wxString::Format(format, val);
|
||||
}
|
||||
|
||||
#ifndef __cpp_lib_to_chars
|
||||
|
||||
/* static */
|
||||
wxString wxString::FromCDouble(double val, int precision)
|
||||
{
|
||||
|
|
@ -1721,6 +1835,8 @@ wxString wxString::FromCDouble(double val, int precision)
|
|||
return s;
|
||||
}
|
||||
|
||||
#endif // !__cpp_lib_to_chars
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// formatted output
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue