@@ -54,9 +54,10 @@ struct DiffFunction
5454template <class T , class Diff = DiffFunction<T>, uint32_t NBITS = 256 >
5555class BitmapRange
5656{
57+ #define NITEMS ((NBITS + 31ul ) / 32ul )
5758public:
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
0 commit comments