|
|
@@ -105,78 +105,283 @@ rspamd_humanize_number (gchar *buf, gchar *last, gint64 num, gboolean bytes) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline unsigned |
|
|
|
rspamd_decimal_digits32 (guint32 val) |
|
|
|
{ |
|
|
|
static const guint32 powers_of_10[] = { |
|
|
|
0, |
|
|
|
10, |
|
|
|
100, |
|
|
|
1000, |
|
|
|
10000, |
|
|
|
100000, |
|
|
|
1000000, |
|
|
|
10000000, |
|
|
|
100000000, |
|
|
|
1000000000 |
|
|
|
}; |
|
|
|
unsigned tmp; |
|
|
|
|
|
|
|
#if defined(_MSC_VER) |
|
|
|
unsigned long r = 0; |
|
|
|
_BitScanReverse (&r, val | 1); |
|
|
|
tmp = (r + 1) * 1233 >> 12; |
|
|
|
#elif defined(__GNUC__) && (__GNUC__ >= 30) |
|
|
|
tmp = (32 - __builtin_clz (val | 1U)) * 1233 >> 12; |
|
|
|
|
|
|
|
#else /* Software version */ |
|
|
|
static const unsigned debruijn_tbl[32] = { 0, 9, 1, 10, 13, 21, 2, 29, |
|
|
|
11, 14, 16, 18, 22, 25, 3, 30, |
|
|
|
8, 12, 20, 28, 15, 17, 24, 7, |
|
|
|
19, 27, 23, 6, 26, 5, 4, 31 }; |
|
|
|
guint32 v = val | 1; |
|
|
|
|
|
|
|
v |= v >> 1; |
|
|
|
v |= v >> 2; |
|
|
|
v |= v >> 4; |
|
|
|
v |= v >> 8; |
|
|
|
v |= v >> 16; |
|
|
|
tmp = (1 + debruijn_tbl[(v * 0x07C4ACDDU) >> 27]) * 1233 >> 12; |
|
|
|
#endif |
|
|
|
return tmp - (val < powers_of_10[tmp]) + 1; |
|
|
|
} |
|
|
|
|
|
|
|
static inline unsigned |
|
|
|
rspamd_decimal_digits64 (guint64 val) |
|
|
|
{ |
|
|
|
static const guint64 powers_of_10[] = { |
|
|
|
0, |
|
|
|
10ULL, |
|
|
|
100ULL, |
|
|
|
1000ULL, |
|
|
|
10000ULL, |
|
|
|
100000ULL, |
|
|
|
1000000ULL, |
|
|
|
10000000ULL, |
|
|
|
100000000ULL, |
|
|
|
1000000000ULL, |
|
|
|
10000000000ULL, |
|
|
|
100000000000ULL, |
|
|
|
1000000000000ULL, |
|
|
|
10000000000000ULL, |
|
|
|
100000000000000ULL, |
|
|
|
1000000000000000ULL, |
|
|
|
10000000000000000ULL, |
|
|
|
100000000000000000ULL, |
|
|
|
1000000000000000000ULL, |
|
|
|
10000000000000000000ULL |
|
|
|
}; |
|
|
|
unsigned tmp; |
|
|
|
|
|
|
|
#if defined(_MSC_VER) |
|
|
|
#if _M_IX86 |
|
|
|
unsigned long r = 0; |
|
|
|
guint64 m = val | 1; |
|
|
|
if (_BitScanReverse (&r, m >> 32)) { |
|
|
|
r += 32; |
|
|
|
} |
|
|
|
else { |
|
|
|
_BitScanReverse (&r, m & 0xFFFFFFFF); |
|
|
|
} |
|
|
|
tmp = (r + 1) * 1233 >> 12; |
|
|
|
#else |
|
|
|
unsigned long r = 0; |
|
|
|
_BitScanReverse64 (&r, val | 1); |
|
|
|
tmp = (r + 1) * 1233 >> 12; |
|
|
|
#endif |
|
|
|
#elif defined(__GNUC__) && (__GNUC__ >= 30) |
|
|
|
tmp = (64 - __builtin_clzll (val | 1ULL)) * 1233 >> 12; |
|
|
|
#else /* Software version */ |
|
|
|
static const unsigned debruijn_tbl[32] = { 0, 9, 1, 10, 13, 21, 2, 29, |
|
|
|
11, 14, 16, 18, 22, 25, 3, 30, |
|
|
|
8, 12, 20, 28, 15, 17, 24, 7, |
|
|
|
19, 27, 23, 6, 26, 5, 4, 31 }; |
|
|
|
guint32 v = val >> 32; |
|
|
|
|
|
|
|
if (v) { |
|
|
|
v |= 1; |
|
|
|
v |= v >> 1; |
|
|
|
v |= v >> 2; |
|
|
|
v |= v >> 4; |
|
|
|
v |= v >> 8; |
|
|
|
v |= v >> 16; |
|
|
|
tmp = 32 + debruijn_tbl[(v * 0x07C4ACDDU) >> 27]; |
|
|
|
} |
|
|
|
else { |
|
|
|
v = val & 0xFFFFFFFF; |
|
|
|
v |= 1; |
|
|
|
v |= v >> 1; |
|
|
|
v |= v >> 2; |
|
|
|
v |= v >> 4; |
|
|
|
v |= v >> 8; |
|
|
|
v |= v >> 16; |
|
|
|
|
|
|
|
tmp = debruijn_tbl[(v * 0x07C4ACDDU) >> 27]; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tmp = (tmp + 1) * 1233 >> 12; |
|
|
|
#endif |
|
|
|
|
|
|
|
return tmp - (val < powers_of_10[tmp]) + 1; |
|
|
|
} |
|
|
|
|
|
|
|
static const char int_lookup_table[200] = { |
|
|
|
'0','0','0','1','0','2','0','3','0','4', |
|
|
|
'0','5','0','6','0','7','0','8','0','9', |
|
|
|
'1','0','1','1','1','2','1','3','1','4', |
|
|
|
'1','5','1','6','1','7','1','8','1','9', |
|
|
|
'2','0','2','1','2','2','2','3','2','4', |
|
|
|
'2','5','2','6','2','7','2','8','2','9', |
|
|
|
'3','0','3','1','3','2','3','3','3','4', |
|
|
|
'3','5','3','6','3','7','3','8','3','9', |
|
|
|
'4','0','4','1','4','2','4','3','4','4', |
|
|
|
'4','5','4','6','4','7','4','8','4','9', |
|
|
|
'5','0','5','1','5','2','5','3','5','4', |
|
|
|
'5','5','5','6','5','7','5','8','5','9', |
|
|
|
'6','0','6','1','6','2','6','3','6','4', |
|
|
|
'6','5','6','6','6','7','6','8','6','9', |
|
|
|
'7','0','7','1','7','2','7','3','7','4', |
|
|
|
'7','5','7','6','7','7','7','8','7','9', |
|
|
|
'8','0','8','1','8','2','8','3','8','4', |
|
|
|
'8','5','8','6','8','7','8','8','8','9', |
|
|
|
'9','0','9','1','9','2','9','3','9','4', |
|
|
|
'9','5','9','6','9','7','9','8','9','9' |
|
|
|
}; |
|
|
|
|
|
|
|
static inline guint |
|
|
|
rspamd_uint32_print (guint32 in, gchar *out) |
|
|
|
{ |
|
|
|
guint ndigits = rspamd_decimal_digits32 (in); |
|
|
|
gchar *p; |
|
|
|
|
|
|
|
p = out + ndigits - 1; |
|
|
|
|
|
|
|
while (in >= 100) { |
|
|
|
unsigned idx = (in % 100) * 2; |
|
|
|
|
|
|
|
/* Do two digits at once */ |
|
|
|
*p-- = int_lookup_table[idx + 1]; |
|
|
|
*p-- = int_lookup_table[idx]; |
|
|
|
|
|
|
|
in /= 100; |
|
|
|
} |
|
|
|
|
|
|
|
if (in < 10) { |
|
|
|
*p = ((char)in) + '0'; |
|
|
|
} |
|
|
|
else { |
|
|
|
unsigned idx = in * 2; |
|
|
|
|
|
|
|
*p-- = int_lookup_table[idx + 1]; |
|
|
|
*p = int_lookup_table[idx]; |
|
|
|
} |
|
|
|
|
|
|
|
return ndigits; |
|
|
|
} |
|
|
|
|
|
|
|
static inline guint |
|
|
|
rspamd_uint64_print (guint64 in, gchar *out) |
|
|
|
{ |
|
|
|
guint ndigits = rspamd_decimal_digits64 (in); |
|
|
|
guint32 v32; |
|
|
|
gchar *p; |
|
|
|
|
|
|
|
p = out + ndigits - 1; |
|
|
|
|
|
|
|
while (in >= 100000000) { |
|
|
|
v32 = (guint32)(in % 100000000); |
|
|
|
guint32 a, b, a1, a2, b1, b2; |
|
|
|
|
|
|
|
/* Initial spill */ |
|
|
|
a = v32 / 10000; |
|
|
|
b = v32 % 10000; |
|
|
|
a1 = (a / 100) * 2; |
|
|
|
a2 = (a % 100) * 2; |
|
|
|
b1 = (b / 100) * 2; |
|
|
|
b2 = (b % 100) * 2; |
|
|
|
|
|
|
|
/* Fill 8 digits at once */ |
|
|
|
*p-- = int_lookup_table[b2 + 1]; |
|
|
|
*p-- = int_lookup_table[b2]; |
|
|
|
*p-- = int_lookup_table[b1 + 1]; |
|
|
|
*p-- = int_lookup_table[b1]; |
|
|
|
*p-- = int_lookup_table[a2 + 1]; |
|
|
|
*p-- = int_lookup_table[a2]; |
|
|
|
*p-- = int_lookup_table[a1 + 1]; |
|
|
|
*p-- = int_lookup_table[a1]; |
|
|
|
|
|
|
|
in /= 100000000; |
|
|
|
} |
|
|
|
|
|
|
|
/* Remaining 32 bit */ |
|
|
|
v32 = (guint32)in; |
|
|
|
|
|
|
|
while (v32 >= 100) { |
|
|
|
unsigned idx = (v32 % 100) << 1; |
|
|
|
|
|
|
|
/* Do 2 digits at once */ |
|
|
|
*p-- = int_lookup_table[idx + 1]; |
|
|
|
*p-- = int_lookup_table[idx]; |
|
|
|
|
|
|
|
v32 /= 100; |
|
|
|
} |
|
|
|
|
|
|
|
if (v32 < 10) { |
|
|
|
*p = ((char)v32) + '0'; |
|
|
|
} |
|
|
|
else { |
|
|
|
unsigned idx = v32 * 2; |
|
|
|
|
|
|
|
*p-- = int_lookup_table[idx + 1]; |
|
|
|
*p = int_lookup_table[idx]; |
|
|
|
} |
|
|
|
|
|
|
|
return ndigits; |
|
|
|
} |
|
|
|
|
|
|
|
static gchar * |
|
|
|
rspamd_sprintf_num (gchar *buf, gchar *last, guint64 ui64, gchar zero, |
|
|
|
guint hexadecimal, guint width) |
|
|
|
guint hexadecimal, guint width) |
|
|
|
{ |
|
|
|
gchar *p, temp[sizeof ("18446744073709551615")]; |
|
|
|
size_t len; |
|
|
|
guint32 ui32; |
|
|
|
|
|
|
|
p = temp + sizeof(temp); |
|
|
|
|
|
|
|
if (hexadecimal == 0) { |
|
|
|
p = temp; |
|
|
|
|
|
|
|
if (ui64 <= G_MAXUINT32) { |
|
|
|
|
|
|
|
/* |
|
|
|
* To divide 64-bit numbers and to find remainders |
|
|
|
* on the x86 platform gcc and icc call the libc functions |
|
|
|
* [u]divdi3() and [u]moddi3(), they call another function |
|
|
|
* in its turn. On FreeBSD it is the qdivrem() function, |
|
|
|
* its source code is about 170 lines of the code. |
|
|
|
* The glibc counterpart is about 150 lines of the code. |
|
|
|
* |
|
|
|
* For 32-bit numbers and some divisors gcc and icc use |
|
|
|
* a inlined multiplication and shifts. For example, |
|
|
|
* guint "i32 / 10" is compiled to |
|
|
|
* |
|
|
|
* (i32 * 0xCCCCCCCD) >> 35 |
|
|
|
*/ |
|
|
|
|
|
|
|
ui32 = (guint32) ui64; |
|
|
|
|
|
|
|
do { |
|
|
|
*--p = (gchar) (ui32 % 10 + '0'); |
|
|
|
} while (ui32 /= 10); |
|
|
|
|
|
|
|
} else { |
|
|
|
do { |
|
|
|
*--p = (gchar) (ui64 % 10 + '0'); |
|
|
|
} while (ui64 /= 10); |
|
|
|
if (ui64 < G_MAXUINT32) { |
|
|
|
len = rspamd_uint32_print ((guint32)ui64, temp); |
|
|
|
} |
|
|
|
|
|
|
|
} else if (hexadecimal == 1) { |
|
|
|
|
|
|
|
else { |
|
|
|
len = rspamd_uint64_print (ui64, temp); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (hexadecimal == 1) { |
|
|
|
p = temp + sizeof(temp); |
|
|
|
do { |
|
|
|
|
|
|
|
/* the "(guint32)" cast disables the BCC's warning */ |
|
|
|
*--p = _hex[(guint32) (ui64 & 0xf)]; |
|
|
|
|
|
|
|
} while (ui64 >>= 4); |
|
|
|
|
|
|
|
} else { /* hexadecimal == 2 */ |
|
|
|
|
|
|
|
len = (temp + sizeof (temp)) - p + 1; |
|
|
|
} |
|
|
|
else { /* hexadecimal == 2 */ |
|
|
|
p = temp + sizeof(temp); |
|
|
|
do { |
|
|
|
|
|
|
|
/* the "(guint32)" cast disables the BCC's warning */ |
|
|
|
*--p = _HEX[(guint32) (ui64 & 0xf)]; |
|
|
|
|
|
|
|
} while (ui64 >>= 4); |
|
|
|
|
|
|
|
len = (temp + sizeof (temp)) - p + 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* zero or space padding */ |
|
|
|
|
|
|
|
len = (temp + sizeof (temp)) - p; |
|
|
|
|
|
|
|
while (len++ < width && buf < last) { |
|
|
|
while (width > 0 && buf < last) { |
|
|
|
*buf++ = zero; |
|
|
|
} |
|
|
|
|
|
|
|
/* number safe copy */ |
|
|
|
|
|
|
|
len = (temp + sizeof (temp)) - p; |
|
|
|
|
|
|
|
if (buf + len > last) { |
|
|
|
len = last - buf; |
|
|
|
} |