Fast DDS  Version 3.6.1.0
Fast DDS
Loading...
Searching...
No Matches
fixed_size_bitmap.hpp
1// Copyright 2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
19
20#ifndef FASTDDS_UTILS__FIXED_SIZE_BITMAP_HPP
21#define FASTDDS_UTILS__FIXED_SIZE_BITMAP_HPP
22
23#include <array>
24#include <cstdint>
25#include <string.h>
26#include <limits>
27
28#if _MSC_VER
29#include <intrin.h>
30
31#if defined(max)
32#pragma push_macro("max")
33#undef max
34#define FASTDDS_RESTORE_MAX
35#endif // defined(max)
36
37#if defined(min)
38#pragma push_macro("min")
39#undef min
40#define FASTDDS_RESTORE_MIN
41#endif // defined(min)
42
43#endif // if _MSC_VER
44
45#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC
46namespace eprosima {
47namespace fastdds {
48
49using std::uint32_t;
50
51template<class T>
53{
54 constexpr auto operator () (
55 T a,
56 T b) const
57 -> decltype(a - b)
58 {
59 return a - b;
60 }
61
62};
63
74template<class T, class Diff = DiffFunction<T>, uint32_t NBITS = 256>
76{
77 #define NITEMS ((NBITS + 31u) / 32u)
78
79public:
80
81 // Alias to improve readability.
82 using bitmap_type = std::array<uint32_t, NITEMS>;
83
88 BitmapRange() noexcept
89 : base_()
90 , range_max_(base_ + (NBITS - 1))
91 , bitmap_()
92 , num_bits_(0u)
93 {
94 }
95
102 explicit BitmapRange(
103 T base) noexcept
104 : BitmapRange(
105 base,
106 NBITS - 1)
107 {
108 }
109
118 T base,
119 uint32_t max_bits) noexcept
120 : base_(base)
121 , range_max_(base_ + (std::min)(max_bits, NBITS - 1))
122 , bitmap_()
123 , num_bits_(0u)
124 {
125 }
126
127 // We don't need to define copy/move constructors/assignment operators as the default ones would be enough
128
133 T base() const noexcept
134 {
135 return base_;
136 }
137
144 void base(
145 T base) noexcept
146 {
147 base_ = base;
148 range_max_ = base_ + (NBITS - 1);
149 num_bits_ = 0;
150 bitmap_.fill(0u);
151 }
152
160 void base(
161 T base,
162 uint32_t max_bits) noexcept
163 {
164 base_ = base;
165 range_max_ = base_ + (std::min)(max_bits, NBITS - 1);
166 num_bits_ = 0;
167 bitmap_.fill(0u);
168 }
169
177 T base) noexcept
178 {
179 // Do nothing if base is not changing
180 if (base == base_)
181 {
182 return;
183 }
184
185 Diff d_func;
186 if (base > base_)
187 {
188 // Current content should move left
189 uint32_t n_bits = d_func(base, base_);
190 shift_map_left(n_bits);
191 }
192 else
193 {
194 // Current content should move right
195 uint32_t n_bits = d_func(base_, base);
196 shift_map_right(n_bits);
197 }
198
199 // Update base and range
200 base_ = base;
201 range_max_ = base_ + (NBITS - 1);
202 }
203
209 bool empty() const noexcept
210 {
211 return num_bits_ == 0u;
212 }
213
219 T max() const noexcept
220 {
221 return base_ + (num_bits_ - 1);
222 }
223
229 T min() const noexcept
230 {
231 // Traverse through the significant items on the bitmap
232 T item = base_;
233 uint32_t n_longs = (num_bits_ + 31u) / 32u;
234 for (uint32_t i = 0; i < n_longs; i++)
235 {
236 // Check if item has at least one bit set
237 uint32_t bits = bitmap_[i];
238 if (bits)
239 {
240 // We use an intrinsic to find the index of the highest bit set.
241 // Most modern CPUs have an instruction to count the leading zeroes of a word.
242 // The number of leading zeroes will give us the index we need.
243#if _MSC_VER
244 unsigned long bit;
245 _BitScanReverse(&bit, bits);
246 uint32_t offset = 31u ^ bit;
247#else
248 uint32_t offset = static_cast<uint32_t>(__builtin_clz(bits));
249#endif // if _MSC_VER
250
251 // Found first bit set in bitmap
252 return item + offset;
253 }
254
255 // There are 32 items on each bitmap item.
256 item = item + 32u;
257 }
258
259 return base_;
260 }
261
269 bool is_set(
270 const T& item) const noexcept
271 {
272 // Check item is inside the allowed range.
273 if ((item >= base_) && (range_max_ >= item))
274 {
275 // Calc distance from base to item, and check the corresponding bit.
276 Diff d_func;
277 uint32_t diff = d_func(item, base_);
278 if (diff < num_bits_)
279 {
280 uint32_t pos = diff >> 5;
281 diff &= 31u;
282 return (bitmap_[pos] & (1u << (31u - diff))) != 0;
283 }
284 }
285
286 return false;
287 }
288
297 bool add(
298 const T& item) noexcept
299 {
300 // Check item is inside the allowed range.
301 if ((item >= base_) && (range_max_ >= item))
302 {
303 // Calc distance from base to item, and set the corresponding bit.
304 Diff d_func;
305 uint32_t diff = d_func(item, base_);
306 num_bits_ = std::max(diff + 1, num_bits_);
307 uint32_t pos = diff >> 5;
308 diff &= 31u;
309 bitmap_[pos] |= (1u << (31u - diff));
310 return true;
311 }
312
313 return false;
314 }
315
326 const T& from,
327 const T& to)
328 {
329 constexpr uint32_t full_mask = (std::numeric_limits<uint32_t>::max)();
330
331 // Adapt incoming range to range limits
332 T min = (base_ >= from) ? base_ : from;
333 T max = (to >= base_ + NBITS) ? base_ + NBITS : to;
334
335 // Check precondition. Max should be explicitly above min.
336 if (min >= max)
337 {
338 return;
339 }
340
341 // Calc offset (distance from base) and num_bits (bits to be set)
342 Diff d_func;
343 uint32_t offset = d_func(min, base_); // Bit position from base
344 uint32_t n_bits = d_func(max, min); // Number of bits pending
345
346 num_bits_ = std::max(num_bits_, offset + n_bits);
347
348 uint32_t pos = offset >> 5; // Item position
349 offset &= 31u; // Bit position inside item
350 uint32_t mask = full_mask; // Mask with all bits set
351 mask >>= offset; // Remove first 'offset' bits from mask
352 uint32_t bits_in_mask = 32u - offset; // Take note of number of set bits in mask
353
354 // This loop enters whenever the whole mask should be added
355 while (n_bits >= bits_in_mask)
356 {
357 bitmap_[pos] |= mask; // Set whole mask of bits
358 pos++; // Go to next position in the array
359 n_bits -= bits_in_mask; // Decrease number of pending bits
360 mask = full_mask; // Mask with all bits set
361 bits_in_mask = 32u; // All bits set in mask (32)
362 }
363
364 // This condition will be true if the last bits of the mask should not be used
365 if (n_bits > 0)
366 {
367 bitmap_[pos] |= mask & (full_mask << (bits_in_mask - n_bits));
368 }
369 }
370
377 void remove(
378 const T& item) noexcept
379 {
380 // Check item is inside the allowed range.
381 T max_value = max();
382 if ((item >= base_) && (max_value >= item))
383 {
384 // Calc distance from base to item, and set the corresponding bit.
385 Diff d_func;
386 uint32_t diff = d_func(item, base_);
387 uint32_t pos = diff >> 5;
388 diff &= 31u;
389 bitmap_[pos] &= ~(1u << (31u - diff));
390
391 if (item == max_value)
392 {
393 calc_maximum_bit_set(pos + 1, 0);
394 }
395 }
396 }
397
407 uint32_t& num_bits,
408 bitmap_type& bitmap,
409 uint32_t& num_longs_used) const noexcept
410 {
411 num_bits = num_bits_;
412 num_longs_used = (num_bits_ + 31u) / 32u;
413 bitmap = bitmap_;
414 }
415
421 uint32_t count() const noexcept
422 {
423 uint32_t total = 0;
424 // Traverse through the significant items on the bitmap
425 uint32_t n_longs = (num_bits_ + 31u) / 32u;
426 for (uint32_t i = 0; i < n_longs; i++)
427 {
428 // Count bits set on the item
429 uint32_t bits = bitmap_[i];
430 // Use algorithm from https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
431 // to count number of bits set in a 32-bit integer
432 bits = bits - ((bits >> 1) & 0x55555555);
433 bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
434 bits = (bits + (bits >> 4)) & 0x0F0F0F0F;
435 total += (bits * 0x1010101) >> 24;
436 }
437
438 return total;
439 }
440
449 uint32_t num_bits,
450 const uint32_t* bitmap) noexcept
451 {
452 num_bits_ = std::min(num_bits, NBITS);
453 uint32_t num_items = ((num_bits_ + 31u) / 32u);
454 uint32_t num_bytes = num_items * static_cast<uint32_t>(sizeof(uint32_t));
455 bitmap_.fill(0u);
456 memcpy(bitmap_.data(), bitmap, num_bytes);
457 // trim unused bits if (0 < num_bits && num_bits % 32 != 0)
458 short shift = num_bits & 31u;
459 if (0 < num_bits && shift != 0)
460 {
461 bitmap_[num_items - 1] &= ~((std::numeric_limits<uint32_t>::max)() >> shift);
462 }
463 calc_maximum_bit_set(num_items, 0);
464 }
465
471 template<class UnaryFunc>
473 UnaryFunc f) const
474 {
475 T item = base_;
476
477 // Traverse through the significant items on the bitmap
478 uint32_t n_longs = (num_bits_ + 31u) / 32u;
479 for (uint32_t i = 0; i < n_longs; i++)
480 {
481 // Traverse through the bits set on the item, msb first.
482 // Loop will stop when there are no bits set.
483 uint32_t bits = bitmap_[i];
484 while (bits)
485 {
486 // We use an intrinsic to find the index of the highest bit set.
487 // Most modern CPUs have an instruction to count the leading zeroes of a word.
488 // The number of leading zeroes will give us the index we need.
489#if _MSC_VER
490 unsigned long bit;
491 _BitScanReverse(&bit, bits);
492 uint32_t offset = 31u ^ bit;
493#else
494 uint32_t offset = static_cast<uint32_t>(__builtin_clz(bits));
495 uint32_t bit = 31u ^ offset;
496#endif // if _MSC_VER
497
498 // Call the function for the corresponding item
499 f(item + offset);
500
501 // Clear the most significant bit
502 bits &= ~(1u << bit);
503 }
504
505 // There are 32 items on each bitmap item.
506 item = item + 32u;
507 }
508 }
509
510protected:
511
515 uint32_t num_bits_;
516
517private:
518
519 void shift_map_left(
520 uint32_t n_bits)
521 {
522 if (n_bits >= num_bits_)
523 {
524 // Shifting more than most significant. Clear whole bitmap.
525 num_bits_ = 0;
526 bitmap_.fill(0u);
527 }
528 else
529 {
530 // Significant bit will move left by n_bits
531 num_bits_ -= n_bits;
532
533 // Div and mod by 32
534 uint32_t n_items = n_bits >> 5;
535 n_bits &= 31u;
536 if (n_bits == 0)
537 {
538 // Shifting a multiple of 32 bits, just move the bitmap integers
539 std::copy(bitmap_.begin() + n_items, bitmap_.end(), bitmap_.begin());
540 std::fill_n(bitmap_.rbegin(), n_items, 0);
541 }
542 else
543 {
544 // Example. Shifting 44 bits. Should shift one complete word and 12 bits.
545 // Need to iterate forward and take 12 bits from next word (shifting it 20 bits).
546 // aaaaaaaa bbbbbbbb cccccccc dddddddd
547 // bbbbbccc bbbbbbbb cccccccc dddddddd
548 // bbbbbccc cccccddd ddddd000 dddddddd
549 // bbbbbccc cccccddd ddddd000 00000000
550 uint32_t overflow_bits = 32u - n_bits;
551 size_t last_index = NITEMS - 1u;
552 for (size_t i = 0, n = n_items; n < last_index; i++, n++)
553 {
554 bitmap_[i] = (bitmap_[n] << n_bits) | (bitmap_[n + 1] >> overflow_bits);
555 }
556 // Last one does not have next word
557 bitmap_[last_index - n_items] = bitmap_[last_index] << n_bits;
558 // Last n_items will become 0
559 std::fill_n(bitmap_.rbegin(), n_items, 0);
560 }
561 }
562 }
563
564 void shift_map_right(
565 uint32_t n_bits)
566 {
567 if (n_bits >= NBITS)
568 {
569 // Shifting more than total bitmap size. Clear whole bitmap.
570 num_bits_ = 0;
571 bitmap_.fill(0u);
572 }
573 else
574 {
575 // Detect if highest bit will be dropped and take note, as we will need
576 // to find new maximum bit in that case
577 uint32_t new_num_bits = num_bits_ + n_bits;
578 bool find_new_max = new_num_bits > NBITS;
579
580 // Div and mod by 32
581 uint32_t n_items = n_bits >> 5;
582 n_bits &= 31u;
583 if (n_bits == 0)
584 {
585 // Shifting a multiple of 32 bits, just move the bitmap integers
586 std::copy(bitmap_.rbegin() + n_items, bitmap_.rend(), bitmap_.rbegin());
587 std::fill_n(bitmap_.begin(), n_items, 0);
588 }
589 else
590 {
591 // Example. Shifting 44 bits. Should shift one complete word and 12 bits.
592 // Need to iterate backwards and take 12 bits from previous word (shifting it 20 bits).
593 // aaaaaaaa bbbbbbbb cccccccc dddddddd
594 // aaaaaaaa bbbbbbbb cccccccc bbbccccc
595 // aaaaaaaa bbbbbbbb aaabbbbb bbbccccc
596 // aaaaaaaa 000aaaaa aaabbbbb bbbccccc
597 // 00000000 000aaaaa aaabbbbb bbbccccc
598 uint32_t overflow_bits = 32u - n_bits;
599 size_t last_index = NITEMS - 1u;
600 for (size_t i = last_index, n = last_index - n_items; n > 0; i--, n--)
601 {
602 bitmap_[i] = (bitmap_[n] >> n_bits) | (bitmap_[n - 1] << overflow_bits);
603 }
604 // First item does not have previous word
605 bitmap_[n_items] = bitmap_[0] >> n_bits;
606 // First n_items will become 0
607 std::fill_n(bitmap_.begin(), n_items, 0);
608 }
609
610 num_bits_ = new_num_bits;
611 if (find_new_max)
612 {
613 calc_maximum_bit_set(NITEMS, n_items);
614 }
615 }
616 }
617
618 void calc_maximum_bit_set(
619 uint32_t starting_index,
620 uint32_t min_index)
621 {
622 num_bits_ = 0;
623 for (uint32_t i = starting_index; i > min_index;)
624 {
625 --i;
626 uint32_t bits = bitmap_[i];
627 if (bits != 0)
628 {
629 bits = (bits & ~(bits - 1));
630#if _MSC_VER
631 unsigned long bit;
632 _BitScanReverse(&bit, bits);
633 uint32_t offset = (31u ^ bit) + 1;
634#else
635 uint32_t offset = static_cast<uint32_t>(__builtin_clz(bits)) + 1u;
636#endif // if _MSC_VER
637 num_bits_ = (i << 5u) + offset;
638 break;
639 }
640 }
641 }
642
643};
644
645} // namespace fastdds
646} // namespace eprosima
647
648#endif // DOXYGEN_SHOULD_SKIP_THIS_PUBLIC
649
650#if _MSC_VER
651
652#if defined(FASTDDS_RESTORE_MIN)
653#pragma pop_macro("min")
654#undef FASTDDS_RESTORE_MIN
655#endif // defined(FASTDDS_RESTORE_MIN)
656
657#if defined(FASTDDS_RESTORE_MAX)
658#pragma pop_macro("max")
659#undef FASTDDS_RESTORE_MAX
660#endif // defined(FASTDDS_RESTORE_MAX)
661
662#endif // if _MSC_VER
663
664#endif // FASTDDS_UTILS__FIXED_SIZE_BITMAP_HPP
bitmap_type bitmap_
Definition fixed_size_bitmap.hpp:514
FragmentNumber_t base() const noexcept
Definition fixed_size_bitmap.hpp:133
uint32_t num_bits_
Definition fixed_size_bitmap.hpp:515
bool empty() const noexcept
Returns whether the range is empty (i.e.
Definition fixed_size_bitmap.hpp:209
bool add(const T &item) noexcept
Adds an element to the range.
Definition fixed_size_bitmap.hpp:297
void bitmap_get(uint32_t &num_bits, bitmap_type &bitmap, uint32_t &num_longs_used) const noexcept
Gets the current value of the bitmap.
Definition fixed_size_bitmap.hpp:406
T min() const noexcept
Returns the lowest value set in the range.
Definition fixed_size_bitmap.hpp:229
std::array< uint32_t, NITEMS > bitmap_type
Definition fixed_size_bitmap.hpp:82
void bitmap_set(uint32_t num_bits, const uint32_t *bitmap) noexcept
Sets the current value of the bitmap.
Definition fixed_size_bitmap.hpp:448
FragmentNumber_t base_
Definition fixed_size_bitmap.hpp:512
void add_range(const T &from, const T &to)
Adds a range of elements to the range.
Definition fixed_size_bitmap.hpp:325
void base_update(T base) noexcept
Set a new base for the range, keeping old values where possible.
Definition fixed_size_bitmap.hpp:176
FragmentNumber_t range_max_
Definition fixed_size_bitmap.hpp:513
BitmapRange(T base) noexcept
Base-specific constructor.
Definition fixed_size_bitmap.hpp:102
void base(T base, uint32_t max_bits) noexcept
Set a new base and maximum bits for the range.
Definition fixed_size_bitmap.hpp:160
void for_each(UnaryFunc f) const
Apply a function on every item on the range.
Definition fixed_size_bitmap.hpp:472
uint32_t count() const noexcept
Counts the number of elements set in the bitmap.
Definition fixed_size_bitmap.hpp:421
bool is_set(const T &item) const noexcept
Checks if an element is present in the bitmap.
Definition fixed_size_bitmap.hpp:269
BitmapRange(T base, uint32_t max_bits) noexcept
Range specific constructor.
Definition fixed_size_bitmap.hpp:117
BitmapRange() noexcept
Default constructor.
Definition fixed_size_bitmap.hpp:88
void base(T base) noexcept
Set a new base for the range.
Definition fixed_size_bitmap.hpp:144
T max() const noexcept
Returns the highest value set in the range.
Definition fixed_size_bitmap.hpp:219
void remove(const T &item) noexcept
Removes an element from the range.
Definition fixed_size_bitmap.hpp:377
eProsima namespace.
Definition fixed_size_bitmap.hpp:53
constexpr auto operator()(T a, T b) const -> decltype(a - b)
Definition fixed_size_bitmap.hpp:54