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