Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract straddling byte array content to std::bitset

Tags:

c++

I need to extract content from a byte array (std::vector) to bitsets. The content could be straddling two bytes.

Here is my unit test:

std::vector<uint8_t> val = { 0xAB, 0xCD, 0xEF }; // is 101010111100110111101111

std::bitset<4> a = extractToBitSet<4>( val, 0 ); // should be 0x0A: 1010
std::bitset<8> bc = extractToBitSet<8>( val, 4 ); // should be 0xBC: 10111100
std::bitset<12> def = extractToBitSet<12>( val, 12 ); // should be 0x0DEF: 110111101111

CPPUNIT_ASSERT( a.to_string() == "1010" );
CPPUNIT_ASSERT( bc.to_string() == "10111100" );
CPPUNIT_ASSERT( def.to_string() == "110111101111" );

unsigned long aVal = a.to_ulong();
unsigned long bcVal = bc.to_ulong();
unsigned long defVal = def.to_ulong();

CPPUNIT_ASSERT( aVal == 0x0A );
CPPUNIT_ASSERT( bcVal == 0xBC );
CPPUNIT_ASSERT( defVal == 0x0DEF );

I came up with this solution:

template<size_t _Count> void reverseBitSet( std::bitset<_Count>& bitset )
{
    bool val;
    for ( size_t pos = 0; pos < _Count/2; ++pos )
    {
        val = bitset[pos];
        bitset[pos] = bitset[_Count-pos-1];
        bitset[_Count-pos-1] = val;
    }
}

template<size_t _Count> std::bitset<_Count> extractToBitSet( const std::vector<uint8_t>& data, size_t offset )
{
    std::bitset<_Count> res;

    size_t pos = 0;
    uint8_t tempVal;
    std::bitset<8> tempBitSet;

    while ( pos < _Count )
    {
        tempVal = data[ (offset + pos)/8 ];

        tempBitSet = tempVal;
        reverseBitSet( tempBitSet );
        res[pos] = tempBitSet[(offset + pos)%8];

        ++pos;
    }

    reverseBitSet( res );

    return res;
}

It works (my test pass) but it seems very unefficient with all those temporary bitsets being created + many reverse operations.

Is there a more elegant way to do that?

like image 489
jpo38 Avatar asked Jan 06 '23 10:01

jpo38


1 Answers

Why all the reversing? You could just explicitly set each bit as you go based on the specific operation you're performing. Just the one loop:

template <size_t N>
std::bitset<N> extract(std::vector<uint8_t> const& vs, size_t offset) {
    std::bitset<N> res;
    for (size_t i = 0; i < N; ++i) {
        size_t full_off = offset + i;
        auto& byte = vs[full_off / 8];
        auto bit = byte & (1 << (7 - (full_off % 8)));

        res.set(N-i-1, bit);
    }
    return res;
}
like image 135
Barry Avatar answered Jan 13 '23 13:01

Barry