Add a version of std::stod which takes locale.

We need a string-to-double conversion function which acts the same on
all computers, irrespective of which locale is running. We need to
guarantee that the function expects '.' as the decimal point, and not
','. The choice of en-US is more or less arbitrary.
This commit is contained in:
Andreas Jönsson 2015-05-17 21:23:08 +02:00
parent 0e42d3348a
commit be230c1a29
3 changed files with 32 additions and 3 deletions

View File

@ -762,3 +762,19 @@ generic_string stringTakeWhileAdmissable(const generic_string& input, const gene
return input.substr(0, idx); return input.substr(0, idx);
} }
} }
double stodLocale(const generic_string& str, _locale_t loc, size_t* idx)
{
// Copied from the std::stod implementation but uses _wcstod_l instead of wcstod.
const wchar_t* ptr = str.c_str();
errno = 0;
wchar_t* eptr;
double ans = ::_wcstod_l(ptr, &eptr, loc);
if (ptr == eptr)
throw new std::invalid_argument("invalid stod argument");
if (errno == ERANGE)
throw new std::out_of_range("stod argument out of range");
if (idx != NULL)
*idx = (size_t)(eptr - ptr);
return ans;
}

View File

@ -191,5 +191,6 @@ generic_string stringReplace(generic_string subject, const generic_string& searc
std::vector<generic_string> stringSplit(const generic_string& input, const generic_string& delimiter); std::vector<generic_string> stringSplit(const generic_string& input, const generic_string& delimiter);
generic_string stringJoin(const std::vector<generic_string>& strings, const generic_string& separator); generic_string stringJoin(const std::vector<generic_string>& strings, const generic_string& separator);
generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable); generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable);
double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL);
#endif //M30_IDE_COMMUN_H #endif //M30_IDE_COMMUN_H

View File

@ -79,7 +79,15 @@ template<typename T_Num>
class NumericSorter : public ISorter class NumericSorter : public ISorter
{ {
public: public:
NumericSorter(bool isDescending) : ISorter(isDescending) { }; NumericSorter(bool isDescending) : ISorter(isDescending)
{
_usLocale = ::_wcreate_locale(LC_NUMERIC, TEXT("en-US"));
};
~NumericSorter()
{
::_free_locale(_usLocale);
}
std::vector<generic_string> sort(std::vector<generic_string> lines) override std::vector<generic_string> sort(std::vector<generic_string> lines) override
{ {
@ -151,6 +159,10 @@ protected:
// Should convert the input string to a number of the correct type. // Should convert the input string to a number of the correct type.
// If unable to convert, throw either std::invalid_argument or std::out_of_range. // If unable to convert, throw either std::invalid_argument or std::out_of_range.
virtual T_Num convertStringToNumber(const generic_string& input) = 0; virtual T_Num convertStringToNumber(const generic_string& input) = 0;
// We need a fixed locale so we get the same string-to-double behavior across all computers.
// This is the "enUS" locale.
_locale_t _usLocale;
}; };
// Converts lines to long long before sorting. // Converts lines to long long before sorting.
@ -186,7 +198,7 @@ protected:
double convertStringToNumber(const generic_string& input) override double convertStringToNumber(const generic_string& input) override
{ {
return std::stod(input); return stodLocale(input, _usLocale);
} }
}; };
@ -204,7 +216,7 @@ protected:
double convertStringToNumber(const generic_string& input) override double convertStringToNumber(const generic_string& input) override
{ {
return std::stod(input); return stodLocale(input, _usLocale);
} }
}; };