mirror of https://github.com/oxen-io/lokinet
Add llarp::buffer_printer for pretty buffer logs
parent
818b4042e9
commit
b61bd82b4b
@ -0,0 +1,45 @@
|
||||
#include "buffer.hpp"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
namespace llarp {
|
||||
std::ostream&
|
||||
operator<<(std::ostream& o, const buffer_printer& bp)
|
||||
{
|
||||
auto& b = bp.buf;
|
||||
auto oldfill = o.fill();
|
||||
o.fill('0');
|
||||
o << "Buffer[" << b.size() << "/0x" << std::hex << b.size() << " bytes]:";
|
||||
for (size_t i = 0; i < b.size(); i += 32)
|
||||
{
|
||||
o << "\n" << std::setw(4) << i << " ";
|
||||
|
||||
size_t stop = std::min(b.size(), i + 32);
|
||||
for (size_t j = 0; j < 32; j++)
|
||||
{
|
||||
auto k = i + j;
|
||||
if (j % 4 == 0)
|
||||
o << ' ';
|
||||
if (k >= stop)
|
||||
o << " ";
|
||||
else
|
||||
o << std::setw(2) << std::to_integer<uint_fast16_t>(b[k]);
|
||||
}
|
||||
o << u8" ┃";
|
||||
for (size_t j = i; j < stop; j++)
|
||||
{
|
||||
auto c = std::to_integer<char>(b[j]);
|
||||
if (c == 0x00)
|
||||
o << u8"∅";
|
||||
else if (c < 0x20 || c > 0x7e)
|
||||
o << u8"·";
|
||||
else
|
||||
o << c;
|
||||
}
|
||||
o << u8"┃";
|
||||
}
|
||||
o << std::dec;
|
||||
o.fill(oldfill);
|
||||
return o;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/util/buffer.hpp>
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
// Buffer printer lets you print a string as a nicely formatted buffer with a hex breakdown and
|
||||
// visual representation of the data for logging purposes. Wraps the string data with a object
|
||||
// that prints the buffer format during output; use as:
|
||||
//
|
||||
// out << buffer_printer(my_buffer);
|
||||
//
|
||||
struct buffer_printer
|
||||
{
|
||||
std::basic_string_view<std::byte> buf;
|
||||
|
||||
// Constructed from any type of string_view<T> for a single-byte T (char, std::byte, uint8_t,
|
||||
// etc.)
|
||||
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
|
||||
explicit buffer_printer(std::basic_string_view<T> buf)
|
||||
: buf{reinterpret_cast<const std::byte*>(buf.data()), buf.size()}
|
||||
{}
|
||||
|
||||
// Constructed from any type of lvalue string<T> for a single-byte T (char, std::byte, uint8_t, etc.)
|
||||
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
|
||||
explicit buffer_printer(const std::basic_string<T>& buf)
|
||||
: buffer_printer(std::basic_string_view<T>{buf})
|
||||
{}
|
||||
|
||||
// *Not* constructable from a string<T> rvalue (because we only hold a view and do not take ownership).
|
||||
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
|
||||
explicit buffer_printer(std::basic_string<T>&& buf) = delete;
|
||||
|
||||
// Constructable from a (T*, size) argument pair, for byte-sized T's.
|
||||
template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
|
||||
explicit buffer_printer(const T* data, size_t size)
|
||||
: buffer_printer(std::basic_string_view<T>{data, size})
|
||||
{}
|
||||
|
||||
// llarp_buffer_t printer:
|
||||
explicit buffer_printer(const llarp_buffer_t& buf)
|
||||
: buffer_printer(std::basic_string_view<byte_t>{buf.base, buf.sz})
|
||||
{}
|
||||
};
|
||||
std::ostream&
|
||||
operator<<(std::ostream& o, const buffer_printer& bp);
|
||||
}
|
Loading…
Reference in New Issue