mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
Merge commit '460321cfe979459e3b78ba87694f29865d321612' into thread-next
This commit is contained in:
commit
6aea356b2a
121
lib/printf.c
121
lib/printf.c
@ -8,7 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "string.h"
|
#include "lib/macro.h"
|
||||||
|
#include "lib/string.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@ -631,3 +632,121 @@ char *lp_sprintf(linpool *p, const char *fmt, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const u64 decadic_multiplier[] = {
|
||||||
|
1, 10, 100, 1000,
|
||||||
|
10000, 100000, 1000000, 10000000,
|
||||||
|
#if 0
|
||||||
|
100000000, 1000000000, 10000000000, 100000000000,
|
||||||
|
1000000000000, 10000000000000, 100000000000000, 1000000000000000,
|
||||||
|
10000000000000000, 100000000000000000, 1000000000000000000,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u64 decmul_limit[] = {
|
||||||
|
~0ULL / 1, ~0ULL / 10,
|
||||||
|
~0ULL / 100, ~0ULL / 1000,
|
||||||
|
~0ULL / 10000, ~0ULL / 100000,
|
||||||
|
~0ULL / 1000000, ~0ULL / 10000000,
|
||||||
|
#if 0
|
||||||
|
~0ULL / 100000000, ~0ULL / 1000000000,
|
||||||
|
~0ULL / 10000000000, ~0ULL / 100000000000,
|
||||||
|
~0ULL / 1000000000000, ~0ULL / 10000000000000,
|
||||||
|
~0ULL / 100000000000000, ~0ULL / 1000000000000000,
|
||||||
|
~0ULL / 10000000000000000, ~0ULL / 100000000000000000,
|
||||||
|
~0ULL / 1000000000000000000,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof decadic_multiplier == sizeof decmul_limit);
|
||||||
|
|
||||||
|
char *fmt_order(u64 value, uint decimals, u64 kb_threshold)
|
||||||
|
{
|
||||||
|
bool too_big = (value + 512 < 512ULL);
|
||||||
|
|
||||||
|
u64 mv = value;
|
||||||
|
uint magnitude = 0;
|
||||||
|
while (mv > kb_threshold)
|
||||||
|
{
|
||||||
|
magnitude++;
|
||||||
|
mv = (mv + (too_big ? 0 : 512)) / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint shift = magnitude * 10;
|
||||||
|
|
||||||
|
/* The trivial case */
|
||||||
|
if (magnitude == 0)
|
||||||
|
return tmp_sprintf("%lu ", value);
|
||||||
|
|
||||||
|
/* Now we can find the suffix and the main divisor */
|
||||||
|
ASSERT_DIE(magnitude < 7);
|
||||||
|
char suffix = " kMGTPE"[magnitude];
|
||||||
|
|
||||||
|
/* The value before the dot is available just by dividing */
|
||||||
|
u64 before_dot = value >> shift;
|
||||||
|
|
||||||
|
/* Remainder is more tricky. First we need to know it. */
|
||||||
|
u64 remainder = value - (before_dot << shift);
|
||||||
|
|
||||||
|
/* We would like to compute (remainder * decmul) / divisor
|
||||||
|
* in integers but it's tricky because of u64 limits. */
|
||||||
|
ASSERT_DIE(decimals < ARRAY_SIZE(decadic_multiplier));
|
||||||
|
u64 decmul = decadic_multiplier[decimals];
|
||||||
|
u64 product;
|
||||||
|
|
||||||
|
if (remainder < decmul_limit[decimals])
|
||||||
|
{
|
||||||
|
/* The easier version: Everything fits into u64 */
|
||||||
|
product = remainder * decmul;
|
||||||
|
product >>= shift - 1;
|
||||||
|
product++;
|
||||||
|
product >>= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Harder version: We have to multiply by parts.
|
||||||
|
* Fortunately, decmul always fits into 32 bits. */
|
||||||
|
/* After this, product = lower + (upper << 32). */
|
||||||
|
u64 lower = (remainder & ((1ULL << 32) - 1)) * decmul;
|
||||||
|
u64 upper = (remainder >> 32) * decmul;
|
||||||
|
|
||||||
|
if (shift < 33)
|
||||||
|
{
|
||||||
|
/* Divide lower */
|
||||||
|
lower >>= shift - 1;
|
||||||
|
|
||||||
|
/* Add the full upper part, not shifted enough to lose any bits */
|
||||||
|
lower += upper << (33 - shift);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* First move the shifted-out bits from upper to lower */
|
||||||
|
lower += (upper & ((1ULL << (shift - 32)) - 1)) << 32;
|
||||||
|
|
||||||
|
/* Then we can divide */
|
||||||
|
lower >>= shift - 1;
|
||||||
|
|
||||||
|
/* And add the shifted upper part */
|
||||||
|
lower += upper >> (shift - 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we finish the division by rounding */
|
||||||
|
product = (lower + 1) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (product == decmul)
|
||||||
|
{
|
||||||
|
product = 0;
|
||||||
|
before_dot++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_DIE(product < decmul);
|
||||||
|
|
||||||
|
/* And now we finally have all the numbers to print! */
|
||||||
|
if (decimals)
|
||||||
|
return tmp_sprintf("%lu.%0*lu %c",
|
||||||
|
before_dot, decimals, product, suffix
|
||||||
|
);
|
||||||
|
else
|
||||||
|
return tmp_sprintf("%lu %c", before_dot, suffix);
|
||||||
|
}
|
||||||
|
@ -117,6 +117,68 @@ t_bstrcmp(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
t_fmt_order(void)
|
||||||
|
{
|
||||||
|
struct fmt_order_tv {
|
||||||
|
u64 value;
|
||||||
|
int decimals;
|
||||||
|
u64 threshold;
|
||||||
|
const char *expect;
|
||||||
|
} test_vectors [] = {
|
||||||
|
{ 9999, 1, 10000, "9999 " },
|
||||||
|
{ 10001, 1, 10000, "9.8 k" },
|
||||||
|
{ 10001, 2, 10000, "9.77 k" },
|
||||||
|
{ 10001, 3, 10000, "9.767 k" },
|
||||||
|
{ 1048575, 0, 10000, "1024 k" },
|
||||||
|
{ 1048575, 1, 10000, "1024.0 k" },
|
||||||
|
{ 1048575, 2, 10000, "1024.00 k" },
|
||||||
|
{ 1048575, 3, 10000, "1023.999 k" },
|
||||||
|
{ 1048575, 4, 10000, "1023.9990 k" },
|
||||||
|
{ 1048575, 5, 10000, "1023.99902 k" },
|
||||||
|
{ 1048575, 6, 10000, "1023.999023 k" },
|
||||||
|
{ 1048575, 0, 1000, "1 M" },
|
||||||
|
{ 1048575, 1, 1000, "1.0 M" },
|
||||||
|
{ 1048575, 2, 1000, "1.00 M" },
|
||||||
|
{ 1048575, 3, 1000, "1.000 M" },
|
||||||
|
{ 1048575, 4, 1000, "1.0000 M" },
|
||||||
|
{ 1048575, 5, 1000, "1.00000 M" },
|
||||||
|
{ 1048575, 6, 1000, "0.999999 M" },
|
||||||
|
{ 1048577, 6, 10000, "1024.000977 k" },
|
||||||
|
{ 1048577, 6, 1000, "1.000001 M" },
|
||||||
|
{ 1048577, 6, 100, "1.000001 M" },
|
||||||
|
{ 1048577, 6, 10, "1.000001 M" },
|
||||||
|
{ 1048577, 6, 1, "1.000001 M" },
|
||||||
|
{ 10000000000000, 6, 10000, "9313.225746 G" },
|
||||||
|
{ 10000000000000, 6, 1000, "9.094947 T" },
|
||||||
|
{ 123456789123456789, 0, 1000, "110 P" },
|
||||||
|
{ 123456789123456789, 4, 1000, "109.6517 P" },
|
||||||
|
{ 123456789123456789, 7, 1000, "109.6516559 P" },
|
||||||
|
{ 1234567890123456789, 0, 1000, "1 E" },
|
||||||
|
{ 1234567890123456789, 1, 1000, "1.1 E" },
|
||||||
|
{ 1234567890123456789, 2, 1000, "1.07 E" },
|
||||||
|
{ 1234567890123456789, 3, 1000, "1.071 E" },
|
||||||
|
{ 1234567890123456789, 4, 1000, "1.0708 E" },
|
||||||
|
{ 1234567890123456789, 5, 1000, "1.07082 E" },
|
||||||
|
{ 1234567890123456789, 6, 1000, "1.070817 E" },
|
||||||
|
{ 1234567890123456789, 7, 1000, "1.0708170 E" },
|
||||||
|
{ 9444732965739290427U, 3, 1000, "8.192 E" },
|
||||||
|
{ 9444732965739290427U, 6, 1000, "8.192000 E" },
|
||||||
|
{ 18446744073709551615U, 2, 1000, "16.00 E" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)ARRAY_SIZE(test_vectors); i++)
|
||||||
|
{
|
||||||
|
const char *result = fmt_order(test_vectors[i].value, test_vectors[i].decimals, test_vectors[i].threshold);
|
||||||
|
const char *expect = test_vectors[i].expect;
|
||||||
|
|
||||||
|
bt_assert_msg(strncmp(result, expect, strlen(expect)) == 0,
|
||||||
|
"case %d, result \"%s\", expect \"%s\"", i, result, expect);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -126,6 +188,7 @@ main(int argc, char *argv[])
|
|||||||
bt_test_suite(t_router_id, "print router id");
|
bt_test_suite(t_router_id, "print router id");
|
||||||
bt_test_suite(t_time, "print time");
|
bt_test_suite(t_time, "print time");
|
||||||
bt_test_suite(t_bstrcmp, "bstrcmp");
|
bt_test_suite(t_bstrcmp, "bstrcmp");
|
||||||
|
bt_test_suite(t_fmt_order, "fmt_order");
|
||||||
|
|
||||||
return bt_exit_value();
|
return bt_exit_value();
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@ char *mb_sprintf(pool *p, const char *fmt, ...);
|
|||||||
char *mb_vsprintf(pool *p, const char *fmt, va_list args);
|
char *mb_vsprintf(pool *p, const char *fmt, va_list args);
|
||||||
char *lp_sprintf(linpool *p, const char *fmt, ...);
|
char *lp_sprintf(linpool *p, const char *fmt, ...);
|
||||||
char *lp_vsprintf(linpool *p, const char *fmt, va_list args);
|
char *lp_vsprintf(linpool *p, const char *fmt, va_list args);
|
||||||
|
#define tmp_sprintf(...) lp_sprintf(tmp_linpool, __VA_ARGS__)
|
||||||
|
#define tmp_vsprintf(...) lp_vsprintf(tmp_linpool, __VA_ARGS__)
|
||||||
|
|
||||||
int buffer_vprint(buffer *buf, const char *fmt, va_list args);
|
int buffer_vprint(buffer *buf, const char *fmt, va_list args);
|
||||||
int buffer_print(buffer *buf, const char *fmt, ...);
|
int buffer_print(buffer *buf, const char *fmt, ...);
|
||||||
@ -33,6 +35,8 @@ u64 bstrtoul10(const char *str, char **end);
|
|||||||
u64 bstrtoul16(const char *str, char **end);
|
u64 bstrtoul16(const char *str, char **end);
|
||||||
byte bstrtobyte16(const char *str);
|
byte bstrtobyte16(const char *str);
|
||||||
|
|
||||||
|
char *fmt_order(u64 value, uint decimals, u64 kb_threshold);
|
||||||
|
|
||||||
int bstrhextobin(const char *s, byte *b);
|
int bstrhextobin(const char *s, byte *b);
|
||||||
int bstrbintohex(const byte *b, size_t len, char *buf, size_t size, char delim) ACCESS_READ(1, 2) ACCESS_WRITE(3, 4);
|
int bstrbintohex(const byte *b, size_t len, char *buf, size_t size, char delim) ACCESS_READ(1, 2) ACCESS_WRITE(3, 4);
|
||||||
|
|
||||||
|
@ -1393,7 +1393,6 @@ bmp_start(struct proto *P)
|
|||||||
struct bmp_proto *p = (void *) P;
|
struct bmp_proto *p = (void *) P;
|
||||||
|
|
||||||
p->buffer_mpool = rp_new(P->pool, proto_domain(&p->p), "BMP Buffer");
|
p->buffer_mpool = rp_new(P->pool, proto_domain(&p->p), "BMP Buffer");
|
||||||
p->map_mem_pool = rp_new(P->pool, proto_domain(&p->p), "BMP Map");
|
|
||||||
p->tx_mem_pool = rp_new(P->pool, proto_domain(&p->p), "BMP Tx");
|
p->tx_mem_pool = rp_new(P->pool, proto_domain(&p->p), "BMP Tx");
|
||||||
p->update_msg_mem_pool = rp_new(P->pool, proto_domain(&p->p), "BMP Update");
|
p->update_msg_mem_pool = rp_new(P->pool, proto_domain(&p->p), "BMP Update");
|
||||||
p->tx_ev = ev_new_init(p->p.pool, bmp_fire_tx, p);
|
p->tx_ev = ev_new_init(p->p.pool, bmp_fire_tx, p);
|
||||||
|
@ -64,7 +64,6 @@ struct bmp_proto {
|
|||||||
// Below fields are for internal use
|
// Below fields are for internal use
|
||||||
// struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer
|
// struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer
|
||||||
pool *buffer_mpool; // Memory pool used for BMP buffer allocations
|
pool *buffer_mpool; // Memory pool used for BMP buffer allocations
|
||||||
pool *map_mem_pool; // Memory pool used for BMP map allocations
|
|
||||||
pool *tx_mem_pool; // Memory pool used for packet allocations designated to BMP collector
|
pool *tx_mem_pool; // Memory pool used for packet allocations designated to BMP collector
|
||||||
pool *update_msg_mem_pool; // Memory pool used for BPG UPDATE MSG allocations
|
pool *update_msg_mem_pool; // Memory pool used for BPG UPDATE MSG allocations
|
||||||
list tx_queue; // Stores queued packets going to be sent
|
list tx_queue; // Stores queued packets going to be sent
|
||||||
|
Loading…
Reference in New Issue
Block a user