Commit 6cc547a1 authored by Maria Matejka's avatar Maria Matejka
Browse files

Bitops: u64_log2() and encoding variable-length bitstrings into u64

parent 3a22a6e8
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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
+41 −5
Original line number Diff line number Diff line
@@ -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();
}
+2 −2
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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);