Improve width computation

This commit is contained in:
Victor Zverovich 2020-03-04 16:43:49 -08:00
parent 0c6919ec72
commit eafd079868
2 changed files with 49 additions and 4 deletions

View File

@ -473,8 +473,8 @@ inline size_t count_code_points(basic_string_view<Char> s) {
} }
// Counts the number of code points in a UTF-8 string. // Counts the number of code points in a UTF-8 string.
inline size_t count_code_points(basic_string_view<char8_t> s) { inline size_t count_code_points(basic_string_view<char> s) {
const char8_t* data = s.data(); const char* 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) {
if ((data[i] & 0xc0) != 0x80) ++num_code_points; if ((data[i] & 0xc0) != 0x80) ++num_code_points;
@ -482,6 +482,11 @@ inline size_t count_code_points(basic_string_view<char8_t> s) {
return num_code_points; return num_code_points;
} }
inline size_t count_code_points(basic_string_view<char8_t> s) {
return count_code_points(basic_string_view<char>(
reinterpret_cast<const char*>(s.data()), s.size()));
}
template <typename Char> template <typename Char>
inline size_t code_point_index(basic_string_view<Char> s, size_t n) { inline size_t code_point_index(basic_string_view<Char> s, size_t n) {
size_t size = s.size(); size_t size = s.size();
@ -1603,6 +1608,18 @@ template <typename Range> class basic_writer {
} }
}; };
struct bytes_writer {
string_view bytes;
size_t size() const { return bytes.size(); }
size_t width() const { return bytes.size(); }
template <typename It> void operator()(It&& it) const {
const char* data = bytes.data();
it = copy_str<char>(data, data + size(), it);
}
};
template <typename UIntPtr> struct pointer_writer { template <typename UIntPtr> struct pointer_writer {
UIntPtr value; UIntPtr value;
int num_digits; int num_digits;
@ -1761,6 +1778,10 @@ template <typename Range> class basic_writer {
write(data, size, specs); write(data, size, specs);
} }
void write_bytes(string_view bytes, const format_specs& specs) {
write_padded(specs, bytes_writer{bytes});
}
template <typename UIntPtr> template <typename UIntPtr>
void write_pointer(UIntPtr value, const format_specs* specs) { void write_pointer(UIntPtr value, const format_specs* specs) {
int num_digits = count_digits<4>(value); int num_digits = count_digits<4>(value);
@ -3150,11 +3171,32 @@ class bytes {
explicit bytes(string_view data) : data_(data) {} explicit bytes(string_view data) : data_(data) {}
}; };
template <> struct formatter<bytes> : formatter<string_view> { template <> struct formatter<bytes> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
using handler_type = internal::dynamic_specs_handler<ParseContext>;
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
internal::type::string_type);
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
internal::check_string_type_spec(specs_.type, ctx.error_handler());
return it;
}
template <typename FormatContext> template <typename FormatContext>
auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) { auto format(bytes b, FormatContext& ctx) -> decltype(ctx.out()) {
return formatter<string_view>::format(b.data_, ctx); internal::handle_dynamic_spec<internal::width_checker>(
specs_.width, specs_.width_ref, ctx);
internal::handle_dynamic_spec<internal::precision_checker>(
specs_.precision, specs_.precision_ref, ctx);
using range_type =
internal::output_range<typename FormatContext::iterator, char>;
internal::basic_writer<range_type> writer(range_type(ctx.out()));
writer.write_bytes(b.data_, specs_);
return writer.out();
} }
private:
internal::dynamic_format_specs<char> specs_;
}; };
template <typename It, typename Char> struct arg_join : internal::view { template <typename It, typename Char> struct arg_join : internal::view {

View File

@ -6,6 +6,7 @@
// For the license information refer to format.h. // For the license information refer to format.h.
#include <stdint.h> #include <stdint.h>
#include <cctype> #include <cctype>
#include <cfloat> #include <cfloat>
#include <climits> #include <climits>
@ -987,7 +988,9 @@ TEST(FormatterTest, Width) {
EXPECT_EQ(" 0xcafe", format("{0:10}", reinterpret_cast<void*>(0xcafe))); EXPECT_EQ(" 0xcafe", format("{0:10}", reinterpret_cast<void*>(0xcafe)));
EXPECT_EQ("x ", format("{0:11}", 'x')); EXPECT_EQ("x ", format("{0:11}", 'x'));
EXPECT_EQ("str ", format("{0:12}", "str")); EXPECT_EQ("str ", format("{0:12}", "str"));
EXPECT_EQ(fmt::format("{:*^5}", "🤡"), "**🤡**");
} }
template <typename T> inline T const_check(T value) { return value; } template <typename T> inline T const_check(T value) { return value; }
TEST(FormatterTest, RuntimeWidth) { TEST(FormatterTest, RuntimeWidth) {