假设您从以下内容开始:
block-1576017486920
您要插入以下位置(八进制):
0、1、2、4、10、20、40、100
这意味着您需要以下内容:
src[0] src[1] src[2] src[3] src[4] src[5] src[6] src[7]
-------- -------- -------- -------- -------- -------- -------- --------
7 6 5 4 3 2 1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
所以
dst[0] dst[1] dst[2] dst[3] dst[4] dst[5] dst[6] dst[7] dst[8]
-------- -------- -------- -------- -------- -------- -------- -------- --------
1
0 7 6 5 4 3 2 1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000
(省略了无用的蒙版。)
,
您可以将输入数组视为64位整数,以使其更快。假设输入和输出值是这样的
array = aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
newArr = aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000
然后您可以通过这种方式获得所需的结果
uin64_t src = htobe64(*(uint64_t*)array); // operate on big endian
uint64_t* dst = (uint64_t*)newArr;
*dst = (src & 0xFE00'0000'0000'0000) >> 0; // aaaaaaa
*dst |= (src & 0x01FF'FFFF'FC00'0000) >> 1; // abbbbbbbbccccccccddddddddeeeeee
*dst |= (src & 0x0000'0000'03FF'F800) >> 2; // eeffffffffggggg
*dst |= (src & 0x0000'0000'0000'07F0) >> 3; // ggghhhh
*dst = be64toh(*dst); // convert back to the native endian
newArr[8] = ((array[7] & 0x0E) << 4) | ((array[7] & 0x01) << 3); // hhh0h000
为避免严格的别名,您可以更改为memcpy,以从array
复制到src
并从dst
复制到newArr
当然,您可能需要对齐输入和输出阵列以提高性能。在许多现代建筑中,这也是必须的
#ifdef _MSC_VER
__declspec(align(8)) uint8_t array[8]; #64 bit array
__declspec(align(8)) uint8_t newArr[9];
#else
uint8_t array[8] __attribute__((aligned(8))); #64 bit array
uint8_t newArr[9] __attribute__((aligned(8)));
#endif
在带有BMI2的现代x86上,您可以使用新的bit deposit instruction直接获取前8个字节
uint64_t src;
memcpy(&src,&array,sizeof src); // avoid strict aliasing
uin64_t src = htobe64(src);
uint64_t dst = _pdep_u64(src >> 4,// aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0
0b11111110'11111111'11111111'11111111'11111110'11111111'11111110'11111110);
// hhh0h000
newArr[8] = _pdep_u32(src,0b11101000);
*dst = be64toh(*dst); // convert back to the native endian
memcpy(&newArr,&dst,sizeof dst); // avoid strict aliasing
本文链接:https://www.f2er.com/2945921.html