File indexing completed on 2025-12-14 09:39:51
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <algorithm>
0012 #include <cctype>
0013 #include <format>
0014 #include <ostream>
0015 #include <stdexcept>
0016 #include <string>
0017 #include <vector>
0018
0019 namespace Acts {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 class Table {
0034 public:
0035
0036 enum class Alignment { Left, Right, Center };
0037
0038 struct Column {
0039 std::string header;
0040 std::string format;
0041 Alignment alignment;
0042 std::size_t width = 0;
0043 };
0044
0045
0046
0047
0048
0049 void addColumn(const std::string& header, const std::string& format,
0050 Alignment alignment = Alignment::Left) {
0051 if (!m_rows.empty()) {
0052 throw std::runtime_error("Cannot add columns after rows have been added");
0053 }
0054 m_columns.push_back({header, format, alignment, header.length()});
0055 }
0056
0057
0058
0059
0060
0061
0062 void addColumn(const std::string& header, const std::string& format,
0063 const std::string& alignment = "left") {
0064 addColumn(header, format, parseAlignment(alignment));
0065 }
0066
0067
0068
0069 void setMarkdownMode(bool includeMarkers) {
0070 m_includeMarkdownMarkers = includeMarkers;
0071 }
0072
0073
0074
0075
0076 template <typename... Args>
0077 void addRow(Args&&... args) {
0078 if (sizeof...(Args) != m_columns.size()) {
0079 throw std::runtime_error("Number of arguments (" +
0080 std::to_string(sizeof...(Args)) +
0081 ") does not match number of columns (" +
0082 std::to_string(m_columns.size()) + ")");
0083 }
0084
0085 std::vector<std::string> row;
0086 std::size_t colIndex = 0;
0087
0088 auto addCell = [&](auto&& arg) {
0089 std::string formatted =
0090 std::vformat(m_columns[colIndex].format, std::make_format_args(arg));
0091 row.push_back(formatted);
0092 m_columns[colIndex].width =
0093 std::max(m_columns[colIndex].width, formatted.length());
0094 ++colIndex;
0095 };
0096
0097 (addCell(args), ...);
0098
0099 m_rows.push_back(std::move(row));
0100 }
0101
0102
0103
0104 std::string toString() const {
0105 if (m_columns.empty()) {
0106 return "";
0107 }
0108
0109 std::string result;
0110
0111
0112 result += "|";
0113 for (std::size_t i = 0; i < m_columns.size(); ++i) {
0114 result += std::format(
0115 " {} |", formatAligned(m_columns[i].header, m_columns[i].width,
0116 m_columns[i].alignment));
0117 }
0118 result += "\n";
0119
0120
0121 result += "|";
0122 for (std::size_t i = 0; i < m_columns.size(); ++i) {
0123 std::size_t contentWidth = m_columns[i].width;
0124
0125 if (m_includeMarkdownMarkers) {
0126 switch (m_columns[i].alignment) {
0127 case Alignment::Left:
0128 result += std::format(":{:-<{}}", "", contentWidth + 1);
0129 break;
0130 case Alignment::Right:
0131 result += std::format("{:-<{}}:", "", contentWidth + 1);
0132 break;
0133 case Alignment::Center:
0134 result += std::format(":{:-<{}}:", "", contentWidth);
0135 break;
0136 }
0137 } else {
0138 result += std::format("{:-<{}}", "", contentWidth + 2);
0139 }
0140 result += "|";
0141 }
0142 result += "\n";
0143
0144
0145 for (const auto& row : m_rows) {
0146 result += "|";
0147 for (std::size_t i = 0; i < row.size(); ++i) {
0148 result += std::format(" {} |", formatAligned(row[i], m_columns[i].width,
0149 m_columns[i].alignment));
0150 }
0151 result += "\n";
0152 }
0153
0154 return result;
0155 }
0156
0157
0158 friend std::ostream& operator<<(std::ostream& os, const Table& table) {
0159 return os << table.toString();
0160 }
0161
0162 private:
0163
0164
0165 static Alignment parseAlignment(const std::string& alignment) {
0166 std::string lower = alignment;
0167 std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
0168
0169 if (lower == "left" || lower == "l") {
0170 return Alignment::Left;
0171 } else if (lower == "right" || lower == "r") {
0172 return Alignment::Right;
0173 } else if (lower == "center" || lower == "c") {
0174 return Alignment::Center;
0175 } else {
0176 throw std::invalid_argument(
0177 "Invalid alignment string: '" + alignment +
0178 "'. Valid options: 'left'/'l', 'right'/'r', 'center'/'c'");
0179 }
0180 }
0181
0182 std::string formatAligned(const std::string& text, std::size_t width,
0183 Alignment alignment) const {
0184 switch (alignment) {
0185 case Alignment::Left:
0186 return std::format("{:<{}}", text, width);
0187 case Alignment::Right:
0188 return std::format("{:>{}}", text, width);
0189 case Alignment::Center:
0190 return std::format("{:^{}}", text, width);
0191 }
0192 return text;
0193 }
0194
0195 std::vector<Column> m_columns;
0196 std::vector<std::vector<std::string>> m_rows;
0197 bool m_includeMarkdownMarkers = true;
0198 };
0199
0200 }