GF2::Vector Append Bits to a Bit-Vector

Add bits/elements taken from various sources to the end of a bit-vector.

constexpr Vector &append(bool src);             (1)
constexpr Vector &append(const Vector &src);    (2)
1 Appends a single value to the end of the bit-vector. It is a synonym for the push method.
2 Appends all the elements from src to the end of the bit-vector.
template<std::unsigned_integral Src>
constexpr Vector &append(Src src);                              (1)

template<std::unsigned_integral Src>
constexpr Vector &append(std::initializer_list<Src> src);       (2)

template<std::unsigned_integral Src>
constexpr Vector &append(const std::vector<Src>& src);          (3)

template<typename Iter>
constexpr Vector &append(Iter b, Iter e);                       (4)

template<std::size_t N>
explicit constexpr Vector &append(const std::bitset<N> &bs);    (5)

Vector &append(std::string_view str, bool bit_order = false)    (6)
1 Appends the bits from a single word src which is some unsigned integer type.
2 Takes an initializer style list of unsigned integers. The bits from each are appended to the vector.
3 Takes a std::vector of unsigned integers. The bits from each element are appended to the vector.
4 Takes any iteration of unsigned integers. The bits from each are appended to the vector.
5 Appends all N bits from a std:::bitset<N> to the vector.
6 Appends the bits encoded in string that typically will be all 0’s and 1’s or all hex characters. See below.

Template Parameters

Src

The type of the unsigned integers whose bits are getting appended to the vector There is no requirement that Src and Block are the same. For example, we can add the bits from a list of 32-bit unsigned integers while the storage scheme for the vector remains the default 64-bit type.

Iter

An iterator—​might be the type returned by any std::cbegin(collection) etc. Iter::value_type should be some unsigned integer type.

Parameters (most are obvious and need no explanation)

str

A string that encodes the bit elements of the vector. See below.

bit_order

This defaults to false but if present and set to true then any binary string is interpreted as encoding the vector in bit-order where the least significant bit v0 is on the right. This parameter is ignored for hex strings.

Returns

All of these methods return a reference to *this so they can be chained with other calls.

Example 1: Appending bits that are not encoded as strings
#include <GF2/GF2.h>

int main()
{
    GF2::Vector v;                          (1)
    std::cout << "v: " << v << '\n';
    v.append(uint8_t(0));                   (2)
    std::cout << "v: " << v << '\n';
    v.append({uint8_t(255), uint8_t(0)});   (3)
    std::cout << "v: " << v << '\n';
    std::vector<uint8_t> vec{255, 0};       (4)
    v.append(vec);
    std::cout << "v: " << v << '\n';
    v.append(vec.cbegin(), vec.cend());     (5)
    std::cout << "v: " << v << '\n';
    std::bitset<8> bs(255);                 (6)
    v.append(bs);
    std::cout << "v: " << v << '\n';
    GF2::Vector u("0000");
    v.append(u);                            (7)
    std::cout << "v: " << v << '\n';
}
1 Default constructor makes an empty vector.
2 Appends 8 0-bits.
3 Appends a list of 8 1-bits and 8 0-bits.
4 Appends a std::vector with 8 1-bits and 8 0-bits.
5 Appends a std::vector with 8 1-bits and 8 0-bits using the usual iterators.
6 Appends a std::bitset with 8 1-bits.
7 Appends the vector u to the end of v.
Output
v:
v: 00000000
v: 000000001111111100000000
v: 0000000011111111000000001111111100000000
v: 00000000111111110000000011111111000000001111111100000000
v: 0000000011111111000000001111111100000000111111110000000011111111
v: 00000000111111110000000011111111000000001111111100000000111111110000
Appending strings

The most straightforward character encoding for any bit-vector is a binary string containing just 0’s and 1’s, e.g. "10101". We allow for an optional prefix "0b" or "0B" to act as a visual clue to the string’s contents, e.g. "0b10101". Apart from the optional prefix, each character in the binary string will translate to one element in the vector.

The other supported encoding is a compact hex type string containing just the 16 hex characters 0123456789ABCDEF. For example, the string "3ED02". Again, we allow for an optional prefix "0x" or "0X" e.g. "0x3ED02".

Each hex character naturally translates to 4 elements in a GF2::Vector. The hex string "0x0" is equivalent to the binary string "0b0000", and so on, up to string "0xF" which is the same as the binary "0b1111".

The hex pair "0x0F" will be interpreted in the vector as 0b00001111. This is of course the advantage of hex—​it is a more compact format that occupies a quarter of the space needed to write out a full binary string.

However, what happens if you want to encode a vector whose size is not a multiple of 4? We handle that by allowing the final character in the string to have a base that is not 16. This is achieved by allowing for an optional suffix which must be one of "_2", "_4", or "_8". If present, the prefix gives the base for just the _final_ character in the otherwise hex based string. If there is no suffix the final character is assumed to be hex just like all the others.

So the string "0x1" (no suffix so the last character is the default hex base 16) is equivalent to "0b0001". On the other hand, the string "0x1_8" (the last character is base 8) is equivalent to "0b001". Similarly the string "0x1_4" (the last character is base 4) is equivalent to "0b01" and finally, the string "0x1_2" (the last character is base 2) is equivalent to "0b1"

In the string "0x3ED01_8", the first four characters '3', 'E', 'D', and '0' are interpreted as hex values and each will consume four slots in the vector. However, that final "1_8" is parsed as an octal 1 so only takes up three slots 0b001. In all then this particular vector has size 4 x 4 + 3 = 19.

If the suffix is present, the final character must fit inside the base given by that suffix. The string "0x3_8" is fine but trying to parse "0x3_2" will result in a std::invalid_argument exception as the final character is not either 0 or 1 which are the only valid options for something that is supposed to be base 2.
Example 2: Appending bits encoded as a string
#include <GF2/GF2.h>
int main()
{
    GF2::Vector v;                  (1)
    std::cout << "v: " << v << '\n';
    v.append("111");                (2)
    std::cout << "v: " << v << '\n';
    v.append("0b111");              (3)
    std::cout << "v: " << v << '\n';
    v.append("0x111");              (4)
    std::cout << "v: " << v << '\n';
    v.append("0xF1");               (5)
    std::cout << "v: " << v << '\n';
    v.append("0xF1_8");             (6)
    std::cout << "v: " << v << '\n';
    v.append("0xF1_4");             (7)
    std::cout << "v: " << v << '\n';
    v.append("0xF1_2");             (8)
    std::cout << "v: " << v << '\n';
}
1 Construct an empty vector.
2 Append bits encoded in a string without a prefix. All characters are 0’s and 1’s so the string is interpreted as being binary,
3 Append bits encoded in the same binary string but now with the binary prefix "0b".
4 Append bits encoded as identical digits but each one is now interpreted as a hex character thanks to the "0x" prefix.
5 Append bits encoded in a string where the final character has no suffix so by default is parsed as a hex/base-16 number.
6 Append bits encoded in a string where the final character has a suffix "_8" so it is parsed as an base-8 number.
7 Append bits encoded in a string where the final character has a suffix "_4" so it is parsed as an base-4 number.
8 Append bits encoded in a string where the final character has a suffix "_2" so it is parsed as an base-2 number.
Output
v:
v: 111
v: 111111
v: 111111100010001000
v: 11111110001000100011111000
v: 111111100010001000111110001111100
v: 111111100010001000111110001111100111110
v: 11111110001000100011111000111110011111011111
See Also

push
clear
join
copy