diff --git a/tools/src/podio-dump.cpp b/tools/src/podio-dump.cpp index e3b983a0b..9d312efdf 100644 --- a/tools/src/podio-dump.cpp +++ b/tools/src/podio-dump.cpp @@ -6,6 +6,10 @@ #include "podio/podioVersion.h" #include "podio/utilities/MiscHelpers.h" +#include +#include +#include + #include #include #include @@ -13,6 +17,9 @@ #include #include +template <> +struct fmt::formatter : ostream_formatter {}; + struct ParsedArgs { std::string inputFile{}; std::string category{"events"}; @@ -39,7 +46,7 @@ positional arguments: )"; void printUsageAndExit() { - std::cerr << usageMsg << std::endl; + fmt::print(stderr, "{}\n", usageMsg); std::exit(1); } @@ -55,7 +62,7 @@ auto getArgumentValueOrExit(const std::vector& argv, std::vector parseEventRange(const std::string& evtRange) { const auto splitRange = splitString(evtRange, ','); const auto parseError = [&evtRange]() { - std::cerr << "'" << evtRange << "' cannot be parsed into a list of entries" << std::endl; + fmt::print(stderr, "'{}' canot be parsed into a list of entries\n", evtRange); std::exit(1); }; @@ -90,9 +97,9 @@ ParsedArgs parseArgs(std::vector argv) { // find help or version if (const auto it = findFlags(argv, "-h", "--help", "--version"); it != argv.end()) { if (*it == "--version") { - std::cout << "podio " << podio::version::build_version << '\n'; + fmt::print("podio {}\n", podio::version::build_version); } else { - std::cout << usageMsg << '\n' << helpMsg << std::flush; + fmt::print("{}\n{}", usageMsg, helpMsg); } std::exit(0); } @@ -123,45 +130,66 @@ ParsedArgs parseArgs(std::vector argv) { } template -void printParameterOverview(const podio::Frame& frame) { +std::string getTypeString() { + if constexpr (std::is_same_v) { + return "int"; + } else if constexpr (std::is_same_v) { + return "float"; + } else if constexpr (std::is_same_v) { + return "double"; + } else if constexpr (std::is_same_v) { + return "std::string"; + } + + return "unknown"; +} + +template +void getParameterOverview(const podio::Frame& frame, std::vector>& rows) { + const auto typeString = getTypeString(); for (const auto& parKey : podio::utils::sortAlphabeticaly(frame.getParameterKeys())) { - std::cout << parKey << "\t" << frame.getParameter>(parKey)->size() << '\n'; + rows.emplace_back(parKey, typeString, frame.getParameter>(parKey)->size()); } } void printFrameOverview(const podio::Frame& frame) { - std::cout << "Collections\n"; - std::cout << "Name\tValueType\tSize\tID\n"; - for (const auto& name : frame.getAvailableCollections()) { + + fmt::print("Collections:\n"); + const auto collNames = frame.getAvailableCollections(); + + std::vector> rows; + rows.reserve(collNames.size()); + + for (const auto& name : podio::utils::sortAlphabeticaly(collNames)) { const auto coll = frame.get(name); - std::cout << name << "\t" << coll->getValueTypeName() << "\t" << coll->size() << "\t" << coll->getID() << '\n'; + rows.emplace_back(name, coll->getValueTypeName(), coll->size(), fmt::format("{:0>8x}", coll->getID())); } + printTable(rows, {"Name", "ValueType", "Size", "ID"}); + + fmt::print("\nParameters:\n"); + std::vector> paramRows{}; + getParameterOverview(frame, paramRows); + getParameterOverview(frame, paramRows); + getParameterOverview(frame, paramRows); + getParameterOverview(frame, paramRows); - std::cout << "\nParameters\n"; - printParameterOverview(frame); - printParameterOverview(frame); - printParameterOverview(frame); - printParameterOverview(frame); + printTable(paramRows, {"Name", "Type", "Elements"}); } void printGeneralInfo(const podio::Reader& reader, const std::string& filename) { - std::cout << "input file: " << filename << '\n'; - std::cout << "datamodel model definitions stored in this file: "; - for (const auto& model : reader.getAvailableDatamodels()) { - std::cout << model << ", "; - } - std::cout << "\n\n"; - - std::cout << "Frame categories in this file:\nName\tEntries\n"; + fmt::print("input file: {}\n", filename); + fmt::print("datamodel model definitions stored in this file: {}\n\n", reader.getAvailableDatamodels()); std::vector> rows{}; for (const auto& cat : reader.getAvailableCategories()) { rows.emplace_back(cat, reader.getEntries(std::string(cat))); } + fmt::print("Frame categories in this file:\nName\tEntries\n"); + printTable(rows, {"Name", "Entries"}); } void printFrame(const podio::Frame& frame, const std::string& category, size_t iEntry, bool detailed) { - std::cout << "################## " << category << ": " << iEntry << " ##################\n"; + fmt::print("{:#^82}\n", fmt::format(" {}: {} ", category, iEntry)); if (detailed) { } else { @@ -182,13 +210,10 @@ int main(int argc, char* argv[]) { const auto& frame = reader.readFrame(args.category, event); printFrame(frame, args.category, event, args.detailed); } catch (std::runtime_error& err) { - std::cerr << err.what() << std::endl; + fmt::print(stderr, "{}\n", err.what()); return 1; } } - // const auto event = reader.readNextEvent(); - // printFrameOverview(event); - return 0; } diff --git a/tools/src/tabulate.h b/tools/src/tabulate.h index bc31a5d20..860ecfa61 100644 --- a/tools/src/tabulate.h +++ b/tools/src/tabulate.h @@ -1,35 +1,71 @@ +#include + #include #include #include +#include #include #include +#include #include +std::string rowFormatString(const std::vector& colWidths) { + std::string rowFmt = ""; + rowFmt.reserve(colWidths.size() * 6); // heuristic working for columns that are 2 digit numbers wide + + for (const auto w : colWidths) { + rowFmt.append(fmt::format("{{:<{}}}", w)); + } + + return rowFmt; +} + template void printTable(const std::vector>& rows, const std::vector& headers) { // Simply assume that all rows have the same widths - const auto nCols = rows[0].size(); - // First figure out how large each column has to be to fit all the content - std::vector colWidths{0, nCols}; + const auto nCols = headers.size(); + constexpr auto nColsFromRows = std::tuple_size_v>; + if (nCols != nColsFromRows) { + throw std::invalid_argument("headers and rows have to have the same size"); + } + // Transform all elements into strings first to determine column widths std::vector> stringRows; stringRows.reserve(rows.size()); + std::transform(rows.begin(), rows.end(), std::back_inserter(stringRows), [&nCols](const auto& elem) { + std::vector strs; + strs.reserve(nCols); + std::apply([&strs](auto&&... args) { (strs.emplace_back(fmt::format("{}", args)), ...); }, elem); + return strs; + }); + // First figure out how large each column has to be to fit all the content + std::vector colWidths(nCols, 0); for (size_t i = 0; i < nCols; ++i) { colWidths[i] = headers[i].size(); } - for (const auto& row : rows) { + for (const auto& row : stringRows) { for (size_t iCol = 0; iCol < nCols; ++iCol) { colWidths[iCol] = std::max(row[iCol].size(), colWidths[iCol]); } } + // print the table header for (size_t iCol = 0; iCol < nCols; ++iCol) { - std::cout << std::setw(colWidths[iCol] + 1) << headers[iCol]; + fmt::print("{:<{}} ", headers[iCol], colWidths[iCol]); } + fmt::print("\n"); std::cout << '\n'; for (size_t iCol = 0; iCol < nCols; ++iCol) { - std::cout << std::setw(colWidths[iCol] + 1) << std::setfill('-') << " "; + fmt::print("{:->{}} ", "", colWidths[iCol]); + } + fmt::print("\n"); + + // and the contents + for (const auto& row : stringRows) { + for (size_t iCol = 0; iCol < nCols; ++iCol) { + fmt::print("{:<{}} ", row[iCol], colWidths[iCol]); + } + fmt::print("\n"); } - std::cout << '\n'; }