#ifndef __FIBRE_PRINT_UTILS_HPP #define __FIBRE_PRINT_UTILS_HPP #include #include #include namespace fibre { template constexpr size_t hex_digits() { return (std::numeric_limits::digits + 3) / 4; } /* @brief Converts a hexadecimal digit to a uint8_t. * @param output If not null, the digit's value is stored in this output * Returns true if the char is a valid hex digit, false otherwise */ static inline bool hex_digit_to_byte(char ch, uint8_t* output) { uint8_t nil_output = 0; if (!output) output = &nil_output; if (ch >= '0' && ch <= '9') return (*output) = ch - '0', true; if (ch >= 'a' && ch <= 'f') return (*output) = ch - 'a' + 10, true; if (ch >= 'A' && ch <= 'F') return (*output) = ch - 'A' + 10, true; return false; } /* @brief Converts a hex string to an integer * @param output If not null, the result is stored in this output * Returns true if the string represents a valid hex value, false otherwise. */ template bool hex_string_to_int(const char * str, size_t length, TInt* output) { constexpr size_t N_DIGITS = hex_digits(); TInt result = 0; if (length > N_DIGITS) length = N_DIGITS; for (size_t i = 0; i < length && str[i]; i++) { uint8_t digit = 0; if (!hex_digit_to_byte(str[i], &digit)) return false; result <<= 4; result += digit; } if (output) *output = result; return true; } template bool hex_string_to_int(const char * str, TInt* output) { return hex_string_to_int(str, hex_digits(), output); } template bool hex_string_to_int_arr(const char * str, size_t length, TInt (&output)[ICount]) { for (size_t i = 0; i < ICount; i++) { if (!hex_string_to_int(&str[i * hex_digits()], &output[i])) return false; } return true; } template bool hex_string_to_int_arr(const char * str, TInt (&output)[ICount]) { return hex_string_to_int_arr(str, hex_digits() * ICount, output); } // TODO: move to print_utils.hpp template class HexPrinter { public: HexPrinter(T val, bool prefix) : val_(val) /*, prefix_(prefix)*/ { const char digits[] = "0123456789abcdef"; size_t prefix_length = prefix ? 2 : 0; if (prefix) { str[0] = '0'; str[1] = 'x'; } str[prefix_length + hex_digits()] = '\0'; for (size_t i = 0; i < hex_digits(); ++i) { str[prefix_length + hex_digits() - i - 1] = digits[val & 0xf]; val >>= 4; } } std::string to_string() const { return str; } void to_string(char* buf) const { for (size_t i = 0; (i < sizeof(str)) && str[i]; ++i) buf[i] = str[i]; } T val_; //bool prefix_; char str[hex_digits() + 3]; // 3 additional characters 0x and \0 }; template std::ostream& operator<<(std::ostream& stream, const HexPrinter& printer) { // TODO: specialize for char return stream << printer.to_string(); } template HexPrinter as_hex(T val, bool prefix = true) { return HexPrinter(val, prefix); } template class HexArrayPrinter { public: HexArrayPrinter(T* ptr, size_t length) : ptr_(ptr), length_(length) {} T* ptr_; size_t length_; }; template TStream& operator<<(TStream& stream, const HexArrayPrinter& printer) { for (size_t pos = 0; pos < printer.length_; ++pos) { stream << " " << as_hex(printer.ptr_[pos]); if (((pos + 1) % 16) == 0) stream << "\n"; } return stream; } template HexArrayPrinter as_hex(T (&val)[ILength]) { return HexArrayPrinter(val, ILength); } template HexArrayPrinter as_hex(generic_bufptr_t buffer) { return HexArrayPrinter(buffer.begin(), buffer.size()); } } #endif // __FIBRE_PRINT_UTILS_HPP