Skip to content
Permalink
Browse files
Merge pull request #8541 from jordan-woyak/float-parse-fix
StringUtil: Make TryParse of floats handle comma and dot decimal separators.
  • Loading branch information
leoetlino committed Jan 5, 2020
2 parents 04e9279 + 0e8d4cb commit f35f4f2
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 56 deletions.
@@ -235,51 +235,6 @@ std::string_view StripQuotes(std::string_view s)
return s;
}

bool TryParse(const std::string& str, u16* const output)
{
u64 value;
if (!TryParse(str, &value))
return false;

if (value >= 0x10000ull && value <= 0xFFFFFFFFFFFF0000ull)
return false;

*output = static_cast<u16>(value);
return true;
}

bool TryParse(const std::string& str, u32* const output)
{
u64 value;
if (!TryParse(str, &value))
return false;

if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull)
return false;

*output = static_cast<u32>(value);
return true;
}

bool TryParse(const std::string& str, u64* const output)
{
char* end_ptr = nullptr;

// Set errno to a clean slate
errno = 0;

u64 value = strtoull(str.c_str(), &end_ptr, 0);

if (end_ptr == nullptr || *end_ptr != '\0')
return false;

if (errno == ERANGE)
return false;

*output = value;
return true;
}

bool TryParse(const std::string& str, bool* const output)
{
float value;
@@ -6,7 +6,9 @@

#include <cstdarg>
#include <cstddef>
#include <cstdlib>
#include <iomanip>
#include <locale>
#include <sstream>
#include <string>
#include <type_traits>
@@ -47,20 +49,60 @@ std::string ArrayToString(const u8* data, u32 size, int line_len = 20, bool spac
std::string_view StripSpaces(std::string_view s);
std::string_view StripQuotes(std::string_view s);

std::string ReplaceAll(std::string result, std::string_view src, std::string_view dest);

bool TryParse(const std::string& str, bool* output);
bool TryParse(const std::string& str, u16* output);
bool TryParse(const std::string& str, u32* output);
bool TryParse(const std::string& str, u64* output);

template <typename N>
static bool TryParse(const std::string& str, N* const output)
template <typename T, std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>* = nullptr>
bool TryParse(const std::string& str, T* output)
{
std::istringstream iss(str);
// is this right? not doing this breaks reading floats on locales that use different decimal
// separators
iss.imbue(std::locale("C"));
char* end_ptr = nullptr;

// Set errno to a clean slate.
errno = 0;

// Read a u64 for unsigned types and s64 otherwise.
using ReadType = std::conditional_t<std::is_unsigned_v<T>, u64, s64>;
ReadType value;

N tmp;
if constexpr (std::is_unsigned_v<T>)
value = std::strtoull(str.c_str(), &end_ptr, 0);
else
value = std::strtoll(str.c_str(), &end_ptr, 0);

// Fail if the end of the string wasn't reached.
if (end_ptr == nullptr || *end_ptr != '\0')
return false;

// Fail if the value was out of 64-bit range.
if (errno == ERANGE)
return false;

using LimitsType = typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
std::common_type<T>>::type;
// Fail if outside numeric limits.
if (value < std::numeric_limits<LimitsType>::min() ||
value > std::numeric_limits<LimitsType>::max())
{
return false;
}

*output = static_cast<T>(value);
return true;
}

template <typename T, std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
bool TryParse(std::string str, T* const output)
{
// Replace commas with dots.
std::istringstream iss(ReplaceAll(std::move(str), ",", "."));

// Use "classic" locale to force a "dot" decimal separator.
iss.imbue(std::locale::classic());

T tmp;

// Succeed if a value was read and the entire string was used.
if (iss >> tmp && iss.eof())
{
*output = tmp;
@@ -118,7 +160,6 @@ bool SplitPath(std::string_view full_path, std::string* path, std::string* filen

void BuildCompleteFilename(std::string& complete_filename, std::string_view path,
std::string_view filename);
std::string ReplaceAll(std::string result, std::string_view src, std::string_view dest);

bool StringBeginsWith(std::string_view str, std::string_view begin);
bool StringEndsWith(std::string_view str, std::string_view end);

0 comments on commit f35f4f2

Please sign in to comment.