Count width in code points (#628)

This commit is contained in:
Victor Zverovich 2018-10-03 18:22:26 -07:00
parent deb901b9e4
commit 38325248e5
4 changed files with 40 additions and 16 deletions

View File

@ -1342,10 +1342,11 @@ struct is_contiguous<internal::basic_buffer<Char> >: std::true_type {};
/** Formats a string and writes the output to ``out``. */ /** Formats a string and writes the output to ``out``. */
template <typename Container, typename S> template <typename Container, typename S>
typename std::enable_if< typename std::enable_if<
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
vformat_to(std::back_insert_iterator<Container> out, vformat_to(
const S &format_str, std::back_insert_iterator<Container> out,
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) { const S &format_str,
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
internal::container_buffer<Container> buf(internal::get_container(out)); internal::container_buffer<Container> buf(internal::get_container(out));
vformat_to(buf, internal::to_string_view(format_str), args); vformat_to(buf, internal::to_string_view(format_str), args);
return out; return out;

View File

@ -192,7 +192,7 @@ void report_error(FormatFunc func, int error_code,
} }
} // namespace } // namespace
FMT_FUNC size_t internal::count_code_points(u8string_view s) { FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
const char8_t *data = s.data(); const char8_t *data = s.data();
size_t num_code_points = 0; size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) { for (size_t i = 0, size = s.size(); i != size; ++i) {
@ -845,7 +845,8 @@ FMT_FUNC void report_windows_error(
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) { FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
memory_buffer buffer; memory_buffer buffer;
vformat_to(buffer, format_str, basic_format_args<buffer_context<char>::type>(args)); vformat_to(buffer, format_str,
basic_format_args<buffer_context<char>::type>(args));
std::fwrite(buffer.data(), 1, buffer.size(), f); std::fwrite(buffer.data(), 1, buffer.size(), f);
} }

View File

@ -922,8 +922,11 @@ inline unsigned count_digits(uint64_t n) {
} }
#endif #endif
template <typename Char>
inline size_t count_code_points(basic_string_view<Char> s) { return s.size(); }
// Counts the number of code points in a UTF-8 string. // Counts the number of code points in a UTF-8 string.
FMT_API size_t count_code_points(u8string_view s); FMT_API size_t count_code_points(basic_string_view<char8_t> s);
inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); } inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }
@ -1456,6 +1459,9 @@ class arg_formatter_base {
struct char_writer { struct char_writer {
char_type value; char_type value;
size_t size() const { return 1; }
template <typename It> template <typename It>
void operator()(It &&it) const { *it++ = value; } void operator()(It &&it) const { *it++ = value; }
}; };
@ -2457,11 +2463,14 @@ class basic_writer {
template <typename F> template <typename F>
struct padded_int_writer { struct padded_int_writer {
size_t size_;
string_view prefix; string_view prefix;
char_type fill; char_type fill;
std::size_t padding; std::size_t padding;
F f; F f;
size_t size() const { return size_; }
template <typename It> template <typename It>
void operator()(It &&it) const { void operator()(It &&it) const {
if (prefix.size() != 0) if (prefix.size() != 0)
@ -2493,7 +2502,7 @@ class basic_writer {
align_spec as = spec; align_spec as = spec;
if (spec.align() == ALIGN_DEFAULT) if (spec.align() == ALIGN_DEFAULT)
as.align_ = ALIGN_RIGHT; as.align_ = ALIGN_RIGHT;
write_padded(size, as, padded_int_writer<F>{prefix, fill, padding, f}); write_padded(size, as, padded_int_writer<F>{size, prefix, fill, padding, f});
} }
// Writes a decimal integer. // Writes a decimal integer.
@ -2659,6 +2668,8 @@ class basic_writer {
char sign; char sign;
const char *str; const char *str;
size_t size() const { return static_cast<std::size_t>(INF_SIZE); }
template <typename It> template <typename It>
void operator()(It &&it) const { void operator()(It &&it) const {
if (sign) if (sign)
@ -2673,6 +2684,8 @@ class basic_writer {
char sign; char sign;
internal::buffer &buffer; internal::buffer &buffer;
size_t size() const { return buffer.size() + (sign ? 1 : 0); }
template <typename It> template <typename It>
void operator()(It &&it) { void operator()(It &&it) {
if (sign) { if (sign) {
@ -2693,11 +2706,15 @@ class basic_writer {
template <typename Char> template <typename Char>
struct str_writer { struct str_writer {
const Char *s; const Char *s;
std::size_t size; size_t size_;
size_t size() const {
return internal::count_code_points(basic_string_view<Char>(s, size_));
}
template <typename It> template <typename It>
void operator()(It &&it) const { void operator()(It &&it) const {
it = internal::copy_str<char_type>(s, s + size, it); it = internal::copy_str<char_type>(s, s + size_, it);
} }
}; };
@ -2796,11 +2813,12 @@ template <typename F>
void basic_writer<Range>::write_padded( void basic_writer<Range>::write_padded(
std::size_t size, const align_spec &spec, F &&f) { std::size_t size, const align_spec &spec, F &&f) {
unsigned width = spec.width(); unsigned width = spec.width();
if (width <= size) size_t num_code_points = width != 0 ? f.size() : size;
if (width <= num_code_points)
return f(reserve(size)); return f(reserve(size));
auto &&it = reserve(width); auto &&it = reserve(width + (size - num_code_points));
char_type fill = static_cast<char_type>(spec.fill()); char_type fill = static_cast<char_type>(spec.fill());
std::size_t padding = width - size; std::size_t padding = width - num_code_points;
if (spec.align() == ALIGN_RIGHT) { if (spec.align() == ALIGN_RIGHT) {
it = std::fill_n(it, padding, fill); it = std::fill_n(it, padding, fill);
f(it); f(it);
@ -3533,12 +3551,14 @@ using format_to_n_context = typename fmt::format_context_t<
fmt::internal::truncating_iterator<OutputIt>, Char>::type; fmt::internal::truncating_iterator<OutputIt>, Char>::type;
template <typename OutputIt, typename Char = typename OutputIt::value_type> template <typename OutputIt, typename Char = typename OutputIt::value_type>
using format_to_n_args = fmt::basic_format_args<format_to_n_context<OutputIt, Char>>; using format_to_n_args =
fmt::basic_format_args<format_to_n_context<OutputIt, Char>>;
template <typename OutputIt, typename Char, typename ...Args> template <typename OutputIt, typename Char, typename ...Args>
inline format_arg_store<format_to_n_context<OutputIt, Char>, Args...> inline format_arg_store<format_to_n_context<OutputIt, Char>, Args...>
make_format_to_n_args(const Args &... args) { make_format_to_n_args(const Args &... args) {
return format_arg_store<format_to_n_context<OutputIt, Char>, Args...>(args...); return format_arg_store<
format_to_n_context<OutputIt, Char>, Args...>(args...);
} }
template <typename OutputIt, typename Char, typename... Args> template <typename OutputIt, typename Char, typename... Args>
@ -3561,7 +3581,8 @@ template <typename OutputIt, typename String, typename... Args>
inline typename std::enable_if< inline typename std::enable_if<
internal::is_format_string<String>::value, internal::is_format_string<String>::value,
format_to_n_result<OutputIt>>::type format_to_n( format_to_n_result<OutputIt>>::type format_to_n(
OutputIt out, std::size_t n, const String &format_str, const Args &... args) { OutputIt out, std::size_t n, const String &format_str,
const Args &... args) {
internal::check_format_string<Args...>(format_str); internal::check_format_string<Args...>(format_str);
typedef FMT_CHAR(String) Char; typedef FMT_CHAR(String) Char;
format_arg_store<format_to_n_context<OutputIt, Char>, Args...> as{ args... }; format_arg_store<format_to_n_context<OutputIt, Char>, Args...> as{ args... };

View File

@ -2448,6 +2448,7 @@ TEST(FormatTest, U8StringViewLiteral) {
const fmt::char8_t *data = s.data(); const fmt::char8_t *data = s.data();
EXPECT_EQ(data[0], 'a'); EXPECT_EQ(data[0], 'a');
EXPECT_EQ(data[1], 'b'); EXPECT_EQ(data[1], 'b');
EXPECT_EQ(format("{:*^5}"_u, "🤡"_u), "**🤡**"_u);
} }
#endif #endif