Locale-independent to_double and from_double conversions.
GitOrigin-RevId: 997ec58422c4128857d395fa49c46ee0605afca9
This commit is contained in:
parent
499e64430b
commit
9d5580f315
@ -40,6 +40,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <clocale>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring> // for strcmp
|
#include <cstring> // for strcmp
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
@ -2929,6 +2930,8 @@ void main(int argc, char **argv) {
|
|||||||
set_signal_handler(SignalType::Abort, fail_signal).ensure();
|
set_signal_handler(SignalType::Abort, fail_signal).ensure();
|
||||||
td::Log::set_fatal_error_callback(on_fatal_error);
|
td::Log::set_fatal_error_callback(on_fatal_error);
|
||||||
|
|
||||||
|
std::setlocale(LC_ALL, "fr-FR");
|
||||||
|
|
||||||
CliLog cli_log;
|
CliLog cli_log;
|
||||||
log_interface = &cli_log;
|
log_interface = &cli_log;
|
||||||
|
|
||||||
|
@ -6,7 +6,11 @@
|
|||||||
//
|
//
|
||||||
#include "td/utils/StringBuilder.h"
|
#include "td/utils/StringBuilder.h"
|
||||||
|
|
||||||
|
#include "td/utils/misc.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <locale>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
@ -63,14 +67,24 @@ StringBuilder &StringBuilder::operator<<(double x) {
|
|||||||
if (unlikely(end_ptr_ < current_ptr_)) {
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
||||||
return on_error();
|
return on_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TD_THREAD_LOCAL std::stringstream *ss;
|
||||||
|
if (init_thread_local<std::stringstream>(ss)) {
|
||||||
|
ss->imbue(std::locale::classic());
|
||||||
|
} else {
|
||||||
|
ss->str(std::string());
|
||||||
|
ss->clear();
|
||||||
|
}
|
||||||
|
*ss << x;
|
||||||
|
|
||||||
|
int len = narrow_cast<int>(static_cast<std::streamoff>(ss->tellp()));
|
||||||
auto left = end_ptr_ + reserved_size - current_ptr_;
|
auto left = end_ptr_ + reserved_size - current_ptr_;
|
||||||
int len = std::snprintf(current_ptr_, left, "%lf", x);
|
|
||||||
if (unlikely(len >= left)) {
|
if (unlikely(len >= left)) {
|
||||||
error_flag_ = true;
|
error_flag_ = true;
|
||||||
current_ptr_ += left - 1;
|
len = left - 1;
|
||||||
} else {
|
|
||||||
current_ptr_ += len;
|
|
||||||
}
|
}
|
||||||
|
ss->read(current_ptr_, len);
|
||||||
|
current_ptr_ += len;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <locale>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
@ -57,7 +59,18 @@ string oneline(Slice str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double to_double(CSlice str) {
|
double to_double(CSlice str) {
|
||||||
return std::atof(str.c_str());
|
static TD_THREAD_LOCAL std::stringstream *ss;
|
||||||
|
if (init_thread_local<std::stringstream>(ss)) {
|
||||||
|
ss->imbue(std::locale::classic());
|
||||||
|
} else {
|
||||||
|
ss->str(std::string());
|
||||||
|
ss->clear();
|
||||||
|
}
|
||||||
|
ss->write(str.begin(), narrow_cast<std::streamsize>(str.size()));
|
||||||
|
|
||||||
|
double result = 0.0;
|
||||||
|
*ss >> result;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -14,9 +14,11 @@
|
|||||||
#include "td/utils/port/Stat.h"
|
#include "td/utils/port/Stat.h"
|
||||||
#include "td/utils/port/thread.h"
|
#include "td/utils/port/thread.h"
|
||||||
#include "td/utils/Random.h"
|
#include "td/utils/Random.h"
|
||||||
|
#include "td/utils/Slice.h"
|
||||||
#include "td/utils/tests.h"
|
#include "td/utils/tests.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <clocale>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
using namespace td;
|
using namespace td;
|
||||||
@ -187,3 +189,35 @@ TEST(Misc, to_integer) {
|
|||||||
ASSERT_EQ(to_integer_safe<uint64>("12345678910111213").ok(), 12345678910111213ull);
|
ASSERT_EQ(to_integer_safe<uint64>("12345678910111213").ok(), 12345678910111213ull);
|
||||||
ASSERT_TRUE(to_integer_safe<uint64>("-12345678910111213").is_error());
|
ASSERT_TRUE(to_integer_safe<uint64>("-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();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user