Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/readers/morphologyASC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,11 @@ class NeurolucidaParser
std::tuple<Point, floatType> parse_point(NeurolucidaLexer& lex, bool is_marker) {
lex.expect(Token::LPAREN, "Point should start in LPAREN");
std::array<morphio::floatType, 4> point{}; // X,Y,Z,D
const auto& stn = morphio::getStringToNumber();

for (unsigned int i = 0; i < 4; i++) {
const std::string s = lex.consume()->str();
try {
point[i] = std::get<0>(stn.toFloat(s, 0));
point[i] = std::get<0>(toFloat(s, 0));
} catch (const std::invalid_argument&) {
throw RawDataError(err_.ERROR_PARSING_POINT(lex.line_num(), s));
}
Expand Down Expand Up @@ -378,6 +377,7 @@ Property::Properties load(const std::string& path,
const std::string& contents,
unsigned int options,
WarningHandler* warning_handler) {
LocaleGuard guard(std::locale("C"));
NeurolucidaParser parser(path);

morphio::mut::Morphology& nb_ = parser.parse(contents);
Expand Down
6 changes: 3 additions & 3 deletions src/readers/morphologySWC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class SWCTokenizer
int64_t read_int() {
advance_to_number();
try {
auto parsed = stn_.toInt(contents_, pos_);
auto parsed = toInt(contents_, pos_);
pos_ = std::get<1>(parsed);
return std::get<0>(parsed);
} catch (std::invalid_argument& e) {
Expand All @@ -103,7 +103,7 @@ class SWCTokenizer

floatType read_float() {
advance_to_number();
auto parsed = stn_.toFloat(contents_, pos_);
auto parsed = toFloat(contents_, pos_);
pos_ = std::get<1>(parsed);
return std::get<0>(parsed);
}
Expand Down Expand Up @@ -137,7 +137,6 @@ class SWCTokenizer
size_t pos_ = 0;
size_t line_ = 1;
std::string contents_;
StringToNumber stn_;
std::string path_;
};

Expand Down Expand Up @@ -540,6 +539,7 @@ Property::Properties load(const std::string& path,
const std::string& contents,
unsigned int options,
std::shared_ptr<WarningHandler>& warning_handler) {
LocaleGuard guard_{std::locale("C")};
auto properties =
details::SWCBuilder(path, warning_handler.get(), options).buildProperties(contents);

Expand Down
80 changes: 0 additions & 80 deletions src/readers/utils.cpp
Original file line number Diff line number Diff line change
@@ -1,80 +0,0 @@
#include "./utils.h"

namespace morphio {
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#define freelocale _free_locale
#define strtol_l _strtol_l

#ifdef MORPHIO_USE_DOUBLE
#define strto_float _strtod_l
#else
#define strto_float _strtof_l
#endif

#else // not WIN32

#ifdef MORPHIO_USE_DOUBLE
#define strto_float strtod_l
#else
#define strto_float strtof_l
#endif

#endif

// Only create the `locale` to facilitate number handling once
StringToNumber::StringToNumber()
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
// On windows, use their locale handling for their runtime
: locale(_create_locale(LC_ALL, "C")){}
#else
// On other platforms, use the POSIX version
: locale(newlocale(LC_NUMERIC_MASK, "POSIX", nullptr)) {
}
#endif

StringToNumber::~StringToNumber() {
freelocale(locale);
}

std::tuple<int64_t, size_t> StringToNumber::toInt(const std::string& s, size_t offset) const {
const size_t base = 10;
const char* pos = &s[offset];
const char* endpos = &s[s.size()];
int64_t ret = strtol_l(pos, const_cast<char**>(&endpos), base, locale);

auto new_offset = static_cast<size_t>(endpos - s.data());

if (ret == 0 && new_offset == 0) {
throw std::invalid_argument("could not parse integer");
}

return {ret, new_offset};
}

std::tuple<floatType, size_t> StringToNumber::toFloat(const std::string& s, size_t offset) const {
const char* pos = &s[offset];
const char* endpos = &s[s.size()];
floatType ret = strto_float(pos, const_cast<char**>(&endpos), locale);

auto new_offset = static_cast<size_t>(endpos - s.data());

if (std::fabs(ret - 0) < morphio::epsilon && new_offset == 0) {
throw std::invalid_argument("could not parse float");
}

return {ret, new_offset};
}

StringToNumber& getStringToNumber() {
static StringToNumber stn;
return stn;
}

#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#undef freelocale
#undef strtol_l
#endif

#undef strto_float

} // namespace morphio
50 changes: 38 additions & 12 deletions src/readers/utils.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,52 @@
#pragma once
#include <clocale> // locale_t
#include <locale> // std::locale
#include <string>
#include <utility> // std::tuple

#include <morphio/vector_types.h> // floatType

namespace morphio {

struct StringToNumber {
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
_locale_t locale;
struct LocaleGuard {
std::locale old;
LocaleGuard(const std::locale& newLoc)
: old(std::locale::global(newLoc)) { }
~LocaleGuard() {
std::locale::global(old);
}
};

inline std::tuple<int64_t, size_t> toInt(const std::string& s, size_t offset) {
const size_t base = 10;
const char* pos = &s[offset];
const char* endpos = &s[s.size()];
int64_t ret = strtol(pos, const_cast<char**>(&endpos), base);

auto new_offset = static_cast<size_t>(endpos - s.data());

if (ret == 0 && new_offset == 0) {
throw std::invalid_argument("could not parse integer");
}

return {ret, new_offset};
}

inline std::tuple<floatType, size_t> toFloat(const std::string& s, size_t offset) {
const char* pos = &s[offset];
const char* endpos = &s[s.size()];

#ifdef MORPHIO_USE_DOUBLE
floatType ret = strtod(pos, const_cast<char**>(&endpos));
#else
locale_t locale;
floatType ret = strtof(pos, const_cast<char**>(&endpos));
#endif

StringToNumber();
~StringToNumber();
auto new_offset = static_cast<size_t>(endpos - s.data());

std::tuple<int64_t, size_t> toInt(const std::string& s, size_t offset) const;
std::tuple<floatType, size_t> toFloat(const std::string& s, size_t offset) const;
};
if (std::fabs(ret - 0) < morphio::epsilon && new_offset == 0) {
throw std::invalid_argument("could not parse float");
}

StringToNumber& getStringToNumber();
return {ret, new_offset};
}

} // namespace morphio
Loading