From bdb39b82263b0bed5ee3c0fb6795e9d789f16bc4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 17 Apr 2024 18:23:39 -0400 Subject: [PATCH] xo-indentlog: + hex printer --- include/xo/indentlog/print/hex.hpp | 144 +++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 include/xo/indentlog/print/hex.hpp diff --git a/include/xo/indentlog/print/hex.hpp b/include/xo/indentlog/print/hex.hpp new file mode 100644 index 00000000..66a34084 --- /dev/null +++ b/include/xo/indentlog/print/hex.hpp @@ -0,0 +1,144 @@ +/** @file hex.hpp **/ + +#pragma once + +#include + +namespace xo { + /** + @class hex indentlog/print/hex.hpp + + @brief Container for a (1-byte) value to be printed in hexadecimal + + Example: + @code + #include "indentlog/print/hex.hpp" + + std::ostream os = ...; + os << hex(16 + 63); // output: 1f + os << hex(16 + 63, true); // output: 1f(O) + @endcode + **/ + struct hex { + /** @brief constructor; create stream-inserter instance */ + hex(std::uint8_t x, bool w_char = false) : x_{x}, with_char_{w_char} {} + + /** + @brief print hexadecimal byte-value on to stream. + @param os print on this stream. + + @tparam Stream typename for character stream. + **/ + template + void print(Stream & os) const { + std::uint8_t lo = x_ & 0xf; + std::uint8_t hi = x_ >> 4; + + char lo_ch = (lo < 10) ? '0' + lo : 'a' + lo - 10; + char hi_ch = (hi < 10) ? '0' + hi : 'a' + hi - 10; + + os << hi_ch << lo_ch; + + if (with_char_) { + os << "("; + if (std::isprint(x_)) + os << static_cast(x_); + else + os << "?"; + os << ")"; + } + } + + private: + /** @brief value to print (in hexadecimal) **/ + std::uint8_t x_; + /** @brief if true, follow with ascii character encoding **/ + bool with_char_; + }; + + /** + @brief stream inserter for an 8-bit quantity to be printed in hexadecimal. + + @param os print on this stream + @param ins package for value to insert + **/ + template + Stream & + operator<< (Stream & os, hex const & ins) { + ins.print(os); + return os; + } + + /** + @class hex_view indentlog/print/hex.hpp + + @brief Container for a range (unowned) of 1-byte values to be printed in hexadecimal + + Print a range of bytes on an arbitrary character stream. + Does not use @c iomanips, so will not alter stream formatting flags if used with @c iostream. + + Example: + @code + #include "indentlog/print/hex.hpp" + + std::ostream os = ...; + os << hex_view("hello", false); // output: [68 65 6c 6c 6f] + os << hex_view("hello", true); // output: [68(h) 65(e) 6c(l) 6c(l) 6f(o)] + @endcode + **/ + struct hex_view { + /** @brief constructor; create stream-inserter instance for a range of bytes **/ + hex_view(std::uint8_t const * lo, std::uint8_t const * hi, bool as_text) + : lo_{lo}, hi_{hi}, as_text_{as_text} {} + /** @brief constructor; create stream-inserter instance for a range of chars **/ + hex_view(char const * lo, char const * hi, bool as_text) + : lo_{reinterpret_cast(lo)}, + hi_{reinterpret_cast(hi)}, + as_text_{as_text} {} + + /** + @brief print hexadecimal byte range on stream. + @param os print on this stream + + @tparam Stream typename for character stream. + **/ + template + void print(Stream & os) const { + os << "["; + std::size_t i = 0; + for (std::uint8_t const * p = lo_; p < hi_; ++p) { + if (i > 0) + os << " "; + os << hex(*p, as_text_); + ++i; + } + os << "]"; + } + + private: + /** @brief print byte range starting at this address **/ + std::uint8_t const * lo_; + /** @brief print byte range up to (but not including) this address **/ + std::uint8_t const * hi_; + /** @brief if true also print ascii encoding (for printable codes), + * \c ? otherwise. @see hex::with_char + **/ + bool as_text_; + }; + + /** + @brief stream inserter for a range of 1-byte values to be printed in hexadecimal + + @param os print on this stream. + @param ins (container for) values to insert. + **/ + template + Stream & + operator<< (Stream & os, hex_view const & ins) { + ins.print(os); + return os; + } + +} /*namespace xo*/ + +/* end hex.hpp */