Impelement char8_t support

This commit is contained in:
Victor Zverovich
2018-09-30 11:39:20 -07:00
parent 76a47d41c8
commit f8027414f5
2 changed files with 107 additions and 77 deletions

View File

@ -192,6 +192,16 @@ void report_error(FormatFunc func, int error_code,
} }
} // namespace } // 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) #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
class locale { class locale {
private: private:
@ -202,21 +212,16 @@ class locale {
std::locale get() { return locale_; } std::locale get() { return locale_; }
}; };
FMT_FUNC size_t internal::count_code_points(u8string_view s) { namespace internal {
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;
}
template <typename Char> 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(); std::locale loc = lp ? lp->locale().get() : std::locale();
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep(); 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 #else
template <typename Char> template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {

View File

@ -713,7 +713,7 @@ class null_terminating_iterator {
} }
FMT_CONSTEXPR Char operator*() const { FMT_CONSTEXPR Char operator*() const {
return ptr_ != end_ ? *ptr_ : 0; return ptr_ != end_ ? *ptr_ : Char();
} }
FMT_CONSTEXPR null_terminating_iterator operator++() { 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. // "Three Optimization Tips for C++". See speed-test for a comparison.
unsigned index = static_cast<unsigned>((value % 100) * 2); unsigned index = static_cast<unsigned>((value % 100) * 2);
value /= 100; value /= 100;
*--buffer = data::DIGITS[index + 1]; *--buffer = static_cast<Char>(data::DIGITS[index + 1]);
thousands_sep(buffer); thousands_sep(buffer);
*--buffer = data::DIGITS[index]; *--buffer = static_cast<Char>(data::DIGITS[index]);
thousands_sep(buffer); thousands_sep(buffer);
} }
if (value < 10) { if (value < 10) {
*--buffer = static_cast<char>('0' + value); *--buffer = static_cast<Char>('0' + value);
return end; return end;
} }
unsigned index = static_cast<unsigned>(value * 2); unsigned index = static_cast<unsigned>(value * 2);
*--buffer = data::DIGITS[index + 1]; *--buffer = static_cast<Char>(data::DIGITS[index + 1]);
thousands_sep(buffer); thousands_sep(buffer);
*--buffer = data::DIGITS[index]; *--buffer = static_cast<Char>(data::DIGITS[index]);
return end; return end;
} }
@ -1097,7 +1097,7 @@ inline Char *format_uint(Char *buffer, UInt value, unsigned num_digits,
do { do {
const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
unsigned digit = (value & ((1 << BASE_BITS) - 1)); 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); } while ((value >>= BASE_BITS) != 0);
return end; return end;
} }
@ -1225,7 +1225,7 @@ class basic_format_specs : public align_spec {
public: public:
unsigned flags_; unsigned flags_;
int precision_; int precision_;
Char type_; char type_;
FMT_CONSTEXPR basic_format_specs( FMT_CONSTEXPR basic_format_specs(
unsigned width = 0, char type = 0, wchar_t fill = ' ') 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 bool flag(unsigned f) const { return (flags_ & f) != 0; }
FMT_CONSTEXPR int precision() const { return precision_; } 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; 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>: S, typename std::enable_if<std::is_base_of<compile_string, S>::value>::type>:
format_string_traits_base<char> {}; format_string_traits_base<char> {};
template <typename Char, typename Handler> template <typename Handler>
FMT_CONSTEXPR void handle_int_type_spec(Char spec, Handler &&handler) { FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler &&handler) {
switch (spec) { switch (spec) {
case 0: case 'd': case 0: case 'd':
handler.on_dec(); handler.on_dec();
@ -1276,8 +1276,8 @@ FMT_CONSTEXPR void handle_int_type_spec(Char spec, Handler &&handler) {
} }
} }
template <typename Char, typename Handler> template <typename Handler>
FMT_CONSTEXPR void handle_float_type_spec(Char spec, Handler &&handler) { FMT_CONSTEXPR void handle_float_type_spec(char spec, Handler &&handler) {
switch (spec) { switch (spec) {
case 0: case 'g': case 'G': case 0: case 'g': case 'G':
handler.on_general(); 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 { class char_specs_checker : public ErrorHandler {
private: private:
CharType type_; char type_;
public: public:
FMT_CONSTEXPR char_specs_checker(CharType type, ErrorHandler eh) FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)
: ErrorHandler(eh), type_(type) {} : ErrorHandler(eh), type_(type) {}
FMT_CONSTEXPR void on_int() { FMT_CONSTEXPR void on_int() {
@ -1478,8 +1478,9 @@ class arg_formatter_base {
} }
template <typename T> template <typename T>
typename std::enable_if<std::is_integral<T>::value, iterator>::type typename std::enable_if<
operator()(T value) { 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 // MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead. // use std::is_same instead.
if (std::is_same<T, bool>::value) { if (std::is_same<T, bool>::value) {
@ -1692,7 +1693,7 @@ class specs_setter {
explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char> &specs): explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char> &specs):
specs_(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_align(alignment align) { specs_.align_ = align; }
FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; } 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 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: protected:
basic_format_specs<Char> &specs_; basic_format_specs<Char> &specs_;
@ -2019,19 +2022,19 @@ FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
int i = 1; int i = 1;
do { do {
auto p = it + i; auto p = it + i;
switch (*p) { switch (static_cast<char>(*p)) {
case '<': case '<':
align = ALIGN_LEFT; align = ALIGN_LEFT;
break; break;
case '>': case '>':
align = ALIGN_RIGHT; align = ALIGN_RIGHT;
break; break;
case '=': case '=':
align = ALIGN_NUMERIC; align = ALIGN_NUMERIC;
break; break;
case '^': case '^':
align = ALIGN_CENTER; align = ALIGN_CENTER;
break; break;
} }
if (align != ALIGN_DEFAULT) { if (align != ALIGN_DEFAULT) {
if (p != it) { if (p != it) {
@ -2048,19 +2051,19 @@ FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
} while (--i >= 0); } while (--i >= 0);
// Parse sign. // Parse sign.
switch (*it) { switch (static_cast<char>(*it)) {
case '+': case '+':
handler.on_plus(); handler.on_plus();
++it; ++it;
break; break;
case '-': case '-':
handler.on_minus(); handler.on_minus();
++it; ++it;
break; break;
case ' ': case ' ':
handler.on_space(); handler.on_space();
++it; ++it;
break; break;
} }
if (*it == '#') { if (*it == '#') {
@ -2178,7 +2181,7 @@ FMT_CONSTEXPR void parse_format_string(
handler.on_text(p, p + 1); handler.on_text(p, p + 1);
} else { } else {
p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler}); 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 == '}') { if (c == '}') {
handler.on_replacement_field(p); handler.on_replacement_field(p);
} else if (c == ':') { } else if (c == ':') {
@ -2297,6 +2300,28 @@ void handle_dynamic_spec(
break; 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 } // namespace internal
/** The default argument formatter. */ /** The default argument formatter. */
@ -2439,7 +2464,7 @@ class basic_writer {
template <typename It> template <typename It>
void operator()(It &&it) const { void operator()(It &&it) const {
if (prefix.size() != 0) 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); it = std::fill_n(it, padding, fill);
f(it); f(it);
} }
@ -2462,7 +2487,7 @@ class basic_writer {
} else if (spec.precision() > static_cast<int>(num_digits)) { } else if (spec.precision() > static_cast<int>(num_digits)) {
size = prefix.size() + static_cast<std::size_t>(spec.precision()); size = prefix.size() + static_cast<std::size_t>(spec.precision());
padding = static_cast<std::size_t>(spec.precision()) - num_digits; padding = static_cast<std::size_t>(spec.precision()) - num_digits;
fill = '0'; fill = static_cast<char_type>('0');
} }
align_spec as = spec; align_spec as = spec;
if (spec.align() == ALIGN_DEFAULT) if (spec.align() == ALIGN_DEFAULT)
@ -2481,7 +2506,7 @@ class basic_writer {
unsigned num_digits = internal::count_digits(abs_value); unsigned num_digits = internal::count_digits(abs_value);
auto &&it = reserve((is_negative ? 1 : 0) + num_digits); auto &&it = reserve((is_negative ? 1 : 0) + num_digits);
if (is_negative) if (is_negative)
*it++ = '-'; *it++ = static_cast<char_type>('-');
it = internal::format_decimal(it, abs_value, num_digits); it = internal::format_decimal(it, abs_value, num_digits);
} }
@ -2636,8 +2661,9 @@ class basic_writer {
template <typename It> template <typename It>
void operator()(It &&it) const { void operator()(It &&it) const {
if (sign) if (sign)
*it++ = sign; *it++ = static_cast<char_type>(sign);
it = std::copy_n(str, static_cast<std::size_t>(INF_SIZE), it); 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> template <typename It>
void operator()(It &&it) { void operator()(It &&it) {
if (sign) { if (sign) {
*it++ = sign; *it++ = static_cast<char_type>(sign);
--n; --n;
} }
it = std::copy_n(buffer.begin(), n, it); it = std::copy_n(buffer.begin(), n, it);
@ -2670,7 +2696,7 @@ class basic_writer {
template <typename It> template <typename It>
void operator()(It &&it) const { 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) { void write(string_view value) {
auto &&it = reserve(value.size()); 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) { void write(wstring_view value) {
static_assert(std::is_same<char_type, wchar_t>::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); write_str(data, size, spec);
} }
template <typename Char>
struct float_spec_handler { struct float_spec_handler {
Char type; char type;
bool upper; 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() { void on_general() {
if (type == 'G') if (type == 'G')
@ -2852,8 +2877,8 @@ template <typename Range>
template <typename T> template <typename T>
void basic_writer<Range>::write_double(T value, const format_specs &spec) { void basic_writer<Range>::write_double(T value, const format_specs &spec) {
// Check type. // Check type.
float_spec_handler<char_type> handler(spec.type()); float_spec_handler handler(static_cast<char>(spec.type()));
internal::handle_float_type_spec(spec.type(), handler); internal::handle_float_type_spec(handler.type, handler);
char sign = 0; char sign = 0;
// Use isnegative instead of value < 0 because the latter is always // 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 (spec.align() == ALIGN_NUMERIC) {
if (sign) { if (sign) {
auto &&it = reserve(1); auto &&it = reserve(1);
*it++ = sign; *it++ = static_cast<char_type>(sign);
sign = 0; sign = 0;
if (as.width_) if (as.width_)
--as.width_; --as.width_;
@ -3157,8 +3182,7 @@ struct formatter<
case internal::char_type: case internal::char_type:
handle_char_specs( handle_char_specs(
&specs_, &specs_,
internal::char_specs_checker<decltype(eh), decltype(type_spec)>( internal::char_specs_checker<decltype(eh)>(type_spec, eh));
type_spec, eh));
break; break;
case internal::double_type: case internal::double_type:
case internal::long_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, basic_memory_buffer<Char, SIZE> &buf, const String &format_str,
const Args &... args) { const Args &... args) {
internal::check_format_string<Args...>(format_str); internal::check_format_string<Args...>(format_str);
return vformat_to( typedef typename buffer_context<Char>::type context;
buf, basic_string_view<Char>(format_str), format_arg_store<context, Args...> as{args...};
make_format_args<typename buffer_context<Char>::type>(args...)); return vformat_to(buf, basic_string_view<Char>(format_str),
basic_format_args<context>(as));
} }
template <typename OutputIt, typename Char = char> template <typename OutputIt, typename Char = char>