More locale

This commit is contained in:
Victor Zverovich 2022-09-04 10:44:05 -07:00
parent 58a5563a9f
commit d59b89e9cd
3 changed files with 56 additions and 31 deletions

View File

@ -116,44 +116,59 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
} }
#endif #endif
FMT_FUNC auto write_int(appender out, basic_format_arg<format_context> value, FMT_FUNC auto write_loc(appender out, basic_format_arg<format_context> value,
const format_specs& specs, locale_ref loc) -> bool { const format_specs& specs, locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
auto locale = loc.get<std::locale>(); auto locale = loc.get<std::locale>();
// We cannot use the num_put<char> facet because it may produce output in // We cannot use the num_put<char> facet because it may produce output in
// a wrong encoding. // a wrong encoding.
if (!std::has_facet<format_facet<std::locale>>(locale)) return {}; using facet = format_facet<std::locale>;
std::use_facet<format_facet<std::locale>>(locale).put(out, value, specs); if (std::has_facet<facet>(locale))
return true; return std::use_facet<facet>(locale).put(out, value, specs);
return facet(locale).put(out, value, specs);
#endif #endif
return false; return false;
} }
struct localize_int { struct localizer {
appender out; appender out;
const format_specs& specs; const format_specs& specs;
std::string sep; std::string sep;
std::string grouping; std::string grouping;
std::string decimal_point;
template <typename T, FMT_ENABLE_IF(detail::is_integer<T>::value)> template <typename T, FMT_ENABLE_IF(detail::is_integer<T>::value)>
void operator()(T value) { auto operator()(T value) -> bool {
auto arg = make_write_int_arg(value, specs.sign); auto arg = make_write_int_arg(value, specs.sign);
write_int(out, static_cast<uint64_or_128_t<T>>(arg.abs_value), arg.prefix, write_int(out, static_cast<uint64_or_128_t<T>>(arg.abs_value), arg.prefix,
specs, digit_grouping<char>(grouping, sep)); specs, digit_grouping<char>(grouping, sep));
return true;
} }
template <typename T, FMT_ENABLE_IF(!detail::is_integer<T>::value)>
void operator()(T) {} template <typename T, FMT_ENABLE_IF(detail::is_floating_point<T>::value)>
auto operator()(T) -> bool {
return false;
}
auto operator()(...) -> bool { return false; }
}; };
} // namespace detail } // namespace detail
template <typename Locale> typename Locale::id format_facet<Locale>::id; template <typename Locale> typename Locale::id format_facet<Locale>::id;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template <typename Locale> format_facet<Locale>::format_facet(Locale& loc) {
auto& numpunct = std::use_facet<std::numpunct<char>>(loc);
grouping_ = numpunct.grouping();
if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep());
}
template <> template <>
FMT_API FMT_FUNC void format_facet<std::locale>::do_put( FMT_API FMT_FUNC auto format_facet<std::locale>::do_put(
appender out, basic_format_arg<format_context> val, appender out, basic_format_arg<format_context> val,
const format_specs& specs) const { const format_specs& specs) const -> bool {
visit_format_arg(detail::localize_int{out, specs, separator_, grouping_}, return visit_format_arg(
detail::localizer{out, specs, separator_, grouping_, decimal_point_},
val); val);
} }
#endif #endif

View File

@ -992,21 +992,26 @@ template <typename Locale> class format_facet : public Locale::facet {
private: private:
std::string separator_; std::string separator_;
std::string grouping_; std::string grouping_;
std::string decimal_point_;
protected: protected:
virtual void do_put(appender out, basic_format_arg<format_context> val, virtual auto do_put(appender out, basic_format_arg<format_context> val,
const format_specs& specs) const; const format_specs& specs) const -> bool;
public: public:
static FMT_API typename Locale::id id; static FMT_API typename Locale::id id;
explicit format_facet(string_view sep = ",", explicit format_facet(Locale& loc);
std::initializer_list<unsigned char> g = {3}) explicit format_facet(string_view sep = "",
: separator_(sep.data(), sep.size()), grouping_(g.begin(), g.end()) {} std::initializer_list<unsigned char> g = {3},
std::string decimal_point = ".")
: separator_(sep.data(), sep.size()),
grouping_(g.begin(), g.end()),
decimal_point_(decimal_point) {}
void put(appender out, basic_format_arg<format_context> val, auto put(appender out, basic_format_arg<format_context> val,
const format_specs& specs) const { const format_specs& specs) const -> bool {
do_put(out, val, specs); return do_put(out, val, specs);
} }
}; };
@ -2042,10 +2047,11 @@ auto write_int(OutputIt out, UInt value, unsigned prefix,
}); });
} }
FMT_API auto write_int(appender out, basic_format_arg<format_context> value, // Writes value with localization.
FMT_API auto write_loc(appender out, basic_format_arg<format_context> value,
const format_specs& specs, locale_ref loc) -> bool; const format_specs& specs, locale_ref loc) -> bool;
template <typename OutputIt, typename Char> template <typename OutputIt, typename Char>
inline auto write_int(OutputIt, basic_format_arg<buffer_context<Char>>, inline auto write_loc(OutputIt, basic_format_arg<buffer_context<Char>>,
const basic_format_specs<Char>&, locale_ref) -> bool { const basic_format_specs<Char>&, locale_ref) -> bool {
return false; return false;
} }
@ -4165,8 +4171,8 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
begin = parse_format_specs(begin, end, handler); begin = parse_format_specs(begin, end, handler);
if (begin == end || *begin != '}') if (begin == end || *begin != '}')
on_error("missing '}' in format string"); on_error("missing '}' in format string");
if (specs.localized && arg.is_integral() && if (specs.localized &&
write_int(context.out(), arg, specs, context.locale())) { write_loc(context.out(), arg, specs, context.locale())) {
return begin; return begin;
} }
auto f = arg_formatter<Char>{context.out(), specs, context.locale()}; auto f = arg_formatter<Char>{context.out(), specs, context.locale()};

View File

@ -2322,21 +2322,25 @@ class format_facet : public fmt::format_facet<std::locale> {
fmt::appender out; fmt::appender out;
template <typename T, FMT_ENABLE_IF(fmt::detail::is_integer<T>::value)> template <typename T, FMT_ENABLE_IF(fmt::detail::is_integer<T>::value)>
void operator()(T value) { auto operator()(T value) -> bool {
fmt::format_to(out, "[{}]", value); fmt::format_to(out, "[{}]", value);
return true;
} }
template <typename T, FMT_ENABLE_IF(!fmt::detail::is_integer<T>::value)> template <typename T, FMT_ENABLE_IF(!fmt::detail::is_integer<T>::value)>
void operator()(T) {} auto operator()(T) -> bool {
return false;
}
}; };
void do_put(fmt::appender out, fmt::basic_format_arg<fmt::format_context> arg, auto do_put(fmt::appender out, fmt::basic_format_arg<fmt::format_context> arg,
const fmt::format_specs&) const override; const fmt::format_specs&) const -> bool override;
}; };
void format_facet::do_put(fmt::appender out, auto format_facet::do_put(fmt::appender out,
fmt::basic_format_arg<fmt::format_context> arg, fmt::basic_format_arg<fmt::format_context> arg,
const fmt::format_specs&) const { const fmt::format_specs&) const -> bool {
visit_format_arg(int_formatter{out}, arg); return visit_format_arg(int_formatter{out}, arg);
} }
TEST(format_test, format_facet) { TEST(format_test, format_facet) {