Skip to content

Latest commit

 

History

History
293 lines (233 loc) · 8.05 KB

263.md

File metadata and controls

293 lines (233 loc) · 8.05 KB
Info

Example

#include <bit>

int main() {
   constexpr auto value = std::uint16_t(0xCAFE);
   std::cout << std::hex << value; // pritns cafe
   std::cout << std::hex << std::byteswap(value); // prints feca
}

https://godbolt.org/z/6aT8GW4Yj

Puzzle

  • Can you implement bytes_to_string (using std::byteswap) which converts given value to its string bytes respresntation?
[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string{
  return {}; // TODO
}

int main(){
  using namespace boost::ut;
  using std::string_literals::operator""s;

  "bytes to string"_test = [] {
    expect("00000000 : 00 00 00 00 "s == bytes_to_string(0));
    expect("00000001 : 00 00 00 01 "s == bytes_to_string(1));
    expect("0000CAFE : 00 00 CA FE "s == bytes_to_string(0xCAFE));
    expect("0000BABA : 00 00 BA BA "s == bytes_to_string(0xBABA));
  };
}

https://godbolt.org/z/zsr91cer6

Solutions

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string {
  constexpr auto size = sizeof(value) * 2 + 3 + sizeof(value) * 3;
  std::array<char, size> output{};
  output.fill(' ');
  output[sizeof(value) * 2 + 1] = ':';

  constexpr auto to_hex = [] (const unsigned char nybble) -> char {
    return "0123456789ABCDEF"[nybble];
  };

  const auto bs_value = std::byteswap(value);
  const auto first = reinterpret_cast<const unsigned char*>(std::addressof(bs_value));
  const auto last = first + sizeof(bs_value);

  auto dest1 = std::begin(output);
  auto dest2 = std::next(dest1, sizeof(bs_value) * 2 + 3);
  for (auto f = first; f != last; ++f) {
    *dest1 = to_hex(*f >> 4);
    *dest2++ = *dest1++;
    *dest1 = to_hex(*f & 0xf);
    *dest2++ = *dest1++;
    ++dest2;
  }

  return std::string{std::data(output), size};
}

https://godbolt.org/z/h9hd7v1xx

[[nodiscard]] auto bytes_to_string(std::integral auto value) -> std::string {
  std::stringstream str{};
  str << std::hex << std::uppercase << std::setfill('0')
      << std::setw(sizeof(value) * 2) << value << " : ";
    value = std::byteswap(value);
    for (auto i = 0u; i != sizeof(value); ++i, value >>= 8) {
        str << std::setw(2) << (0xFFu & value) << ' ';
    }
    return str.str();
}

https://godbolt.org/z/36TPaevW9

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string{
    char digits[] = "0123456789ABCDEF";
    char ret[] = "00000000 : 00 00 00 00 ";
    for(int i=0; i<8; i++) {
        ret[21-(i+i/2)] = ret[7-i] = digits[value & 0xF];
        value >>= 4;
    }
    return ret;
}

https://godbolt.org/z/jenxjsqKj

[[nodiscard]] auto convert_to_string(std::integral auto value) -> std::string {
    static constexpr auto MAX_BYTES = 4;
    static_assert(sizeof(value) <= MAX_BYTES,
                  "This function is not setup to print 64b values");

    std::array<uint8_t, MAX_BYTES> bytes{};
    std::memcpy(&bytes, &value, sizeof(value));

    return fmt::format("{1:0{0}X} : {2:02X} {3:02X} {4:02X} {5:02X}",
                       MAX_BYTES * 2, value, bytes[3], bytes[2], bytes[1],
                       bytes[0]);
}

}  // namespace detail

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value)
    -> std::string {
    if constexpr (std::endian::native == std::endian::big) {
        return detail::convert_to_string(std::byteswap(value));
    } else {
        return detail::convert_to_string(value);
    }
}

https://godbolt.org/z/6qbG1q6f3

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string{

    value = std::byteswap(value);

    const BYTE d = (value & 0xFF); //extract first byte
    const BYTE c = ((value >> 8) & 0xFF); //extract second byte
    const BYTE b = ((value >> 16) & 0xFF); //extract third byte
    const BYTE a = ((value >> 24) & 0xFF); //extract fourth byte

    char buffer[23];
    unsigned int len = sprintf(buffer,"%02X%02X%02X%02X : %02X %02X %02X %02X", d, c, b, a, d, c, b, a);
    buffer[len] = ' ';
    std::string out_str(buffer);

  return out_str;
}

https://godbolt.org/z/v371e3nPz

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value)
    -> std::string {
  return [=]<auto... Is>(std::index_sequence<Is...>) {
    constexpr auto to_hex = [](std::integral auto value) {
      return fmt::format("{:0>{}X} ", value, 2 * sizeof(value));
    };
    const auto array = std::bit_cast<std::array<std::uint8_t, sizeof(value)>>(
        std::byteswap(value));

    return ((to_hex(value) + ": ") + ... + to_hex(array[Is]));
  }
  (std::make_index_sequence<sizeof(value)>{});
}

https://godbolt.org/z/3WGsnj7xa

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string{
  std::string str{"00000000 : 00 00 00 00 "};

  auto nibblesToChars = [](unsigned char byte) {
    byte &= 0x0F;
    byte += (byte < 0x0A) ? '0' : '7';
    return byte;
  };

  auto insertCharIntoOutputString = [&](auto index, auto nibble_offset, char ch){
    str[(index*2)+nibble_offset   ] = ch;
    str[(index*3)+nibble_offset+11] = ch;
  };

  auto bytesToChars = [&](std::integral auto value){
    for(auto ii = 0; ii < 4; ii++){
      insertCharIntoOutputString(ii, 0, nibblesToChars(value>>4));
      insertCharIntoOutputString(ii, 1, nibblesToChars(value   ));
      value >>= 8;
    }
  };

  bytesToChars(std::byteswap(value));
  return str;
}

https://godbolt.org/z/4oPsvdGYE

template<typename InputIt>
std::string join(InputIt first, InputIt last, const std::string& separator = ",") {
    std::ostringstream result;
    if (first != last) {
        result << *first;
        while (++first != last) {
            result << separator << *first;
        }
    }
    return result.str();
}

auto extract_byte(auto number, auto n){
    int x = (number >> (8*n)) & 0xff;
    return x;
}

auto to_hex(auto value) {
    std::string s = fmt::format("{:02X}", value);
    return s;
}

auto swap_bytes = [](const auto x) {return std::optional{ std::byteswap(x) };};

template<int size=2>
auto split_bytes = [](auto x){
    std::array<std::string, size> bytes{};

    for( auto i = 0; i<size; ++i) {
        bytes[i] = to_hex(extract_byte(x, i));
    }

    return std::optional{bytes};
};

auto make_output = [](auto x){
    std::string combined_bytes = join(std::begin(x), std::end(x), "");
    std::string split_bytes = join(std::begin(x), std::end(x), " ");

    return std::optional{ fmt::format("{} : {}", combined_bytes, split_bytes) };
};

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string{
    return std::optional{value}
        .and_then(swap_bytes)
        .and_then(split_bytes<sizeof(value)>)
        .and_then(make_output).value();
}

https://godbolt.org/z/5nYs6rxzr

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string{
    uint8_t bytes[sizeof(value)];
    for(int i=0; i < sizeof(value); i++){
        bytes[i] = value%16 << 4;
        value = value/16;
        bytes[i] |= value%16;
        value = value/16;
    }
    decltype(value) *x = reinterpret_cast<decltype(value) *>(bytes);
    *x = std::byteswap(*x);
    std::string s1{""};
    std::string s2{""};
    const char* digits = "0123456789ABCDEF";
    for(int i=0; i < sizeof(value); i++){
        s1 += digits[bytes[i] & 0x0F];
        s1 += digits[bytes[i] >> 4 & 0x0F];
        s2 += digits[bytes[i] & 0x0F];
        s2 += digits[bytes[i] >> 4 & 0x0F];
        s2 += " ";
    }
    return s1 + " : " + s2;
}

https://godbolt.org/z/Tfs5no1f1

[[nodiscard]] constexpr auto bytes_to_string(std::integral auto value) -> std::string {
  constexpr auto n_bytes = sizeof(value);
  const auto bytes = std::bit_cast<std::array<std::uint8_t, n_bytes>>(std::byteswap(value));
  return fmt::format("{:02X} : {:02X} ", fmt::join(bytes, ""), fmt::join(bytes, " "));
}

https://godbolt.org/z/M5e1xxbcc