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;
            }
        }
    }
}