Add FormatInt for fast stand-alone integer formatting.
This commit is contained in:
parent
75daf81895
commit
65d47e5e09
12
format.cc
12
format.cc
@ -108,14 +108,14 @@ struct CharTraits<wchar_t> {
|
||||
swprintf(buffer, size, format, width, precision, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const char DIGITS[] =
|
||||
const char fmt::internal::DIGITS[] =
|
||||
"0001020304050607080910111213141516171819"
|
||||
"2021222324252627282930313233343536373839"
|
||||
"4041424344454647484950515253545556575859"
|
||||
"6061626364656667686970717273747576777879"
|
||||
"8081828384858687888990919293949596979899";
|
||||
}
|
||||
|
||||
void fmt::internal::ReportUnknownType(char code, const char *type) {
|
||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||
@ -154,8 +154,8 @@ void fmt::BasicWriter<Char>::FormatDecimal(
|
||||
// "Three Optimization Tips for C++". See speed-test for a comparison.
|
||||
unsigned index = (value % 100) * 2;
|
||||
value /= 100;
|
||||
buffer[num_digits] = DIGITS[index + 1];
|
||||
buffer[num_digits - 1] = DIGITS[index];
|
||||
buffer[num_digits] = internal::DIGITS[index + 1];
|
||||
buffer[num_digits - 1] = internal::DIGITS[index];
|
||||
num_digits -= 2;
|
||||
}
|
||||
if (value < 10) {
|
||||
@ -163,8 +163,8 @@ void fmt::BasicWriter<Char>::FormatDecimal(
|
||||
return;
|
||||
}
|
||||
unsigned index = static_cast<unsigned>(value * 2);
|
||||
buffer[1] = DIGITS[index + 1];
|
||||
buffer[0] = DIGITS[index];
|
||||
buffer[1] = internal::DIGITS[index + 1];
|
||||
buffer[0] = internal::DIGITS[index];
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
|
52
format.h
52
format.h
@ -188,6 +188,8 @@ inline unsigned CountDigits(uint64_t n) {
|
||||
}
|
||||
}
|
||||
|
||||
extern const char DIGITS[];
|
||||
|
||||
template <typename Char>
|
||||
class FormatterProxy;
|
||||
}
|
||||
@ -1055,6 +1057,56 @@ class Formatter : private Action, public BasicFormatter<Char> {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Fast integer formatter.
|
||||
*/
|
||||
class FormatInt {
|
||||
private:
|
||||
// Buffer should be large enough to hold all digits (digits10 + 1),
|
||||
// a sign and a null character.
|
||||
enum {BUFFER_SIZE = std::numeric_limits<uint64_t>::digits10 + 3};
|
||||
char buffer_[BUFFER_SIZE];
|
||||
char *str_;
|
||||
|
||||
// Formats value in reverse and returns the number of digits.
|
||||
char *FormatDecimal(uint64_t value) {
|
||||
char *buffer_end = buffer_ + BUFFER_SIZE;
|
||||
*--buffer_end = '\0';
|
||||
while (value >= 100) {
|
||||
// Integer division is slow so do it for a group of two digits instead
|
||||
// of for every digit. The idea comes from the talk by Alexandrescu
|
||||
// "Three Optimization Tips for C++". See speed-test for a comparison.
|
||||
unsigned index = (value % 100) * 2;
|
||||
value /= 100;
|
||||
*--buffer_end = internal::DIGITS[index + 1];
|
||||
*--buffer_end = internal::DIGITS[index];
|
||||
}
|
||||
if (value < 10) {
|
||||
*--buffer_end = static_cast<char>('0' + value);
|
||||
return buffer_end;
|
||||
}
|
||||
unsigned index = static_cast<unsigned>(value * 2);
|
||||
*--buffer_end = internal::DIGITS[index + 1];
|
||||
*--buffer_end = internal::DIGITS[index];
|
||||
return buffer_end;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit FormatInt(int value) {
|
||||
uint64_t abs_value = value;
|
||||
bool negative = value < 0;
|
||||
if (negative)
|
||||
abs_value = 0 - value;
|
||||
str_ = FormatDecimal(abs_value);
|
||||
if (negative)
|
||||
*--str_ = '-';
|
||||
}
|
||||
explicit FormatInt(unsigned value) : str_(FormatDecimal(value)) {}
|
||||
|
||||
const char *c_str() const { return str_; }
|
||||
std::string str() const { return str_; }
|
||||
};
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats a string similarly to Python's `str.format
|
||||
|
Loading…
Reference in New Issue
Block a user