@@ -213,17 +213,32 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
213213 const wchar_t *format, unsigned width, int precision, T value);
214214};
215215
216+ // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
217+ template <bool FitsIn32Bits>
218+ struct TypeSelector { typedef uint32_t Type; };
219+
220+ template <>
221+ struct TypeSelector <false > { typedef uint64_t Type; };
222+
223+ template <typename T>
224+ struct IntTraitsBase {
225+ // Smallest of uint32_t and uint64_t that is large enough to represent
226+ // all values of T.
227+ typedef typename
228+ TypeSelector<std::numeric_limits<T>::digits <= 32 >::Type MainType;
229+ };
230+
216231// Information about an integer type.
217232// IntTraits is not specialized for integer types smaller than int,
218233// since these are promoted to int.
219234template <typename T>
220- struct IntTraits {
235+ struct IntTraits : IntTraitsBase<T> {
221236 typedef T UnsignedType;
222237 static bool IsNegative (T) { return false ; }
223238};
224239
225240template <typename T, typename UnsignedT>
226- struct SignedIntTraits {
241+ struct SignedIntTraits : IntTraitsBase<T> {
227242 typedef UnsignedT UnsignedType;
228243 static bool IsNegative (T value) { return value < 0 ; }
229244};
@@ -245,17 +260,28 @@ struct IsLongDouble<long double> { enum {VALUE = 1}; };
245260
246261void ReportUnknownType (char code, const char *type);
247262
248- extern const uint64_t POWERS_OF_10[];
263+ extern const uint32_t POWERS_OF_10_32[];
264+ extern const uint64_t POWERS_OF_10_64[];
249265
266+ #if FMT_GCC_VERSION >= 400 || __has_builtin(__builtin_clzll)
250267// Returns the number of decimal digits in n. Leading zeros are not counted
251268// except for n == 0 in which case CountDigits returns 1.
252269inline unsigned CountDigits (uint64_t n) {
253- #if FMT_GCC_VERSION >= 400 || __has_builtin(__builtin_clzll)
254270 // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
255271 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
256272 uint64_t t = (64 - __builtin_clzll (n | 1 )) * 1233 >> 12 ;
257- return t - (n < POWERS_OF_10[t]) + 1 ;
273+ return t - (n < POWERS_OF_10_64[t]) + 1 ;
274+ }
275+ # if FMT_GCC_VERSION >= 400 || __has_builtin(__builtin_clz)
276+ // Optional version of CountDigits for better performance on 32-bit platforms.
277+ inline unsigned CountDigits (uint32_t n) {
278+ uint32_t t = (32 - __builtin_clz (n | 1 )) * 1233 >> 12 ;
279+ return t - (n < POWERS_OF_10_32[t]) + 1 ;
280+ }
281+ # endif
258282#else
283+ // Slower version of CountDigits used when __builtin_clz is not available.
284+ inline unsigned CountDigits (uint64_t n) {
259285 unsigned count = 1 ;
260286 for (;;) {
261287 // Integer division is slow so do it for a group of four digits instead
@@ -268,8 +294,8 @@ inline unsigned CountDigits(uint64_t n) {
268294 n /= 10000u ;
269295 count += 4 ;
270296 }
271- #endif
272297}
298+ #endif
273299
274300extern const char DIGITS[];
275301
@@ -838,7 +864,7 @@ template <typename T, typename Spec>
838864void BasicWriter<Char>::FormatInt(T value, const Spec &spec) {
839865 unsigned size = 0 ;
840866 char sign = 0 ;
841- typedef typename internal::IntTraits<T>::UnsignedType UnsignedType;
867+ typedef typename internal::IntTraits<T>::MainType UnsignedType;
842868 UnsignedType abs_value = value;
843869 if (internal::IntTraits<T>::IsNegative (value)) {
844870 sign = ' -' ;
@@ -850,7 +876,8 @@ void BasicWriter<Char>::FormatInt(T value, const Spec &spec) {
850876 }
851877 switch (spec.type ()) {
852878 case 0 : case ' d' : {
853- unsigned num_digits = internal::CountDigits (abs_value);
879+ typename internal::IntTraits<T>::MainType normalized_value = abs_value;
880+ unsigned num_digits = internal::CountDigits (normalized_value);
854881 CharPtr p =
855882 PrepareFilledBuffer (size + num_digits, spec, sign) + 1 - num_digits;
856883 internal::FormatDecimal (GetBase (p), abs_value, num_digits);
@@ -1380,7 +1407,7 @@ class FormatInt {
13801407// write a terminating null character.
13811408template <typename T>
13821409inline void FormatDec (char *&buffer, T value) {
1383- typedef typename internal::IntTraits<T>::UnsignedType UnsignedType;
1410+ typedef typename internal::IntTraits<T>::MainType UnsignedType;
13841411 UnsignedType abs_value = value;
13851412 if (internal::IntTraits<T>::IsNegative (value)) {
13861413 *buffer++ = ' -' ;
0 commit comments