mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-23 02:01:55 +00:00
Bitops: u64_log2() and encoding variable-length bitstrings into u64
This commit is contained in:
parent
3a22a6e858
commit
6cc547a13d
12
lib/bitops.c
12
lib/bitops.c
@ -68,3 +68,15 @@ u32_log2(u32 v)
|
||||
return r;
|
||||
}
|
||||
|
||||
u64
|
||||
u64_log2(u64 v)
|
||||
{
|
||||
u64 r, shift;
|
||||
r = (v > 0xFFFFFFFFLL) << 5; v >>= r;
|
||||
shift = (v > 0xFFFF ) << 4; v >>= shift; r |= shift;
|
||||
shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
|
||||
shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
|
||||
shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
|
||||
r |= (v >> 1);
|
||||
return r;
|
||||
}
|
||||
|
38
lib/bitops.h
38
lib/bitops.h
@ -18,15 +18,53 @@
|
||||
* from the left and the rest filled with zeroes.
|
||||
* E.g., u32_mkmask(5) = 0xf8000000.
|
||||
* u32_masklen Inverse operation to u32_mkmask, -1 if not a bitmask.
|
||||
*
|
||||
* u32_log2
|
||||
* u64_log2 Find the first 1 in the number
|
||||
*
|
||||
* u32_hash Compute a common hash
|
||||
*
|
||||
* u64_var_encode Encode a variable-length bitstring into fixed-length u64
|
||||
* u64_var_decode Decode the bitstring
|
||||
*/
|
||||
|
||||
u32 u32_mkmask(uint n);
|
||||
uint u32_masklen(u32 x);
|
||||
|
||||
u32 u32_log2(u32 v);
|
||||
u64 u64_log2(u64 v);
|
||||
|
||||
static inline u32 u32_hash(u32 v) { return v * 2902958171u; }
|
||||
|
||||
static inline u8 u32_popcount(u32 v) { return __builtin_popcount(v); }
|
||||
|
||||
static inline u64 u64_var_encode(u64 data, uint padlen)
|
||||
{
|
||||
ASSERT(padlen > 0);
|
||||
|
||||
/* Append the other bit than the last */
|
||||
if (data & 1)
|
||||
return data << padlen;
|
||||
else
|
||||
return (data << padlen) | ((1ULL << padlen) - 1);
|
||||
}
|
||||
|
||||
static inline u64 u64_var_decode(u64 enc, uint *padlen)
|
||||
{
|
||||
/* If enc is ....|100..00, then cpl is ....|011..11
|
||||
* If enc is ....|011..11, then cpl is ....|100..00
|
||||
*
|
||||
* In both cases, enc ^ cpl is then 0...0|111..11
|
||||
* so u64_log2((enc ^ cpl) + 1) is the number of bits to shift right.
|
||||
* */
|
||||
u64 cpl = (enc & 1) ? (enc + 1) : (enc - 1);
|
||||
if ((~enc == 0) || (~cpl == 0)) {
|
||||
*padlen = 64;
|
||||
return 0;
|
||||
} else {
|
||||
*padlen = u64_log2(enc ^ cpl);
|
||||
return enc >> *padlen;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -82,11 +82,14 @@ t_masklen(void)
|
||||
}
|
||||
|
||||
static void
|
||||
check_log2(u32 n)
|
||||
check_log2(u64 n)
|
||||
{
|
||||
u32 log = u32_log2(n);
|
||||
u32 low = bt_naive_pow(2, log);
|
||||
u32 high = bt_naive_pow(2, log+1);
|
||||
u64 log = u64_log2(n);
|
||||
u64 low = bt_naive_pow(2, log);
|
||||
u64 high = bt_naive_pow(2, log+1);
|
||||
|
||||
if (n <= 0xffffffff)
|
||||
bt_assert(u32_log2(n) == log);
|
||||
|
||||
bt_assert_msg(n >= low && n < high,
|
||||
"u32_log2(%u) = %u, %u should be in the range <%u, %u)",
|
||||
@ -101,15 +104,47 @@ t_log2(void)
|
||||
for (i = 0; i < 31; i++)
|
||||
bt_assert(u32_log2(bt_naive_pow(2, i+1)) == i+1);
|
||||
|
||||
for (i = 0; i < 63; i++)
|
||||
bt_assert(u64_log2(bt_naive_pow(2, i+1)) == i+1);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i++)
|
||||
check_log2(i);
|
||||
|
||||
for (i = 1; i < MAX_NUM; i++)
|
||||
check_log2(((u32) bt_random()) % 0x0fffffff);
|
||||
check_log2((unsigned long int) bt_random());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
var_enc_dec(u64 data, uint padlen)
|
||||
{
|
||||
uint olen = ~0;
|
||||
u64 enc = u64_var_encode(data, padlen);
|
||||
u64 odata = u64_var_decode(enc, &olen);
|
||||
bt_assert_msg(
|
||||
(odata == data) && (olen == padlen),
|
||||
"u64_var_encode(0x%llx, %u) == 0x%llx; u64_var_decode(0x%llx, %u) == 0x%llx",
|
||||
data, padlen, enc, enc, olen, odata
|
||||
);
|
||||
}
|
||||
|
||||
static int
|
||||
t_var(void)
|
||||
{
|
||||
for (uint i = 0; i < 63; i++)
|
||||
for (uint j = 1; j+i < 64; j++) {
|
||||
var_enc_dec(1ULL << i, j);
|
||||
var_enc_dec((1ULL << i) - 1, j);
|
||||
var_enc_dec(((unsigned long int) bt_random()) & ((1ULL << (64-j)) - 1), j);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@ -118,6 +153,7 @@ main(int argc, char *argv[])
|
||||
bt_test_suite(t_mkmask, "u32_mkmask()");
|
||||
bt_test_suite(t_masklen, "u32_masklen()");
|
||||
bt_test_suite(t_log2, "u32_log2()");
|
||||
bt_test_suite(t_var, "u64_var_(en|de)code()");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
||||
|
@ -195,10 +195,10 @@ bt_config_file_parse(const char *filepath)
|
||||
/*
|
||||
* Returns @base raised to the power of @power.
|
||||
*/
|
||||
uint
|
||||
u64
|
||||
bt_naive_pow(uint base, uint power)
|
||||
{
|
||||
uint result = 1;
|
||||
u64 result = 1;
|
||||
uint i;
|
||||
for (i = 0; i < power; i++)
|
||||
result *= base;
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define BT_CONFIG_PARSE_STATIC_PROTO "protocol static { ipv4; } \n"
|
||||
#define BT_CONFIG_SIMPLE BT_CONFIG_PARSE_ROUTER_ID BT_CONFIG_PARSE_STATIC_PROTO
|
||||
|
||||
uint bt_naive_pow(uint base, uint power);
|
||||
u64 bt_naive_pow(uint base, uint power);
|
||||
void bt_bytes_to_hex(char *buf, const byte *in_data, size_t size);
|
||||
|
||||
void bt_bird_init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user