#include <iostream> #include <sstream> #include <iomanip> #include <string_view> #include <cstring> #include <j/memory_entry.hpp> #define PRINT_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.') namespace j { namespace { constexpr int MAX_BUFFER_SIZE = 1024; } /** * 指定された出力ストリームにメモリエントリの情報を出力します。 * * @param os 出力ストリーム * @param entry メモリエントリ * @param bytes 出力するバイト最大バイト数 * @param binary true の場合、データの16進数情報が出力されます。 * @param ascii true の場合、データのASCII 情報が出力されます。 * @param maxColumn 出力文字数 * @param noEndl 改行出力無し */ void MemoryEntry::dump( std::ostream &os, int bytes, bool binary, bool ascii, int maxColumn, bool noEndl) const { // <ファイル名>:<行番号> (<size> bytes) [<関数名>] 部分のカラム数を算出する。 int infoColumn = maxColumn; infoColumn -= (binary) ? (bytes * 3) + 3 : 0; infoColumn -= (ascii) ? (bytes) + 3 : 0; if (infoColumn <= 0) { // カラム数不足のため、基本データのみを出力 printBase(os, maxColumn); } else { // 基本データ出力 printBase(os, infoColumn); if (binary) { // 16進数ダンプ os << " | "; printBinary(os, bytes); } if (ascii) { // ASCII出力 os << " | "; printAscii(os, bytes); } } // 改行出力 if (!noEndl) { os << std::endl; } } /** * <ファイル名>:<行番号> (<size> bytes) [<関数名>] を指定されたストリームに出力します。 * column に従い、出力の切り詰めもしくは、スペース' 'によるパディングを行います。 * * @param os 出力ストリーム * @param column カラム数 */ void MemoryEntry::printBase(std::ostream &os, int column) const { char buff[MAX_BUFFER_SIZE]; int maxColumn = (column < MAX_BUFFER_SIZE) ? column : MAX_BUFFER_SIZE - 1; int baseLength = snprintf(buff, MAX_BUFFER_SIZE, "%s:%d (%s) [%s]", file, line, getSizeStr(), func); os << buff; if (baseLength < maxColumn) { // パディング出力 int padding = maxColumn - baseLength; memset(buff, ' ', padding); buff[padding] = '\0'; os << buff; } } /** * 指定された出力ストリームにバイナリの16進数ダンプを出力します。 * * @param os 出力ストリーム * @param bytes 出力するバイト数 */ void MemoryEntry::printBinary(std::ostream &os, int bytes) const { os << std::hex << std::setfill('0'); int dataLen = (this->size < bytes) ? this->size : bytes; unsigned char *dataPtr = static_cast<unsigned char *>(this->_data); int idx = 0; for (; idx < dataLen; idx++) { os << std::setw(2) << (dataPtr[idx] & 0xFF) << " "; } for (; idx < bytes; idx++) { os << "-- "; } } /** * 指定された出力ストリームに ASCII を出力します。 * * @param os 出力ストリーム * @param bytes 出力するバイト数 */ void MemoryEntry::printAscii(std::ostream &os, int bytes) const { int dataLen = (this->size < bytes) ? this->size : bytes; char *dataPtr = static_cast<char *>(this->_data); int idx = 0; for (; idx < dataLen; idx++) { os << PRINT_ASCII(dataPtr[idx]); } for (; idx < bytes; idx++) { os << " "; } } /** * サイズ情報取得 */ const char *MemoryEntry::getSizeStr() const { static char sizeStr[16]; static constexpr const char *SIZE_UNIT[] = {" B", "KB", "MB", "GB", "TB", "PB", "EB"}; int unitIndex = 0; double viewSize = (double)this->size; while (viewSize >= 1024) { viewSize /= 1024; unitIndex++; } snprintf(sizeStr, sizeof(sizeStr), "%8.3lf %s", viewSize, SIZE_UNIT[unitIndex]); return sizeStr; } } // namespace j