0

Is there any mentioning of having a specific bitstream object either in a future release of C++ beyond C++20 or within the standard library? For example; we can have an std::bitset<n> object where n is a constant known integral value.

Pseudo Example:

#include <bitstream>

template<unsigned N>
class Foo {
public:
     std::bitset<N> bits_;
};

Here we have a class template that will specify how many bits are in the std::bitset object. Which is fine.

We also have stream objects such as iostream, fstream, sstream, etc. where we can feed values of various data types into these streams either reading or writing them to a string stream, a file stream, the I/O stream to the console or terminal, etc...


What I would like to know is there any proposal of having a stream object like the ones above but specific for an arbitrary sequence of bits similar to the nature of std::bitset, where you could feed a set of bits into the stream. For example, it might look something like this:

#include <bitset>
#include <bitstream> // not an actual library - only suggestive

int main() {
    std::bitset<8>  byte{0xFE};
    std::bitset<16> word{0xFEDC};
    std::bitset<32> dword{0xFEDCBA98};
    std::bitset<64> qword{0xFEDCBA9876543210};

    std::bitstream bs;
    bs << byte << word << dword << qword;
    std::cout << bs; 
    return 0;
}

Here the expected output would be:

11111110111111101101110011111110110111001011101010011000111111101101110010111010100110000111011001010100001100100001000

Depending on the endian notation of the intended use...


The reversal would be applicable too. If we had an already populated bitstream object like the one from the example above we could extract specific bit sequences from the bitstream as follows:

#include <bitset>
#include <bitstream> // not an actual library - only suggestive
#include <iomanip>  // manipulators for bitstreams not yet implemented...

int main() {
    std::bitset<8>  byte{0xFE};
    std::bitset<16> word{0xFEDC};
    std::bitset<32> dword{0xFEDCBA98};
    std::bitset<64> qword{0xFEDCBA9876543210};

    std::bitstream bs;
    bs << byte << word << dword << qword;

    std::bitset<3> odd3;
    std::bitset<5> odd5;
    std::bitset<7> odd7;

    bs >> bs::msb >> odd3 >> odd7 >> odd5;
    std::cout << odd3 << '\n' << odd7 << '\n' << odd5;

    bs >> bs::lsb >> odd5 << odd3 << odd7;
    std::cout << odd5 << '\n' << odd3 << '\n' << odd7;

    // Or by using a constructor with a value for the bit size...
    std::bitset<9> odd9( bs ); // odd9(bs::msb), odd9(bs::lsb)... 

    return 0;
}

And the expected results would pull the bits either from the MSB or the LSB directions by the amount of the size of the bitset object respectively.


Just like iostream and the other stream libraries by using the <iomanip> library we can have formatting modifiers that would break this input or output into discrete bit-segments of any specified length such as every 4 or 8 bits, or display it as hex, etc... All of the bit manipulation and calculations would still be the responsibility of std::bitset.

Being able to push or retrieve arbitrary bitset objects in and out of a bitstream object that would be compatible with all of the other stream like objects could be a very powerful and useful tool or feature.

Is there any mention of something like this or does there already exist something similar to this nature without having to convert back and forth between strings or other types, etc.?


EDIT -User- walnut gave some great examples in his answer regarding this and that it can already be done using the existing iostream objects and operators. You can read his answer and the comments within the discussion, however, I just wanted to illustrate my reasoning for a stream object library that is written and designed to work explicitly and specifically with bitset data types.

Imagine a function as such:

// Not written with perfect syntax or compilation in mind,
// only psuedo to illustrate a point.
template<typename... T>
std::ostream& concatinateBitSequences( T&& ... t ) { // assuming all t are bitset<n>
    std::stringstream sstream;
    sstream << t...;
    return sstream; 
}

and compare that too...

// Not written with perfect syntax or compilation in mind,
// only psuedo to illustrate a point.
template<typename... T>
std::bitstream& concatinateBitSequences( T&& ... t ) { // assuming all t are bitset<n>
   std::bitstream bs;
   bs << t...;
   return bs;
}

The caller, the user will know that it is returning a bitstream explicitly or specifically compared to an arbitrary stream object! This was my main intention or goal... It is geared more towards readability and being more expressive in the code showing proper intentions. Also, it would be tightly coupled with bitset objects meaning the bitstream object would only accept data coming in from bitsets or other bitstream objects, but it can pass its data out to bitsets, bitstreams or other stream objects.

walnut
  • 21,629
  • 4
  • 23
  • 59
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • 1
    If you have a use case for this, then sure go ahead and write it (though seems very edge-case and we seem to be moving away from streams). I would personally use a `std::vector` and create a `bitset_iterator` and just manipulate that (I think `boost::dynamic_bitset` can do this out-of-the-box without an iterator class too) – Artyer Feb 25 '20 at 08:02
  • Not a bad proposal, but `std::bitset` can be very powerful if you know how to use it correctly! – Francis Cugler Feb 25 '20 at 08:12

1 Answers1

1

This already works as you intend:

std::cout << byte << word << dword << qword;

and

std::cin >> odd5 >> odd3 >> odd7;

For intermediate storage one can simply use std::stringstream which will also work as you describe.

There is however no endianess, because operations are bitwise, not bytewise.

walnut
  • 21,629
  • 4
  • 23
  • 59
  • I know that you can pass the `bitset` to existing streams. I was just wondering if there was any notion of having a specific stream object just for `bitset`s! Meaning that there would be a coupling between `bitset` and `bitstream` as a `bitstream` object can only work with either `bitset` types or other `stream` objects... – Francis Cugler Feb 25 '20 at 07:59
  • @FrancisCugler I don't understand what purpose you see in that. Can you describe a use case that isn't solved by what is already possible? – walnut Feb 25 '20 at 08:01
  • @FrancisCugler Also, a C++ stream is supposed to represent a destination or source of character input/output (i.e. it is inherited from `std::ostream` or `std::istream`). How does your `std::bitstream` fit that? How would `std::bistream` store characters? E.g. what is the result of `bs << "Hello world!";` and how does it differ from `std::stringstream`? – walnut Feb 25 '20 at 08:03
  • The concept is for readability as it would make the intent very clear. The bitstream object would be intended to work specifically with a bitset type. It is more explicit and expressive by knowing the intent of the code toward other users. For example, I could have a function that would take a set of bitset objects and pass them into a string stream object where that function would return the string stream object, however, the caller only knows that it's a string stream. Now if you passed the objects into a bitstream object and returned a bitstream object, the caller knows it's a bitstream. – Francis Cugler Feb 25 '20 at 08:08
  • Good point on your second comment. But like I said the `<<` and `>>` operators for `bitstream` would only work with either `bitset` or other `stream objects` such as `stringstream`, `iostream` {`cin`,`cout`}, `fstream`, etc... It wouldn't accept a `char`, `int` or other type. It would be coupled with the explicit use of `std::bitset`. – Francis Cugler Feb 25 '20 at 08:11
  • 1
    @FrancisCugler Then it seems what you are looking for is really just a dynamically-sized version of `std::bitset` with `operator<<`/`operator>>` overloaded for concatenation and extraction, similar to `boost::dynamic_bitset` or `std::vector`. Neither of these has *all* the features you require, but could be easily extended to. – walnut Feb 25 '20 at 08:13
  • Okay, I don't use `boost` it conflicts with my current setup and configuration. It's a pain to get working correctly on Windows using Visual Studio and half the features don't work because some of their libraries depend on Linux libraries such as the ones from the `GNU` library... I'm slightly familiar with `bitset` I've used it a couple of times but was just curious. I don't exactly want a complete `dynamically allocated` type of `bitset`. I like how `bitset` is fast and efficient, and just wanted an explicit stream object for when working with them. – Francis Cugler Feb 25 '20 at 08:19
  • 1
    @FrancisCugler That's just a matter of providing a `<<`/`>>` overload for `(dynamic_bitset&, std::bitset&)` arguments (which it doesn't currently seem to have). – walnut Feb 25 '20 at 08:21
  • Yeah, I guess it wouldn't be too hard to write my own stream object class and call it bitstream where I just inherit it directly from the streams base class... and just make sure that the `<<` and `>>` `operators` only accept either other stream objects or `bitset` specifically. Just wasn't in the mood of writing boilerplate type code... – Francis Cugler Feb 25 '20 at 08:23