簡體   English   中英

C ++中的短(ASCII,每個字符7位)字符串存儲和比較優化

[英]Short (ASCII, 7-bit per character) string storage and comparison optimization in C++

在我的項目中,我正在使用大量的ASCII 7位短字符串集,並且必須以最佳性能處理(存儲,比較,搜索等)這些字符串。 基本上,我建立了一些uint64_t類型的Index數組,每個元素存儲一個單詞的9個字符,並將該索引用作任何字符串比較操作的Numeric元素。 當前的實現工作很快,但是如果您願意的話,可能可以對其進行一些改進。

此函數最多將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);
}

您可以一次加載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你的機器(這是有可能的),可能在效率方面是不壞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM