From 9d5580f315086fb174c0377311890b1968b1d68f Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 3 Feb 2018 22:40:06 +0300 Subject: [PATCH] Locale-independent to_double and from_double conversions. GitOrigin-RevId: 997ec58422c4128857d395fa49c46ee0605afca9 --- td/telegram/cli.cpp | 3 +++ tdutils/td/utils/StringBuilder.cpp | 22 +++++++++++++++---- tdutils/td/utils/misc.cpp | 15 ++++++++++++- tdutils/test/misc.cpp | 34 ++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index a87c4a1dbfa7..33573c4eb615 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include // for strcmp #include @@ -2929,6 +2930,8 @@ void main(int argc, char **argv) { set_signal_handler(SignalType::Abort, fail_signal).ensure(); td::Log::set_fatal_error_callback(on_fatal_error); + std::setlocale(LC_ALL, "fr-FR"); + CliLog cli_log; log_interface = &cli_log; diff --git a/tdutils/td/utils/StringBuilder.cpp b/tdutils/td/utils/StringBuilder.cpp index 83fcb3c305cd..a36f5e5748c3 100644 --- a/tdutils/td/utils/StringBuilder.cpp +++ b/tdutils/td/utils/StringBuilder.cpp @@ -6,7 +6,11 @@ // #include "td/utils/StringBuilder.h" +#include "td/utils/misc.h" + #include +#include +#include namespace td { @@ -63,14 +67,24 @@ StringBuilder &StringBuilder::operator<<(double x) { if (unlikely(end_ptr_ < current_ptr_)) { return on_error(); } + + static TD_THREAD_LOCAL std::stringstream *ss; + if (init_thread_local(ss)) { + ss->imbue(std::locale::classic()); + } else { + ss->str(std::string()); + ss->clear(); + } + *ss << x; + + int len = narrow_cast(static_cast(ss->tellp())); auto left = end_ptr_ + reserved_size - current_ptr_; - int len = std::snprintf(current_ptr_, left, "%lf", x); if (unlikely(len >= left)) { error_flag_ = true; - current_ptr_ += left - 1; - } else { - current_ptr_ += len; + len = left - 1; } + ss->read(current_ptr_, len); + current_ptr_ += len; return *this; } diff --git a/tdutils/td/utils/misc.cpp b/tdutils/td/utils/misc.cpp index 83db9da425b0..e61ef61a6172 100644 --- a/tdutils/td/utils/misc.cpp +++ b/tdutils/td/utils/misc.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include namespace td { @@ -57,7 +59,18 @@ string oneline(Slice str) { } double to_double(CSlice str) { - return std::atof(str.c_str()); + static TD_THREAD_LOCAL std::stringstream *ss; + if (init_thread_local(ss)) { + ss->imbue(std::locale::classic()); + } else { + ss->str(std::string()); + ss->clear(); + } + ss->write(str.begin(), narrow_cast(str.size())); + + double result = 0.0; + *ss >> result; + return result; } } // namespace td diff --git a/tdutils/test/misc.cpp b/tdutils/test/misc.cpp index b86e1f030f2a..4d6c05314ff0 100644 --- a/tdutils/test/misc.cpp +++ b/tdutils/test/misc.cpp @@ -14,9 +14,11 @@ #include "td/utils/port/Stat.h" #include "td/utils/port/thread.h" #include "td/utils/Random.h" +#include "td/utils/Slice.h" #include "td/utils/tests.h" #include +#include #include using namespace td; @@ -187,3 +189,35 @@ TEST(Misc, to_integer) { ASSERT_EQ(to_integer_safe("12345678910111213").ok(), 12345678910111213ull); ASSERT_TRUE(to_integer_safe("-12345678910111213").is_error()); } + +static void test_to_double_one(CSlice str, Slice expected) { + auto result = PSTRING() << to_double(str); + if (expected != result) { + LOG(ERROR) << "To double conversion failed: have " << str << ", expected " << expected << ", parsed " + << to_double(str) << ", got " << result; + } +} + +static void test_to_double() { + test_to_double_one("0", "0"); + test_to_double_one("1", "1"); + test_to_double_one("-10", "-10"); + test_to_double_one("1.234", "1.234"); + test_to_double_one("-1.234e2", "-123.4"); + test_to_double_one("inf", "inf"); + test_to_double_one(" inF asdasd", "inf"); + test_to_double_one(" inFasdasd", "0"); + test_to_double_one(" NaN", "nan"); + test_to_double_one(" 12345678910111213141516171819 asdasd", "1.23457e+28"); + test_to_double_one("1.234567891011121314E123", "1.23457e+123"); + test_to_double_one("123456789", "1.23457e+08"); + test_to_double_one("-1,234567891011121314E123", "-1"); +} + +TEST(Misc, to_double) { + test_to_double(); + std::setlocale(LC_ALL, "fr-FR"); + test_to_double(); + std::setlocale(LC_ALL, "C"); + test_to_double(); +}