diff --git a/src/ucs/datastruct/bitmap.h b/src/ucs/datastruct/bitmap.h index 20c0af1ca16..5d962fb7119 100644 --- a/src/ucs/datastruct/bitmap.h +++ b/src/ucs/datastruct/bitmap.h @@ -7,7 +7,10 @@ #ifndef UCS_BITMAP_H_ #define UCS_BITMAP_H_ +#include +#include #include +#include #include BEGIN_C_DECLS @@ -23,7 +26,17 @@ typedef uint64_t ucs_bitmap_word_t; (sizeof(ucs_bitmap_word_t) * 8) -/* +/** + * Get the number of words in a given bitmap + * + * @param _bitmap Words number in this bitmap + * + * @return Number of words + */ +#define _UCS_BITMAP_NUM_WORDS(_bitmap) ucs_static_array_size((_bitmap).bits) + + +/** * Word index of a bit in bitmap * * @param _bit_index Index of this bit relative to the bitmap @@ -42,19 +55,103 @@ typedef uint64_t ucs_bitmap_word_t; ((((_length) + (UCS_BITMAP_BITS_IN_WORD - 1)) / UCS_BITMAP_BITS_IN_WORD)) -#define _UCS_BITMAP_WORD(_bitmap, _index) \ - ((_bitmap)->bits[UCS_BITMAP_WORD_INDEX(_index)]) +#define _UCS_BITMAP_WORD(_bitmap, _word_index) ((_bitmap).bits[_word_index]) + + +/** + * Given a bitmap and a bit index, get the whole word that contains it + * + * @param _bitmap Take the word from this bitmap + * @param _bit_index Index of the bit for fetching the word + * + * @return The word which containt + */ +#define _UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) \ + _UCS_BITMAP_WORD((_bitmap), UCS_BITMAP_WORD_INDEX(_bit_index)) #define _UCS_BITMAP_WORD_INDEX0(_bit_index) \ ((_bit_index) & ~(UCS_BITMAP_BITS_IN_WORD - 1)) -#define _UCS_BITMAP_GET_NEXT_BIT(_index) \ - (-2ull << (uint64_t)((_index) & (UCS_BITMAP_BITS_IN_WORD - 1))) +#define _UCS_BITMAP_GET_NEXT_BIT(_bit_index) \ + (-2ull << (uint64_t)((_bit_index) & (UCS_BITMAP_BITS_IN_WORD - 1))) -/* +#define _UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) \ + for (_word_index = 0; _word_index < _UCS_BITMAP_NUM_WORDS(_bitmap); \ + _word_index++) + + +/** + * Perform inplace bitwise NOT of a bitmap + * + * @param _bitmap Negate this bitmap + */ +#define UCS_BITMAP_NOT_INPLACE(_bitmap) \ + { \ + size_t _word_index; \ + _UCS_BITMAP_FOR_EACH_WORD(*(_bitmap), _word_index) { \ + _UCS_BITMAP_WORD(*(_bitmap), _word_index) = \ + ~_UCS_BITMAP_WORD(*(_bitmap), _word_index); \ + } \ + } + + +#define _UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, _op) \ + { \ + typeof(*(_bitmap1)) _bitmap2_copy = (_bitmap2); \ + size_t _word_index; \ + _UCS_BITMAP_FOR_EACH_WORD(*(_bitmap1), _word_index) { \ + _UCS_BITMAP_WORD(*(_bitmap1), _word_index) = \ + _UCS_BITMAP_WORD(*(_bitmap1), _word_index) _op \ + _UCS_BITMAP_WORD(_bitmap2_copy, _word_index); \ + } \ + } + + +/** + * Perform inplace bitwise AND of 2 bitmaps, storing the result in the first one + * + * @param _bitmap1 First operand + * @param _bitmap2 Second operand + */ +#define UCS_BITMAP_AND_INPLACE(_bitmap1, _bitmap2) \ + _UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, &) + + +/** + * Perform inplace bitwise OR of 2 bitmaps, storing the result in the first one + * + * @param _bitmap1 First operand + * @param _bitmap2 Second operand + */ +#define UCS_BITMAP_OR_INPLACE(_bitmap1, _bitmap2) \ + _UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, |) + + +/** + * Perform inplace bitwise XOR of 2 bitmaps, storing the result in the first one + * + * @param _bitmap1 First operand + * @param _bitmap2 Second operand + */ +#define UCS_BITMAP_XOR_INPLACE(_bitmap1, _bitmap2) \ + _UCS_BITMAP_OP_INPLACE(_bitmap1, _bitmap2, ^) + + +/** + * Check whether all bits of a given bitmap are set to 0 + * + * @param _bitmap Check bits of this bitmap + * + * @return Whether this bitmap consists only of bits set to 0 + */ +#define UCS_BITMAP_IS_ZERO(_bitmap) \ + _ucs_bitmap_is_zero(&_bitmap, _UCS_BITMAP_NUM_WORDS(_bitmap)) + + +/** * Represents an n-bit bitmap, by using an array * of 64-bit unsigned long integers. * @@ -63,7 +160,35 @@ typedef uint64_t ucs_bitmap_word_t; #define _UCS_BITMAP_DECLARE_TYPE(_length) \ typedef struct { \ ucs_bitmap_word_t bits[_UCS_BITMAP_BITS_TO_WORDS(_length)]; \ - } ucs_bitmap_t(_length); + } ucs_bitmap_t(_length); \ + \ + static inline ucs_bitmap_t(_length) \ + _ucs_bitmap_##_length##_not(ucs_bitmap_t(_length) bitmap) \ + { \ + UCS_BITMAP_NOT_INPLACE(&bitmap); \ + return bitmap; \ + } \ + \ + static inline ucs_bitmap_t(_length) _ucs_bitmap_##_length##_and( \ + ucs_bitmap_t(_length) bitmap1, ucs_bitmap_t(_length) bitmap2) \ + { \ + UCS_BITMAP_AND_INPLACE(&bitmap1, bitmap2); \ + return bitmap1; \ + } \ + \ + static inline ucs_bitmap_t(_length) _ucs_bitmap_##_length##_or( \ + ucs_bitmap_t(_length) bitmap1, ucs_bitmap_t(_length) bitmap2) \ + { \ + UCS_BITMAP_OR_INPLACE(&bitmap1, bitmap2); \ + return bitmap1; \ + } \ + \ + static inline ucs_bitmap_t(_length) _ucs_bitmap_##_length##_xor( \ + ucs_bitmap_t(_length) bitmap1, ucs_bitmap_t(_length) bitmap2) \ + { \ + UCS_BITMAP_XOR_INPLACE(&bitmap1, bitmap2); \ + return bitmap1; \ + } /** @@ -77,47 +202,42 @@ typedef uint64_t ucs_bitmap_word_t; * ucs_bitmap_t(64) my_bitmap; * @endcode */ -#define ucs_bitmap_t(_length) ucs_bitmap_##_length##_suffix - - -_UCS_BITMAP_DECLARE_TYPE(64) -_UCS_BITMAP_DECLARE_TYPE(128) -_UCS_BITMAP_DECLARE_TYPE(256) +#define ucs_bitmap_t(_length) ucs_bitmap_##_length##_t /** * Get the value of a bit in the bitmap * - * @param _bitmap Read value from this bitmap - * @param _index Bit index to read + * @param _bitmap Read value from this bitmap + * @param _bit_index Bit index to read * * @return Bit value (0 or 1) */ -#define UCS_BITMAP_GET(_bitmap, _index) \ - (!!(_UCS_BITMAP_WORD(_bitmap, _index) & \ - UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_index)))) +#define UCS_BITMAP_GET(_bitmap, _bit_index) \ + (!!(_UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) & \ + UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index)))) /** * Set the value of a bit in the bitmap * - * @param _bitmap Set value in this bitmap - * @param _index Bit index to set + * @param _bitmap Set value in this bitmap + * @param _bit_index Bit index to set */ - #define UCS_BITMAP_SET(_bitmap, _index) \ - (_UCS_BITMAP_WORD(_bitmap, _index) |= \ - (UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_index)))); + #define UCS_BITMAP_SET(_bitmap, _bit_index) \ + (_UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) |= \ + (UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index)))); /** * Unset (clear) the value of a bit in the bitmap * - * @param _bitmap Unset value in this bitmap - * @param _index Bit index to unset + * @param _bitmap Unset value in this bitmap + * @param _bit_index Bit index to unset */ - #define UCS_BITMAP_UNSET(_bitmap, _index) \ - ((_bitmap)->bits)[UCS_BITMAP_WORD_INDEX(_index)] &= \ - ~((UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_index)))); + #define UCS_BITMAP_UNSET(_bitmap, _bit_index) \ + (_UCS_BITMAP_WORD_BY_BIT(_bitmap, _bit_index) &= \ + ~(UCS_BIT(_UCS_BITMAP_BIT_IN_WORD_INDEX(_bit_index)))); /** @@ -130,67 +250,127 @@ _UCS_BITMAP_DECLARE_TYPE(256) /** - * Iterate over all set (1) bits of a given bitmap + * Find the index of the first bit set to 1 in a given bitmap * - * @param _bitmap Iterate over bits of this bitmap - * @param _index Bit index (global offset - relative to the whole bitmap) + * @param _bitmap Look for the first bit in this bitmap */ -#define UCS_BITMAP_FOR_EACH_BIT(_bitmap, _index) \ - for (_index = ucs_ffs64_safe((_bitmap)->bits[0]); \ - _index < ucs_static_array_size((_bitmap)->bits) * UCS_BITMAP_BITS_IN_WORD; \ - _index = _UCS_BITMAP_WORD_INDEX0(_index) + \ - ucs_ffs64_safe(_UCS_BITMAP_WORD((_bitmap), (_index)) & \ - _UCS_BITMAP_GET_NEXT_BIT(_index))) \ - if (UCS_BITMAP_GET((_bitmap), (_index))) +#define UCS_BITMAP_FFS(_bitmap) \ + ({ \ + size_t _bit_index = UCS_BITMAP_BITS_IN_WORD * \ + _UCS_BITMAP_NUM_WORDS(_bitmap); \ + size_t _word_index, _temp; \ + _UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \ + _temp = _UCS_BITMAP_WORD(_bitmap, _word_index); \ + if (_temp != 0) { \ + _bit_index = ucs_ffs64(_temp) + (_word_index * \ + UCS_BITMAP_BITS_IN_WORD); \ + break; \ + } \ + } \ + _bit_index; \ + }) /** - * Perform bitwise NOT of a bitmap + * Return the number of bits set to 1 in a given bitmap * - * @param _bitmap Negate this bitmap + * @param _bitmap Check bits number in this bitmap + * + * @return Number of bits set to 1 */ -#define UCS_BITMAP_NOT(_bitmap) \ +#define UCS_BITMAP_POPCOUNT(_bitmap) \ ({ \ - int _word; \ - for (_word = 0; _word < ucs_static_array_size((_bitmap)->bits); _word++) \ - (_bitmap)->bits[_word] = ~(_bitmap)->bits[_word]; \ + size_t _word_index = 0, _popcount = 0; \ + _UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \ + _popcount += ucs_popcount(_UCS_BITMAP_WORD(_bitmap, _word_index)); \ + } \ + _popcount; \ }) -#define _UCS_BITMAP_OP(_bitmap1, _bitmap2, _op) \ +/** + * Returns the number of bits set to 1 in a given bitmap, + * up to a particular bit index + * + * @param _bitmap Check bits number in this bitmap + * @param _bit_index Check bits up to this bit + * + * @return Number of bits set to 1 + */ +#define UCS_BITMAP_POPCOUNT_UPTO_INDEX(_bitmap, _bit_index) \ ({ \ - int _word; \ - for (_word = 0; _word < ucs_static_array_size((_bitmap1)->bits); _word++) \ - (_bitmap1)->bits[_word] = (_bitmap1)->bits[_word] _op \ - (_bitmap2)->bits[_word]; \ + size_t _word_index = 0, _popcount = 0; \ + _UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \ + if ((_bit_index) >= ((_word_index) + 1) * UCS_BITMAP_BITS_IN_WORD) { \ + _popcount += ucs_popcount( \ + _UCS_BITMAP_WORD(_bitmap, _word_index)); \ + } else { \ + _popcount += ucs_popcount( \ + _UCS_BITMAP_WORD(_bitmap, _word_index) & \ + (UCS_MASK((_bit_index) % UCS_BITMAP_BITS_IN_WORD))); \ + } \ + } \ + _popcount; \ }) /** - * Perform bitwise AND of 2 bitmaps, storing the result in the first one + * Return a word-mask for the word at '_word_index' for all the bits up to + * (and not including) '_mask_index'. * - * @param _bitmap1 First operand - * @param _bitmap1 Second operand + * @param _bitmap Mask bits in this bitmap + * @param _word_index Index of the word to be masked + * @param _mask_index Mask bits up to this bit index */ -#define UCS_BITMAP_AND(_bitmap1, _bitmap2) _UCS_BITMAP_OP(_bitmap1, _bitmap2, &) +#define _UCS_BITMAP_MASK_WORD(_bitmap, _word_index, _mask_index) \ + ((_mask_index) > (_word_index) * UCS_BITMAP_BITS_IN_WORD) ? \ + ((((_mask_index) >= ((_word_index) + 1) * UCS_BITMAP_BITS_IN_WORD) ? UINT64_MAX : \ + UCS_MASK((_mask_index) % UCS_BITMAP_BITS_IN_WORD))) : 0; \ /** - * Perform bitwise OR of 2 bitmaps, storing the result in the first one + * Mask a bitmap by setting all bits up to a given index (excluding it) to 1 * - * @param _bitmap1 First operand - * @param _bitmap1 Second operand + * @param _bitmap Mask bits in this bitmap + * @param _mask_index Mask all bits up to this index (excluding it) */ -#define UCS_BITMAP_OR(_bitmap1, _bitmap2) _UCS_BITMAP_OP(_bitmap1, _bitmap2, |) +#define UCS_BITMAP_MASK(_bitmap, _mask_index) \ + { \ + size_t _word_index = 0; \ + UCS_BITMAP_CLEAR(_bitmap); \ + _UCS_BITMAP_FOR_EACH_WORD(*_bitmap, _word_index) { \ + _UCS_BITMAP_WORD(*_bitmap, _word_index) = \ + _UCS_BITMAP_MASK_WORD(*_bitmap, _word_index, _mask_index); \ + } \ + } \ /** - * Perform bitwise XOR of 2 bitmaps, storing the result in the first one + * Set all bits of a given bitmap to 1 * - * @param _bitmap1 First operand - * @param _bitmap1 Second operand + * @param _bitmap Set bits in this bitmap */ -#define UCS_BITMAP_XOR(_bitmap1, _bitmap2) _UCS_BITMAP_OP(_bitmap1, _bitmap2, ^) +#define UCS_BITMAP_SET_ALL(_bitmap) \ + { \ + size_t _word_index = 0; \ + _UCS_BITMAP_FOR_EACH_WORD(_bitmap, _word_index) { \ + _UCS_BITMAP_WORD(_bitmap, _word_index) = UINT64_MAX; \ + } \ + } + + +/** + * Iterate over all set (1) bits of a given bitmap + * + * @param _bitmap Iterate over bits of this bitmap + * @param _bit_index Bit index (global offset - relative to the whole bitmap) + */ +#define UCS_BITMAP_FOR_EACH_BIT(_bitmap, _bit_index) \ + for (_bit_index = ucs_ffs64_safe(_UCS_BITMAP_WORD(_bitmap, 0)); \ + _bit_index < _UCS_BITMAP_NUM_WORDS(_bitmap) * UCS_BITMAP_BITS_IN_WORD; \ + _bit_index = _UCS_BITMAP_WORD_INDEX0(_bit_index) + \ + ucs_ffs64_safe(_UCS_BITMAP_WORD_BY_BIT((_bitmap), (_bit_index)) & \ + _UCS_BITMAP_GET_NEXT_BIT(_bit_index))) /** @@ -200,8 +380,78 @@ _UCS_BITMAP_DECLARE_TYPE(256) * @param _src_bitmap Copy bits from this bitmap */ #define UCS_BITMAP_COPY(_dest_bitmap, _src_bitmap) \ - memcpy((_dest_bitmap)->bits, (_src_bitmap)->bits, \ - ucs_static_array_size((_src_bitmap)->bits)); + memcpy((_dest_bitmap).bits, (_src_bitmap).bits, \ + _UCS_BITMAP_NUM_WORDS(_src_bitmap)); + + +/** + * Perform bitwise NOT of a bitmap + * + * @param _bitmap Negate this bitmap + * @param _length Length of the bitmaps (in bits) + * + * @return A new bitmap, which is the negation of the given one + */ +#define UCS_BITMAP_NOT(_bitmap, _length) \ + _ucs_bitmap_##_length##_not(_bitmap); + + +/** + * Perform bitwise AND of 2 bitmaps and return the result + * + * @param _bitmap1 First operand + * @param _bitmap2 Second operand + * @param _length Length of the bitmaps (in bits) + * + * @return A new bitmap, which is the logical AND of the operands + */ +#define UCS_BITMAP_AND(_bitmap1, _bitmap2, _length) \ + _ucs_bitmap_##_length##_and(_bitmap1, _bitmap2); + + +/** + * Perform bitwise OR of 2 bitmaps and return the result + * + * @param _bitmap1 First operand + * @param _bitmap2 Second operand + * @param _length Length of the bitmaps (in bits) + * + * @return A new bitmap, which is the logical OR of the operands + */ +#define UCS_BITMAP_OR(_bitmap1, _bitmap2, _length) \ + _ucs_bitmap_##_length##_or(_bitmap1, _bitmap2); + + +/** + * Perform bitwise XOR of 2 bitmaps and return the result + * + * @param _bitmap1 First operand + * @param _bitmap2 Second operand + * @param _length Length of the bitmaps (in bits) + * + * @return A new bitmap, which is the logical XOR of the operands + */ +#define UCS_BITMAP_XOR(_bitmap1, _bitmap2, _length) \ + _ucs_bitmap_##_length##_xor(_bitmap1, _bitmap2); + + +static UCS_F_ALWAYS_INLINE bool _ucs_bitmap_is_zero(const void *bitmap, size_t num_words) +{ + size_t i; + + for (i = 0; i < num_words; i++) { + if (((ucs_bitmap_word_t *)bitmap)[i]) { + return 0; + } + } + + return 1; +} + + +_UCS_BITMAP_DECLARE_TYPE(64) +_UCS_BITMAP_DECLARE_TYPE(128) +_UCS_BITMAP_DECLARE_TYPE(256) END_C_DECLS diff --git a/test/gtest/ucs/test_bitmap.cc b/test/gtest/ucs/test_bitmap.cc index 15791e1be5e..073156d6397 100644 --- a/test/gtest/ucs/test_bitmap.cc +++ b/test/gtest/ucs/test_bitmap.cc @@ -19,7 +19,7 @@ class test_ucs_bitmap : public ucs::test { { int i; - UCS_BITMAP_FOR_EACH_BIT(bitmap, i) { + UCS_BITMAP_FOR_EACH_BIT(*bitmap, i) { dest[UCS_BITMAP_WORD_INDEX(i)] |= UCS_BIT(i % UCS_BITMAP_BITS_IN_WORD); } } @@ -30,15 +30,78 @@ class test_ucs_bitmap : public ucs::test { void test_set_get_unset(ucs_bitmap_t(128) *bitmap, uint64_t offset) { - UCS_BITMAP_SET(bitmap, offset); - EXPECT_EQ(UCS_BITMAP_GET(bitmap, offset), 1); + UCS_BITMAP_SET(*bitmap, offset); + EXPECT_EQ(UCS_BITMAP_GET(*bitmap, offset), 1); EXPECT_EQ(bitmap->bits[offset >= UCS_BITMAP_BITS_IN_WORD], UCS_BIT(offset % 64)); EXPECT_EQ(bitmap->bits[offset < UCS_BITMAP_BITS_IN_WORD], 0); - UCS_BITMAP_UNSET(bitmap, offset); + UCS_BITMAP_UNSET(*bitmap, offset); EXPECT_EQ(bitmap->bits[0], 0); EXPECT_EQ(bitmap->bits[1], 0); - EXPECT_EQ(UCS_BITMAP_GET(bitmap, offset), 0); + EXPECT_EQ(UCS_BITMAP_GET(*bitmap, offset), 0); +} + +UCS_TEST_F(test_ucs_bitmap, test_popcount) { + int popcount = UCS_BITMAP_POPCOUNT(bitmap); + EXPECT_EQ(popcount, 0); + UCS_BITMAP_SET(bitmap, 12); + UCS_BITMAP_SET(bitmap, 53); + UCS_BITMAP_SET(bitmap, 71); + UCS_BITMAP_SET(bitmap, 110); + popcount = UCS_BITMAP_POPCOUNT(bitmap); + EXPECT_EQ(popcount, 4); +} + +UCS_TEST_F(test_ucs_bitmap, test_popcount_upto_index) { + int popcount; + UCS_BITMAP_SET(bitmap, 17); + UCS_BITMAP_SET(bitmap, 71); + UCS_BITMAP_SET(bitmap, 121); + popcount = UCS_BITMAP_POPCOUNT_UPTO_INDEX(bitmap, 110); + EXPECT_EQ(popcount, 2); +} + +UCS_TEST_F(test_ucs_bitmap, test_mask) { + UCS_BITMAP_SET(bitmap, 64 + 42); + UCS_BITMAP_MASK(&bitmap, 64 + 42); + + EXPECT_EQ(bitmap.bits[0], UINT64_MAX); + EXPECT_EQ(bitmap.bits[1], (1ul << 42) - 1); +} + +UCS_TEST_F(test_ucs_bitmap, test_set_all) { + UCS_BITMAP_SET_ALL(bitmap); + EXPECT_EQ(bitmap.bits[0], UINT64_MAX); + EXPECT_EQ(bitmap.bits[1], UINT64_MAX); +} + +UCS_TEST_F(test_ucs_bitmap, test_ffs) { + size_t bit_index; + + bit_index = UCS_BITMAP_FFS(bitmap); + EXPECT_EQ(bit_index, 128); + + UCS_BITMAP_SET(bitmap, 90); + UCS_BITMAP_SET(bitmap, 100); + bit_index = UCS_BITMAP_FFS(bitmap); + EXPECT_EQ(bit_index, 90); + + UCS_BITMAP_CLEAR(&bitmap); + UCS_BITMAP_SET(bitmap, 0); + bit_index = UCS_BITMAP_FFS(bitmap); + EXPECT_EQ(bit_index, 0); + + UCS_BITMAP_CLEAR(&bitmap); + UCS_BITMAP_SET(bitmap, 64); + bit_index = UCS_BITMAP_FFS(bitmap); + EXPECT_EQ(bit_index, 64); +} + +UCS_TEST_F(test_ucs_bitmap, test_is_zero) { + EXPECT_EQ(UCS_BITMAP_IS_ZERO(bitmap), true); + + UCS_BITMAP_SET(bitmap, 71); + EXPECT_EQ(UCS_BITMAP_IS_ZERO(bitmap), false); } UCS_TEST_F(test_ucs_bitmap, test_get_set_clear) @@ -47,14 +110,14 @@ UCS_TEST_F(test_ucs_bitmap, test_get_set_clear) EXPECT_EQ(bitmap.bits[0], 0); EXPECT_EQ(bitmap.bits[1], 0); - EXPECT_EQ(UCS_BITMAP_GET(&bitmap, offset), 0); + EXPECT_EQ(UCS_BITMAP_GET(bitmap, offset), 0); test_set_get_unset(&bitmap, offset); test_set_get_unset(&bitmap, offset + 64); UCS_BITMAP_CLEAR(&bitmap); for (int i = 0; i < 128; i++) { - EXPECT_EQ(UCS_BITMAP_GET(&bitmap, i), 0); + EXPECT_EQ(UCS_BITMAP_GET(bitmap, i), 0); } } @@ -62,13 +125,13 @@ UCS_TEST_F(test_ucs_bitmap, test_foreach) { uint64_t bitmap_words[2] = {}; - UCS_BITMAP_SET(&bitmap, 1); - UCS_BITMAP_SET(&bitmap, 25); - UCS_BITMAP_SET(&bitmap, 61); + UCS_BITMAP_SET(bitmap, 1); + UCS_BITMAP_SET(bitmap, 25); + UCS_BITMAP_SET(bitmap, 61); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 0); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 37); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 58); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 0); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 37); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 58); copy_bitmap(&bitmap, bitmap_words); @@ -78,79 +141,114 @@ UCS_TEST_F(test_ucs_bitmap, test_foreach) UCS_TEST_F(test_ucs_bitmap, test_not) { - UCS_BITMAP_SET(&bitmap, 1); - UCS_BITMAP_NOT(&bitmap); + ucs_bitmap_t(128) bitmap2; + + UCS_BITMAP_SET(bitmap, 1); + bitmap2 = UCS_BITMAP_NOT(bitmap, 128); + UCS_BITMAP_NOT_INPLACE(&bitmap); EXPECT_EQ(bitmap.bits[0], -3ull); - EXPECT_EQ(bitmap.bits[1], -1); + EXPECT_EQ(bitmap.bits[1], UINT64_MAX); + EXPECT_EQ(bitmap2.bits[0], -3ull); + EXPECT_EQ(bitmap2.bits[1], UINT64_MAX); } UCS_TEST_F(test_ucs_bitmap, test_and) { - ucs_bitmap_t(128) bitmap2; + ucs_bitmap_t(128) bitmap2, bitmap3; UCS_BITMAP_CLEAR(&bitmap2); - UCS_BITMAP_SET(&bitmap, 1); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 1); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 16); + UCS_BITMAP_SET(bitmap, 1); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 1); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 16); - UCS_BITMAP_SET(&bitmap2, 25); - UCS_BITMAP_SET(&bitmap2, UCS_BITMAP_BITS_IN_WORD + 1); - UCS_BITMAP_SET(&bitmap2, UCS_BITMAP_BITS_IN_WORD + 30); - UCS_BITMAP_AND(&bitmap, &bitmap2); + UCS_BITMAP_SET(bitmap2, 25); + UCS_BITMAP_SET(bitmap2, UCS_BITMAP_BITS_IN_WORD + 1); + UCS_BITMAP_SET(bitmap2, UCS_BITMAP_BITS_IN_WORD + 30); + bitmap3 = UCS_BITMAP_AND(bitmap, bitmap2, 128); + UCS_BITMAP_AND_INPLACE(&bitmap, bitmap2); EXPECT_EQ(bitmap.bits[0], 0); EXPECT_EQ(bitmap.bits[1], UCS_BIT(1)); + EXPECT_EQ(bitmap3.bits[0], 0); + EXPECT_EQ(bitmap3.bits[1], UCS_BIT(1)); } UCS_TEST_F(test_ucs_bitmap, test_or) { - ucs_bitmap_t(128) bitmap2; + ucs_bitmap_t(128) bitmap2, bitmap3; UCS_BITMAP_CLEAR(&bitmap2); - UCS_BITMAP_SET(&bitmap, 1); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 1); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 16); + UCS_BITMAP_SET(bitmap, 1); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 1); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 16); - UCS_BITMAP_SET(&bitmap2, 25); - UCS_BITMAP_SET(&bitmap2, UCS_BITMAP_BITS_IN_WORD + 1); - UCS_BITMAP_SET(&bitmap2, UCS_BITMAP_BITS_IN_WORD + 30); - UCS_BITMAP_OR(&bitmap, &bitmap2); + UCS_BITMAP_SET(bitmap2, 25); + UCS_BITMAP_SET(bitmap2, UCS_BITMAP_BITS_IN_WORD + 1); + UCS_BITMAP_SET(bitmap2, UCS_BITMAP_BITS_IN_WORD + 30); + bitmap3 = UCS_BITMAP_OR(bitmap, bitmap2, 128); + UCS_BITMAP_OR_INPLACE(&bitmap, bitmap2); EXPECT_EQ(bitmap.bits[0], UCS_BIT(1) | UCS_BIT(25)); EXPECT_EQ(bitmap.bits[1], UCS_BIT(1) | UCS_BIT(16) | UCS_BIT(30)); + EXPECT_EQ(bitmap3.bits[0], UCS_BIT(1) | UCS_BIT(25)); + EXPECT_EQ(bitmap3.bits[1], UCS_BIT(1) | UCS_BIT(16) | UCS_BIT(30)); } UCS_TEST_F(test_ucs_bitmap, test_xor) { - ucs_bitmap_t(128) bitmap2; + ucs_bitmap_t(128) bitmap2, bitmap3; UCS_BITMAP_CLEAR(&bitmap2); bitmap.bits[0] = 1; - bitmap.bits[1] = -1; - bitmap2.bits[0] = -1; + bitmap.bits[1] = UINT64_MAX; + bitmap2.bits[0] = UINT64_MAX; bitmap2.bits[1] = 1; - UCS_BITMAP_XOR(&bitmap, &bitmap2); + bitmap3 = UCS_BITMAP_XOR(bitmap, bitmap2, 128); + UCS_BITMAP_XOR_INPLACE(&bitmap, bitmap2); EXPECT_EQ(bitmap.bits[0], -2); EXPECT_EQ(bitmap.bits[1], -2); + EXPECT_EQ(bitmap3.bits[0], -2); + EXPECT_EQ(bitmap3.bits[1], -2); } UCS_TEST_F(test_ucs_bitmap, test_copy) { ucs_bitmap_t(128) bitmap2; - UCS_BITMAP_SET(&bitmap, 1); - UCS_BITMAP_SET(&bitmap, 25); - UCS_BITMAP_SET(&bitmap, 61); + UCS_BITMAP_SET(bitmap, 1); + UCS_BITMAP_SET(bitmap, 25); + UCS_BITMAP_SET(bitmap, 61); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 0); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 37); - UCS_BITMAP_SET(&bitmap, UCS_BITMAP_BITS_IN_WORD + 58); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 0); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 37); + UCS_BITMAP_SET(bitmap, UCS_BITMAP_BITS_IN_WORD + 58); - UCS_BITMAP_COPY(&bitmap2, &bitmap); + UCS_BITMAP_COPY(bitmap2, bitmap); EXPECT_EQ(bitmap.bits[0], UCS_BIT(1) | UCS_BIT(25) | UCS_BIT(61)); EXPECT_EQ(bitmap.bits[1], UCS_BIT(0) | UCS_BIT(37) | UCS_BIT(58)); } + +UCS_TEST_F(test_ucs_bitmap, test_for_each_bit) +{ + int i = 0, bit_index; + int bits[128] = {0}; + + UCS_BITMAP_SET(bitmap, 0); + UCS_BITMAP_SET(bitmap, 25); + UCS_BITMAP_SET(bitmap, 64); + UCS_BITMAP_SET(bitmap, 100); + UCS_BITMAP_FOR_EACH_BIT(bitmap, bit_index) { + i++; + bits[bit_index]++; + } + + EXPECT_EQ(i, 4); + EXPECT_EQ(bits[0], 1); + EXPECT_EQ(bits[25], 1); + EXPECT_EQ(bits[64], 1); + EXPECT_EQ(bits[100], 1); +}