C++ 扫描位阵列以获得多个位的模式
我正在编写一个内存分配器,它由一个位图(数组ofC++ 扫描位阵列以获得多个位的模式,c++,c++11,memory-management,bit-manipulation,dynamic-allocation,C++,C++11,Memory Management,Bit Manipulation,Dynamic Allocation,我正在编写一个内存分配器,它由一个位图(数组ofuint8\t)支持。当前,当出现分配请求时,我按从0到n位的顺序扫描位图,并搜索一个可以满足请求的空间。(位1表示使用了一个0表示的页面是空闲的)现在不是一次一位搜索一个空间,有没有技术可以更快地扫描整个阵列?i、 e如果3页内存的请求到达,我想一次搜索数组中的000模式,理想情况下没有循环 PS:我没有使用std::bitset,因为它不适用于我正在使用的编译器。AFAIK不允许我也搜索多个位 编辑:位被压缩到字节中。一个uint8\u t有8
uint8\t
)支持。当前,当出现分配请求时,我按从0到n位的顺序扫描位图,并搜索一个可以满足请求的空间。(位1表示使用了一个0表示的页面是空闲的)现在不是一次一位搜索一个空间,有没有技术可以更快地扫描整个阵列?i、 e如果3页内存的请求到达,我想一次搜索数组中的000
模式,理想情况下没有循环
PS:我没有使用std::bitset
,因为它不适用于我正在使用的编译器。AFAIK不允许我也搜索多个位
编辑:位被压缩到字节中。一个
uint8\u t
有8页(每位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.
这样,您就不必担心(或检查)字节/uint32/uint64边界处的零范围重叠
对于每种类型,都可以保留/更新带有第一个自由块的起始位置。我想这不是对您问题的完整回答,但我希望以下功能可以有所帮助
template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
{
while ( --num )
iVal |= ((iVal << 1) | I{1});
return iVal != I(-1);
}
这是否会形成uint16,以便我可以将两个字节分组到uint16中,以说明从一个字节到下一个字节的转换,然后将窗口从开始到结束滑动一个字节?@HamzaYerlikaya-我开发了一个模板函数,正是因为它适用于所有整数无符号类型。您能稍微扩展一下位移位的工作原理吗。
#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
}