mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Improve locale support
This commit is contained in:
@ -28,7 +28,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "locale.h"
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template <typename Locale> typename Locale::id num_format_facet<Locale>::id;
|
template <typename Locale> typename Locale::id num_format_facet<Locale>::id;
|
||||||
@ -120,24 +119,18 @@ template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename Char>
|
FMT_FUNC auto write_int(unsigned long long value, const format_specs& specs,
|
||||||
FMT_FUNC auto write_int(unsigned long long value, locale_ref loc)
|
locale_ref loc) -> std::string {
|
||||||
-> std::basic_string<Char> {
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
auto&& ios = std::basic_ios<Char>(nullptr);
|
|
||||||
auto locale = loc.get<std::locale>();
|
auto locale = loc.get<std::locale>();
|
||||||
ios.imbue(locale);
|
|
||||||
auto&& buf = std::basic_stringbuf<Char>();
|
|
||||||
auto out = std::ostreambuf_iterator<Char>(&buf);
|
|
||||||
// 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.
|
||||||
using facet_t =
|
if (!std::has_facet<num_format_facet<std::locale>>(locale)) return {};
|
||||||
conditional_t<std::is_same<Char, char>::value,
|
auto&& buf = std::basic_stringbuf<char>();
|
||||||
num_format_facet<std::locale>, std::num_put<Char>>;
|
auto out = std::ostreambuf_iterator<char>(&buf);
|
||||||
if (std::has_facet<facet_t>(locale)) {
|
std::use_facet<num_format_facet<std::locale>>(locale).put(out, value, specs,
|
||||||
std::use_facet<facet_t>(locale).put(out, ios, ' ', value);
|
locale);
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -706,6 +706,7 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// We could avoid branches by using utf8_decode directly.
|
||||||
for_each_codepoint(s, count_code_points{&num_code_points});
|
for_each_codepoint(s, count_code_points{&num_code_points});
|
||||||
return num_code_points;
|
return num_code_points;
|
||||||
}
|
}
|
||||||
@ -2013,18 +2014,20 @@ auto write_int(OutputIt out, UInt value, unsigned prefix,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMT_API auto write_int(unsigned long long value, const format_specs& specs,
|
||||||
|
locale_ref loc) -> std::string;
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_API auto write_int(unsigned long long value, locale_ref loc)
|
inline auto write_int(unsigned long long, const basic_format_specs<Char>&,
|
||||||
-> std::basic_string<Char>;
|
locale_ref) -> std::string {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename UInt, typename Char>
|
template <typename OutputIt, typename UInt, typename Char>
|
||||||
auto write_int(OutputIt& out, UInt value, unsigned prefix,
|
auto write_int(OutputIt& out, UInt value, unsigned prefix,
|
||||||
const basic_format_specs<Char>& specs, locale_ref loc) -> bool {
|
const basic_format_specs<Char>& specs, locale_ref loc) -> bool {
|
||||||
using char_t =
|
auto str = std::string();
|
||||||
conditional_t<std::is_same<Char, wchar_t>::value, wchar_t, char>;
|
|
||||||
auto str = std::basic_string<char_t>();
|
|
||||||
if (sizeof(value) <= sizeof(unsigned long long))
|
if (sizeof(value) <= sizeof(unsigned long long))
|
||||||
str = write_int<char_t>(static_cast<unsigned long long>(value), loc);
|
str = write_int(static_cast<unsigned long long>(value), specs, loc);
|
||||||
if (str.empty()) {
|
if (str.empty()) {
|
||||||
auto grouping = digit_grouping<Char>(loc);
|
auto grouping = digit_grouping<Char>(loc);
|
||||||
out = write_int(out, value, prefix, specs, grouping);
|
out = write_int(out, value, prefix, specs, grouping);
|
||||||
@ -4171,6 +4174,25 @@ extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
|||||||
|
|
||||||
FMT_END_DETAIL_NAMESPACE
|
FMT_END_DETAIL_NAMESPACE
|
||||||
|
|
||||||
|
// A locale facet that formats numeric values in UTF-8.
|
||||||
|
// It is parameterized on the locale to avoid heavy <locale> include.
|
||||||
|
template <typename Locale> class num_format_facet : public Locale::facet {
|
||||||
|
public:
|
||||||
|
static FMT_API typename Locale::id id;
|
||||||
|
|
||||||
|
using iter_type = std::ostreambuf_iterator<char>;
|
||||||
|
|
||||||
|
auto put(iter_type out, unsigned long long val, const format_specs& specs,
|
||||||
|
Locale& loc) const -> iter_type {
|
||||||
|
return do_put(out, val, specs, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual auto do_put(iter_type out, unsigned long long val,
|
||||||
|
const format_specs& specs, Locale& loc) const
|
||||||
|
-> iter_type = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
/**
|
/**
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
// Formatting library for C++ - optional locale support
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 - present, Victor Zverovich
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// For the license information refer to format.h.
|
|
||||||
|
|
||||||
#ifndef FMT_LOCALE_H_
|
|
||||||
#define FMT_LOCALE_H_
|
|
||||||
|
|
||||||
#include <ios> // std::ios_base
|
|
||||||
#include <iterator> // std::ostreambuf_iterator
|
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
// A locale facet that formats numeric values in UTF-8.
|
|
||||||
template <typename Locale> class num_format_facet : public Locale::facet {
|
|
||||||
public:
|
|
||||||
static FMT_API typename Locale::id id;
|
|
||||||
|
|
||||||
using iter_type = std::ostreambuf_iterator<char>;
|
|
||||||
|
|
||||||
auto put(iter_type out, std::ios_base& str, char fill,
|
|
||||||
unsigned long long val) const -> iter_type {
|
|
||||||
return do_put(out, str, fill, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual auto do_put(iter_type out, std::ios_base& str, char fill,
|
|
||||||
unsigned long long val) const -> iter_type = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
#endif // FMT_LOCALE_H_
|
|
@ -22,9 +22,6 @@ template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
|||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
template FMT_API auto write_int(unsigned long long, locale_ref)
|
|
||||||
-> std::basic_string<char>;
|
|
||||||
|
|
||||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||||
-> thousands_sep_result<char>;
|
-> thousands_sep_result<char>;
|
||||||
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
||||||
@ -37,9 +34,6 @@ template FMT_API void vformat_to(buffer<char>&, string_view,
|
|||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
template FMT_API auto write_int(unsigned long long, locale_ref)
|
|
||||||
-> std::basic_string<wchar_t>;
|
|
||||||
|
|
||||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||||
-> thousands_sep_result<wchar_t>;
|
-> thousands_sep_result<wchar_t>;
|
||||||
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
#include "fmt/color.h"
|
#include "fmt/color.h"
|
||||||
#include "fmt/locale.h"
|
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
#include "fmt/ranges.h"
|
#include "fmt/ranges.h"
|
||||||
#include "gtest-extra.h" // Contains
|
#include "gtest-extra.h" // Contains
|
||||||
@ -523,13 +522,13 @@ TEST(locale_test, sign) {
|
|||||||
|
|
||||||
class num_format : public fmt::num_format_facet<std::locale> {
|
class num_format : public fmt::num_format_facet<std::locale> {
|
||||||
protected:
|
protected:
|
||||||
using fmt::num_format_facet<std::locale>::do_put;
|
iter_type do_put(iter_type out, unsigned long long, const fmt::format_specs&,
|
||||||
iter_type do_put(iter_type out, std::ios_base&, char,
|
std::locale&) const override;
|
||||||
unsigned long long) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
num_format::iter_type num_format::do_put(iter_type out, std::ios_base&, char,
|
num_format::iter_type num_format::do_put(iter_type out, unsigned long long,
|
||||||
unsigned long long) const {
|
const fmt::format_specs&,
|
||||||
|
std::locale&) const {
|
||||||
const char s[] = "foo";
|
const char s[] = "foo";
|
||||||
return std::copy_n(s, sizeof(s) - 1, out);
|
return std::copy_n(s, sizeof(s) - 1, out);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user