mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-07 17:41:11 +00:00
Improve width computation
This commit is contained in:
parent
0c6919ec72
commit
eafd079868
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user