From e93ab5531c808c63a7ac4a12739530982ba0eaeb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 25 Apr 2013 11:18:10 -0700 Subject: [PATCH] util: New macros ROUND_UP_POW2, ROUND_DOWN_POW2. Signed-off-by: Ben Pfaff --- lib/util.h | 19 ++++++++++++++ tests/library.at | 2 ++ tests/test-util.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/lib/util.h b/lib/util.h index ae8bfd7a2..2159594cb 100644 --- a/lib/util.h +++ b/lib/util.h @@ -108,6 +108,25 @@ is_pow2(uintmax_t x) return IS_POW2(x); } +/* Returns X rounded up to a power of 2. X must be a constant expression. */ +#define ROUND_UP_POW2(X) RUP2__(X) +#define RUP2__(X) (RUP2_1(X) + 1) +#define RUP2_1(X) (RUP2_2(X) | (RUP2_2(X) >> 16)) +#define RUP2_2(X) (RUP2_3(X) | (RUP2_3(X) >> 8)) +#define RUP2_3(X) (RUP2_4(X) | (RUP2_4(X) >> 4)) +#define RUP2_4(X) (RUP2_5(X) | (RUP2_5(X) >> 2)) +#define RUP2_5(X) (RUP2_6(X) | (RUP2_6(X) >> 1)) +#define RUP2_6(X) ((X) - 1) + +/* Returns X rounded down to a power of 2. X must be a constant expression. */ +#define ROUND_DOWN_POW2(X) RDP2__(X) +#define RDP2__(X) (RDP2_1(X) - (RDP2_1(X) >> 1)) +#define RDP2_1(X) (RDP2_2(X) | (RDP2_2(X) >> 16)) +#define RDP2_2(X) (RDP2_3(X) | (RDP2_3(X) >> 8)) +#define RDP2_3(X) (RDP2_4(X) | (RDP2_4(X) >> 4)) +#define RDP2_4(X) (RDP2_5(X) | (RDP2_5(X) >> 2)) +#define RDP2_5(X) ( (X) | ( (X) >> 1)) + #ifndef MIN #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #endif diff --git a/tests/library.at b/tests/library.at index 541a41687..ded0a2230 100644 --- a/tests/library.at +++ b/tests/library.at @@ -112,6 +112,8 @@ AT_CLEANUP m4_foreach( [testname], [[ctz], + [round_up_pow2], + [round_down_pow2], [popcount], [log_2_floor], [bitwise_copy], diff --git a/tests/test-util.c b/tests/test-util.c index 5afe2f7c5..6bf8ed52c 100644 --- a/tests/test-util.c +++ b/tests/test-util.c @@ -90,6 +90,69 @@ test_ctz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) check_ctz(0, 32); } +/* Returns a random number in the range 'min'...'max' inclusive. */ +static uint32_t +random_in_range(uint32_t min, uint32_t max) +{ + return min == max ? min : min + random_range(max - min + 1); +} + +static void +check_rup2(uint32_t x, int n) +{ + uint32_t rup2 = ROUND_UP_POW2(x); + if (rup2 != n) { + fprintf(stderr, "ROUND_UP_POW2(%#"PRIx32") is %#"PRIx32" " + "but should be %#"PRIx32"\n", x, rup2, n); + abort(); + } +} + +static void +test_round_up_pow2(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +{ + int n; + + for (n = 0; n < 32; n++) { + /* Min, max value for which ROUND_UP_POW2 should yield (1 << n). */ + uint32_t min = ((1u << n) >> 1) + 1; + uint32_t max = 1u << n; + + check_rup2(min, 1u << n); + check_rup2(max, 1u << n); + check_rup2(random_in_range(min, max), 1u << n); + } + check_rup2(0, 0); +} + +static void +check_rdp2(uint32_t x, int n) +{ + uint32_t rdp2 = ROUND_DOWN_POW2(x); + if (rdp2 != n) { + fprintf(stderr, "ROUND_DOWN_POW2(%#"PRIx32") is %#"PRIx32" " + "but should be %#"PRIx32"\n", x, rdp2, n); + abort(); + } +} + +static void +test_round_down_pow2(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) +{ + int n; + + for (n = 0; n < 32; n++) { + /* Min, max value for which ROUND_DOWN_POW2 should yield (1 << n). */ + uint32_t min = 1u << n; + uint32_t max = ((1u << n) << 1) - 1; + + check_rdp2(min, 1u << n); + check_rdp2(max, 1u << n); + check_rdp2(random_in_range(min, max), 1u << n); + } + check_rdp2(0, 0); +} + static void shuffle(unsigned int *p, size_t n) { @@ -346,6 +409,8 @@ test_assert(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) static const struct command commands[] = { {"ctz", 0, 0, test_ctz}, + {"round_up_pow2", 0, 0, test_round_up_pow2}, + {"round_down_pow2", 0, 0, test_round_down_pow2}, {"popcount", 0, 0, test_popcount}, {"log_2_floor", 0, 0, test_log_2_floor}, {"bitwise_copy", 0, 0, test_bitwise_copy}, -- 2.43.0