优化字符串搜索单个字节

时间:2015-09-30 20:07:08

标签: c++ string-search

通常,字符串搜索算法(如Boyer-Moore)针对搜索字符串为long-ish的情况进行了优化。也就是说,Boyer-Moore很棒,因为通过使用我们的文本排列搜索字符串,如果搜索字符串的末尾与文本不匹配,我们可以跳过N = len(search string)个字符。

但是如果我们的搜索字符串真的很短怎么办?像一个字节或字符?在这种情况下,Boyer-Moore并没有多大帮助。

那么,有哪些替代算法可以加速搜索?

我知道许多优化的库搜索例程(如C中的memchr)采取逐字逐句读取输入字符串的策略,而不是char字符。因此,在64位机器上,可以同时检查8个字节,而不是单个字节。

我想知道这些优化的字符串/字节搜索实际上是如何工作的。那么实际比较是如何工作的呢?我知道它显然必须涉及位屏蔽 - 但我不知道如何执行所有位屏蔽比仅仅逐字符搜索更好。

因此,假设我们的搜索字符为0xFF。忽略对齐问题,我们假设我们有一些输入缓冲区:void* buf。我们可以通过以下方式逐字阅读:

const unsigned char search_char = 0xFF;
unsigned char* bufptr = static_cast<unsigned char*>(buf);
unsigned char* bufend = bufptr + BUF_SIZE;

while (bufptr != bufend)
{
   // Ignore alignment concerns for now, assume BUF_SIZE % sizeof(uintptr_t) == 0
   //
   std::uinptr_t next_word = *reinterpret_cast<std::uintptr_t*>(bufptr);

   // ... but how do we compare next_word with our search char?

   bufptr += sizeof(std::uintptr_t);
}

我也意识到上面的代码不是严格可移植的,因为std::uintptr_t并不能保证实际上是字大小。但是,为了这个问题,我们假设std::uinptr_t等于处理器字大小。 (实际实现可能需要特定于平台的宏来获取实际的字大小)

那么,我们如何实际检查字节0xFF是否出现在next_word的值的任何位置?

我们当然可以使用OR操作,但似乎我们仍然需要执行大量的OR和位移以检查next_word的每个字节,对于这种优化实际上是否比简单地逐字符扫描更有意义,这一点值得怀疑。

1 个答案:

答案 0 :(得分:2)

您可以使用this snippet from Bit Twiddling Hacks

#define haszero(v) (((v) - 0x01010101UL) & ~(v) & 0x80808080UL)
#define hasvalue(x,n) \
(haszero((x) ^ (~0UL/255 * (n))))

它有效地将每个字节与要测试的字符进行异或,然后确定是否有任何字节现在为零。

此时,您可以从表达式的返回值中获取匹配字节(或字节)的位置,例如:如果最低有效字节与值匹配,则该值将为0x00000080。