Skip to content

Commit

Permalink
Add missing float conversion overload.
Browse files Browse the repository at this point in the history
* Add xconvert function for parsing floats to prevent usage of
  (locale dependent) fallback parser.

* Adjust "double parsing is locale-independent" test to make it work
  on more platforms.
  • Loading branch information
BenKaufmann committed Jul 23, 2024
1 parent 6800f64 commit 6358d68
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 12 deletions.
1 change: 1 addition & 0 deletions potassco/string_convert.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ int xconvert(const char* x, int& out, const char** errPos = 0, int = 0);
int xconvert(const char* x, long& out, const char** errPos = 0, int = 0);
int xconvert(const char* x, unsigned long& out, const char** errPos = 0, int = 0);
int xconvert(const char* x, double& out, const char** errPos = 0, int = 0);
int xconvert(const char* x, float& out, const char** errPos = 0, int = 0);
int xconvert(const char* x, const char*& out, const char** errPos = 0, int = 0);
int xconvert(const char* x, std::string& out, const char** errPos = 0, int sep = 0);
template <class T>
Expand Down
7 changes: 7 additions & 0 deletions src/string_convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ int xconvert(const char* x, double& out, const char** errPos, int) {
return parsed(err != x, err, errPos);
}

int xconvert(const char* x, float& out, const char** errPos, int i) {
double temp;
int r = xconvert(x, temp, errPos, i);
if (r > 0) { out = static_cast<float>(temp); }
return r;
}

int xconvert(const char* x, const char*& out, const char** errPos, int) {
out = x;
if (errPos) { *errPos = x + strlen(x); }
Expand Down
34 changes: 22 additions & 12 deletions tests/test_string_convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,29 @@ TEST_CASE("String conversion", "[string]") {

SECTION("double parsing is locale-independent") {
typedef std::pair<std::string, std::string> P;
P lcg[] = {P("de", "DE"), P("el", "GR"), P("ru", "RU"), P("es", "ES"), P("it", "IT")};
const char* x = 0;
#if defined(_MSC_VER) && _MSC_VER <= 1600
x = setlocale(LC_ALL, "deu_deu");
#endif
for (const P* it = lcg, *end = it + sizeof(lcg)/sizeof(P); it != end && !x; ++it) {
x = setlocale(LC_ALL, std::string(it->first).append(1, '_').append(it->second).c_str());
if (x != 0) { break; }
x = setlocale(LC_ALL, std::string(it->first).append(1, '-').append(it->second).c_str());
typedef std::pair<std::string, std::locale> R;
P lcg[] = {P("deu", "deu"), P("de", "DE"), P("el", "GR"), P("ru", "RU"), P("es", "ES"), P("it", "IT")};
char sep[3] = {'_', '-', 0};
const char* codeset[3] = {"", ".utf8", 0};
R restore(setlocale(LC_ALL, nullptr), std::locale());
bool set = false;
for (const P* it = lcg, *end = it + sizeof(lcg)/sizeof(P); it != end && !set; ++it) {
for (const char* s = sep; *s && !set; ++s) {
for (const char** code = codeset; *code && !set; ++code) {
std::string loc(it->first);
loc.append(1, *s).append(it->second).append(*code);
if (setlocale(LC_ALL, loc.c_str())) {
restore.second = std::locale::global(std::locale(loc));
set = true;
}
}
}
}
if (x) {
REQUIRE(Potassco::string_cast<double>("12.32") == 12.32);
setlocale(LC_ALL, "C");
if (set) {
CHECK_NOTHROW(Potassco::string_cast<double>("12.32") == 12.32);
CHECK_NOTHROW(Potassco::string_cast<float>("12.32") == 12.32f);
setlocale(LC_ALL, restore.first.c_str());
REQUIRE_NOTHROW(std::locale::global(restore.second));
}
else {
WARN("could not set locale - test ignored");
Expand Down

0 comments on commit 6358d68

Please sign in to comment.