Browse Source
In particular, this gets some MacOS fixes from #1327. It also includes a major intmap update which fixes corner cases in traversals, and requires ccan/bitops. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
7 years ago
committed by
Christian Decker
22 changed files with 1148 additions and 81 deletions
@ -1,3 +1,3 @@ |
|||||
CCAN imported from http://ccodearchive.net. |
CCAN imported from http://ccodearchive.net. |
||||
|
|
||||
CCAN version: init-2405-g41a0af50 |
CCAN version: init-2419-g9bdb4be8 |
||||
|
@ -0,0 +1 @@ |
|||||
|
../../licenses/CC0 |
@ -0,0 +1,43 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* bitops - bit counting routines |
||||
|
* |
||||
|
* These offer convenience wrappers around (and, as necessary, |
||||
|
* replacements for) the builtin bit testing/counting routines. |
||||
|
* |
||||
|
* Example: |
||||
|
* #include <ccan/bitops/bitops.h> |
||||
|
* #include <stdio.h> |
||||
|
* |
||||
|
* int main(int argc, char *argv[]) |
||||
|
* { |
||||
|
* unsigned int v = atoi(argv[1]); |
||||
|
* |
||||
|
* printf("Number of 1 bits: %i\n", bitops_weight32(v)); |
||||
|
* if (v != 0) { |
||||
|
* printf("Least-significant set bit: %i\n", bitops_ls32(v)); |
||||
|
* printf("Most-significant set bit: %i\n", bitops_hs32(v)); |
||||
|
* printf("Least-significant clear bit: %i\n", bitops_lc32(v)); |
||||
|
* printf("Most-significant clear bit: %i\n", bitops_hc32(v)); |
||||
|
* } |
||||
|
* return 0; |
||||
|
* } |
||||
|
* |
||||
|
* License: CC0 (Public Domain) |
||||
|
* Author: Rusty Russell <rusty@rustcorp.com.au> |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,79 @@ |
|||||
|
/* CC0 license (public domain) - see LICENSE file for details */ |
||||
|
#include <ccan/bitops/bitops.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
/* We do naive replacement versions: good for testing, and really your
|
||||
|
* compiler should do better. */ |
||||
|
#ifdef BITOPS_NEED_FFS |
||||
|
int bitops_ffs32(uint32_t u) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 0; i < 32; i++) |
||||
|
if (u & ((uint32_t)1 << i)) |
||||
|
return i + 1; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int bitops_ffs64(uint64_t u) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 0; i < 64; i++) |
||||
|
if (u & ((uint64_t)1 << i)) |
||||
|
return i + 1; |
||||
|
return 0; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#ifdef BITOPS_NEED_CLZ |
||||
|
int bitops_clz32(uint32_t u) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 0; i < 32; i++) |
||||
|
if (u & ((uint32_t)1 << (31 - i))) |
||||
|
return i; |
||||
|
abort(); |
||||
|
} |
||||
|
|
||||
|
int bitops_clz64(uint64_t u) |
||||
|
{ |
||||
|
int i; |
||||
|
for (i = 0; i < 64; i++) |
||||
|
if (u & ((uint64_t)1 << (63 - i))) |
||||
|
return i; |
||||
|
abort(); |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#ifdef BITOPS_NEED_CTZ |
||||
|
int bitops_ctz32(uint32_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return bitops_ffs32(u) - 1; |
||||
|
} |
||||
|
|
||||
|
int bitops_ctz64(uint64_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return bitops_ffs64(u) - 1; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#ifdef BITOPS_NEED_WEIGHT |
||||
|
int bitops_weight32(uint32_t u) |
||||
|
{ |
||||
|
int i, num = 0; |
||||
|
for (i = 0; i < 32; i++) |
||||
|
if (u & ((uint32_t)1 << i)) |
||||
|
num++; |
||||
|
return num; |
||||
|
} |
||||
|
|
||||
|
int bitops_weight64(uint64_t u) |
||||
|
{ |
||||
|
int i, num = 0; |
||||
|
for (i = 0; i < 64; i++) |
||||
|
if (u & ((uint64_t)1 << i)) |
||||
|
num++; |
||||
|
return num; |
||||
|
} |
||||
|
#endif |
@ -0,0 +1,223 @@ |
|||||
|
/* CC0 license (public domain) - see LICENSE file for details */ |
||||
|
#ifndef CCAN_BITOPS_H |
||||
|
#define CCAN_BITOPS_H |
||||
|
#include "config.h" |
||||
|
#include <stdint.h> |
||||
|
|
||||
|
#if defined(CCAN_DEBUG) || defined(CCAN_BITOPS_DEBUG) |
||||
|
#include <assert.h> |
||||
|
#define BITOPS_ASSERT_NONZERO(u) assert((u) != 0) |
||||
|
#else |
||||
|
#define BITOPS_ASSERT_NONZERO(u) |
||||
|
#endif |
||||
|
|
||||
|
#if HAVE_BUILTIN_FFS && HAVE_BUILTIN_FFSL && HAVE_BUILTIN_FFSLL |
||||
|
/**
|
||||
|
* bitops_ffs32: find first set bit in a uint32_t |
||||
|
* |
||||
|
* Returns 1 for least signficant bit, 32 for most significant bit, 0 |
||||
|
* for no bits set. |
||||
|
*/ |
||||
|
static inline int bitops_ffs32(uint32_t u) |
||||
|
{ |
||||
|
return __builtin_ffs(u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_ffs64: find lowest set bit in a uint64_t |
||||
|
* |
||||
|
* Returns 1 for least signficant bit, 32 for most significant bit, 0 |
||||
|
* for no bits set. |
||||
|
*/ |
||||
|
static inline int bitops_ffs64(uint64_t u) |
||||
|
{ |
||||
|
if (sizeof(u) == sizeof(long)) |
||||
|
return __builtin_ffsl(u); |
||||
|
else |
||||
|
return __builtin_ffsll(u); |
||||
|
} |
||||
|
#else |
||||
|
int bitops_ffs32(uint32_t u); |
||||
|
int bitops_ffs64(uint64_t u); |
||||
|
#define BITOPS_NEED_FFS 1 |
||||
|
#endif |
||||
|
|
||||
|
#if HAVE_BUILTIN_CLZ && HAVE_BUILTIN_CLZL && HAVE_BUILTIN_CLZLL |
||||
|
/**
|
||||
|
* bitops_clz32: count leading zeros in a uint32_t (must not be 0) |
||||
|
* |
||||
|
* Returns 0 if most signficant bit is set, 31 if only least |
||||
|
* signficant bit is set. |
||||
|
*/ |
||||
|
static inline int bitops_clz32(uint32_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return __builtin_clz(u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_clz64: count leading zeros in a uint64_t (must not be 0) |
||||
|
* |
||||
|
* Returns 0 if most signficant bit is set, 63 if only least |
||||
|
* signficant bit is set. |
||||
|
*/ |
||||
|
static inline int bitops_clz64(uint64_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
if (sizeof(u) == sizeof(long)) |
||||
|
return __builtin_clzl(u); |
||||
|
else |
||||
|
return __builtin_clzll(u); |
||||
|
} |
||||
|
#else |
||||
|
int bitops_clz32(uint32_t u); |
||||
|
int bitops_clz64(uint64_t u); |
||||
|
#define BITOPS_NEED_CLZ 1 |
||||
|
#endif |
||||
|
|
||||
|
#if HAVE_BUILTIN_CTZ && HAVE_BUILTIN_CTZL && HAVE_BUILTIN_CTZLL |
||||
|
/**
|
||||
|
* bitops_ctz32: count trailing zeros in a uint32_t (must not be 0) |
||||
|
* |
||||
|
* Returns 0 if least signficant bit is set, 31 if only most |
||||
|
* signficant bit is set. |
||||
|
*/ |
||||
|
static inline int bitops_ctz32(uint32_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return __builtin_ctz(u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_ctz64: count trailing zeros in a uint64_t (must not be 0) |
||||
|
* |
||||
|
* Returns 0 if least signficant bit is set, 63 if only most |
||||
|
* signficant bit is set. |
||||
|
*/ |
||||
|
static inline int bitops_ctz64(uint64_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
if (sizeof(u) == sizeof(long)) |
||||
|
return __builtin_ctzl(u); |
||||
|
else |
||||
|
return __builtin_ctzll(u); |
||||
|
} |
||||
|
#else |
||||
|
int bitops_ctz32(uint32_t u); |
||||
|
int bitops_ctz64(uint64_t u); |
||||
|
#define BITOPS_NEED_CTZ 1 |
||||
|
#endif |
||||
|
|
||||
|
/**
|
||||
|
* bitops_ls32: find lowest set bit in a uint32_t (must not be zero) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 31 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_ls32(uint32_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return bitops_ffs32(u) - 1; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_ls64: find lowest set bit in a uint64_t (must not be zero) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 63 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_ls64(uint64_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return bitops_ffs64(u) - 1; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_hs32: find highest set bit in a uint32_t (must not be zero) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 31 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_hs32(uint32_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return 31 - bitops_clz32(u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_hs64: find highest set bit in a uint64_t (must not be zero) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 63 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_hs64(uint64_t u) |
||||
|
{ |
||||
|
BITOPS_ASSERT_NONZERO(u); |
||||
|
return 63 - bitops_clz64(u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_lc32: find lowest clear bit in a uint32_t (must not be 0xFFFFFFFF) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 31 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_lc32(uint32_t u) |
||||
|
{ |
||||
|
return bitops_ctz32(~u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_lc64: find lowest clear bit in a uint64_t (must not be 0xFFFFFFFFFFFFFFFF) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 63 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_lc64(uint64_t u) |
||||
|
{ |
||||
|
return bitops_ctz64(~u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_hc32: find highest clear bit in a uint32_t (must not be 0xFFFFFFFF) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 31 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_hc32(uint32_t u) |
||||
|
{ |
||||
|
return 31 - bitops_clz32(~u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_hc64: find highest clear bit in a uint64_t (must not be 0xFFFFFFFFFFFFFFFF) |
||||
|
* |
||||
|
* Returns 0 for least signficant bit, 63 for most significant bit. |
||||
|
*/ |
||||
|
static inline int bitops_hc64(uint64_t u) |
||||
|
{ |
||||
|
return 63 - bitops_clz64(~u); |
||||
|
} |
||||
|
|
||||
|
#if HAVE_BUILTIN_POPCOUNT && HAVE_BUILTIN_POPCOUNTL && HAVE_BUILTIN_POPCOUNTLL |
||||
|
/**
|
||||
|
* bitops_weight32: count number of bits set in a uint32_t |
||||
|
* |
||||
|
* Returns 0 to 32. |
||||
|
*/ |
||||
|
static inline int bitops_weight32(uint32_t u) |
||||
|
{ |
||||
|
return __builtin_popcount(u); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* bitops_weight64: count number of bits set in a uint64_t |
||||
|
* |
||||
|
* Returns 0 to 64. |
||||
|
*/ |
||||
|
static inline int bitops_weight64(uint64_t u) |
||||
|
{ |
||||
|
if (sizeof(u) == sizeof(long)) |
||||
|
return __builtin_popcountl(u); |
||||
|
else |
||||
|
return __builtin_popcountll(u); |
||||
|
} |
||||
|
#else |
||||
|
int bitops_weight32(uint32_t u); |
||||
|
int bitops_weight64(uint64_t u); |
||||
|
#define BITOPS_NEED_WEIGHT 1 |
||||
|
#endif |
||||
|
#endif /* CCAN_BITOPS_H */ |
@ -0,0 +1,89 @@ |
|||||
|
#include <ccan/bitops/bitops.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
/* Get naive versions */ |
||||
|
#ifndef BITOPS_NEED_FFS |
||||
|
#define BITOPS_NEED_FFS |
||||
|
#endif |
||||
|
|
||||
|
#ifndef BITOPS_NEED_CLZ |
||||
|
#define BITOPS_NEED_CLZ |
||||
|
#endif |
||||
|
|
||||
|
#ifndef BITOPS_NEED_CTZ |
||||
|
#define BITOPS_NEED_CTZ |
||||
|
#endif |
||||
|
|
||||
|
#ifndef BITOPS_NEED_WEIGHT |
||||
|
#define BITOPS_NEED_WEIGHT |
||||
|
#endif |
||||
|
|
||||
|
int naive_bitops_ffs32(uint32_t u); |
||||
|
int naive_bitops_ffs64(uint64_t u); |
||||
|
int naive_bitops_clz32(uint32_t u); |
||||
|
int naive_bitops_clz64(uint64_t u); |
||||
|
int naive_bitops_ctz32(uint32_t u); |
||||
|
int naive_bitops_ctz64(uint64_t u); |
||||
|
int naive_bitops_weight32(uint32_t u); |
||||
|
int naive_bitops_weight64(uint64_t u); |
||||
|
|
||||
|
#define bitops_ffs32 naive_bitops_ffs32 |
||||
|
#define bitops_ffs64 naive_bitops_ffs64 |
||||
|
#define bitops_clz32 naive_bitops_clz32 |
||||
|
#define bitops_clz64 naive_bitops_clz64 |
||||
|
#define bitops_ctz32 naive_bitops_ctz32 |
||||
|
#define bitops_ctz64 naive_bitops_ctz64 |
||||
|
#define bitops_weight32 naive_bitops_weight32 |
||||
|
#define bitops_weight64 naive_bitops_weight64 |
||||
|
#include <ccan/bitops/bitops.c> |
||||
|
|
||||
|
static void test_against_naive32(uint32_t v) |
||||
|
{ |
||||
|
ok1(bitops_ffs32(v) == naive_bitops_ffs32(v)); |
||||
|
ok1(bitops_clz32(v) == naive_bitops_clz32(v)); |
||||
|
ok1(bitops_ctz32(v) == naive_bitops_ctz32(v)); |
||||
|
ok1(bitops_weight32(v) == naive_bitops_weight32(v)); |
||||
|
} |
||||
|
|
||||
|
static void test_against_naive64(uint64_t v) |
||||
|
{ |
||||
|
ok1(bitops_ffs64(v) == naive_bitops_ffs64(v)); |
||||
|
ok1(bitops_clz64(v) == naive_bitops_clz64(v)); |
||||
|
ok1(bitops_ctz64(v) == naive_bitops_ctz64(v)); |
||||
|
ok1(bitops_weight64(v) == naive_bitops_weight64(v)); |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
int i, j; |
||||
|
uint64_t v; |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(32 * 32 * 8 + (64 * 64) * 8 + 4 + 4); |
||||
|
|
||||
|
/* Various comparisons with any one or two bits set */ |
||||
|
for (i = 0; i < 32; i++) { |
||||
|
for (j = 0; j < 32; j++) { |
||||
|
v = ((uint64_t)1 << i) | ((uint64_t)1 << j); |
||||
|
test_against_naive32(v); |
||||
|
test_against_naive32(~v); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (i = 0; i < 64; i++) { |
||||
|
for (j = 0; j < 64; j++) { |
||||
|
v = ((uint64_t)1 << i) | ((uint64_t)1 << j); |
||||
|
test_against_naive64(v); |
||||
|
test_against_naive64(~v); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
test_against_naive64(0xFFFFFFFFFFFFFFFFULL); |
||||
|
ok1(bitops_ffs32(0) == naive_bitops_ffs32(0)); |
||||
|
ok1(bitops_ffs64(0) == naive_bitops_ffs64(0)); |
||||
|
ok1(bitops_weight32(0) == naive_bitops_weight32(0)); |
||||
|
ok1(bitops_weight64(0) == naive_bitops_weight64(0)); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,113 @@ |
|||||
|
#define CCAN_BITOPS_DEBUG 1 |
||||
|
#include <ccan/bitops/bitops.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(68 + 6 * (31 + 63)); |
||||
|
|
||||
|
for (i = 0; i < 32; i++) |
||||
|
ok1(bitops_ffs32(1 << i) == i+1); |
||||
|
ok1(bitops_ffs32(0) == 0); |
||||
|
for (i = 0; i < 64; i++) |
||||
|
ok1(bitops_ffs64((uint64_t)1 << i) == i+1); |
||||
|
ok1(bitops_ffs64(0) == 0); |
||||
|
|
||||
|
/* Higher bits don't affect result */ |
||||
|
for (i = 0; i < 32; i++) |
||||
|
ok1(bitops_ffs32(0xFFFFFFFFFFFFFFFFULL << i) == i+1); |
||||
|
ok1(bitops_ffs32(0) == 0); |
||||
|
for (i = 0; i < 64; i++) |
||||
|
ok1(bitops_ffs64(0xFFFFFFFFFFFFFFFFULL << i) == i+1); |
||||
|
ok1(bitops_ffs64(0) == 0); |
||||
|
|
||||
|
for (i = 0; i < 32; i++) |
||||
|
ok1(bitops_clz32(1 << i) == 31 - i); |
||||
|
for (i = 0; i < 64; i++) |
||||
|
ok1(bitops_clz64((uint64_t)1 << i) == 63 - i); |
||||
|
|
||||
|
/* Lower bits don't effect results */ |
||||
|
for (i = 0; i < 32; i++) |
||||
|
ok1(bitops_clz32((1 << i) + (1 << i)-1) == 31 - i); |
||||
|
for (i = 0; i < 64; i++) |
||||
|
ok1(bitops_clz64(((uint64_t)1 << i) + ((uint64_t)1 << i)-1) |
||||
|
== 63 - i); |
||||
|
|
||||
|
for (i = 0; i < 32; i++) |
||||
|
ok1(bitops_ctz32(1 << i) == i); |
||||
|
for (i = 0; i < 64; i++) |
||||
|
ok1(bitops_ctz64((uint64_t)1 << i) == i); |
||||
|
|
||||
|
/* Higher bits don't affect result */ |
||||
|
for (i = 0; i < 32; i++) |
||||
|
ok1(bitops_ctz32(0xFFFFFFFFFFFFFFFFULL << i) == i); |
||||
|
for (i = 0; i < 64; i++) |
||||
|
ok1(bitops_ctz64(0xFFFFFFFFFFFFFFFFULL << i) == i); |
||||
|
|
||||
|
/* Now we've tested low-level, test higher ones */ |
||||
|
ok1(bitops_ls32(1U) == 0); |
||||
|
ok1(bitops_ls32(0xFFFFFFFF) == 0); |
||||
|
ok1(bitops_ls32(1U << 31) == 31); |
||||
|
ok1(bitops_ls32(0xFFFF0000) == 16); |
||||
|
|
||||
|
ok1(bitops_ls64(1U) == 0); |
||||
|
ok1(bitops_ls64(0xFFFFFFFF) == 0); |
||||
|
ok1(bitops_ls64(1U << 31) == 31); |
||||
|
ok1(bitops_ls64(0xFFFF0000) == 16); |
||||
|
ok1(bitops_ls64((uint64_t)1 << 32) == 32); |
||||
|
ok1(bitops_ls64((uint64_t)1 << 63) == 63); |
||||
|
ok1(bitops_ls64(0xFFFFFFFFFFFF0000ULL) == 16); |
||||
|
ok1(bitops_ls64(0xFFFF000000000000ULL) == 48); |
||||
|
|
||||
|
ok1(bitops_hs32(1U) == 0); |
||||
|
ok1(bitops_hs32(0xFFFFFFFF) == 31); |
||||
|
ok1(bitops_hs32(1U << 31) == 31); |
||||
|
ok1(bitops_hs32(0xFFFF0000) == 31); |
||||
|
ok1(bitops_hs32(0x0000FFFF) == 15); |
||||
|
|
||||
|
ok1(bitops_hs64(1U) == 0); |
||||
|
ok1(bitops_hs64(0xFFFFFFFF) == 31); |
||||
|
ok1(bitops_hs64(1U << 31) == 31); |
||||
|
ok1(bitops_hs64(0xFFFF0000) == 31); |
||||
|
ok1(bitops_hs32(0x0000FFFF) == 15); |
||||
|
ok1(bitops_hs64((uint64_t)1 << 32) == 32); |
||||
|
ok1(bitops_hs64((uint64_t)1 << 63) == 63); |
||||
|
ok1(bitops_hs64(0xFFFFFFFFFFFF0000ULL) == 63); |
||||
|
ok1(bitops_hs64(0x0000FFFF00000000ULL) == 47); |
||||
|
|
||||
|
ok1(bitops_lc32(~(1U)) == 0); |
||||
|
ok1(bitops_lc32(~(0xFFFFFFFF)) == 0); |
||||
|
ok1(bitops_lc32(~(1U << 31)) == 31); |
||||
|
ok1(bitops_lc32(~(0xFFFF0000)) == 16); |
||||
|
|
||||
|
ok1(bitops_lc64(~(1U)) == 0); |
||||
|
ok1(bitops_lc64(~(0xFFFFFFFF)) == 0); |
||||
|
ok1(bitops_lc64(~(1U << 31)) == 31); |
||||
|
ok1(bitops_lc64(~(0xFFFF0000)) == 16); |
||||
|
ok1(bitops_lc64(~((uint64_t)1 << 32)) == 32); |
||||
|
ok1(bitops_lc64(~((uint64_t)1 << 63)) == 63); |
||||
|
ok1(bitops_lc64(~(0xFFFFFFFFFFFF0000ULL)) == 16); |
||||
|
ok1(bitops_lc64(~(0xFFFF000000000000ULL)) == 48); |
||||
|
|
||||
|
ok1(bitops_hc32(~(1U)) == 0); |
||||
|
ok1(bitops_hc32(~(0xFFFFFFFF)) == 31); |
||||
|
ok1(bitops_hc32(~(1U << 31)) == 31); |
||||
|
ok1(bitops_hc32(~(0xFFFF0000)) == 31); |
||||
|
ok1(bitops_hc32(~(0x0000FFFF)) == 15); |
||||
|
|
||||
|
ok1(bitops_hc64(~(1ULL)) == 0); |
||||
|
ok1(bitops_hc64(~(0xFFFFFFFFULL)) == 31); |
||||
|
ok1(bitops_hc64(~(1ULL << 31)) == 31); |
||||
|
ok1(bitops_hc64(~(0xFFFF0000ULL)) == 31); |
||||
|
ok1(bitops_hc64(~(0x0000FFFFULL)) == 15); |
||||
|
ok1(bitops_hc64(~((uint64_t)1 << 32)) == 32); |
||||
|
ok1(bitops_hc64(~((uint64_t)1 << 63)) == 63); |
||||
|
ok1(bitops_hc64(~(0xFFFFFFFFFFFF0000ULL)) == 63); |
||||
|
ok1(bitops_hc64(~(0x0000FFFF00000000ULL)) == 47); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
CCANDIR=../../.. |
||||
|
CFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -flto |
||||
|
#CFLAGS=-Wall -Werror -g3 -I$(CCANDIR)
|
||||
|
LDFLAGS := -flto -O3 |
||||
|
|
||||
|
all: speed |
||||
|
|
||||
|
CCAN_OBJS:=ccan-intmap.o ccan-time.o ccan-isaac64.o ccan-htable.o ccan-siphash24.o |
||||
|
|
||||
|
speed: speed.o $(CCAN_OBJS) |
||||
|
|
||||
|
clean: |
||||
|
rm -f speed *.o |
||||
|
|
||||
|
ccan-time.o: $(CCANDIR)/ccan/time/time.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-intmap.o: $(CCANDIR)/ccan/intmap/intmap.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-isaac64.o: $(CCANDIR)/ccan/isaac/isaac64.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-htable.o: $(CCANDIR)/ccan/htable/htable.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-siphash24.o: $(CCANDIR)/ccan/crypto/siphash24/siphash24.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
@ -0,0 +1,246 @@ |
|||||
|
/* Test speed of intmap */ |
||||
|
#include <ccan/time/time.h> |
||||
|
#include <ccan/intmap/intmap.h> |
||||
|
#include <ccan/isaac/isaac64.h> |
||||
|
#include <ccan/htable/htable_type.h> |
||||
|
#include <ccan/crypto/siphash24/siphash24.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <assert.h> |
||||
|
#include <inttypes.h> |
||||
|
|
||||
|
/* hack to let us gather span. */ |
||||
|
struct node { |
||||
|
/* These point to strings or nodes. */ |
||||
|
struct intmap child[2]; |
||||
|
/* Encoding both prefix and critbit: 1 is appended to prefix. */ |
||||
|
intmap_index_t prefix_and_critbit; |
||||
|
}; |
||||
|
|
||||
|
static void update_span(const void *p, size_t s, uintptr_t *min, uintptr_t *max) |
||||
|
{ |
||||
|
if ((uintptr_t)p < *min) |
||||
|
*min = (uintptr_t)p; |
||||
|
if ((uintptr_t)p + s > *max) |
||||
|
*max = (uintptr_t)p + s; |
||||
|
} |
||||
|
|
||||
|
static void getspan(const struct intmap *m, uintptr_t *min, uintptr_t *max) |
||||
|
{ |
||||
|
struct node *n; |
||||
|
/* Leaf node? */ |
||||
|
if (m->v) |
||||
|
return; |
||||
|
|
||||
|
n = m->u.n; |
||||
|
update_span(n, sizeof(*n), min, max); |
||||
|
getspan(&n->child[0], min, max); |
||||
|
getspan(&n->child[1], min, max); |
||||
|
} |
||||
|
|
||||
|
struct htable_elem { |
||||
|
uint64_t index; |
||||
|
uint64_t *v; |
||||
|
}; |
||||
|
|
||||
|
static struct siphash_seed sipseed; |
||||
|
|
||||
|
static uint64_t keyof(const struct htable_elem *elem) |
||||
|
{ |
||||
|
return elem->index; |
||||
|
} |
||||
|
|
||||
|
static size_t hashfn(const uint64_t index) |
||||
|
{ |
||||
|
return siphash24(&sipseed, &index, sizeof(index)); |
||||
|
} |
||||
|
|
||||
|
static bool eqfn(const struct htable_elem *elem, const uint64_t index) |
||||
|
{ |
||||
|
return elem->index == index; |
||||
|
} |
||||
|
HTABLE_DEFINE_TYPE(struct htable_elem, keyof, hashfn, eqfn, hash); |
||||
|
|
||||
|
static bool check_val(intmap_index_t i, uint64_t *v, uint64_t *expected) |
||||
|
{ |
||||
|
if (v != expected) |
||||
|
abort(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
uint64_t i, total = 0, seed, *v; |
||||
|
size_t max = argv[1] ? atol(argv[1]) : 100000000; |
||||
|
isaac64_ctx isaac; |
||||
|
struct timeabs start, end; |
||||
|
UINTMAP(uint64_t *) map; |
||||
|
struct hash hash; |
||||
|
struct htable_elem *e; |
||||
|
struct hash_iter it; |
||||
|
uintptr_t span_min, span_max; |
||||
|
|
||||
|
uintmap_init(&map); |
||||
|
hash_init(&hash); |
||||
|
|
||||
|
/* We don't want our randomness function to dominate the time,
|
||||
|
* nor deal with duplicates (just abort, that's v. unlikely) */ |
||||
|
seed = time_now().ts.tv_sec + time_now().ts.tv_nsec; |
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
|
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) |
||||
|
total += isaac64_next_uint64(&isaac); |
||||
|
end = time_now(); |
||||
|
printf("%zu,random generation (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (!uintmap_add(&map, isaac64_next_uint64(&isaac), &i)) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit insert (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (uintmap_get(&map, isaac64_next_uint64(&isaac)) != &i) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit successful lookup (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (uintmap_get(&map, isaac64_next_uint64(&isaac))) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit failed lookup (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (v = uintmap_first(&map, &i); v; v = uintmap_after(&map, &i)) { |
||||
|
if (v != &i) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit iteration (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
start = time_now(); |
||||
|
uintmap_iterate(&map, check_val, &i); |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit callback iteration (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
span_min = -1ULL; |
||||
|
span_max = 0; |
||||
|
getspan(uintmap_unwrap_(&map), &span_min, &span_max); |
||||
|
printf("%zu,critbit memory (bytes),%zu\n", |
||||
|
max, (size_t)(span_max - span_min + max / 2) / max); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (!uintmap_del(&map, isaac64_next_uint64(&isaac))) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit delete (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
/* Fill with consecutive values */ |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (!uintmap_add(&map, i, &i)) |
||||
|
abort(); |
||||
|
} |
||||
|
start = time_now(); |
||||
|
for (v = uintmap_first(&map, &i); v; v = uintmap_after(&map, &i)) { |
||||
|
if (v != &i) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit consecutive iteration (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
start = time_now(); |
||||
|
uintmap_iterate(&map, check_val, &i); |
||||
|
end = time_now(); |
||||
|
printf("%zu,critbit consecutive callback iteration (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
sipseed.u.u64[0] = isaac64_next_uint64(&isaac); |
||||
|
sipseed.u.u64[1] = isaac64_next_uint64(&isaac); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
e = malloc(sizeof(*e)); |
||||
|
e->v = &i; |
||||
|
e->index = isaac64_next_uint64(&isaac); |
||||
|
hash_add(&hash, e); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,hash insert (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (hash_get(&hash, isaac64_next_uint64(&isaac))->v != &i) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,hash successful lookup (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
if (hash_get(&hash, isaac64_next_uint64(&isaac))) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,hash failed lookup (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (e = hash_first(&hash, &it); e; e = hash_next(&hash, &it)) { |
||||
|
if (e->v != &i) |
||||
|
abort(); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,hash iteration (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
span_min = -1ULL; |
||||
|
span_max = 0; |
||||
|
for (e = hash_first(&hash, &it); e; e = hash_next(&hash, &it)) |
||||
|
update_span(e, sizeof(*e), &span_min, &span_max); |
||||
|
/* table itself tends to be allocated in separate memory. */ |
||||
|
span_max += (sizeof(uintptr_t) << hash.raw.bits); |
||||
|
printf("%zu,hash memory (bytes),%zu\n", |
||||
|
max, (size_t)(span_max - span_min + max / 2) / max); |
||||
|
|
||||
|
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
||||
|
start = time_now(); |
||||
|
for (i = 0; i < max; i++) { |
||||
|
e = hash_get(&hash, isaac64_next_uint64(&isaac)); |
||||
|
if (!hash_del(&hash, e)) |
||||
|
abort(); |
||||
|
free(e); |
||||
|
} |
||||
|
end = time_now(); |
||||
|
printf("%zu,hash delete (nsec),%"PRIu64"\n", max, |
||||
|
time_to_nsec(time_divide(time_between(end, start), max))); |
||||
|
|
||||
|
/* Use total, but "never happens". */ |
||||
|
return (total == 0); |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
#include <ccan/bitops/bitops.h> |
||||
|
#include <ccan/intmap/intmap.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <stdio.h> |
||||
|
|
||||
|
#define ELEMENTS 8 |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
UINTMAP(void *) umap; |
||||
|
|
||||
|
plan_tests((1 << ELEMENTS) * ELEMENTS); |
||||
|
|
||||
|
/* Run through every combination of elements */ |
||||
|
for (int i = 0; i < (1 << ELEMENTS); i++) { |
||||
|
/* Set up map */ |
||||
|
uintmap_init(&umap); |
||||
|
for (int j = 0; j < ELEMENTS; j++) { |
||||
|
if ((1 << j) & i) |
||||
|
uintmap_add(&umap, j, &umap); |
||||
|
} |
||||
|
|
||||
|
/* Try each uintmap_after value */ |
||||
|
for (int j = 0; j < ELEMENTS; j++) { |
||||
|
intmap_index_t idx = j, next; |
||||
|
|
||||
|
if ((i >> (j + 1)) == 0) |
||||
|
next = 0; |
||||
|
else |
||||
|
next = j + 1 + bitops_ls32(i >> (j + 1)); |
||||
|
|
||||
|
if (!uintmap_after(&umap, &idx)) |
||||
|
idx = 0; |
||||
|
ok1(idx == next); |
||||
|
} |
||||
|
uintmap_clear(&umap); |
||||
|
} |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
#include <ccan/intmap/intmap.h> |
||||
|
#include <ccan/intmap/intmap.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
UINTMAP(const char *) map; |
||||
|
u64 idx; |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(2); |
||||
|
|
||||
|
uintmap_init(&map); |
||||
|
assert(uintmap_add(&map, 0x103, "103")); |
||||
|
assert(uintmap_add(&map, 0x10b, "10b")); |
||||
|
|
||||
|
uintmap_first(&map, &idx); |
||||
|
ok1(idx > 0xF); |
||||
|
idx = 0xF; |
||||
|
ok1(strcmp(uintmap_after(&map, &idx), "103") == 0); |
||||
|
|
||||
|
uintmap_clear(&map); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
Loading…
Reference in new issue