短(ASCII,每个字符的7位)串存储和比较优化在C ++中(Short (ASCII, 7-bit

2019-10-29 23:08发布

在我的项目,我用巨大的一套短字符串的ASCII 7位和必须处理(存储,比较,搜索等),这些字符串以最大性能。 基本上,我建立uint64_t中类型的一些索引阵列,并且每个元素存储一个字的9个字符,并使用该索引作为数字元件,用于任何字符串比较操作。 当前执行工作的快速,但可能这是可能的,如果你会去改善它一点..

此函数向上转换为9个初始字符uint64_t中值 - 该数字的任何比较的等效标准“的strcmp”的功能。

#include <cstdint>
#include <iostream>

uint64_t cnv(const char* str, size_t len)
{
    uint64_t res = 0;

    switch (len)
    {
    default:
    case 9: res = str[8];
    case 8: res |= uint64_t(str[7]) << 7;
    case 7: res |= uint64_t(str[6]) << 14;
    case 6: res |= uint64_t(str[5]) << 21;
    case 5: res |= uint64_t(str[4]) << 28;
    case 4: res |= uint64_t(str[3]) << 35;
    case 3: res |= uint64_t(str[2]) << 42;
    case 2: res |= uint64_t(str[1]) << 49;
    case 1: res |= uint64_t(str[0]) << 56;
    case 0: break;
    }

    return res;
}

int main()
{
    uint64_t v0 = cnv("000", 3);
    uint64_t v1 = cnv("0000000", 7);

    std::cout << (v1 < v0);
}

Answer 1:

您可能会加载8个字节的原始字符串的一次比凝结他们得到的整内(和扭转他们,如果你的机器有一个小端数表示)。

#include <iostream>

uint64_t ascii2ulong (const char  *s, int len)
{
    uint64_t i = (*(uint64_t*)s);
    if (len < 8) i &= ((1UL << (len<<3))-1);
#ifndef BIG_ENDIAN
    i = (i&0x007f007f007f007fUL) | ((i & 0x7f007f007f007f00) >> 1);
    i = (i&0x00003fff00003fffUL) | ((i & 0x3fff00003fff0000) >> 2);
    i = ((i&0x000000000fffffffUL) << 7) | ((i & 0x0fffffff00000000) << (7-4));
    // Note: Previous line: an additional left shift of 7 is applied
    // to make room for s[8] character
#else
    i = ((i&0x007f007f007f007fUL) << 7)  | ((i & 0x7f007f007f007f00) >> 8);
    i = ((i&0x00003fff00003fffUL) << 14) | ((i & 0x3fff00003fff0000) >> 16);
    i = ((i&0x000000000fffffffUL) << (28+7)) | ((i & 0x0fffffff00000000) >> (32-7));
#endif

    if (len > 8) i |= ((uint64_t)s[8]);
    return i;
}


//Test
std::string ulong2str(uint64_t compressed) {
    std::string s;
    for (int i = 56; i >= 0; i-=7) 
        if (char nxt=(compressed>>i)&0x7f) s+= nxt;
    return s;
}
int main() {
    std::cout << ulong2str(ascii2ulong("ABCDEFGHI", 9))<<std::endl;
    std::cout << ulong2str(ascii2ulong("ABCDE", 5))<<std::endl;
    std::cout << (ascii2ulong("AB", 2) < ascii2ulong("B", 1))<<std::endl;
    std::cout << (ascii2ulong("AB", 2) < ascii2ulong("A", 1))<<std::endl;
    return 0;
}

但请注意:在做你正式也就侵犯了分配的地址范围,这样的方式(如果您的原始字符串具有<8个字节分配)。 如果你的内存完整性检查运行一个程序,它可能会产生一个运行时错误。 为了避免这种情况,你当然可以使用memcpy复制的字节数,你在地方的需要uint64_t i = (*(uint64_t*)s);

uint64_t i;
memcpy(&i,s,std::min(len,8));

如果某些硬件加速用于memcpy你的机器(这是有可能的),可能在效率方面是不坏。



文章来源: Short (ASCII, 7-bit per character) string storage and comparison optimization in C++