你能改变编码吗?如你所发现,使用每个字节上的一位来指示是否有另一个字节跟随,对处理效率真的很不好。
更好的方法是采用UTF-8模型,将完整int的长度编码到第一个字节中:
0xxxxxxx // one byte with 7 bits of data
10xxxxxx 10xxxxxx // two bytes with 12 bits of data
110xxxxx 10xxxxxx 10xxxxxx // three bytes with 16 bits of data
1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx // four bytes with 22 bits of data
// etc.
但是UTF-8有特殊的属性,使其与ASCII更容易区分。这会使数据膨胀,而你并不关心ASCII,所以你需要修改它,使其看起来像这样:
0xxxxxxx // one byte with 7 bits of data
10xxxxxx xxxxxxxx // two bytes with 14 bits of data.
110xxxxx xxxxxxxx xxxxxxxx // three bytes with 21 bits of data
1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx // four bytes with 28 bits of data
// etc.
这个方法的压缩级别与你的方法相同(最多64位=9字节),但对CPU的处理更加容易。通过这个方法,您可以构建一个查找表,用于获取第一个字节的掩码和长度:
uint8_t const byte_counts[256];
uint8_t const byte_masks[256];
然后进行解码:
uint64_t v = 0;
v = *data & byte_masks[*data];
switch(byte_counts[*data])
{
case 3: v = v << 8 | *++data;
case 2: v = v << 8 | *++data;
case 1: v = v << 8 | *++data;
case 0: return v;
default:
__assume(0);
}
无论整数的大小如何,它只会命中一个分支点:开关语句,这通常会被放入跳转表中。您可以通过不让每个情况都落空来进一步优化它,从而为指令级并行(ILP)做出贡献。
func
不通知使用了多少字节?我认为这种设计需要牺牲效率... - Mooing Duck