Optimize pointer formatting

This commit is contained in:
Victor Zverovich 2019-04-05 20:06:32 -07:00
parent bb6842ba35
commit 0302927f56

View File

@ -314,6 +314,8 @@ class numeric_limits<fmt::internal::uintptr_t>
static uintptr_t to_uint(const void* p) { static uintptr_t to_uint(const void* p) {
return fmt::internal::bit_cast<uintptr_t>(p); return fmt::internal::bit_cast<uintptr_t>(p);
} }
typedef uintptr_t uintptr_type;
}; };
} // namespace std } // namespace std
@ -780,6 +782,15 @@ inline int count_digits(uint64_t n) {
} }
#endif #endif
// Counts the number of digits in n. BITS = log2(radix).
template <unsigned BITS, typename UInt> inline int count_digits(UInt n) {
int num_digits = 0;
do {
++num_digits;
} while ((n >>= BITS) != 0);
return num_digits;
}
template <typename Char> template <typename Char>
inline size_t count_code_points(basic_string_view<Char> s) { inline size_t count_code_points(basic_string_view<Char> s) {
return s.size(); return s.size();
@ -1409,10 +1420,7 @@ template <typename Range> class arg_formatter_base {
} }
void write_pointer(const void* p) { void write_pointer(const void* p) {
format_specs specs = specs_ ? *specs_ : format_specs(); writer_.write(p, specs_);
specs.flags = HASH_FLAG;
specs.type = 'x';
writer_.write_int(internal::numutil::to_uint(p), specs);
} }
protected: protected:
@ -2486,16 +2494,6 @@ template <typename Range> class basic_writer {
string_view get_prefix() const { return string_view(prefix, prefix_size); } string_view get_prefix() const { return string_view(prefix, prefix_size); }
// Counts the number of digits in abs_value. BITS = log2(radix).
template <unsigned BITS> int count_digits() const {
unsigned_type n = abs_value;
int num_digits = 0;
do {
++num_digits;
} while ((n >>= BITS) != 0);
return num_digits;
}
int_writer(basic_writer<Range>& w, Int value, const Spec& s) int_writer(basic_writer<Range>& w, Int value, const Spec& s)
: writer(w), : writer(w),
spec(s), spec(s),
@ -2541,7 +2539,7 @@ template <typename Range> class basic_writer {
prefix[prefix_size++] = '0'; prefix[prefix_size++] = '0';
prefix[prefix_size++] = static_cast<char>(spec.type); prefix[prefix_size++] = static_cast<char>(spec.type);
} }
int num_digits = count_digits<4>(); int num_digits = internal::count_digits<4>(abs_value);
writer.write_int(num_digits, get_prefix(), spec, writer.write_int(num_digits, get_prefix(), spec,
hex_writer{*this, num_digits}); hex_writer{*this, num_digits});
} }
@ -2560,13 +2558,13 @@ template <typename Range> class basic_writer {
prefix[prefix_size++] = '0'; prefix[prefix_size++] = '0';
prefix[prefix_size++] = static_cast<char>(spec.type); prefix[prefix_size++] = static_cast<char>(spec.type);
} }
int num_digits = count_digits<1>(); int num_digits = internal::count_digits<1>(abs_value);
writer.write_int(num_digits, get_prefix(), spec, writer.write_int(num_digits, get_prefix(), spec,
bin_writer<1>{abs_value, num_digits}); bin_writer<1>{abs_value, num_digits});
} }
void on_oct() { void on_oct() {
int num_digits = count_digits<3>(); int num_digits = internal::count_digits<3>(abs_value);
if (spec.has(HASH_FLAG) && spec.precision <= num_digits) { if (spec.has(HASH_FLAG) && spec.precision <= num_digits) {
// Octal prefix '0' is counted as a digit, so only add it if precision // Octal prefix '0' is counted as a digit, so only add it if precision
// is not greater than the number of digits. // is not greater than the number of digits.
@ -2692,6 +2690,20 @@ template <typename Range> class basic_writer {
} }
}; };
struct pointer_writer {
internal::numutil::uintptr_type value;
int num_digits;
size_t size() const { return num_digits + 2; }
size_t width() const { return size(); }
template <typename It> void operator()(It&& it) const {
*it++ = static_cast<char_type>('0');
*it++ = static_cast<char_type>('x');
it = internal::format_uint<4, char_type>(it, value, num_digits, false);
}
};
template <typename Char> friend class internal::arg_formatter_base; template <typename Char> friend class internal::arg_formatter_base;
public: public:
@ -2780,11 +2792,14 @@ template <typename Range> class basic_writer {
} }
template <typename T, FMT_ENABLE_IF(std::is_same<T, void>::value)> template <typename T, FMT_ENABLE_IF(std::is_same<T, void>::value)>
void write(const T* p) { void write(const T* p, const align_spec* spec) {
format_specs specs; auto value = internal::numutil::to_uint(p);
specs.flags = HASH_FLAG; int num_digits = internal::count_digits<4>(value);
specs.type = 'x'; auto pw = pointer_writer{value, num_digits};
write_int(internal::numutil::to_uint(p), specs); if (!spec) return pw(reserve(num_digits + 2));
align_spec as = *spec;
if (as.align() == ALIGN_DEFAULT) as.align_ = ALIGN_RIGHT;
write_padded(as, pw);
} }
}; };