bit::vector
— Factory Constructors
From Unsigned Integers
We can always copy the bits of any unsigned integer value to create a valid bit-vector.
1static constexpr bit::vector from(std::unsigned_integral auto src);
- 1
-
This templated method returns a bit-vector constructed from the bits that make up the
src
word.
The size of the bit-vector will be the std::sizeof
for the specific std::unsigned_integral
used as the argument. Note that there is no requirement for the argument type and Block
to be the same. The argument might be a 32-bit unsigned, creating a bit-vector of size 32 packed into the default 64-bit block.
This method isn’t a constructor because we don’t want src to be treated as the number of vector elements. Instead, we copy the actual bits from src into the bit-vector.
|
Example
#include <bit/bit.h>
int main()
{
uint16_t val = 65535;
auto v1 = bit::vector<>::from(val);
std::cout << "v1 = " << v1 << " has size " << v1.size() << '\n';
}
Output
v1 = [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1] has size 16
From Strings
We provide a factory method that attempts to parse a string as a bit-vector.
Of course, that isn’t always possible, so this method returns a std::optional
static std::optional<bit::vector>
1(std::string_view src, bool bit_order = false); from
- 1
-
Attempts to parse a bit-vector from a string and returns
std::nullopt
on failure.
There are two principal ways we can encode a bit-vector as a string:
Binary String Encodings
The straightforward character encoding for a bit-vector is a binary string containing just 0’s and 1’s, e.g., “10101”. Each character in a binary string represents a single element in the bit-vector.
By default, we encode bit-vectors to binary strings in vector order \(v_0 v_1 \cdots v_{n-1}\). However, methods that read or write binary strings typically have an extra boolean argument, bit_order
. This argument always defaults to false
, but if present and set to true
, then the binary string will encode the bit-vector in bit-order where the least significant bit v0 is on the right, so \(v_{n-1} \cdots v_1 v_0\). Hex-strings ignore the bit_order
parameter.
Hex String Encodings
The other supported encoding for bit-vectors is a compact hex-type string containing just the 16 hex characters 0123456789ABCDEF
. For example, the string “3ED02”. We allow for hex strings with an optional prefix “0x” or “0X,” e.g. “0x3ED02”.
Hex strings are not affected by a bit_order
argument — we ignore that argument.
Each hex character naturally translates to four elements in a bit::vector
. The hex string 0x0
is equivalent to the binary string 0000
, and so on, up to string 0xF,
which is the same as the binary 1111
.
The hex pair 0x0F
will be interpreted in the vector as 00001111
. Of course, this is the advantage of hex. It is a more compact format that occupies a quarter of the space needed to write out the equivalent 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. To accomplish that, we allow for an optional suffix, which must be one of _2
, _4
, or _8
. If present, the prefix gives the base for just the preceding character in the otherwise hex-based string. If there is no suffix, the final character is assumed to be hex like all the others.
So the string 0x1
(no suffix, so the last character is the default hex base 16) is equivalent to 0001
. On the other hand, the string 0x1_8
(the last character is base 8) is equivalent to 001
. Similarly, the string 0x1_4
(the last character is base 4) is equivalent to 01,
and finally, the string 0x1_2
(the previous character is base 2) is comparable to 1
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, which takes up three slots 001
. Therefore, this vector has size 19 (i.e., 4*4 + 3).
If the suffix is present, the final character must fit inside the base given by that suffix. The string 0x3_8 is OK, but trying to parse 0x3_2 will result in a std::nullopt return value because the final character is not either 0 or 1, which are the only valid options for something that is supposed to be base 2.
|
Binary String Example:
#include <bit/bit.h>
int main()
{
1auto v1 = bit::vector<>::from("11100");
2auto v2 = bit::vector<>::from("11100", true);
3auto v3 = bit::vector<>::from("1 1 1");
std::cout << "v1 = " << (v2 ? v2->to_string() : "FAILED TO PARSE") << '\n';
std::cout << "v2 = " << (v3 ? v3->to_string() : "FAILED TO PARSE") << '\n';
std::cout << "v3 = " << (v4 ? v4->to_string() : "FAILED TO PARSE") << '\n';
}
- 1
- The string without a prefix is all zeros and ones, so we assume it’s a binary encoding.
- 2
- This is the same thing, but now we interpret the bits as having the least significant bit v0 is on the right.
- 3
- This is a string with a deliberate error.
Output
- 1
- The characters are interpreted as encoding the least significant bit v0 is on the right.
- 2
- The last string cannot be interpreted as a valid bit-vector.
Hex String Example
#include <bit/bit.h>
int main()
{
1auto v1 = bit::vector<>::from("111");
2auto v2 = bit::vector<>::from("0x111");
3auto v3 = bit::vector<>::from("0xF1");
4auto v4 = bit::vector<>::from("0xF1_8");
5auto v5 = bit::vector<>::from("0xF1_4");
6auto v6 = bit::vector<>::from("0xF1_2");
if(v1) std::cout << "v1 = " << *v1 << '\n';
if(v2) std::cout << "v2 = " << *v2 << '\n';
if(v3) std::cout << "v3 = " << *v3 << '\n';
if(v4) std::cout << "v4 = " << *v4 << '\n';
if(v5) std::cout << "v5 = " << *v5 << '\n';
if(v6) std::cout << "v6 = " << *v6 << '\n';
}
- 1
- This string without a prefix is all zeros and ones, so we assume it’s a binary encoding.
- 2
- This string has the same digits, but thanks to the ‘0x’ prefix, it will be interpreted as a hex string.
- 3
- Construction where the final character has no suffix, so by default, it is parsed as a hex/base-16 number.
- 4
-
Construction where the final character has a suffix
_8
so is parsed as a base-8 number. - 5
-
Construction where the final character has a suffix
_4
so is parsed as a base-4 number. - 6
-
Construction where the final character has a suffix
_2
so is parsed as a base-2 number.
Output
1v1 = [1 1 1]
2v2 = [1 0 0 0 1 0 0 0 1 0 0 0]
3v3 = [1 1 1 1 1 0 0 0]
4v4 = [1 1 1 1 1 0 0]
5v5 = [1 1 1 1 1 0]
6v6 = [1 1 1 1 1]
- 1
- Binary string so each character is a single element in the bit-vector.
- 2
- Same digits, but now it is hex, so each character is four elements in the bit-vector.
- 3
-
The final
1
is interpreted as 1 base 16. - 4
-
The final
1_8
is interpreted as 1 base 8. - 5
-
The final
1_4
is interpreted as 1 base 4. - 6
-
The final
1_2
is interpreted as 1 base 2.