C 什么';复制未对齐的位数组是一种高效的算法?
过去我已经做过很多次了,但我从来没有对结果感到满意 有人能提出一种从源到目标复制连续位数组的快速方法吗?在这种情况下,源和目标可能不会在方便的处理器边界上对齐(右移) 如果源和目标都没有对齐,那么问题很快就会变成只有其中一个没有对齐(在第一次拷贝之后) 作为一个起点,我的代码不可避免地会出现以下情况(未经测试,忽略副作用这只是一个即兴示例):C 什么';复制未对齐的位数组是一种高效的算法?,c,copy,bitarray,C,Copy,Bitarray,过去我已经做过很多次了,但我从来没有对结果感到满意 有人能提出一种从源到目标复制连续位数组的快速方法吗?在这种情况下,源和目标可能不会在方便的处理器边界上对齐(右移) 如果源和目标都没有对齐,那么问题很快就会变成只有其中一个没有对齐(在第一次拷贝之后) 作为一个起点,我的代码不可避免地会出现以下情况(未经测试,忽略副作用这只是一个即兴示例): const char mask[8]={1,3,7,15,31,63,127,255}; /*假设: *-目的地已归零, *-偏移是右移 *-要复制的位很
const char mask[8]={1,3,7,15,31,63,127,255};
/*假设:
*-目的地已归零,
*-偏移是右移
*-要复制的位很大(>32位)
*/
int位数组拷贝(char*src,int-src\u位偏移量,int-src\u位长度,
字符*dst,整数dst_位_偏移量){
如果(src_bit_offset==dst_bit_offset){/*不是很有趣*/
}否则{
int bit_diff_offset=src_bit_offset-dst_bit_offset;/*假设为正*/
循环计数;
字符c;
char mask_val=掩码[位差异偏移];
/*开始,把目的地排好*/
c=(*src++>(8位差异偏移量)和掩码值);
c&=掩码[8-dst位偏移];
*dst++|=c;
src_bit_len-=8-dst_bit_偏移量;
循环计数=src位长度>>3;
而(--循环计数>=0)
*dst++=(*src++>(8位差分偏移量))&掩码值;
/*尾随副本等*/
如果(src_bit_len%8)/**/
}
}
(事实上,这比我以前做的要好。看起来还不错)您的内部循环将两个字节的片段移动到目标字节。这几乎是最优的。以下是一些没有特定顺序的提示:
- 没有必要一次只限制一个字节。使用平台允许的最大整数大小。这当然会使你的开始和尾随逻辑复杂化
- 如果使用无符号字符或整数,则可能不需要在源代码的第二部分右移后屏蔽它。这将取决于您的编译器
- 如果确实需要掩码,请确保编译器将表查找移到循环之外。如果不是,则将其复制到临时变量并使用该变量
你的解决方案看起来和我所看到的差不多:基本上在开始和结束时做一些未对齐的工作,中间的主循环使用对齐的访问。如果您确实需要效率,并且需要在很长的比特流上执行此操作,我建议在主循环中使用特定于体系结构的东西,如SSE2。
什么是最佳的取决于目标平台。在一些没有桶形移位器的平台上,将整个向量向右或向左移动一位,n次,因为n这就是我最后要做的。(编辑于2014年8月21日针对单位复制错误进行了更改。)#包括
#包括
#包括
#定义PREPARE_FIRST_COPY()\
做{\
如果(src_len>=(字符位-dst_偏移量(模)){\
*dst&=反向屏蔽[dst_偏移量_模]\
src_len-=CHAR_BIT-dst_offset_模\
}否则{\
*dst&=反向屏蔽[dst\U偏移量\U模]\
|反向屏蔽异或[dst_偏移量_模+src_len]\
c&=反向屏蔽[dst_偏移量_模+src_len]\
src_len=0\
}}while(0)
静态空隙
位数组拷贝(常量无符号字符*src\u组织,int src\u偏移量,int src\u len,
无符号字符*dst_组织,整数dst_偏移)
{
静态常量无符号字符掩码[]=
{0x00、0x01、0x03、0x07、0x0f、0x1f、0x3f、0x7f、0xff};
静态常量无符号字符反向_掩码[]=
{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
静态常量无符号字符反向掩码异或[]=
{0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00};
如果(src_len){
常量无符号字符*src;
无符号字符*dst;
int src_offset_模,
dst_偏移量_模;
src=src_org+(src_偏移量/字符位);
dst=dst_组织+(dst_偏移量/字符位);
src_offset_modulo=src_offset%CHAR_位;
dst_偏移量_模=dst_偏移量%CHAR_位;
if(src_offset_modulo==dst_offset_modulo){
int字节_len;
int src_len_模;
if(src_偏移量_模){
无符号字符c;
c=反向屏蔽异或[dst\U偏移量\U模]&*src++;
准备第一份副本();
*dst++|=c;
}
byte_len=src_len/CHAR_位;
src_len_modulo=src_len%CHAR_位;
如果(字节长度){
memcpy(dst、src、byte_len);
src+=字节长度;
dst+=字节长度;
}
if(src_len_模){
*dst&=反向屏蔽异或[src_len_modulo];
*dst |=反向屏蔽[src_len_modulo]和*src;
}
}否则{
整数位差分,
位差;
int字节_len;
int src_len_模;
无符号字符c;
/*
*开始:在目的地排好队。
*/
if(src_offset_modulo>dst_offset_modulo){
bit_diff_ls=src_offset_modulo-dst_offset_modulo;
bit_diff_rs=字符位-bit_diff_ls;
c=*src++>位d
const char mask[8] = { 1, 3, 7, 15, 31, 63, 127, 255 };
/* Assume:
* - destination is already zeroed,
* - offsets are right shifts
* - bits to copy is big (> 32 say)
*/
int bitarray_copy(char * src, int src_bit_offset, int src_bit_len,
char * dst, int dst_bit_offset) {
if (src_bit_offset == dst_bit_offset) { /* Not very interesting */
} else {
int bit_diff_offset = src_bit_offset - dst_bit_offset; /* assume positive */
int loop_count;
char c;
char mask_val = mask[bit_diff_offset];
/* Get started, line up the destination. */
c = (*src++ << bit_diff_offset) | ((*src >> (8 - bit_diff_offset)) & mask_val);
c &= mask[8-dst_bit_offset];
*dst++ |= c;
src_bit_len -= 8 - dst_bit_offset;
loop_count = src_bit_len >> 3;
while (--loop_count >= 0)
* dst ++ = (*src++ << bit_diff_offset) | ((*src >> (8 - bit_diff_offset)) & mask_val);
/* Trailing tail copy etc ... */
if (src_bit_len % 8) /* ... */
}
}
src1 = *src++;
src2 = (src1 shl shiftamount1) | (src2 shr shiftamount2);
*dest++ = src2;
src2 = *src++;
src1 = (src2 shl shiftamount1) | (src1 shr shiftamount2);
*dest++ = src1;
src0 = *src++;
src1 = *src++;
src2 = *src++;
src3 = *src++;
tmp = src0;
src0 = src0 shr shiftamount1
src0 = src0 | src1 shl shiftamount2
src1 = src1 shr shiftamount1
src1 = src1 | src2 shl shiftamount2
src2 = src2 shr shiftamount1
src2 = src2 | src3 shl shiftamount2
src3 = src3 shr shiftamount1
src3 = src3 | tmp shl shiftamount2
*dest++ = src0;
*dest++ = src1;
*dest++ = src2;
*dest++ = src3;
#include <limits.h>
#include <string.h>
#include <stddef.h>
#define PREPARE_FIRST_COPY() \
do { \
if (src_len >= (CHAR_BIT - dst_offset_modulo)) { \
*dst &= reverse_mask[dst_offset_modulo]; \
src_len -= CHAR_BIT - dst_offset_modulo; \
} else { \
*dst &= reverse_mask[dst_offset_modulo] \
| reverse_mask_xor[dst_offset_modulo + src_len]; \
c &= reverse_mask[dst_offset_modulo + src_len]; \
src_len = 0; \
} } while (0)
static void
bitarray_copy(const unsigned char *src_org, int src_offset, int src_len,
unsigned char *dst_org, int dst_offset)
{
static const unsigned char mask[] =
{ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
static const unsigned char reverse_mask[] =
{ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
static const unsigned char reverse_mask_xor[] =
{ 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00 };
if (src_len) {
const unsigned char *src;
unsigned char *dst;
int src_offset_modulo,
dst_offset_modulo;
src = src_org + (src_offset / CHAR_BIT);
dst = dst_org + (dst_offset / CHAR_BIT);
src_offset_modulo = src_offset % CHAR_BIT;
dst_offset_modulo = dst_offset % CHAR_BIT;
if (src_offset_modulo == dst_offset_modulo) {
int byte_len;
int src_len_modulo;
if (src_offset_modulo) {
unsigned char c;
c = reverse_mask_xor[dst_offset_modulo] & *src++;
PREPARE_FIRST_COPY();
*dst++ |= c;
}
byte_len = src_len / CHAR_BIT;
src_len_modulo = src_len % CHAR_BIT;
if (byte_len) {
memcpy(dst, src, byte_len);
src += byte_len;
dst += byte_len;
}
if (src_len_modulo) {
*dst &= reverse_mask_xor[src_len_modulo];
*dst |= reverse_mask[src_len_modulo] & *src;
}
} else {
int bit_diff_ls,
bit_diff_rs;
int byte_len;
int src_len_modulo;
unsigned char c;
/*
* Begin: Line things up on destination.
*/
if (src_offset_modulo > dst_offset_modulo) {
bit_diff_ls = src_offset_modulo - dst_offset_modulo;
bit_diff_rs = CHAR_BIT - bit_diff_ls;
c = *src++ << bit_diff_ls;
c |= *src >> bit_diff_rs;
c &= reverse_mask_xor[dst_offset_modulo];
} else {
bit_diff_rs = dst_offset_modulo - src_offset_modulo;
bit_diff_ls = CHAR_BIT - bit_diff_rs;
c = *src >> bit_diff_rs &
reverse_mask_xor[dst_offset_modulo];
}
PREPARE_FIRST_COPY();
*dst++ |= c;
/*
* Middle: copy with only shifting the source.
*/
byte_len = src_len / CHAR_BIT;
while (--byte_len >= 0) {
c = *src++ << bit_diff_ls;
c |= *src >> bit_diff_rs;
*dst++ = c;
}
/*
* End: copy the remaing bits;
*/
src_len_modulo = src_len % CHAR_BIT;
if (src_len_modulo) {
c = *src++ << bit_diff_ls;
c |= *src >> bit_diff_rs;
c &= reverse_mask[src_len_modulo];
*dst &= reverse_mask_xor[src_len_modulo];
*dst |= c;
}
}
}
}