From: Youngjae Cho Date: Wed, 12 Jul 2023 10:05:44 +0000 (+0900) Subject: libcommon: Introduce bitmap X-Git-Tag: accepted/tizen/unified/riscv/20230718.003634~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2b794736a23ff141b160862adc18f49b3c604b7e;p=platform%2Fcore%2Fsystem%2Flibsyscommon.git libcommon: Introduce bitmap These have come from the deviced. Change-Id: I8d5eb95703d32d8fd17054c4446378adb4db97b2 Signed-off-by: Youngjae Cho --- diff --git a/src/libcommon/bitmap.c b/src/libcommon/bitmap.c new file mode 100644 index 0000000..07a7117 --- /dev/null +++ b/src/libcommon/bitmap.c @@ -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 +#include +#include + +#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 index 0000000..75ff7c5 --- /dev/null +++ b/src/libcommon/bitmap.h @@ -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 + +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 diff --git a/tests/libcommon/test-common.c b/tests/libcommon/test-common.c index 392830a..3b988f9 100644 --- a/tests/libcommon/test-common.c +++ b/tests/libcommon/test-common.c @@ -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);