changeset 795:952b4ab949eb

int: add is_p2 function to check if an integer is a power of two Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Sat, 28 Mar 2020 10:36:52 -0400
parents d018af7c979c
children cf1cd2707dfb
files include/jeffpc/int.h tests/.hgignore tests/CMakeLists.txt tests/test_is_p2.c
diffstat 4 files changed, 94 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/include/jeffpc/int.h	Sun Mar 15 15:52:09 2020 +0200
+++ b/include/jeffpc/int.h	Sat Mar 28 10:36:52 2020 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ * Copyright (c) 2016-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,7 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include <jeffpc/config.h>
@@ -108,6 +109,15 @@
 #define str2u8(s, i)	str2u8_full((s), (i), 10, '\0')
 
 /*
+ * Powers of 2 mangling
+ */
+/* is the value a power of two? */
+static inline bool is_p2(uint64_t val)
+{
+	return !(val & (val - 1));
+}
+
+/*
  * These prototypes exist to catch bugs in the code generating macros below.
  */
 /* return byte swapped input */
--- a/tests/.hgignore	Sun Mar 15 15:52:09 2020 +0200
+++ b/tests/.hgignore	Sat Mar 28 10:36:52 2020 -0400
@@ -14,6 +14,7 @@
 test_endian
 test_errno
 test_hexdump
+test_is_p2
 test_list
 test_mutex-destroy-held
 test_mutex-destroy-memcpy
--- a/tests/CMakeLists.txt	Sun Mar 15 15:52:09 2020 +0200
+++ b/tests/CMakeLists.txt	Sat Mar 28 10:36:52 2020 -0400
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+# Copyright (c) 2016-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -40,6 +40,7 @@
 build_test_bin_and_run(endian)
 build_test_bin_and_run(errno)
 build_test_bin_and_run(hexdump)
+build_test_bin_and_run(is_p2)
 build_test_bin_and_run(list)
 build_test_bin_and_run(mutex-destroy-memcpy)
 build_test_bin_and_run(mutex-destroy-null)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_is_p2.c	Sat Mar 28 10:36:52 2020 -0400
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <jeffpc/int.h>
+
+#include "test.c"
+
+#define CHECK(name, idx, _val, exp)					\
+	do {								\
+		const uint64_t v = (_val);				\
+									\
+		fprintf(stderr, "%s: %2d: is_p2(%#018"PRIx64")...",	\
+			(name), (idx), v);				\
+									\
+		if (is_p2(v) != (exp))					\
+			fail("expected %s, got %s",			\
+			     (exp) ? "true" : "false",			\
+			     (exp) ? "false" : "true");			\
+									\
+		fprintf(stderr, "ok.\n");				\
+	} while (0)
+
+static void test_powers(void)
+{
+	int i;
+
+	CHECK("powers", 0, 0ul, true);
+
+	for (i = 0; i < 64; i++)
+		CHECK("powers", i + 1, 1ull << i, true);
+}
+
+static void test_nonpowers(void)
+{
+	int i;
+
+	/*
+	 * There are many non-powers, so we cannot test them all.
+	 * Therefore, we check only a subset.
+	 */
+
+	/* all powers of two + 1 */
+	for (i = 0; i < 64; i++) {
+		const uint64_t val = (1ull << i) + 1;
+
+		CHECK("p2+1", i + 1, val, val <= 2);
+	}
+
+	/* all powers of two - 1 */
+	for (i = 0; i < 64; i++) {
+		const uint64_t val = (1ull << i) - 1;
+
+		CHECK("p2-1", i + 1, val, val <= 2);
+	}
+}
+
+void test(void)
+{
+	test_powers();
+	test_nonpowers();
+}