mirror of
https://github.com/fmtlib/fmt.git
synced 2025-01-16 01:20:06 +00:00
Add a 32-bit version of CountDigits.
This commit is contained in:
parent
3017fc6fb7
commit
e9b2191689
@ -170,6 +170,24 @@ TEST(UtilTest, Increment) {
|
|||||||
EXPECT_STREQ("200", s);
|
EXPECT_STREQ("200", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests fmt::internal::CountDigits for integer type Int.
|
||||||
|
template <typename Int>
|
||||||
|
void TestCountDigits(Int) {
|
||||||
|
for (Int i = 0; i < 10; ++i)
|
||||||
|
EXPECT_EQ(1, fmt::internal::CountDigits(i));
|
||||||
|
for (Int i = 1, n = 1,
|
||||||
|
end = std::numeric_limits<Int>::max() / 10; n <= end; ++i) {
|
||||||
|
n *= 10;
|
||||||
|
EXPECT_EQ(i, fmt::internal::CountDigits(n - 1));
|
||||||
|
EXPECT_EQ(i + 1, fmt::internal::CountDigits(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UtilTest, CountDigits) {
|
||||||
|
TestCountDigits(uint32_t());
|
||||||
|
TestCountDigits(uint64_t());
|
||||||
|
}
|
||||||
|
|
||||||
class TestString {
|
class TestString {
|
||||||
private:
|
private:
|
||||||
std::string value_;
|
std::string value_;
|
||||||
@ -1427,18 +1445,21 @@ TEST(FormatIntTest, FormatInt) {
|
|||||||
EXPECT_EQ(os.str(), fmt::FormatInt(std::numeric_limits<int64_t>::max()).str());
|
EXPECT_EQ(os.str(), fmt::FormatInt(std::numeric_limits<int64_t>::max()).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatIntTest, FormatDec) {
|
template <typename T>
|
||||||
|
std::string FormatDec(T value) {
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
char *ptr = buffer;
|
char *ptr = buffer;
|
||||||
fmt::FormatDec(ptr, 42);
|
fmt::FormatDec(ptr, value);
|
||||||
EXPECT_EQ(buffer + 2, ptr);
|
return std::string(buffer, ptr);
|
||||||
*ptr = '\0';
|
}
|
||||||
EXPECT_STREQ("42", buffer);
|
|
||||||
ptr = buffer;
|
TEST(FormatIntTest, FormatDec) {
|
||||||
fmt::FormatDec(ptr, -42);
|
EXPECT_EQ("42", FormatDec(42));
|
||||||
*ptr = '\0';
|
EXPECT_EQ("-42", FormatDec(-42));
|
||||||
EXPECT_EQ(buffer + 3, ptr);
|
EXPECT_EQ("42", FormatDec(42l));
|
||||||
EXPECT_STREQ("-42", buffer);
|
EXPECT_EQ("42", FormatDec(42ul));
|
||||||
|
EXPECT_EQ("42", FormatDec(42ll));
|
||||||
|
EXPECT_EQ("42", FormatDec(42ull));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
36
format.cc
36
format.cc
@ -118,27 +118,23 @@ const char fmt::internal::DIGITS[] =
|
|||||||
"4041424344454647484950515253545556575859"
|
"4041424344454647484950515253545556575859"
|
||||||
"6061626364656667686970717273747576777879"
|
"6061626364656667686970717273747576777879"
|
||||||
"8081828384858687888990919293949596979899";
|
"8081828384858687888990919293949596979899";
|
||||||
|
|
||||||
const uint64_t fmt::internal::POWERS_OF_10[] = {
|
#define FMT_POWERS_OF_10(prefix) \
|
||||||
|
prefix 10, \
|
||||||
|
prefix 100, \
|
||||||
|
prefix 1000, \
|
||||||
|
prefix 10000, \
|
||||||
|
prefix 100000, \
|
||||||
|
prefix 1000000, \
|
||||||
|
prefix 10000000, \
|
||||||
|
prefix 100000000, \
|
||||||
|
prefix 1000000000
|
||||||
|
|
||||||
|
const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10()};
|
||||||
|
const uint64_t fmt::internal::POWERS_OF_10_64[] = {
|
||||||
0,
|
0,
|
||||||
10,
|
FMT_POWERS_OF_10(),
|
||||||
100,
|
FMT_POWERS_OF_10(ULongLong(1000000000) *),
|
||||||
1000,
|
|
||||||
10000,
|
|
||||||
100000,
|
|
||||||
1000000,
|
|
||||||
10000000,
|
|
||||||
100000000,
|
|
||||||
1000000000,
|
|
||||||
ULongLong(1000000000) * 10,
|
|
||||||
ULongLong(1000000000) * 100,
|
|
||||||
ULongLong(1000000000) * 1000,
|
|
||||||
ULongLong(1000000000) * 10000,
|
|
||||||
ULongLong(1000000000) * 100000,
|
|
||||||
ULongLong(1000000000) * 1000000,
|
|
||||||
ULongLong(1000000000) * 10000000,
|
|
||||||
ULongLong(1000000000) * 100000000,
|
|
||||||
ULongLong(1000000000) * 1000000000,
|
|
||||||
ULongLong(1000000000) * ULongLong(1000000000) * 10
|
ULongLong(1000000000) * ULongLong(1000000000) * 10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
45
format.h
45
format.h
@ -213,17 +213,32 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
|
|||||||
const wchar_t *format, unsigned width, int precision, T value);
|
const wchar_t *format, unsigned width, int precision, T value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
|
||||||
|
template <bool FitsIn32Bits>
|
||||||
|
struct TypeSelector { typedef uint32_t Type; };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct TypeSelector<false> { typedef uint64_t Type; };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IntTraitsBase {
|
||||||
|
// Smallest of uint32_t and uint64_t that is large enough to represent
|
||||||
|
// all values of T.
|
||||||
|
typedef typename
|
||||||
|
TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;
|
||||||
|
};
|
||||||
|
|
||||||
// Information about an integer type.
|
// Information about an integer type.
|
||||||
// IntTraits is not specialized for integer types smaller than int,
|
// IntTraits is not specialized for integer types smaller than int,
|
||||||
// since these are promoted to int.
|
// since these are promoted to int.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IntTraits {
|
struct IntTraits : IntTraitsBase<T> {
|
||||||
typedef T UnsignedType;
|
typedef T UnsignedType;
|
||||||
static bool IsNegative(T) { return false; }
|
static bool IsNegative(T) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename UnsignedT>
|
template <typename T, typename UnsignedT>
|
||||||
struct SignedIntTraits {
|
struct SignedIntTraits : IntTraitsBase<T> {
|
||||||
typedef UnsignedT UnsignedType;
|
typedef UnsignedT UnsignedType;
|
||||||
static bool IsNegative(T value) { return value < 0; }
|
static bool IsNegative(T value) { return value < 0; }
|
||||||
};
|
};
|
||||||
@ -245,17 +260,28 @@ struct IsLongDouble<long double> { enum {VALUE = 1}; };
|
|||||||
|
|
||||||
void ReportUnknownType(char code, const char *type);
|
void ReportUnknownType(char code, const char *type);
|
||||||
|
|
||||||
extern const uint64_t POWERS_OF_10[];
|
extern const uint32_t POWERS_OF_10_32[];
|
||||||
|
extern const uint64_t POWERS_OF_10_64[];
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION >= 400 || __has_builtin(__builtin_clzll)
|
||||||
// Returns the number of decimal digits in n. Leading zeros are not counted
|
// Returns the number of decimal digits in n. Leading zeros are not counted
|
||||||
// except for n == 0 in which case CountDigits returns 1.
|
// except for n == 0 in which case CountDigits returns 1.
|
||||||
inline unsigned CountDigits(uint64_t n) {
|
inline unsigned CountDigits(uint64_t n) {
|
||||||
#if FMT_GCC_VERSION >= 400 || __has_builtin(__builtin_clzll)
|
|
||||||
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
|
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
|
||||||
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
|
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
|
||||||
uint64_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12;
|
uint64_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12;
|
||||||
return t - (n < POWERS_OF_10[t]) + 1;
|
return t - (n < POWERS_OF_10_64[t]) + 1;
|
||||||
|
}
|
||||||
|
# if FMT_GCC_VERSION >= 400 || __has_builtin(__builtin_clz)
|
||||||
|
// Optional version of CountDigits for better performance on 32-bit platforms.
|
||||||
|
inline unsigned CountDigits(uint32_t n) {
|
||||||
|
uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12;
|
||||||
|
return t - (n < POWERS_OF_10_32[t]) + 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
|
// Slower version of CountDigits used when __builtin_clz is not available.
|
||||||
|
inline unsigned CountDigits(uint64_t n) {
|
||||||
unsigned count = 1;
|
unsigned count = 1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Integer division is slow so do it for a group of four digits instead
|
// Integer division is slow so do it for a group of four digits instead
|
||||||
@ -268,8 +294,8 @@ inline unsigned CountDigits(uint64_t n) {
|
|||||||
n /= 10000u;
|
n /= 10000u;
|
||||||
count += 4;
|
count += 4;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
extern const char DIGITS[];
|
extern const char DIGITS[];
|
||||||
|
|
||||||
@ -838,7 +864,7 @@ template <typename T, typename Spec>
|
|||||||
void BasicWriter<Char>::FormatInt(T value, const Spec &spec) {
|
void BasicWriter<Char>::FormatInt(T value, const Spec &spec) {
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
char sign = 0;
|
char sign = 0;
|
||||||
typedef typename internal::IntTraits<T>::UnsignedType UnsignedType;
|
typedef typename internal::IntTraits<T>::MainType UnsignedType;
|
||||||
UnsignedType abs_value = value;
|
UnsignedType abs_value = value;
|
||||||
if (internal::IntTraits<T>::IsNegative(value)) {
|
if (internal::IntTraits<T>::IsNegative(value)) {
|
||||||
sign = '-';
|
sign = '-';
|
||||||
@ -850,7 +876,8 @@ void BasicWriter<Char>::FormatInt(T value, const Spec &spec) {
|
|||||||
}
|
}
|
||||||
switch (spec.type()) {
|
switch (spec.type()) {
|
||||||
case 0: case 'd': {
|
case 0: case 'd': {
|
||||||
unsigned num_digits = internal::CountDigits(abs_value);
|
typename internal::IntTraits<T>::MainType normalized_value = abs_value;
|
||||||
|
unsigned num_digits = internal::CountDigits(normalized_value);
|
||||||
CharPtr p =
|
CharPtr p =
|
||||||
PrepareFilledBuffer(size + num_digits, spec, sign) + 1 - num_digits;
|
PrepareFilledBuffer(size + num_digits, spec, sign) + 1 - num_digits;
|
||||||
internal::FormatDecimal(GetBase(p), abs_value, num_digits);
|
internal::FormatDecimal(GetBase(p), abs_value, num_digits);
|
||||||
@ -1380,7 +1407,7 @@ class FormatInt {
|
|||||||
// write a terminating null character.
|
// write a terminating null character.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void FormatDec(char *&buffer, T value) {
|
inline void FormatDec(char *&buffer, T value) {
|
||||||
typedef typename internal::IntTraits<T>::UnsignedType UnsignedType;
|
typedef typename internal::IntTraits<T>::MainType UnsignedType;
|
||||||
UnsignedType abs_value = value;
|
UnsignedType abs_value = value;
|
||||||
if (internal::IntTraits<T>::IsNegative(value)) {
|
if (internal::IntTraits<T>::IsNegative(value)) {
|
||||||
*buffer++ = '-';
|
*buffer++ = '-';
|
||||||
|
Loading…
Reference in New Issue
Block a user