mirror of
https://github.com/fmtlib/fmt.git
synced 2025-03-30 04:20:58 +00:00
Simplify locale handling
This commit is contained in:
parent
cd8d01d8cd
commit
e582d377c2
@ -14,10 +14,6 @@
|
||||
# include <climits>
|
||||
# include <cmath>
|
||||
# include <exception>
|
||||
|
||||
# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
# include <locale>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE)
|
||||
@ -26,6 +22,19 @@
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#ifdef FMT_USE_LOCALE
|
||||
// Use the provided definition.
|
||||
#elif defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
# define FMT_USE_LOCALE 0
|
||||
#else
|
||||
# define FMT_USE_LOCALE 1
|
||||
#endif
|
||||
#if FMT_USE_LOCALE
|
||||
# include <locale>
|
||||
#elif !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
# define FMT_STATIC_THOUSANDS_SEPARATOR ','
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
@ -77,53 +86,56 @@ inline void fwrite_fully(const void* ptr, size_t count, FILE* stream) {
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||
#if FMT_USE_LOCALE
|
||||
using std::locale;
|
||||
using std::numpunct;
|
||||
using std::use_facet;
|
||||
#else
|
||||
struct locale {};
|
||||
template <typename Char> struct numpunct {
|
||||
auto grouping() const -> std::string { return "\03"; }
|
||||
auto thousands_sep() const -> Char { return FMT_STATIC_THOUSANDS_SEPARATOR; }
|
||||
auto decimal_point() const -> Char { return '.'; }
|
||||
};
|
||||
template <typename Facet> Facet use_facet(locale) { return {}; }
|
||||
#endif // FMT_USE_LOCALE
|
||||
|
||||
template <typename Locale>
|
||||
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
|
||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||
static_assert(std::is_same<Locale, locale>::value, "");
|
||||
}
|
||||
|
||||
template <typename Locale> auto locale_ref::get() const -> Locale {
|
||||
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
|
||||
static_assert(std::is_same<Locale, locale>::value, "");
|
||||
return locale_ ? *static_cast<const locale*>(locale_) : locale();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> {
|
||||
auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>());
|
||||
auto&& facet = use_facet<numpunct<Char>>(loc.get<locale>());
|
||||
auto grouping = facet.grouping();
|
||||
auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep();
|
||||
return {std::move(grouping), thousands_sep};
|
||||
}
|
||||
template <typename Char>
|
||||
FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char {
|
||||
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
|
||||
.decimal_point();
|
||||
return use_facet<numpunct<Char>>(loc.get<locale>()).decimal_point();
|
||||
}
|
||||
#else
|
||||
template <typename Char>
|
||||
FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> {
|
||||
return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR};
|
||||
}
|
||||
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
|
||||
return '.';
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_FUNC auto write_loc(appender out, loc_value value,
|
||||
const format_specs& specs, locale_ref loc) -> bool {
|
||||
#ifdef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||
value.visit(loc_writer<>{
|
||||
out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."});
|
||||
return true;
|
||||
#else
|
||||
#if FMT_USE_LOCALE
|
||||
auto locale = loc.get<std::locale>();
|
||||
// We cannot use the num_put<char> facet because it may produce output in
|
||||
// a wrong encoding.
|
||||
using facet = format_facet<std::locale>;
|
||||
if (std::has_facet<facet>(locale))
|
||||
return std::use_facet<facet>(locale).put(out, value, specs);
|
||||
return use_facet<facet>(locale).put(out, value, specs);
|
||||
return facet(locale).put(out, value, specs);
|
||||
#else
|
||||
value.visit(loc_writer<>{
|
||||
out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."});
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
} // namespace detail
|
||||
@ -134,13 +146,13 @@ FMT_FUNC void report_error(const char* message) {
|
||||
|
||||
template <typename Locale> typename Locale::id format_facet<Locale>::id;
|
||||
|
||||
#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());
|
||||
auto& np = detail::use_facet<detail::numpunct<char>>(loc);
|
||||
grouping_ = np.grouping();
|
||||
if (!grouping_.empty()) separator_ = std::string(1, np.thousands_sep());
|
||||
}
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
template <>
|
||||
FMT_API FMT_FUNC auto format_facet<std::locale>::do_put(
|
||||
appender out, loc_value val, const format_specs& specs) const -> bool {
|
||||
@ -1019,7 +1031,8 @@ template <> struct cache_accessor<double> {
|
||||
{0xe4d5e82392a40515, 0x0fabaf3feaa5334b},
|
||||
{0xb8da1662e7b00a17, 0x3d6a751f3b936244},
|
||||
{0x95527a5202df0ccb, 0x0f37801e0c43ebc9},
|
||||
{0xf13e34aabb430a15, 0x647726b9e7c68ff0}
|
||||
{ 0xf13e34aabb430a15,
|
||||
0x647726b9e7c68ff0 }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -765,16 +765,6 @@ using is_integer =
|
||||
!std::is_same<T, char>::value &&
|
||||
!std::is_same<T, wchar_t>::value>;
|
||||
|
||||
#ifndef FMT_USE_FLOAT
|
||||
# define FMT_USE_FLOAT 1
|
||||
#endif
|
||||
#ifndef FMT_USE_DOUBLE
|
||||
# define FMT_USE_DOUBLE 1
|
||||
#endif
|
||||
#ifndef FMT_USE_LONG_DOUBLE
|
||||
# define FMT_USE_LONG_DOUBLE 1
|
||||
#endif
|
||||
|
||||
#if defined(FMT_USE_FLOAT128)
|
||||
// Use the provided definition.
|
||||
#elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE(<quadmath.h>)
|
||||
@ -1132,14 +1122,6 @@ constexpr auto is_negative(T) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool {
|
||||
if (std::is_same<T, float>()) return FMT_USE_FLOAT;
|
||||
if (std::is_same<T, double>()) return FMT_USE_DOUBLE;
|
||||
if (std::is_same<T, long double>()) return FMT_USE_LONG_DOUBLE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
|
||||
// represent all values of an integral type T.
|
||||
template <typename T>
|
||||
@ -3556,7 +3538,6 @@ template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(is_floating_point<T>::value)>
|
||||
FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs,
|
||||
locale_ref loc = {}) -> OutputIt {
|
||||
if (const_check(!is_supported_floating_point(value))) return out;
|
||||
return specs.localized() && write_loc(out, value, specs, loc)
|
||||
? out
|
||||
: write_float<Char>(out, value, specs, loc);
|
||||
@ -3566,7 +3547,6 @@ template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(is_fast_float<T>::value)>
|
||||
FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
|
||||
if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
|
||||
if (const_check(!is_supported_floating_point(value))) return out;
|
||||
|
||||
auto s = detail::signbit(value) ? sign::minus : sign::none;
|
||||
|
||||
@ -3708,28 +3688,23 @@ template <typename Char> struct default_arg_formatter {
|
||||
};
|
||||
|
||||
template <typename Char> struct arg_formatter {
|
||||
using iterator = basic_appender<Char>;
|
||||
using context = buffered_context<Char>;
|
||||
|
||||
iterator out;
|
||||
basic_appender<Char> out;
|
||||
const format_specs& specs;
|
||||
locale_ref locale;
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(is_builtin<T>::value)>
|
||||
FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator {
|
||||
return detail::write<Char>(out, value, specs, locale);
|
||||
FMT_CONSTEXPR FMT_INLINE void operator()(T value) {
|
||||
detail::write<Char>(out, value, specs, locale);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!is_builtin<T>::value)>
|
||||
auto operator()(T) -> iterator {
|
||||
void operator()(T) {
|
||||
FMT_ASSERT(false, "");
|
||||
return out;
|
||||
}
|
||||
|
||||
auto operator()(typename basic_format_arg<context>::handle) -> iterator {
|
||||
void operator()(typename basic_format_arg<buffered_context<Char>>::handle) {
|
||||
// User-defined types are handled separately because they require access
|
||||
// to the parse context.
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user