mirror of
https://github.com/shadps4-emu/ext-fmt.git
synced 2025-02-17 16:57:33 +00:00
Impelement char8_t support
This commit is contained in:
parent
76a47d41c8
commit
f8027414f5
@ -192,6 +192,16 @@ void report_error(FormatFunc func, int error_code,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
|
||||
const char8_t *data = s.data();
|
||||
size_t num_code_points = 0;
|
||||
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||
if ((data[i] & 0xc0) != 0x80)
|
||||
++num_code_points;
|
||||
}
|
||||
return num_code_points;
|
||||
}
|
||||
|
||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||
class locale {
|
||||
private:
|
||||
@ -202,21 +212,16 @@ class locale {
|
||||
std::locale get() { return locale_; }
|
||||
};
|
||||
|
||||
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
|
||||
const char8_t *data = s.data();
|
||||
int num_code_points = 0;
|
||||
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||
if ((data[i] & 0xc0) != 0x80)
|
||||
++num_code_points;
|
||||
}
|
||||
return num_code_points;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
template <typename Char>
|
||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
||||
FMT_FUNC Char thousands_sep(locale_provider *lp) {
|
||||
std::locale loc = lp ? lp->locale().get() : std::locale();
|
||||
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
|
||||
}
|
||||
template <> FMT_FUNC char8_t thousands_sep<char8_t>(locale_provider *) {
|
||||
return static_cast<char8_t>(',');
|
||||
}
|
||||
}
|
||||
#else
|
||||
template <typename Char>
|
||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
||||
|
@ -713,7 +713,7 @@ class null_terminating_iterator {
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR Char operator*() const {
|
||||
return ptr_ != end_ ? *ptr_ : 0;
|
||||
return ptr_ != end_ ? *ptr_ : Char();
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR null_terminating_iterator operator++() {
|
||||
@ -1058,19 +1058,19 @@ inline Char *format_decimal(Char *buffer, UInt value, unsigned num_digits,
|
||||
// "Three Optimization Tips for C++". See speed-test for a comparison.
|
||||
unsigned index = static_cast<unsigned>((value % 100) * 2);
|
||||
value /= 100;
|
||||
*--buffer = data::DIGITS[index + 1];
|
||||
*--buffer = static_cast<Char>(data::DIGITS[index + 1]);
|
||||
thousands_sep(buffer);
|
||||
*--buffer = data::DIGITS[index];
|
||||
*--buffer = static_cast<Char>(data::DIGITS[index]);
|
||||
thousands_sep(buffer);
|
||||
}
|
||||
if (value < 10) {
|
||||
*--buffer = static_cast<char>('0' + value);
|
||||
*--buffer = static_cast<Char>('0' + value);
|
||||
return end;
|
||||
}
|
||||
unsigned index = static_cast<unsigned>(value * 2);
|
||||
*--buffer = data::DIGITS[index + 1];
|
||||
*--buffer = static_cast<Char>(data::DIGITS[index + 1]);
|
||||
thousands_sep(buffer);
|
||||
*--buffer = data::DIGITS[index];
|
||||
*--buffer = static_cast<Char>(data::DIGITS[index]);
|
||||
return end;
|
||||
}
|
||||
|
||||
@ -1097,7 +1097,7 @@ inline Char *format_uint(Char *buffer, UInt value, unsigned num_digits,
|
||||
do {
|
||||
const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
unsigned digit = (value & ((1 << BASE_BITS) - 1));
|
||||
*--buffer = BASE_BITS < 4 ? static_cast<char>('0' + digit) : digits[digit];
|
||||
*--buffer = static_cast<Char>(BASE_BITS < 4 ? '0' + digit : digits[digit]);
|
||||
} while ((value >>= BASE_BITS) != 0);
|
||||
return end;
|
||||
}
|
||||
@ -1225,7 +1225,7 @@ class basic_format_specs : public align_spec {
|
||||
public:
|
||||
unsigned flags_;
|
||||
int precision_;
|
||||
Char type_;
|
||||
char type_;
|
||||
|
||||
FMT_CONSTEXPR basic_format_specs(
|
||||
unsigned width = 0, char type = 0, wchar_t fill = ' ')
|
||||
@ -1233,7 +1233,7 @@ class basic_format_specs : public align_spec {
|
||||
|
||||
FMT_CONSTEXPR bool flag(unsigned f) const { return (flags_ & f) != 0; }
|
||||
FMT_CONSTEXPR int precision() const { return precision_; }
|
||||
FMT_CONSTEXPR Char type() const { return type_; }
|
||||
FMT_CONSTEXPR char type() const { return type_; }
|
||||
};
|
||||
|
||||
typedef basic_format_specs<char> format_specs;
|
||||
@ -1253,8 +1253,8 @@ struct format_string_traits<
|
||||
S, typename std::enable_if<std::is_base_of<compile_string, S>::value>::type>:
|
||||
format_string_traits_base<char> {};
|
||||
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void handle_int_type_spec(Char spec, Handler &&handler) {
|
||||
template <typename Handler>
|
||||
FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler &&handler) {
|
||||
switch (spec) {
|
||||
case 0: case 'd':
|
||||
handler.on_dec();
|
||||
@ -1276,8 +1276,8 @@ FMT_CONSTEXPR void handle_int_type_spec(Char spec, Handler &&handler) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void handle_float_type_spec(Char spec, Handler &&handler) {
|
||||
template <typename Handler>
|
||||
FMT_CONSTEXPR void handle_float_type_spec(char spec, Handler &&handler) {
|
||||
switch (spec) {
|
||||
case 0: case 'g': case 'G':
|
||||
handler.on_general();
|
||||
@ -1361,13 +1361,13 @@ class float_type_checker : private ErrorHandler {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ErrorHandler, typename CharType>
|
||||
template <typename ErrorHandler>
|
||||
class char_specs_checker : public ErrorHandler {
|
||||
private:
|
||||
CharType type_;
|
||||
char type_;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR char_specs_checker(CharType type, ErrorHandler eh)
|
||||
FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)
|
||||
: ErrorHandler(eh), type_(type) {}
|
||||
|
||||
FMT_CONSTEXPR void on_int() {
|
||||
@ -1478,8 +1478,9 @@ class arg_formatter_base {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, iterator>::type
|
||||
operator()(T value) {
|
||||
typename std::enable_if<
|
||||
std::is_integral<T>::value || std::is_same<T, char_type>::value,
|
||||
iterator>::type operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||
// use std::is_same instead.
|
||||
if (std::is_same<T, bool>::value) {
|
||||
@ -1692,7 +1693,7 @@ class specs_setter {
|
||||
explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char> &specs):
|
||||
specs_(specs) {}
|
||||
|
||||
FMT_CONSTEXPR specs_setter(const specs_setter &other) : specs_(other.specs_) {}
|
||||
FMT_CONSTEXPR specs_setter(const specs_setter &other): specs_(other.specs_) {}
|
||||
|
||||
FMT_CONSTEXPR void on_align(alignment align) { specs_.align_ = align; }
|
||||
FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; }
|
||||
@ -1712,7 +1713,9 @@ class specs_setter {
|
||||
}
|
||||
FMT_CONSTEXPR void end_precision() {}
|
||||
|
||||
FMT_CONSTEXPR void on_type(Char type) { specs_.type_ = type; }
|
||||
FMT_CONSTEXPR void on_type(Char type) {
|
||||
specs_.type_ = static_cast<char>(type);
|
||||
}
|
||||
|
||||
protected:
|
||||
basic_format_specs<Char> &specs_;
|
||||
@ -2019,19 +2022,19 @@ FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
|
||||
int i = 1;
|
||||
do {
|
||||
auto p = it + i;
|
||||
switch (*p) {
|
||||
case '<':
|
||||
align = ALIGN_LEFT;
|
||||
break;
|
||||
case '>':
|
||||
align = ALIGN_RIGHT;
|
||||
break;
|
||||
case '=':
|
||||
align = ALIGN_NUMERIC;
|
||||
break;
|
||||
case '^':
|
||||
align = ALIGN_CENTER;
|
||||
break;
|
||||
switch (static_cast<char>(*p)) {
|
||||
case '<':
|
||||
align = ALIGN_LEFT;
|
||||
break;
|
||||
case '>':
|
||||
align = ALIGN_RIGHT;
|
||||
break;
|
||||
case '=':
|
||||
align = ALIGN_NUMERIC;
|
||||
break;
|
||||
case '^':
|
||||
align = ALIGN_CENTER;
|
||||
break;
|
||||
}
|
||||
if (align != ALIGN_DEFAULT) {
|
||||
if (p != it) {
|
||||
@ -2048,19 +2051,19 @@ FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
|
||||
} while (--i >= 0);
|
||||
|
||||
// Parse sign.
|
||||
switch (*it) {
|
||||
case '+':
|
||||
handler.on_plus();
|
||||
++it;
|
||||
break;
|
||||
case '-':
|
||||
handler.on_minus();
|
||||
++it;
|
||||
break;
|
||||
case ' ':
|
||||
handler.on_space();
|
||||
++it;
|
||||
break;
|
||||
switch (static_cast<char>(*it)) {
|
||||
case '+':
|
||||
handler.on_plus();
|
||||
++it;
|
||||
break;
|
||||
case '-':
|
||||
handler.on_minus();
|
||||
++it;
|
||||
break;
|
||||
case ' ':
|
||||
handler.on_space();
|
||||
++it;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*it == '#') {
|
||||
@ -2178,7 +2181,7 @@ FMT_CONSTEXPR void parse_format_string(
|
||||
handler.on_text(p, p + 1);
|
||||
} else {
|
||||
p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler});
|
||||
Char c = p != end ? *p : 0;
|
||||
Char c = p != end ? *p : Char();
|
||||
if (c == '}') {
|
||||
handler.on_replacement_field(p);
|
||||
} else if (c == ':') {
|
||||
@ -2297,6 +2300,28 @@ void handle_dynamic_spec(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }
|
||||
|
||||
template <typename InputIt, typename OutChar>
|
||||
struct needs_conversion: std::integral_constant<bool,
|
||||
std::is_same<
|
||||
typename std::iterator_traits<InputIt>::value_type, char>::value &&
|
||||
std::is_same<OutChar, char8_t>::value> {};
|
||||
|
||||
template <typename OutChar, typename InputIt, typename OutputIt>
|
||||
typename std::enable_if<
|
||||
!needs_conversion<InputIt, OutChar>::value, OutputIt>::type
|
||||
copy_str(InputIt begin, InputIt end, OutputIt it) {
|
||||
return std::copy(begin, end, it);
|
||||
}
|
||||
|
||||
template <typename OutChar, typename InputIt, typename OutputIt>
|
||||
typename std::enable_if<
|
||||
needs_conversion<InputIt, OutChar>::value, OutputIt>::type
|
||||
copy_str(InputIt begin, InputIt end, OutputIt it) {
|
||||
return std::transform(begin, end, it, to_char8_t);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/** The default argument formatter. */
|
||||
@ -2439,7 +2464,7 @@ class basic_writer {
|
||||
template <typename It>
|
||||
void operator()(It &&it) const {
|
||||
if (prefix.size() != 0)
|
||||
it = std::copy_n(prefix.data(), prefix.size(), it);
|
||||
it = internal::copy_str<char_type>(prefix.begin(), prefix.end(), it);
|
||||
it = std::fill_n(it, padding, fill);
|
||||
f(it);
|
||||
}
|
||||
@ -2462,7 +2487,7 @@ class basic_writer {
|
||||
} else if (spec.precision() > static_cast<int>(num_digits)) {
|
||||
size = prefix.size() + static_cast<std::size_t>(spec.precision());
|
||||
padding = static_cast<std::size_t>(spec.precision()) - num_digits;
|
||||
fill = '0';
|
||||
fill = static_cast<char_type>('0');
|
||||
}
|
||||
align_spec as = spec;
|
||||
if (spec.align() == ALIGN_DEFAULT)
|
||||
@ -2481,7 +2506,7 @@ class basic_writer {
|
||||
unsigned num_digits = internal::count_digits(abs_value);
|
||||
auto &&it = reserve((is_negative ? 1 : 0) + num_digits);
|
||||
if (is_negative)
|
||||
*it++ = '-';
|
||||
*it++ = static_cast<char_type>('-');
|
||||
it = internal::format_decimal(it, abs_value, num_digits);
|
||||
}
|
||||
|
||||
@ -2636,8 +2661,9 @@ class basic_writer {
|
||||
template <typename It>
|
||||
void operator()(It &&it) const {
|
||||
if (sign)
|
||||
*it++ = sign;
|
||||
it = std::copy_n(str, static_cast<std::size_t>(INF_SIZE), it);
|
||||
*it++ = static_cast<char_type>(sign);
|
||||
it = internal::copy_str<char_type>(
|
||||
str, str + static_cast<std::size_t>(INF_SIZE), it);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2649,7 +2675,7 @@ class basic_writer {
|
||||
template <typename It>
|
||||
void operator()(It &&it) {
|
||||
if (sign) {
|
||||
*it++ = sign;
|
||||
*it++ = static_cast<char_type>(sign);
|
||||
--n;
|
||||
}
|
||||
it = std::copy_n(buffer.begin(), n, it);
|
||||
@ -2670,7 +2696,7 @@ class basic_writer {
|
||||
|
||||
template <typename It>
|
||||
void operator()(It &&it) const {
|
||||
it = std::copy_n(s, size, it);
|
||||
it = internal::copy_str<char_type>(s, s + size, it);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2750,7 +2776,7 @@ class basic_writer {
|
||||
*/
|
||||
void write(string_view value) {
|
||||
auto &&it = reserve(value.size());
|
||||
it = std::copy(value.begin(), value.end(), it);
|
||||
it = internal::copy_str<char_type>(value.begin(), value.end(), it);
|
||||
}
|
||||
void write(wstring_view value) {
|
||||
static_assert(std::is_same<char_type, wchar_t>::value, "");
|
||||
@ -2809,12 +2835,11 @@ void basic_writer<Range>::write_str(
|
||||
write_str(data, size, spec);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
struct float_spec_handler {
|
||||
Char type;
|
||||
char type;
|
||||
bool upper;
|
||||
|
||||
explicit float_spec_handler(Char t) : type(t), upper(false) {}
|
||||
explicit float_spec_handler(char t) : type(t), upper(false) {}
|
||||
|
||||
void on_general() {
|
||||
if (type == 'G')
|
||||
@ -2852,8 +2877,8 @@ template <typename Range>
|
||||
template <typename T>
|
||||
void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
||||
// Check type.
|
||||
float_spec_handler<char_type> handler(spec.type());
|
||||
internal::handle_float_type_spec(spec.type(), handler);
|
||||
float_spec_handler handler(static_cast<char>(spec.type()));
|
||||
internal::handle_float_type_spec(handler.type, handler);
|
||||
|
||||
char sign = 0;
|
||||
// Use isnegative instead of value < 0 because the latter is always
|
||||
@ -2903,7 +2928,7 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
||||
if (spec.align() == ALIGN_NUMERIC) {
|
||||
if (sign) {
|
||||
auto &&it = reserve(1);
|
||||
*it++ = sign;
|
||||
*it++ = static_cast<char_type>(sign);
|
||||
sign = 0;
|
||||
if (as.width_)
|
||||
--as.width_;
|
||||
@ -3157,8 +3182,7 @@ struct formatter<
|
||||
case internal::char_type:
|
||||
handle_char_specs(
|
||||
&specs_,
|
||||
internal::char_specs_checker<decltype(eh), decltype(type_spec)>(
|
||||
type_spec, eh));
|
||||
internal::char_specs_checker<decltype(eh)>(type_spec, eh));
|
||||
break;
|
||||
case internal::double_type:
|
||||
case internal::long_double_type:
|
||||
@ -3464,9 +3488,10 @@ inline typename buffer_context<Char>::type::iterator format_to(
|
||||
basic_memory_buffer<Char, SIZE> &buf, const String &format_str,
|
||||
const Args &... args) {
|
||||
internal::check_format_string<Args...>(format_str);
|
||||
return vformat_to(
|
||||
buf, basic_string_view<Char>(format_str),
|
||||
make_format_args<typename buffer_context<Char>::type>(args...));
|
||||
typedef typename buffer_context<Char>::type context;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vformat_to(buf, basic_string_view<Char>(format_str),
|
||||
basic_format_args<context>(as));
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char = char>
|
||||
|
Loading…
x
Reference in New Issue
Block a user