扫描位阵列以获得多位模式

时间:2017-05-20 12:47:52

标签: c++ c++11 memory-management bit-manipulation dynamic-allocation

我正在编写一个内存分配器,它由位图(uint8_t数组)支持当前当分配请求出现时我将位图从0位扫描到n位并搜索可以满足的空间请求。 (位1表示使用0表示页面的页面是免费的)现在,不是一次一位地搜索空格,是否有技术可以更快地扫描整个阵列?即如果有3页内存请求到达,我想在一次搜索中一次性搜索000模式而不进行循环?

PS:我没有使用std::bitset,因为它不适用于我正在使用的编译器。 AFAIK也不允许我搜索多个位。

编辑:比特被打包成字节,一个uint8_t有8页(每比特1个)编码。

2 个答案:

答案 0 :(得分:1)

要扫描一个空页,您可以一次遍历位数一个完整字节并检查它是否小于255.如果它小于,则至少有一个零位。更好的方法是一次扫描32位或64位(无符号整数),然后缩小uint内的搜索范围。

要优化一位,您可以用零位跟踪第一个字节(并在释放页面时更新该位置)。一旦分配了这个空闲页面,这可能会产生误报,但至少下次扫描可以从那里开始而不是在开始时。

如果您愿意在功率为2的情况下对齐较大的块(取决于您的数据结构),则可以优化对多个页面的扫描。例如,要分配8个页面,您只需扫描整个字节为零:

1 page: scan for any zero bit (up to 64 bits at a time)
2 pages: scan for 2 zero bits at bit position 0,2,4,6
3-4 pages: scan for zero nibble (for 3 pages, the fourth would be available for 1 page then)
5-8 pages: scan for an empty byte

for each of the above, you could first scan 64 bits at a time.

这样,您就不必担心(或检查)byte / uint32 / uint64边界处的重叠零范围。

对于每种类型,可以保留/更新第一个空闲块的起始位置。

答案 1 :(得分:1)

不是你问题的完整答案(我想),但我希望以下功能可以提供帮助。

template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
 {
   while ( --num )
      iVal |= ((iVal << 1) | I{1});

   return iVal != I(-1);
 }

它返回(如果我已正确写入)true 如果(不在哪里)num中至少有iVal个连续的零位。

以下是Tuint8_t

时的完整工作示例
#include <iostream>

template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
 {
   while ( --num )
      iVal |= ((iVal << 1) | I{1});

   return iVal != I(-1);
 }

int main()
 {
   uint8_t  u0 { 0b00100100 };
   uint8_t  u1 { 0b00001111 };
   uint8_t  u2 { 0b10000111 };
   uint8_t  u3 { 0b11000011 };
   uint8_t  u4 { 0b11100001 };
   uint8_t  u5 { 0b11110000 };

   std::cout << scan_n_zeros(u0, 2U) << std::endl; // print 1
   std::cout << scan_n_zeros(u0, 3U) << std::endl; // print 0
   std::cout << scan_n_zeros(u1, 4U) << std::endl; // print 1
   std::cout << scan_n_zeros(u1, 5U) << std::endl; // print 0
   std::cout << scan_n_zeros(u2, 4U) << std::endl; // print 1
   std::cout << scan_n_zeros(u2, 5U) << std::endl; // print 0
   std::cout << scan_n_zeros(u3, 4U) << std::endl; // print 1
   std::cout << scan_n_zeros(u3, 5U) << std::endl; // print 0
   std::cout << scan_n_zeros(u4, 4U) << std::endl; // print 1
   std::cout << scan_n_zeros(u4, 5U) << std::endl; // print 0
   std::cout << scan_n_zeros(u5, 4U) << std::endl; // print 1
   std::cout << scan_n_zeros(u5, 5U) << std::endl; // print 0
 }