diff options
author | Thomas Haller <thaller@redhat.com> | 2015-05-12 09:24:05 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-06-17 11:41:43 +0200 |
commit | 0a3c1f57741677e21ec9efb9c67bfac81c31d208 (patch) | |
tree | 3035ab63e870fca5792433e131c340f9fbd637e2 | |
parent | 56b07b1a3f26da472ae93ffb94a5928390057ef8 (diff) | |
download | NetworkManager-0a3c1f57741677e21ec9efb9c67bfac81c31d208.tar.gz |
utils: add nm_utils_is_power_of_two() macro
-rw-r--r-- | include/nm-macros-internal.h | 17 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 98 |
2 files changed, 115 insertions, 0 deletions
diff --git a/include/nm-macros-internal.h b/include/nm-macros-internal.h index 9be6b0f321..0cb85cea74 100644 --- a/include/nm-macros-internal.h +++ b/include/nm-macros-internal.h @@ -181,6 +181,23 @@ nm_clear_g_source (guint *id) /*****************************************************************************/ +/* Determine whether @x is a power of two (@x being an integer type). + * For the special cases @x equals zero or one, it also returns true. + * For negative @x, always returns FALSE. That only applies, is the data + * type of @x is signed. */ +#define nm_utils_is_power_of_two(x) ({ \ + const typeof(x) __x = (x); \ + \ + ((__x & (__x - 1)) == 0) && \ + /* Check if the value is negative. In that case, return FALSE. + * The first expression is a compile time constant, depending on whether + * the type is signed. The second expression is a clumsy way for (__x >= 0), + * which causes a compiler warning for unsigned types. */ \ + ( ( ((typeof(__x)) -1) > ((typeof(__x)) 0) ) || (__x > 0) || (__x == 0) ); \ + }) + +/*****************************************************************************/ + /* check if @flags has exactly one flag (@check) set. You should call this * only with @check being a compile time constant and a power of two. */ #define NM_FLAGS_HAS(flags, check) \ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 1aca515a88..106b67606e 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4358,6 +4358,103 @@ test_nm_utils_dns_option_find_idx (void) /******************************************************************************/ +enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED { + _DUMMY_1 = -1, +}; + +enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED { + _DUMMY_2, +}; + +enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED_64 { + _DUMMY_3 = (1LL << 40), +}; + +enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED_64 { + _DUMMY_4a = -1, + _DUMMY_4b = (1LL << 40), +}; + +#define test_nm_utils_is_power_of_two_do(type, x, expect) \ + G_STMT_START { \ + typeof (x) x1 = (x); \ + type x2 = (type) x1; \ + \ + if (((typeof (x1)) x2) == x1 && (x2 > 0 || x2 == 0)) { \ + /* x2 equals @x, and is positive. Compare to @expect */ \ + g_assert_cmpint (expect, ==, nm_utils_is_power_of_two (x2)); \ + } else if (!(x2 > 0) && !(x2 == 0)) { \ + /* a (signed) negative value is always FALSE. */ \ + g_assert_cmpint (FALSE, ==, nm_utils_is_power_of_two (x2));\ + } \ + g_assert_cmpint (expect, ==, nm_utils_is_power_of_two (x1)); \ + } G_STMT_END + +static void +test_nm_utils_is_power_of_two () +{ + guint64 xyes, xno; + gint i, j; + GRand *rand = nmtst_get_rand (); + int numbits; + + for (i = -1; i < 64; i++) { + + /* find a (positive) x which is a power of two. */ + if (i == -1) + xyes = 0; + else { + xyes = (1LL << i); + g_assert (xyes != 0); + } + + xno = xyes; + if (xyes != 0) { +again: + /* Find another @xno, that is not a power of two. Do that, + * by randomly setting bits. */ + numbits = g_rand_int_range (rand, 1, 65); + while (xno != ~((guint64) 0) && numbits > 0) { + guint64 v = (1LL << g_rand_int_range (rand, 0, 65)); + + if ((xno | v) != xno) { + xno |= v; + --numbits; + } + } + if (xno == xyes) + goto again; + } + + for (j = 0; j < 2; j++) { + gboolean expect = j == 0; + guint64 x = expect ? xyes : xno; + + if (!expect && xno == 0) + continue; + + /* check if @x is as @expect, when casted to a certain data type. */ + test_nm_utils_is_power_of_two_do (gint8, x, expect); + test_nm_utils_is_power_of_two_do (guint8, x, expect); + test_nm_utils_is_power_of_two_do (gint16, x, expect); + test_nm_utils_is_power_of_two_do (guint16, x, expect); + test_nm_utils_is_power_of_two_do (gint32, x, expect); + test_nm_utils_is_power_of_two_do (guint32, x, expect); + test_nm_utils_is_power_of_two_do (gint64, x, expect); + test_nm_utils_is_power_of_two_do (guint64, x, expect); + test_nm_utils_is_power_of_two_do (char, x, expect); + test_nm_utils_is_power_of_two_do (unsigned char, x, expect); + test_nm_utils_is_power_of_two_do (signed char, x, expect); + test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED, x, expect); + test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED, x, expect); + test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_SIGNED_64, x, expect); + test_nm_utils_is_power_of_two_do (enum TEST_IS_POWER_OF_TWP_ENUM_UNSIGNED_64, x, expect); + } + } +} + +/******************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -4459,6 +4556,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/_nm_utils_uuid_generate_from_strings", test_nm_utils_uuid_generate_from_strings); g_test_add_func ("/core/general/_nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64); + g_test_add_func ("/core/general/nm_utils_is_power_of_two", test_nm_utils_is_power_of_two); g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate); g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx); |