PaperBirdMaster
PaperBirdMaster

Reputation: 13320

Format custom types with ostream

We can change the stream behaviour with different options:

std::cout << 0xfabadau << '\n';
std::cout << std::hex << std::setfill('0') << std::setw(8) << 0xfabadau << '\n';

Outputs:

16431834
00fabada

Now lets say I have a byte_buffer custom type:

using byte        = std::uint8_t;
using byte_buffer = std::vector<byte>;

std::ostream &operator <<(std::ostream &o, const byte_buffer &buffer)
{
    for (const auto &b : buffer) o << std::hex << int{b};
    return o << std::dec;
}

Using it I cannot apply custom format::

byte_buffer b { 0xfau, 0xbau, 0xdau, };
std::cout << b << '\n';
std::cout << std::hex << std::setfill('0') << std::setw(8) << b << '\n';

The code above shows the following output:

fabada
000000fabada

The std::setfill and std::setw outside of the std::ostream &operator << is affecting the first byte of byte_buffer inside of the std::ostream &operator << hence the observed output, this isn't unexpected byt is not what I want. The output I want is:

fabada
00fabada

How should I change the std::ostream &operator <<(std::ostream &o, const byte_buffer &buffer) in order to make byte_buffer behave the way I want?

Upvotes: 1

Views: 1942

Answers (2)

n. m. could be an AI
n. m. could be an AI

Reputation: 119867

You can always get the flags and use them in your function however you want. For example (only dealing with the width here)

int width = o.width(), item_width;
int fill = o.fill();
if (width > 2*buffer.size())
  item_width = width - 2*(buffer.size()-1);
else
  item_width = 2;
for (const auto &b : buffer) 
{
   o << std::hex << std::setw(item_width) << setfill(fill) << int{b};
   item_width = 2; fill = '0';
}

Upvotes: 2

quazeeee
quazeeee

Reputation: 323

You can work with byte something like this

std::ostream &operator <<(std::ostream &o, const byte_buffer &buffer)
{
    std::uint32_t temp=0;
    for (const auto &b : buffer)
    {
        temp<<=8;
        temp|=b;
    }
    return o << std::hex << temp << std::dec;
}

More flexible approach

std::ostream &operator <<(std::ostream &o, const byte_buffer &buffer)
{
    std::ostringstream ss;
    for (const auto &b : buffer)
    {
        ss<< std::hex << int{b};
    }
    return o << ss.str();
}

Upvotes: 1

Related Questions