Search code examples
c++stdvectorstringstream

How can I format values from std::vector to std::string efficiently?


I have a program that takes a std::vector<uint8_t> and returns a std::string formatted as hex characters followed by the ASCII text like so:

03 00 00 54 00 00 00 08 00 00 00 00 00 00 00 00 ASCII ...T............

74 21 B8 30 00 2C 2E 31 62 30 74 21 A8 30 00 2C ASCII t!.0.,.1b0t!.0.,

This is the main part of the code:

std::vector<uint8_t> value;
std::stringstream printed_line;
std::stringstream tempHexLine;
std::stringstream tempAsciiLine;

for (size_t printed_bytes = 0; printed_bytes < value.size(); printed_bytes += bytes_line) {

    for (int i = 0; i < bytes_line; ++i) {
        tempHexLine << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << static_cast<uint16_t>(value[printed_bytes + i]) << " ";
    }

    for (int i = 0; i < bytes_line; ++i) {

            if(isprint(value[printed_bytes + i])) {

                if (value[printed_bytes + i] == 60) {
                    tempAsciiLine << "&lt;";

                } else if(value[printed_bytes + i] == 62) {
                    tempAsciiLine << "&gt;";

                } else {
                    tempAsciiLine << static_cast<char>(value[printed_bytes + i]);
                }

            } else {
                tempAsciiLine << ".";
            }
        }
    }

    printed_line << tempHexLine.str() << "   " << tempAsciiLine .str();

The problem that I'm trying to solve is that when the vector size is large (> 1000 elements), the this takes a long time - approximately 70% of the samples using Very Sleepy where to the ::operator<< function.

What is the fastest way to apply a format like this to the values in the vector? There are well defined chucks of data that the vector needs to be broken into, so it seems like outputting a byte at a time is an inefficient way.


Solution

  • This should be trivial to write efficiently. Try this:

    #include <algorithm>
    #include <cstdint>
    #include <iterator>
    #include <string>
    #include <vector>
    
    std::string to_hex(std::vector<uint8_t> const & v)
    {
        std::string result;
        result.reserve(4 * v.size() + 6);
    
        for (uint8_t c : v)
        {
            static constexpr char alphabet[] = "0123456789ABCDEF";
    
            result.push_back(alphabet[c / 16]);
            result.push_back(alphabet[c % 16]);
            result.push_back(' ');
        }
    
        result.append("ASCII ", 6);
        std::copy(v.begin(), v.end(), std::back_inserter(result));
    
        return result;
    }