* 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
}
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)",
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[])
{
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();
}