Vector elements into contiguous memory

G'day
Is there a way to move the elements from a vector <bitset<6> > into contiguous memory while retaining their binary format?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <vector>
#include <bitset>
#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>

template< std::size_t N > std::string bitsets_to_string( const std::vector< std::bitset<N> >& data )
{
    std::string str_bits ;
    for( auto bs : data ) str_bits += bs.to_string() ;
    return str_bits ;
}

int main()
{
    std::vector <int> Ascii6bit;
    {
    for (int i=0; i<j; i++)
        {
        int a = Ascii8bit[i];
        int b = a - 48;
        if( b >= 41) b = b - 8;
        Ascii6bit.push_back(b);
        }
    }

    std::vector <std::bitset<6> > BitSeq;
    {
        for (int i=0; i<j; i++)
        {
        std::bitset<6> a = (Ascii6bit[i]);
        BitSeq.push_back(a);
        }
    }

    const std::vector< std::bitset<6> > my_bits = { BitSeq };
    std::string BitVal = bitsets_to_string(my_bits);
}


The code above got it into contiguous memory, but stored it as individual characters, not as a string of binary and i am unable to convert it.
I am trying to make an AIS (NMEA 0183) decoder and need to be able to convert the segments i grab (in various sizes, ranging from 1 bit to 36 bits) into decimal.

The only thing i can think of is;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

{
   std::ofstream BinData("Temp.txt");
   BinData << BitVal << std::endl;

   std::ifstream NewBin("Temp.txt", std::ios_base::binary)
   
   std::string NewBitVal;
   getline(NewBin, NewBitVal)

   BinData.close();
   NewBin.close();

   remove("Temp.txt")
}


Apart from being messy is this approach going to cause issues, like reduced performance of the decoder etc?
Is there a better way to achieve my desired result?

Thanks in advance

Edit: Correction of spelling mistake.
Last edited on
> need to be able to convert the segments i grab (in various sizes, ranging from 1 bit to 36 bits) into decimal.
iirc you don't want elements of 6 bits, ¿so why do you make a vector of bitset<6>?


you may try std::vector<bool>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <vector>
#include <bitset>
#include <string>
#include <limits>

template< std::size_t N > std::string bitsets_to_string( const std::vector< std::bitset<N> >& data )
{
    std::string str_bits ;
    for( auto bs : data ) str_bits += bs.to_string() ;
    return str_bits ;
}

std::vector< unsigned char > pack_bits( std::string str_bits )
{
    static constexpr std::size_t BITS_PER_BYTE = std::numeric_limits< unsigned char >::digits ;
    using byte_bits = std::bitset<BITS_PER_BYTE> ;

    while( str_bits.size() % BITS_PER_BYTE ) str_bits.push_back( '0' ) ; // pad to multiple of BITS_PER_BYTE

    std::vector< unsigned char > result ;

    for( std::size_t i = 0 ; i < str_bits.size() ; i += BITS_PER_BYTE )
    { result.push_back( byte_bits( str_bits, i, BITS_PER_BYTE ).to_ulong() ) ; }

    return result ;
}

int main()
{
    const std::vector< std::bitset<6> > my_bits =
    {
        0b000001, 0b000011, 0b011000, 0b011111, 0b011001, 0b001010, 0b000000, 0b100000, 0b000000,
        0b000000, 0b000000, 0b000000, 0b100110, 0b011111, 0b011000, 0b011100, 0b010011, 0b110110,
        // more ...
    };

    const auto contiguous_bytes = pack_bits( bitsets_to_string(my_bits) ) ;
    
    // ...
}
Ne555 thanks for the response and the idea.

I converted to 6 bit as NMEA 0183 uses a 6 bit ASCII encoding that contains a total of 63 characters. To obtain the correct 6 bit value you subtract 48 from the 8 bit ASCII value and if the returned value is still greater than 40, you subtract a further 8.

Next you string the 6 bit representation of the 6 bit ASCII values into a string and start grabbing bits. for example the first 6 bits represent the Message Type when converted to decimal, the next 2 are the Repeat Indicator, the following 36 are the MMSI and so on until all 128 bits have been used.

I know that this is a complicated program to try for a person who has never done any programming before, but I have found it to be an excellent learning exercise.

Any input or corrections to my method are more than welcome.

If you're interested in AIS decoding, a comprehensive resource is "AIS technical standard - Recommendation ITU-R M.1371-5" which can be obtained from the ITU website
Last edited on
JLBorges you are a scholar and a gentleman.

As soon as i finish looking up the sections of your code, so as to try and understand the process I'll implement it.

Thanks again for all the time you've spent on this
> I know that this is a complicated program to try for a person who has never done any programming before,
> but I have found it to be an excellent learning exercise.

Yes, and yes.


> looking up the sections of your code, so as to try and understand the process

Annotated code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
std::vector< unsigned char > pack_bits( std::string str_bits )
{
    // in C++, the fundamental unit of storage and addressability is a byte (char, signed char or unsigned char)
    // in theory, we should favour a narrow character type (char, signed char or unsigned char) to hold the packed bits;
    // these are the only types where every bit in the object representation is guaranteed to also be a bit
    // that participates in the value representation

    // note that std::vector<bool>, which may appear attractive superficially, is quite unsuitable for this task:
    // 'The manner in which std::vector<bool> is made space efficient (as well as whether it is optimized at all)
    // is implementation defined.'
    // std::vector<bool> 'does not necessarily store its elements as a contiguous array'
    // http://en.cppreference.com/w/cpp/container/vector_bool

    // determine (at compile-time) the number of bits in a byte
    // this is somewhat pedantic; in real-life C++ implementations, a byte is an octet
    static constexpr std::size_t BITS_PER_BYTE = std::numeric_limits< unsigned char >::digits ;
    using byte_bits = std::bitset<BITS_PER_BYTE> ; // a bitset that holds the bits in a byte

    // we want the number of bits to make up an integral number of bytes
    while( str_bits.size() % BITS_PER_BYTE ) str_bits.push_back( '0' ) ; // pad to multiple of BITS_PER_BYTE

    // 'The elements (in std::vector<unsigned char>) are stored contiguously, which means that elements can be accessed
    // not only through iterators, but also using offsets on regular pointers to elements.
    // This means that a pointer to an element of a vector may be passed to any function that expects
    // a pointer to an element of an array.' - http://en.cppreference.com/w/cpp/container/vector
    std::vector< unsigned char > result ;

    // for each sequence of BITS_PER_BYTE 'bits' ('0' or '1')s in the string
    for( std::size_t i = 0 ; i < str_bits.size() ; i += BITS_PER_BYTE )
    {
        // byte_bits( str_bits, i, BITS_PER_BYTE ): construct a bitset to hold the BITS_PER_BYTE bits
        // in a single 'byte' starting at position 'i'

        // .to_ulong(): get the numeric value of this byte as an unsigned integer

        // push_back(): add this byte to the result. note: the value is within the range of unsigned char

        result.push_back( byte_bits( str_bits, i, BITS_PER_BYTE ).to_ulong() ) ;
    }

    return result ;
}
Topic archived. No new replies allowed.