mirror of
https://github.com/fmtlib/fmt.git
synced 2025-01-27 06:35:37 +00:00
Implement format_facet
This commit is contained in:
parent
91ecb38a34
commit
768d79a839
@ -29,8 +29,6 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template <typename Locale> typename Locale::id format_facet<Locale>::id;
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
FMT_FUNC void assert_fail(const char* file, int line, const char* message) {
|
FMT_FUNC void assert_fail(const char* file, int line, const char* message) {
|
||||||
@ -132,8 +130,34 @@ FMT_FUNC auto write_int(appender out, basic_format_arg<format_context> value,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct localize_int {
|
||||||
|
appender out;
|
||||||
|
const format_specs& specs;
|
||||||
|
locale_ref loc;
|
||||||
|
|
||||||
|
template <typename T, FMT_ENABLE_IF(detail::is_integer<T>::value)>
|
||||||
|
void operator()(T value) {
|
||||||
|
auto arg = make_write_int_arg(value, specs.sign);
|
||||||
|
write_int(out, static_cast<uint64_or_128_t<T>>(arg.abs_value), arg.prefix,
|
||||||
|
specs, digit_grouping<char>(loc));
|
||||||
|
}
|
||||||
|
template <typename T, FMT_ENABLE_IF(!detail::is_integer<T>::value)>
|
||||||
|
void operator()(T) {}
|
||||||
|
};
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename Locale> typename Locale::id format_facet<Locale>::id;
|
||||||
|
|
||||||
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
template <>
|
||||||
|
FMT_API FMT_FUNC void format_facet<std::locale>::do_put(
|
||||||
|
appender out, basic_format_arg<format_context> val,
|
||||||
|
const format_specs& specs, std::locale& loc) const {
|
||||||
|
visit_format_arg(detail::localize_int{out, specs, detail::locale_ref(loc)},
|
||||||
|
val);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !FMT_MSC_VERSION
|
#if !FMT_MSC_VERSION
|
||||||
FMT_API FMT_FUNC format_error::~format_error() noexcept = default;
|
FMT_API FMT_FUNC format_error::~format_error() noexcept = default;
|
||||||
#endif
|
#endif
|
||||||
|
@ -988,17 +988,23 @@ constexpr auto compile_string_to_view(detail::std_string_view<Char> s)
|
|||||||
// A locale facet that formats values in UTF-8.
|
// A locale facet that formats values in UTF-8.
|
||||||
// It is parameterized on the locale to avoid the heavy <locale> include.
|
// It is parameterized on the locale to avoid the heavy <locale> include.
|
||||||
template <typename Locale> class format_facet : public Locale::facet {
|
template <typename Locale> class format_facet : public Locale::facet {
|
||||||
|
private:
|
||||||
|
std::string separator_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void do_put(appender out, basic_format_arg<format_context> val,
|
||||||
|
const format_specs& specs, Locale& loc) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_API typename Locale::id id;
|
static FMT_API typename Locale::id id;
|
||||||
|
|
||||||
|
explicit format_facet(string_view sep = ",")
|
||||||
|
: separator_(sep.data(), sep.size()) {}
|
||||||
|
|
||||||
void put(appender out, basic_format_arg<format_context> val,
|
void put(appender out, basic_format_arg<format_context> val,
|
||||||
const format_specs& specs, Locale& loc) const {
|
const format_specs& specs, Locale& loc) const {
|
||||||
do_put(out, val, specs, loc);
|
do_put(out, val, specs, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void do_put(appender out, basic_format_arg<format_context> val,
|
|
||||||
const format_specs& specs, Locale& loc) const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
FMT_BEGIN_DETAIL_NAMESPACE
|
||||||
@ -1949,19 +1955,19 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits,
|
|||||||
|
|
||||||
template <typename Char> class digit_grouping {
|
template <typename Char> class digit_grouping {
|
||||||
private:
|
private:
|
||||||
thousands_sep_result<Char> sep_;
|
std::string grouping_;
|
||||||
|
std::basic_string<Char> thousands_sep_;
|
||||||
|
|
||||||
struct next_state {
|
struct next_state {
|
||||||
std::string::const_iterator group;
|
std::string::const_iterator group;
|
||||||
int pos;
|
int pos;
|
||||||
};
|
};
|
||||||
next_state initial_state() const { return {sep_.grouping.begin(), 0}; }
|
next_state initial_state() const { return {grouping_.begin(), 0}; }
|
||||||
|
|
||||||
// Returns the next digit group separator position.
|
// Returns the next digit group separator position.
|
||||||
int next(next_state& state) const {
|
int next(next_state& state) const {
|
||||||
if (!sep_.thousands_sep) return max_value<int>();
|
if (thousands_sep_.empty()) return max_value<int>();
|
||||||
if (state.group == sep_.grouping.end())
|
if (state.group == grouping_.end()) return state.pos += grouping_.back();
|
||||||
return state.pos += sep_.grouping.back();
|
|
||||||
if (*state.group <= 0 || *state.group == max_value<char>())
|
if (*state.group <= 0 || *state.group == max_value<char>())
|
||||||
return max_value<int>();
|
return max_value<int>();
|
||||||
state.pos += *state.group++;
|
state.pos += *state.group++;
|
||||||
@ -1970,14 +1976,16 @@ template <typename Char> class digit_grouping {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit digit_grouping(locale_ref loc, bool localized = true) {
|
explicit digit_grouping(locale_ref loc, bool localized = true) {
|
||||||
if (localized)
|
if (!localized) return;
|
||||||
sep_ = thousands_sep<Char>(loc);
|
auto sep = thousands_sep<Char>(loc);
|
||||||
else
|
grouping_ = sep.grouping;
|
||||||
sep_.thousands_sep = Char();
|
if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep);
|
||||||
}
|
}
|
||||||
explicit digit_grouping(thousands_sep_result<Char> sep) : sep_(sep) {}
|
explicit digit_grouping(thousands_sep_result<Char> sep)
|
||||||
|
: grouping_(sep.grouping),
|
||||||
|
thousands_sep_(sep.thousands_sep ? 1 : 0, sep.thousands_sep) {}
|
||||||
|
|
||||||
Char separator() const { return sep_.thousands_sep; }
|
bool has_separator() const { return !thousands_sep_.empty(); }
|
||||||
|
|
||||||
int count_separators(int num_digits) const {
|
int count_separators(int num_digits) const {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@ -2000,7 +2008,9 @@ template <typename Char> class digit_grouping {
|
|||||||
for (int i = 0, sep_index = static_cast<int>(separators.size() - 1);
|
for (int i = 0, sep_index = static_cast<int>(separators.size() - 1);
|
||||||
i < num_digits; ++i) {
|
i < num_digits; ++i) {
|
||||||
if (num_digits - i == separators[sep_index]) {
|
if (num_digits - i == separators[sep_index]) {
|
||||||
*out++ = separator();
|
out =
|
||||||
|
copy_str<Char>(thousands_sep_.data(),
|
||||||
|
thousands_sep_.data() + thousands_sep_.size(), out);
|
||||||
--sep_index;
|
--sep_index;
|
||||||
}
|
}
|
||||||
*out++ = static_cast<Char>(digits[to_unsigned(i)]);
|
*out++ = static_cast<Char>(digits[to_unsigned(i)]);
|
||||||
@ -2307,7 +2317,7 @@ template <typename Char, typename OutputIt, typename T, typename Grouping>
|
|||||||
FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
|
FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
|
||||||
int significand_size, int exponent,
|
int significand_size, int exponent,
|
||||||
const Grouping& grouping) -> OutputIt {
|
const Grouping& grouping) -> OutputIt {
|
||||||
if (!grouping.separator()) {
|
if (!grouping.has_separator()) {
|
||||||
out = write_significand<Char>(out, significand, significand_size);
|
out = write_significand<Char>(out, significand, significand_size);
|
||||||
return detail::fill_n(out, exponent, static_cast<Char>('0'));
|
return detail::fill_n(out, exponent, static_cast<Char>('0'));
|
||||||
}
|
}
|
||||||
@ -2369,7 +2379,7 @@ FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
|
|||||||
int significand_size, int integral_size,
|
int significand_size, int integral_size,
|
||||||
Char decimal_point,
|
Char decimal_point,
|
||||||
const Grouping& grouping) -> OutputIt {
|
const Grouping& grouping) -> OutputIt {
|
||||||
if (!grouping.separator()) {
|
if (!grouping.has_separator()) {
|
||||||
return write_significand(out, significand, significand_size, integral_size,
|
return write_significand(out, significand, significand_size, integral_size,
|
||||||
decimal_point);
|
decimal_point);
|
||||||
}
|
}
|
||||||
@ -2492,7 +2502,7 @@ template <typename Char> class fallback_digit_grouping {
|
|||||||
public:
|
public:
|
||||||
constexpr fallback_digit_grouping(locale_ref, bool) {}
|
constexpr fallback_digit_grouping(locale_ref, bool) {}
|
||||||
|
|
||||||
constexpr Char separator() const { return Char(); }
|
constexpr bool has_separator() const { return false; }
|
||||||
|
|
||||||
constexpr int count_separators(int) const { return 0; }
|
constexpr int count_separators(int) const { return 0; }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user