From 32ec13f1490f14876d52e72b5047eaac2e335008 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 25 Mar 2017 08:20:06 -0700 Subject: [PATCH] Switch to C++ locale --- fmt/format.h | 36 ++++++++++++++---------------------- test/format-test.cc | 25 ++----------------------- test/util-test.cc | 14 -------------- 3 files changed, 16 insertions(+), 59 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 502a6ab8..1e96513b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -30,11 +30,11 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -645,6 +645,8 @@ class basic_buffer { T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } + + virtual const std::locale* locale() const { return 0; } }; template @@ -962,18 +964,18 @@ struct no_thousands_sep { }; // A functor that adds a thousands separator. +template class add_thousands_sep { private: - fmt::string_view sep_; + fmt::basic_string_view sep_; // Index of a decimal digit with the least significant digit having index 0. unsigned digit_index_; public: - explicit add_thousands_sep(fmt::string_view sep) + explicit add_thousands_sep(fmt::basic_string_view sep) : sep_(sep), digit_index_(0) {} - template void operator()(Char *&buffer) { if (++digit_index_ % 3 != 0) return; @@ -1483,21 +1485,6 @@ basic_arg make_arg(const T &value) { return arg; } -template struct lconv_check { - lconv_check(int) {} -}; - -// Returns the thousands separator for the current locale. -// We check if ``lconv`` contains ``thousands_sep`` because on Android -// ``lconv`` is stubbed as an empty struct. -template -inline string_view thousands_sep( - LConv *lc, lconv_check = 0) { - return lc->thousands_sep; -} - -inline fmt::string_view thousands_sep(...) { return ""; } - #define FMT_CONCAT(a, b) a##b #if FMT_GCC_VERSION >= 407 @@ -2323,7 +2310,7 @@ class basic_writer { /** \rst - Destroys a ``basic_writer`` object. + Destroys the ``basic_writer`` object. \endrst */ virtual ~basic_writer() {} @@ -2629,12 +2616,17 @@ void basic_writer::write_int(T value, Spec spec) { } case 'n': { unsigned num_digits = internal::count_digits(abs_value); - fmt::string_view sep = internal::thousands_sep(std::localeconv()); + const std::locale *loc = buffer_.locale(); + if (!loc) + loc = &std::locale::classic(); + Char thousands_sep = + std::use_facet>(*loc).thousands_sep(); + fmt::basic_string_view sep(&thousands_sep, 1); unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0, - internal::add_thousands_sep(sep)); + internal::add_thousands_sep(sep)); break; } default: diff --git a/test/format-test.cc b/test/format-test.cc index 66397856..b5414d81 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -43,22 +43,6 @@ // Test that the library compiles if None is defined to 0 as done by xlib.h. #define None 0 -struct LocaleMock { - static LocaleMock *instance; - - MOCK_METHOD0(localeconv, lconv *()); -} *LocaleMock::instance; - -namespace fmt { -namespace std { -using namespace ::std; -lconv *localeconv() { - return LocaleMock::instance ? - LocaleMock::instance->localeconv() : ::std::localeconv(); -} -} -} - #include "fmt/format.h" #include "util.h" @@ -1115,14 +1099,9 @@ TEST(FormatterTest, FormatOct) { } TEST(FormatterTest, FormatIntLocale) { - ScopedMock mock; - lconv lc = {}; - char sep[] = "--"; - lc.thousands_sep = sep; - EXPECT_CALL(mock, localeconv()).Times(3).WillRepeatedly(testing::Return(&lc)); EXPECT_EQ("123", format("{:n}", 123)); - EXPECT_EQ("1--234", format("{:n}", 1234)); - EXPECT_EQ("1--234--567", format("{:n}", 1234567)); + EXPECT_EQ("1,234", format("{:n}", 1234)); + EXPECT_EQ("1,234,567", format("{:n}", 1234567)); } TEST(FormatterTest, FormatFloat) { diff --git a/test/util-test.cc b/test/util-test.cc index fc805b8f..1ca29817 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -845,17 +845,3 @@ TEST(UtilTest, Conditional) { fmt::internal::conditional::type *pc = &c; (void)pc; } - -struct TestLConv { - char *thousands_sep; -}; - -struct EmptyLConv {}; - -TEST(UtilTest, ThousandsSep) { - char foo[] = "foo"; - TestLConv lc = {foo}; - EXPECT_EQ("foo", fmt::internal::thousands_sep(&lc).to_string()); - EmptyLConv empty_lc; - EXPECT_EQ("", fmt::internal::thousands_sep(&empty_lc)); -}