GF2::Vector — Stream Operators
Methods to insert or extract a bit-vector from a stream.
template<std::unsigned_integral Block, typename Allocator>
std::ostream &
operator<<(std::ostream &s, const Vector<Block, Allocator> &rhs); (1)
template<std::unsigned_integral Block, typename Allocator>
std::istream &
operator>>(std::istream &s, Vector<Block, Allocator> &rhs); (2)
| 1 | Writes a binary string representation of a bit-vector to an output stream. |
| 2 | Fill a bit-vector by reading bits encoded as a binary or hex string from a stream. |
The input stream operator will throw a std::invalid_argument exception on parse failures.
| Binary strings are written or read as being in vector-order where the least significant element is on the left, so as v0v1v2… |
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.
|
#include <GF2/GF2.h>
int main()
{
// Read from a stream until we have a parse error ...
while (true) {
GF2::Vector<> v;
std::cout << "GF2::Vector? ";
try {
std::cin >> v;
std::cout << "Parsed as " << v << std::endl;
}
catch (...) {
std::cout << "Couldn't parse that input as a GF2::Vector! Quitting ..." << std::endl;
break;
}
}
}
GF2::Vector? 111
Parsed as 111
GF2::Vector? 0b111
Parsed as 111
GF2::Vector? 0x111
Parsed as 100010001000
GF2::Vector? 0x111_8
Parsed as 10001000100
GF2::Vector? 0x111_4
Parsed as 1000100010
GF2::Vector? 0x111_2
Parsed as 100010001
GF2::Vector? q
Couldn't parse that input as a GF2::Vector! Quitting ...