4

我想知道是否有支持任意位置位操作的高性能 C/C++ 库?

例如: int BitCompare(const void* src, size_t srcOffsetInBits, const void* dst, size_t dstOffsetInBits, size_t sizeInBits); 比较[srcOffsetInBits, srcOffsetInBits + sizeInBits - 1]src 和[dstOffsetInBits, dstOffsetInBits + sizeInBits - 1]dst 中的位的函数,这些位被认为是 little-endian 无符号整数。假定所有缓冲区都足够大。

bool BitEqual(...);

void BitMove(...); // src and dst can overlap.

void BitCopy(...); // src and dst cannot overlap.

所有操作都应该只修改正在操作的位,而所有其他位都应该保留。

我做了一些尝试来实现 BitCompare。

static uint8_t mask8l1[9] = {
    0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
};

static uint8_t mask8l0[9] = {
    0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
};

// Offset-less compare.
int BitCompare8(const void* src, const void* dst, size_t sizeInBits)/*{{{*/
{
    const uint8_t* _src = static_cast<const uint8_t*>(src);
    const uint8_t* _dst = static_cast<const uint8_t*>(dst);

    size_t sizeInUint8s  = sizeInBits >> 3;
    size_t sizeRemaining = sizeInBits & 0x07;

    // MSB ---> LSB
    //           :               bits-to-compare                               :
    //       -----------------------------------------     ---------------------
    //       |   : sizeRemaining |                   | ... |                   |
    //       -----------------------------------------     ---------------------
    //                           @_src + sizeInUint8s                          @_src
    //
    // -----------------------------------------     ---------------------
    // |   : sizeRemaining |                   | ... |                   |
    // -----------------------------------------     ---------------------
    //                     @_dst + sizeInUint8s                          @_dst

    _src += sizeInUint8s;
    _dst += sizeInUint8s;

    // Compare the MSB sizeRemaining bits first.
    if (sizeRemaining)
    {
        //                               : sizeRemaining :
        //                          ----------------------
        //                          |    :      s        |
        //                          ----------------------
        //                                               @_src
        //      : sizeRemaining :
        // ----------------------
        // |    :      d        |
        // ----------------------
        //                      @_dst

        uint8_t s = *_src & mask8l1[sizeRemaining];
        uint8_t d = *_dst & mask8l1[sizeRemaining];

        if (s < d)
        {
            return -1;
        }
        else if (d < s)
        {
            return 1;
        }
    }

    // Then compare the LSB uint8s.
    while (sizeInUint8s)
    {
        //                         ----------------------
        //                         |         s          |
        //                         ----------------------
        //                                              @_src - 1
        // ---------------------
        // |        d          |
        // ---------------------
        //                     @_dst - 1

        uint8_t s = *--_src;
        uint8_t d = *--_dst;

        if (s < d)
        {
            return -1;
        }
        else if (d < s)
        {
            return 1;
        }

        --sizeInUint8s;
    }

    return 0;
}/*}}}*/


// Source-side offset compare.
int BitCompare8(const void* src, size_t offsetInBits, /*{{{*/
                const void* dst, size_t sizeInBits)
{
    const uint8_t* _src = static_cast<const uint8_t*>(src);
    const uint8_t* _dst = static_cast<const uint8_t*>(dst);

    _src += offsetInBits >> 3;
    offsetInBits &= 0x07;

    if (!offsetInBits)
    {
        return BitCompare8(_src, _dst, sizeInBits);
    }

    size_t sizeInUint8s  = sizeInBits >> 3;
    size_t sizeRemaining = sizeInBits & 0x07;

    // MSB ---> LSB
    //                :                 bits-to-compare                        :
    //                : sizeRemaining :                                        :
    //       -----------------------------------------     ---------------------
    //       |                   |    : offsetInBits | ... |    : offsetInBits |
    //       -----------------------------------------     ---------------------
    //                           @_src + sizeInUint8s                          @_src
    //
    // -----------------------------------------     ---------------------
    // |   : sizeRemaining |                   | ... |                   |
    // -----------------------------------------     ---------------------
    //                     @_dst + sizeInUint8s                          @_dst

    _src += sizeInUint8s;
    _dst += sizeInUint8s;

    // Move the MSB sizeRemaining bits first.
    if (sizeRemaining)
    {
        if (sizeRemaining + offsetInBits <= 8)
        {
            //                                        : sizeRemaining :
            //                                      ----------------------------------
            //                                      | :       s       : offsetInBits |
            //                                      ----------------------------------
            //                                                                       @_src
            //                  : sizeRemaining :
            // ----------------------------------
            // |                :       d       |
            // ----------------------------------
            //                                  @_dst

            uint8_t s = (*_src >> offsetInBits) & mask8l1[sizeRemaining];
            uint8_t d = *_dst & mask8l1[sizeRemaining];

            if (s < d)
            {
                return -1;
            }
            else if (d < s)
            {
                return 1;
            }
        }
        else // if (sizeRemaining + offsetInBits > 8)
        {
            //                                                           :      sizeRemaining          :
            //                                      -------------------------------------------------------------------
            //                                      |                    :     a     |        b        : offsetInBits |
            //                                      -------------------------------------------------------------------
            //                                                                       @_src + 1                        @_src    
            //
            //    :      sizeRemaining          :
            // ----------------------------------
            // |  :     a     :        b        |
            // ----------------------------------
            // :              :                  @_dst
            // : offsetInBits :
            //
            // a = sizeRemaining - (8 - offsetInBits)
            // b = 8 - offsetInBits
            //
            // Note: offsetInBits > 8 - sizeRemaining > 0
            //       a < 8

            uint8_t a = (*(_src + 1) << (8 - offsetInBits))
                      & mask8l1[sizeRemaining];
            uint8_t b = *_src >> offsetInBits;

            uint8_t s = a | b;
            uint8_t d = *_dst & mask8l1[sizeRemaining];

            if (s < d)
            {
                return -1;
            }
            else if (d < s)
            {
                return 1;
            }
        }
    }

    // Then move the LSB uint8s.
    while (sizeInUint8s)
    {
        //                              : offsetInBits :
        //                         -----------------------------------------
        //                         |    :      a       |  b : offsetInBits |
        //                         -----------------------------------------
        //                                             @_src               @_src - 1
        // : offsetInBits :
        // ---------------------
        // |      a       :  b |
        // ---------------------
        //                     @_dst - 1
        //

        uint8_t a = *_src << (8 - offsetInBits);
        uint8_t b = *--_src >> offsetInBits;

        uint8_t s = a | b;
        uint8_t d = *--_dst;

        if (s < d)
        {
            return -1;
        }
        else if (d < s)
        {
            return 1;
        }

        --sizeInUint8s;
    }

    return 0;
}/*}}}*/

// Destination-side offset compare.
int BitCompare8(const void* src, /*{{{*/
                const void* dst, size_t offsetInBits, 
                                 size_t sizeInBits)
{
    return -BitCompare8(dst, offsetInBits, src, sizeInBits);
}/*}}}*/

// Generic compare.
int BitCompare8(const void* src, size_t srcOffsetInBits, /*{{{*/
                const void* dst, size_t dstOffsetInBits, 
                                 size_t sizeInBits)
{
    const uint8_t* _src = static_cast<const uint8_t*>(src);
    const uint8_t* _dst = static_cast<const uint8_t*>(dst);

    _src += srcOffsetInBits >> 3;
    srcOffsetInBits &= 0x07;

    if (!srcOffsetInBits)
    {
        return -BitCompare8(_dst, dstOffsetInBits, _src, sizeInBits);
    }

    _dst += dstOffsetInBits >> 3;
    dstOffsetInBits &= 0x07;

    if (!dstOffsetInBits)
    {
        return BitCompare8(_src, srcOffsetInBits, _dst, sizeInBits);
    }

    size_t sizeInUint8s = sizeInBits >> 3;
    size_t sizeRemaining = sizeInBits & 0x07;

    // MSB ---> LSB
    //             :                 bits-to-compare            :
    //             : sizeRemaining :                            :
    // -----------------------------------------------     ------------------------
    // |                      |    : srcOffsetInBits | ... |    : srcOffsetInBits |
    // -----------------------------------------------     ------------------------
    //                                               @_src + sizeInUint8s         @_src
    //
    //                                    : sizeRemaining :
    //                        -----------------------------------------------     ------------------------
    //                        |                      |    : dstOffsetInBits | ... |    : dstOffsetInBits |
    //                        -----------------------------------------------     ------------------------
    //                                                                      @_dst + sizeInUint8s         @_dst

    if (srcOffsetInBits <= dstOffsetInBits)
    {
        //             : sizeRemaining :
        // -----------------------------------------------
        // |                      |    : srcOffsetInBits |
        // -----------------------------------------------
        //                                               @_src
        //
        //                                  : sizeRemaining :
        //                        -----------------------------------------------
        //                        |                      |  :  dstOffsetInBits  |
        //                        -----------------------------------------------
        //                                                                      @_dst

        if (!sizeInUint8s)
        {
            if (sizeRemaining + dstOffsetInBits <= 8)
            {
                //             : sizeRemaining :
                // -----------------------------------------------
                // |           :       s       : srcOffsetInBits |
                // -----------------------------------------------
                //                                               @_src
                //
                //                                  : sizeRemaining :
                //                        -----------------------------------------------
                //                        |         :       d       :  dstOffsetInBits  |
                //                        -----------------------------------------------
                //                                                                      @_dst

                // There're only sizeRemaining bits to compare.
                uint8_t s = (*_src >> srcOffsetInBits)
                          & mask8l1[sizeRemaining];

                uint8_t d = (*_dst >> dstOffsetInBits)
                          & mask8l1[sizeRemaining];

                if (s < d)
                {
                    return -1;
                }
                else if (d < s)
                {
                    return 1;
                }
            }
            else // if (sizeRemaining + dstOffsetInBits > 8)
            {
                //                  : sizeRemaining  :
                //     -------------------------------------------------
                //     |            :    a     |  b  : srcOffsetInBits |
                //     -------------------------------------------------
                //                                                     @_src
                //
                //                                       : sizeRemaining  :
                //                            -------------------------------------------------
                //                            |          :     a      | b :  dstOffsetInBits  |
                //                            -------------------------------------------------
                //                                                    @_dst + 1               @_dst

                uint8_t a = *_src++ >> srcOffsetInBits;
                uint8_t b = (*_src << (8 - srcOffsetInBits))
                          & mask8l1[sizeRemaining];
                uint8_t s = a | b;

                a = *_dst++ >> dstOffsetInBits;
                b = (*_dst << (8 - dstOffsetInBits))
                  & mask8l1[sizeRemaining];
                uint8_t d = a | b;

                if (s < d)
                {
                    return -1;
                }
                else if (d < s)
                {
                    return 1;
                }
            }

            return 0;
        }

        // There're more than (8 - dstOffsetInBits) bits to compare.
        // Compare MSB bits first.
        // <-   MSB bits to compare    ->:
        //                               :---:>(8 - dstOffsetInBits)
        //                  : sizeRemaining  :
        //     -------------------------------------------------
        //     |            :          | : s : srcOffsetInBits |
        //     -------------------------------------------------
        //                                                     @_src
        //
        //                      <-   MSB bits to compare    ->:
        //                                       : sizeRemaining  :
        //                            -------------------------------------------------
        //                            |          :            | d :  dstOffsetInBits  |
        //                            -------------------------------------------------
        //                                                    @_dst + 1               @_dst

        int result = BitCompare8(
                        _src, srcOffsetInBits + (8 - dstOffsetInBits), 
                        _dst + 1, sizeInBits - (8 - dstOffsetInBits));

        if (result)
        {
            return result;
        }

        // Then compare LSB (8 - dstOffsetInBits) bits.
        uint8_t s = (*_src >> srcOffsetInBits) & mask8m0[dstOffsetInBits];
        uint8_t d = *_dst++ >> dstOffsetInBits;

        if (s < d)
        {
            return -1;
        }
        else if (d < s)
        {
            return 1;
        }
    }
    else // if (dstOffsetInBits < srcOffsetInBits)
    {
        //                                  : sizeRemaining :
        //                        -----------------------------------------------
        //                        |                      |  :  srcOffsetInBits  |
        //                        -----------------------------------------------
        //                                                                      @_src
        //
        //             : sizeRemaining :
        // -----------------------------------------------
        // |                      |    : dstOffsetInBits |
        // -----------------------------------------------
        //                                               @_dst

        if (!sizeInUint8s)
        {
            if (sizeRemaining + srcOffsetInBits <= 8)
            {
                //                                  : sizeRemaining :
                //                        -----------------------------------------------
                //                        |         :       s       :  srcOffsetInBits  |
                //                        -----------------------------------------------
                //                                                                      @_src
                //
                //             : sizeRemaining :
                // -----------------------------------------------
                // |           :       d       : dstOffsetInBits |
                // -----------------------------------------------
                //                                               @_dst

                // There're only sizeRemaining bits to compare.
                uint8_t s = (*_src >> srcOffsetInBits)
                          & mask8l1[sizeRemaining];

                uint8_t d = (*_dst >> dstOffsetInBits)
                          & mask8l1[sizeRemaining];

                if (s < d)
                {
                    return -1;
                }
                else if (d < s)
                {
                    return 1;
                }
            }
            else // if (sizeRemaining + srcOffsetInBits > 8)
            {
                //                                       : sizeRemaining  :
                //                            -------------------------------------------------
                //                            |          :     a      | b :  srcOffsetInBits  |
                //                            -------------------------------------------------
                //                                                    @_src + 1               @_src
                //
                //                  : sizeRemaining  :
                //     -------------------------------------------------
                //     |            :    a     |  b  : dstOffsetInBits |
                //     -------------------------------------------------
                //                             @_dst + 1               @_dst

                uint8_t a = *_src++ >> srcOffsetInBits;
                uint8_t b = (*_src << (8 - srcOffsetInBits))
                          & mask8l1[sizeRemaining];
                uint8_t s = a | b;

                a = *_dst++ >> dstOffsetInBits;
                b = (*_dst << (8 - dstOffsetInBits))
                  & mask8l1[sizeRemaining];
                uint8_t d = a | b;

                if (s < d)
                {
                    return -1;
                }
                else if (d < s)
                {
                    return 1;
                }
            }

            return 0;
        }

        // There're more than (8 - srcOffsetInBits) bits to compare.
        // Compare MSB bits first.
        //
        //                      <-   MSB bits to compare    ->:
        //                                       : sizeRemaining  :
        //                            -------------------------------------------------
        //                            |          :            | s :  srcOffsetInBits  |
        //                            -------------------------------------------------
        //                                                    @_src + 1               @_src
        //
        // <-   MSB bits to compare    ->:
        //                               :---:>(8 - srcOffsetInBits)
        //                  : sizeRemaining  :
        //     -------------------------------------------------
        //     |            :          | : d : dstOffsetInBits |
        //     -------------------------------------------------
        //                             @_dst + 1               @_dst

        int result = BitCompare8(
                        _dst, dstOffsetInBits + (8 - srcOffsetInBits), 
                        _src + 1, sizeInBits - (8 - srcOffsetInBits));

        if (result)
        {
            return result;
        }

        // Then compare LSB (8 - srcOffsetInBits) bits.
        uint8_t s = *_src++ >> srcOffsetInBits;
        uint8_t d = (*_dst >> dstOffsetInBits) & mask8m0[srcOffsetInBits];

        if (s < d)
        {
            return -1;
        }
        else if (d < s)
        {
            return 1;
        }
    }

    return 0;
}/*}}}*/
4

2 回答 2

4

GNU 多精度算术库支持任意长整数的按位算术,并提供 C++ 接口。

于 2013-09-01T07:51:42.630 回答
1

看起来你可以使用boost::dynamic_bitset. 您可以使用一个相等运算符。通过创造性地使用 << 和 .resize() 你应该能够很容易地比较你想要的东西。

于 2013-09-01T07:42:25.400 回答