libcommon: Introduce bitmap 94/295694/2
authorYoungjae Cho <y0.cho@samsung.com>
Wed, 12 Jul 2023 10:05:44 +0000 (19:05 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Thu, 13 Jul 2023 02:46:56 +0000 (11:46 +0900)
These have come from the deviced.

Change-Id: I8d5eb95703d32d8fd17054c4446378adb4db97b2
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
src/libcommon/bitmap.c [new file with mode: 0644]
src/libcommon/bitmap.h [new file with mode: 0644]
tests/libcommon/test-common.c

diff --git a/src/libcommon/bitmap.c b/src/libcommon/bitmap.c
new file mode 100644 (file)
index 0000000..07a7117
--- /dev/null
@@ -0,0 +1,199 @@
+/* MIT License
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "bitmap.h"
+#include "shared/log.h"
+
+/**
+ * Align bits by size of long, and convert it to long,
+ * for example, if long is 64bit then,
+ *   ROUNDUP_BITS_TO_LONGS(0) -> 0
+ *   ROUNDUP_BITS_TO_LONGS(1) -> 1
+ *   ROUNDUP_BITS_TO_LONGS(64) -> 1
+ *   ROUNDUP_BITS_TO_LONGS(65) -> 2
+ *   ROUNDUP_BITS_TO_LONGS(128) -> 2
+ *   ROUNDUP_BITS_TO_LONGS(129) -> 3
+ *   ...
+ */
+#define BYTES_PER_LONG                 (sizeof(unsigned long))
+#define BITS_PER_LONG                  (BYTES_PER_LONG * 8)
+#define ROUNDUP(n, d)                  ((((n) + (d) - 1) / (d)) * (d))
+#define ROUNDUP_BITS_TO_LONGS(nbits)   (ROUNDUP(nbits, BITS_PER_LONG) / BITS_PER_LONG)
+
+#define BIT_WORD(nr)                   ((nr) / BITS_PER_LONG)
+#define BIT_MASK(nr)                   (1UL << ((nr) % BITS_PER_LONG))
+#define BITMAP_MARGIN                  (BYTES_PER_LONG * 2) /* trailing margin for safety, bytes */
+
+struct syscommon_bitmap {
+       /* bitmap */
+       unsigned long *b;
+
+       /* number of bits, not the maximum bit.
+        * maximum bit is size - 1 */
+       unsigned long size;
+};
+
+static void bitmap_alloc_size(struct syscommon_bitmap *bm, unsigned int nbits)
+{
+       unsigned int bytes = ROUNDUP_BITS_TO_LONGS(nbits) * BYTES_PER_LONG;
+
+       bytes += BITMAP_MARGIN;
+
+       bm->b = (unsigned long *) malloc(bytes);
+       if (!bm->b)
+               return;
+
+       bm->size = nbits;
+}
+
+void syscommon_bitmap_set_all_bits(struct syscommon_bitmap *bm)
+{
+       unsigned long complete_longs;
+       unsigned long complete_bytes;
+       unsigned long residue_bits;
+
+       if (!bm)
+               return;
+
+       complete_longs = bm->size / BITS_PER_LONG;
+       complete_bytes = complete_longs * BYTES_PER_LONG;
+       residue_bits = bm->size % BITS_PER_LONG;
+
+       /* set all bits of the long element except the last long element */
+       memset(bm->b, ~0, complete_bytes);
+
+       /* set residue bits in the last long element */
+       if (residue_bits)
+               bm->b[complete_longs] = (1UL << residue_bits) - 1;
+}
+
+void syscommon_bitmap_clear_all_bits(struct syscommon_bitmap *bm)
+{
+       unsigned int bytes;
+
+       if (!bm)
+               return;
+
+       bytes = ROUNDUP_BITS_TO_LONGS(bm->size) * BYTES_PER_LONG;
+
+       memset(bm->b, 0, bytes);
+}
+
+void syscommon_bitmap_set_bit(struct syscommon_bitmap *bm, unsigned long nr)
+{
+       if (!bm)
+               return;
+
+       if (nr >= bm->size) {
+               _E("Requested nr=%lu exceeds max bit=%lu", nr, bm->size - 1);
+               return;
+       }
+
+       bm->b[BIT_WORD(nr)] |= BIT_MASK(nr);
+}
+
+void syscommon_bitmap_clear_bit(struct syscommon_bitmap *bm, unsigned long nr)
+{
+       if (!bm)
+               return;
+
+       if (nr >= bm->size) {
+               _E("Requested nr=%lu exceeds max bit=%lu", nr, bm->size - 1);
+               return;
+       }
+
+       bm->b[BIT_WORD(nr)] &= ~BIT_MASK(nr);
+}
+
+bool syscommon_bitmap_test_bit(struct syscommon_bitmap *bm, unsigned long nr)
+{
+       if (!bm)
+               return false;
+
+       if (nr >= bm->size) {
+               _E("Requested nr=%lu exceeds max bit=%lu", nr, bm->size - 1);
+               return false;
+       }
+
+       return bm->b[BIT_WORD(nr)] & BIT_MASK(nr);
+}
+
+int syscommon_bitmap_count_set_bit(struct syscommon_bitmap *bm)
+{
+       int i;
+       int count = 0;
+
+       if (!bm)
+               return -1;
+
+       for (i = 0; i < ROUNDUP_BITS_TO_LONGS(bm->size); ++i)
+               count += __builtin_popcountl(bm->b[i]);
+
+       return count;
+}
+
+int syscommon_bitmap_count_unset_bit(struct syscommon_bitmap *bm)
+{
+       if (!bm)
+               return -1;
+
+       return bm->size - syscommon_bitmap_count_set_bit(bm);
+}
+
+struct syscommon_bitmap* syscommon_bitmap_init_bitmap(unsigned int nbits)
+{
+       struct syscommon_bitmap *bm = NULL;
+
+       if (nbits == 0)
+               return NULL;
+
+       bm = (struct syscommon_bitmap *) malloc(sizeof(struct syscommon_bitmap));
+       if (!bm)
+               return NULL;
+
+       bm->b = NULL;
+       bm->size = 0;
+
+       bitmap_alloc_size(bm, nbits);
+       if (!bm->b) {
+               free(bm);
+               return NULL;
+       }
+
+       syscommon_bitmap_clear_all_bits(bm);
+       bm->size = nbits;
+
+       return bm;
+}
+
+void syscommon_bitmap_deinit_bitmap(struct syscommon_bitmap *bm)
+{
+       if (!bm)
+               return;
+
+       free(bm->b);
+       free(bm);
+}
diff --git a/src/libcommon/bitmap.h b/src/libcommon/bitmap.h
new file mode 100644 (file)
index 0000000..75ff7c5
--- /dev/null
@@ -0,0 +1,40 @@
+/* MIT License
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * 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. */
+
+#ifndef __SYSCOMMON_BITMAP_H__
+#define __SYSCOMMON_BITMAP_H__
+
+#include <stdbool.h>
+
+struct syscommon_bitmap;
+
+void syscommon_bitmap_set_bit(struct syscommon_bitmap *b, unsigned long nr);
+void syscommon_bitmap_clear_bit(struct syscommon_bitmap *b, unsigned long nr);
+bool syscommon_bitmap_test_bit(struct syscommon_bitmap *b, unsigned long nr);
+void syscommon_bitmap_set_all_bits(struct syscommon_bitmap *b);
+void syscommon_bitmap_clear_all_bits(struct syscommon_bitmap *b);
+int syscommon_bitmap_count_set_bit(struct syscommon_bitmap *b);
+int syscommon_bitmap_count_unset_bit(struct syscommon_bitmap *b);
+struct syscommon_bitmap* syscommon_bitmap_init_bitmap(unsigned int nbits);
+void syscommon_bitmap_deinit_bitmap(struct syscommon_bitmap *b);
+
+#endif
index 392830a..3b988f9 100644 (file)
@@ -9,6 +9,7 @@
 #include "libcommon/file.h"
 #include "libcommon/list.h"
 #include "libcommon/ini-parser.h"
+#include "libcommon/bitmap.h"
 #include "../test-main.h"
 #include "../test-mock.h"
 
@@ -193,6 +194,85 @@ static void test_config_parse_p(void **state)
        assert_false(garbage);
 }
 
+static void test_init_bitmap_p(void **state)
+{
+       struct syscommon_bitmap *bm;
+
+       bm = syscommon_bitmap_init_bitmap(10);
+       assert_non_null(bm);
+
+       syscommon_bitmap_deinit_bitmap(bm);
+}
+
+static void test_init_bitmap_n(void **state)
+{
+       struct syscommon_bitmap *bm = NULL;
+
+       bm = syscommon_bitmap_init_bitmap(0);
+       assert_null(bm);
+}
+
+static void test_test_bit(void **state)
+{
+       struct syscommon_bitmap *bm;
+       const int bmsize = 37;
+       bool bit;
+       int i, nbit;
+
+       bm = syscommon_bitmap_init_bitmap(bmsize);
+       assert_non_null(bm);
+
+       for (i = 0; i < bmsize; ++i) {
+               bit = syscommon_bitmap_test_bit(bm, i);
+               assert_false(bit);
+       }
+
+       /* count bit by setting one by one */
+       for (i = 0; i < bmsize; ++i) {
+               syscommon_bitmap_set_bit(bm, i);
+               nbit = syscommon_bitmap_count_set_bit(bm);
+               assert_int_equal(nbit, i + 1);
+       }
+
+       /* test the marginal bit */
+       bit = syscommon_bitmap_test_bit(bm, 0);
+       assert_true(bit);
+       bit = syscommon_bitmap_test_bit(bm, bmsize - 1);
+       assert_true(bit);
+       bit = syscommon_bitmap_test_bit(bm, bmsize);
+       assert_false(bit);
+
+
+       /* count bit by clearing one by one */
+       for (i = 0; i < bmsize; ++i) {
+               syscommon_bitmap_clear_bit(bm, i);
+               nbit = syscommon_bitmap_count_set_bit(bm);
+               assert_int_equal(nbit, bmsize - i - 1);
+       }
+
+       syscommon_bitmap_deinit_bitmap(bm);
+}
+
+static void test_all_bit(void **state)
+{
+       struct syscommon_bitmap *bm;
+       const int bmsize = 37;
+       int nbit;
+
+       bm = syscommon_bitmap_init_bitmap(bmsize);
+       assert_non_null(bm);
+
+       syscommon_bitmap_set_all_bits(bm);
+       nbit = syscommon_bitmap_count_set_bit(bm);
+       assert_int_equal(nbit, bmsize);
+
+       syscommon_bitmap_clear_all_bits(bm);
+       nbit = syscommon_bitmap_count_set_bit(bm);
+       assert_int_equal(nbit, 0);
+
+       syscommon_bitmap_deinit_bitmap(bm);
+}
+
 int run_test_suite(void)
 {
        const struct CMUnitTest testsuite[] = {
@@ -202,6 +282,10 @@ int run_test_suite(void)
                cmocka_unit_test(test_list_append_p),
                cmocka_unit_test(test_list_prepend_p),
                cmocka_unit_test(test_config_parse_p),
+               cmocka_unit_test(test_init_bitmap_p),
+               cmocka_unit_test(test_init_bitmap_n),
+               cmocka_unit_test(test_test_bit),
+               cmocka_unit_test(test_all_bit),
        };
 
        return cmocka_run_group_tests(testsuite, NULL, NULL);