Skip to content

Commit 9403432

Browse files
MiguelCompanyraquelalvarezbanos
authored andcommitted
Adding sliding window to BitmapRange [6043] (eProsima#622)
* Refs eProsima#5783. New sliding window base_update method. * Refs eProsima#5783. Adding unit test.
1 parent 57ca219 commit 9403432

File tree

2 files changed

+185
-2
lines changed

2 files changed

+185
-2
lines changed

include/fastrtps/utils/fixed_size_bitmap.hpp

Lines changed: 153 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ struct DiffFunction
5454
template<class T, class Diff = DiffFunction<T>, uint32_t NBITS = 256>
5555
class BitmapRange
5656
{
57+
#define NITEMS ((NBITS + 31ul) / 32ul)
5758
public:
5859
// Alias to improve readability.
59-
using bitmap_type = std::array<uint32_t, (NBITS + 31) / 32>;
60+
using bitmap_type = std::array<uint32_t, NITEMS>;
6061

6162
/**
6263
* Default constructor.
@@ -95,7 +96,40 @@ class BitmapRange
9596
}
9697

9798
/**
98-
* Returns whether the range is empty (i.e. has at least one bit set).
99+
* Set a new base for the range, keeping old values where possible.
100+
* This method implements a sliding window mechanism for changing the base of the range.
101+
*
102+
* @param base New base value to set.
103+
*/
104+
void base_update(T base) noexcept
105+
{
106+
// Do nothing if base is not changing
107+
if (base == base_)
108+
{
109+
return;
110+
}
111+
112+
Diff d_func;
113+
if (base > base_)
114+
{
115+
// Current content should move left
116+
uint32_t n_bits = d_func(base, base_);
117+
shift_map_left(n_bits);
118+
}
119+
else
120+
{
121+
// Current content should move right
122+
uint32_t n_bits = d_func(base_, base);
123+
shift_map_right(n_bits);
124+
}
125+
126+
// Update base and range
127+
base_ = base;
128+
range_max_ = base_ + (NBITS - 1);
129+
}
130+
131+
/**
132+
* Returns whether the range is empty (i.e. has all bits unset).
99133
*
100134
* @return true if the range is empty, false otherwise.
101135
*/
@@ -212,6 +246,123 @@ class BitmapRange
212246
T range_max_; ///< Holds maximum allowed value of the range.
213247
bitmap_type bitmap_; ///< Holds the bitmap values.
214248
uint32_t num_bits_; ///< Holds the highest bit set in the bitmap.
249+
250+
private:
251+
252+
void shift_map_left(uint32_t n_bits)
253+
{
254+
if (n_bits >= num_bits_)
255+
{
256+
// Shifting more than most significant. Clear whole bitmap.
257+
num_bits_ = 0;
258+
bitmap_.fill(0UL);
259+
}
260+
else
261+
{
262+
// Significant bit will move left by n_bits
263+
num_bits_ -= n_bits;
264+
265+
// Div and mod by 32
266+
uint32_t n_items = n_bits >> 5;
267+
n_bits &= 31UL;
268+
if (n_bits == 0)
269+
{
270+
// Shifting a multiple of 32 bits, just move the bitmap integers
271+
std::copy(bitmap_.begin() + n_items, bitmap_.end(), bitmap_.begin());
272+
std::fill_n(bitmap_.rbegin(), n_items, 0);
273+
}
274+
else
275+
{
276+
// Example. Shifting 44 bits. Should shift one complete word and 12 bits.
277+
// Need to iterate forward and take 12 bits from next word (shifting it 20 bits).
278+
// aaaaaaaa bbbbbbbb cccccccc dddddddd
279+
// bbbbbccc bbbbbbbb cccccccc dddddddd
280+
// bbbbbccc cccccddd ddddd000 dddddddd
281+
// bbbbbccc cccccddd ddddd000 00000000
282+
uint32_t overflow_bits = 32UL - n_bits;
283+
size_t last_index = NITEMS - 1u;
284+
for (size_t i = 0, n = n_items; n < last_index; i++, n++)
285+
{
286+
bitmap_[i] = (bitmap_[n] << n_bits) | (bitmap_[n + 1] >> overflow_bits);
287+
}
288+
// Last one does not have next word
289+
bitmap_[last_index - n_items] = bitmap_[last_index] << n_bits;
290+
// Last n_items will become 0
291+
std::fill_n(bitmap_.rbegin(), n_items, 0);
292+
}
293+
}
294+
}
295+
296+
void shift_map_right(uint32_t n_bits)
297+
{
298+
if (n_bits >= NBITS)
299+
{
300+
// Shifting more than total bitmap size. Clear whole bitmap.
301+
num_bits_ = 0;
302+
bitmap_.fill(0UL);
303+
}
304+
else
305+
{
306+
// Detect if highest bit will be dropped and take note, as we will need
307+
// to find new maximum bit in that case
308+
uint32_t new_num_bits = num_bits_ + n_bits;
309+
bool find_new_max = new_num_bits > NBITS;
310+
311+
// Div and mod by 32
312+
uint32_t n_items = n_bits >> 5;
313+
n_bits &= 31UL;
314+
if (n_bits == 0)
315+
{
316+
// Shifting a multiple of 32 bits, just move the bitmap integers
317+
std::copy(bitmap_.rbegin() + n_items, bitmap_.rend(), bitmap_.rbegin());
318+
std::fill_n(bitmap_.begin(), n_items, 0);
319+
}
320+
else
321+
{
322+
// Example. Shifting 44 bits. Should shift one complete word and 12 bits.
323+
// Need to iterate backwards and take 12 bits from previous word (shifting it 20 bits).
324+
// aaaaaaaa bbbbbbbb cccccccc dddddddd
325+
// aaaaaaaa bbbbbbbb cccccccc bbbccccc
326+
// aaaaaaaa bbbbbbbb aaabbbbb bbbccccc
327+
// aaaaaaaa 000aaaaa aaabbbbb bbbccccc
328+
// 00000000 000aaaaa aaabbbbb bbbccccc
329+
uint32_t overflow_bits = 32UL - n_bits;
330+
size_t last_index = NITEMS - 1u;
331+
for (size_t i = last_index, n = last_index - n_items; n > 0; i--, n--)
332+
{
333+
bitmap_[i] = (bitmap_[n] >> n_bits) | (bitmap_[n - 1] << overflow_bits);
334+
}
335+
// First item does not have previous word
336+
bitmap_[n_items] = bitmap_[0] >> n_bits;
337+
// First n_items will become 0
338+
std::fill_n(bitmap_.begin(), n_items, 0);
339+
}
340+
341+
if (find_new_max)
342+
{
343+
new_num_bits = 0;
344+
for (uint32_t i = NITEMS; i > n_items;)
345+
{
346+
--i;
347+
uint32_t bits = bitmap_[i];
348+
if (bits != 0)
349+
{
350+
bits = (bits & ~(bits - 1));
351+
#if _MSC_VER
352+
unsigned long bit;
353+
_BitScanReverse(&bit, bits);
354+
uint32_t offset = 32UL - bit;
355+
#else
356+
uint32_t offset = __builtin_clz(bits) + 1;
357+
#endif
358+
new_num_bits = (i << 5UL) + offset;
359+
break;
360+
}
361+
}
362+
}
363+
num_bits_ = new_num_bits;
364+
}
365+
}
215366
};
216367

217368
} // namespace fastrtps

test/unittest/utils/BitmapRangeTests.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class BitmapRangeTests: public ::testing::Test
7575
{
7676
public:
7777
const ValueType explicit_base = 123UL;
78+
const ValueType sliding_base = 513UL;
7879

7980
const TestCase test0 =
8081
{
@@ -241,6 +242,37 @@ TEST_F(BitmapRangeTests, traversal)
241242
ASSERT_TRUE(items.empty());
242243
}
243244

245+
TEST_F(BitmapRangeTests, sliding_window)
246+
{
247+
TestType uut(sliding_base);
248+
uut.add(sliding_base);
249+
250+
// Check shifting right and then left
251+
for (ValueType i = 0; i < 256UL; i++)
252+
{
253+
uut.base_update(sliding_base - i);
254+
ASSERT_EQ(uut.max(), sliding_base);
255+
uut.base_update(sliding_base);
256+
ASSERT_EQ(uut.max(), sliding_base);
257+
}
258+
259+
// Check shifting left and then right
260+
for (ValueType i = 0; i < 256UL; i++)
261+
{
262+
uut.base_update(sliding_base - i);
263+
ASSERT_EQ(uut.max(), sliding_base);
264+
uut.base_update(sliding_base - 255UL);
265+
ASSERT_EQ(uut.max(), sliding_base);
266+
}
267+
268+
// Check cases dropping the most significant bit
269+
uut.add(sliding_base - 100UL);
270+
uut.base_update(sliding_base - 256UL);
271+
ASSERT_EQ(uut.max(), sliding_base - 100UL);
272+
uut.base_update(0);
273+
ASSERT_TRUE(uut.empty());
274+
}
275+
244276
int main(int argc, char **argv)
245277
{
246278
testing::InitGoogleTest(&argc, argv);

0 commit comments

Comments
 (0)