Skip to content

Commit

Permalink
Count width in code points (#628)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Oct 4, 2018
1 parent deb901b commit 6db47ed
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 16 deletions.
9 changes: 5 additions & 4 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1342,10 +1342,11 @@ struct is_contiguous<internal::basic_buffer<Char> >: std::true_type {};
/** Formats a string and writes the output to ``out``. */
template <typename Container, typename S>
typename std::enable_if<
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
vformat_to(std::back_insert_iterator<Container> out,
const S &format_str,
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
vformat_to(
std::back_insert_iterator<Container> out,
const S &format_str,
basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) {
internal::container_buffer<Container> buf(internal::get_container(out));
vformat_to(buf, internal::to_string_view(format_str), args);
return out;
Expand Down
5 changes: 3 additions & 2 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ void report_error(FormatFunc func, int error_code,
}
} // 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();
size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) {
Expand Down Expand Up @@ -845,7 +845,8 @@ FMT_FUNC void report_windows_error(

FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
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);
}

Expand Down
41 changes: 31 additions & 10 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -922,8 +922,11 @@ inline unsigned count_digits(uint64_t n) {
}
#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.
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); }

Expand Down Expand Up @@ -1456,6 +1459,9 @@ class arg_formatter_base {

struct char_writer {
char_type value;

size_t size() const { return 1; }

template <typename It>
void operator()(It &&it) const { *it++ = value; }
};
Expand Down Expand Up @@ -2457,11 +2463,14 @@ class basic_writer {

template <typename F>
struct padded_int_writer {
size_t size_;
string_view prefix;
char_type fill;
std::size_t padding;
F f;

size_t size() const { return size_; }

template <typename It>
void operator()(It &&it) const {
if (prefix.size() != 0)
Expand Down Expand Up @@ -2493,7 +2502,7 @@ class basic_writer {
align_spec as = spec;
if (spec.align() == ALIGN_DEFAULT)
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.
Expand Down Expand Up @@ -2659,6 +2668,8 @@ class basic_writer {
char sign;
const char *str;

size_t size() const { return static_cast<std::size_t>(INF_SIZE); }

template <typename It>
void operator()(It &&it) const {
if (sign)
Expand All @@ -2673,6 +2684,8 @@ class basic_writer {
char sign;
internal::buffer &buffer;

size_t size() const { return buffer.size() + (sign ? 1 : 0); }

template <typename It>
void operator()(It &&it) {
if (sign) {
Expand All @@ -2693,11 +2706,15 @@ class basic_writer {
template <typename Char>
struct str_writer {
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>
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);
}
};

Expand Down Expand Up @@ -2796,11 +2813,12 @@ template <typename F>
void basic_writer<Range>::write_padded(
std::size_t size, const align_spec &spec, F &&f) {
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));
auto &&it = reserve(width);
auto &&it = reserve(width + (size - num_code_points));
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) {
it = std::fill_n(it, padding, fill);
f(it);
Expand Down Expand Up @@ -3533,12 +3551,14 @@ using format_to_n_context = typename fmt::format_context_t<
fmt::internal::truncating_iterator<OutputIt>, Char>::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>
inline format_arg_store<format_to_n_context<OutputIt, Char>, 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>
Expand All @@ -3561,7 +3581,8 @@ template <typename OutputIt, typename String, typename... Args>
inline typename std::enable_if<
internal::is_format_string<String>::value,
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);
typedef FMT_CHAR(String) Char;
format_arg_store<format_to_n_context<OutputIt, Char>, Args...> as{ args... };
Expand Down
1 change: 1 addition & 0 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2448,6 +2448,7 @@ TEST(FormatTest, U8StringViewLiteral) {
const fmt::char8_t *data = s.data();
EXPECT_EQ(data[0], 'a');
EXPECT_EQ(data[1], 'b');
EXPECT_EQ(format("{:*^5}"_u, "🤡"_u), "**🤡**"_u);
}
#endif

Expand Down

0 comments on commit 6db47ed

Please sign in to comment.