Commit ae85c91e authored by Victor Zverovich's avatar Victor Zverovich Committed by Jonathan Müller

Detect if lconv contains thousands_sep

(cherry picked from commit 96c28f74)
parent 584fa85d
......@@ -910,23 +910,6 @@ class ThousandsSep {
}
};
// Returns the thousands separator for the current locale.
// On android the lconv structure is stubbed using an empty structure.
// The test is for the size only, not for the presense of
// thousands_sep in std::lconv, because if one would add thousands_sep
// at some point, the size of structure would be at least sizeof(char*).
template<typename Lconv, bool=(sizeof(Lconv) >= sizeof(char*))>
struct Locale {
static fmt::StringRef thousands_sep() { return ""; }
};
template<typename Lconv>
struct Locale<Lconv, true> {
static fmt::StringRef thousands_sep() {
return static_cast<Lconv*>(std::localeconv())->thousands_sep;
}
};
// Formats a decimal unsigned integer value writing into buffer.
// thousands_sep is a functor that is called after writing each char to
// add a thousands separator if necessary.
......@@ -1138,6 +1121,21 @@ struct Not { enum { value = 0 }; };
template<>
struct Not<false> { enum { value = 1 }; };
template<typename T, T> struct LConvCheck {
LConvCheck(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 <typename LConv>
inline StringRef thousands_sep(
LConv *lc, LConvCheck<char *LConv::*, &LConv::thousands_sep> = 0) {
return lc->thousands_sep;
}
inline fmt::StringRef thousands_sep(...) { return ""; }
// Makes an Arg object from any type.
template <typename Formatter>
class MakeValue : public Arg {
......@@ -2786,7 +2784,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
}
case 'n': {
unsigned num_digits = internal::count_digits(abs_value);
fmt::StringRef sep = internal::Locale<lconv>::thousands_sep();
fmt::StringRef sep = internal::thousands_sep(std::localeconv());
unsigned size = static_cast<unsigned>(
num_digits + sep.size() * (num_digits - 1) / 3);
CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1;
......
......@@ -956,3 +956,17 @@ TEST(UtilTest, Conditional) {
fmt::internal::Conditional<false, int, char>::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));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment