]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2012 Inktank Storage, Inc. | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #ifndef TEXT_TABLE_H_ | |
16 | #define TEXT_TABLE_H_ | |
17 | ||
18 | #include <vector> | |
19 | #include <sstream> | |
11fdf7f2 | 20 | #include "include/ceph_assert.h" |
7c673cae FG |
21 | |
22 | /** | |
23 | * TextTable: | |
24 | * Manage tabular output of data. Caller defines heading of each column | |
25 | * and alignment of heading and column data, | |
26 | * then inserts rows of data including tuples of | |
27 | * length (ncolumns) terminated by TextTable::endrow. When all rows | |
28 | * are inserted, caller asks for output with ostream << | |
29 | * which sizes/pads/dumps the table to ostream. | |
30 | * | |
31 | * Columns autosize to largest heading or datum. One space is printed | |
32 | * between columns. | |
33 | */ | |
34 | ||
35 | class TextTable { | |
36 | ||
37 | public: | |
38 | enum Align {LEFT = 1, CENTER, RIGHT}; | |
39 | ||
40 | private: | |
41 | struct TextTableColumn { | |
42 | std::string heading; | |
43 | int width; | |
44 | Align hd_align; | |
45 | Align col_align; | |
46 | ||
47 | TextTableColumn() {} | |
11fdf7f2 | 48 | TextTableColumn(const std::string &h, int w, Align ha, Align ca) : |
7c673cae FG |
49 | heading(h), width(w), hd_align(ha), col_align(ca) { } |
50 | ~TextTableColumn() {} | |
51 | }; | |
52 | ||
53 | std::vector<TextTableColumn> col; // column definitions | |
54 | unsigned int curcol, currow; // col, row being inserted into | |
55 | unsigned int indent; // indent width when rendering | |
9f95a23c | 56 | std::string column_separation = {" "}; |
7c673cae FG |
57 | |
58 | protected: | |
59 | std::vector<std::vector<std::string> > row; // row data array | |
60 | ||
61 | public: | |
62 | TextTable(): curcol(0), currow(0), indent(0) {} | |
63 | ~TextTable() {} | |
64 | ||
65 | /** | |
66 | * Define a column in the table. | |
67 | * | |
68 | * @param heading Column heading string (or "") | |
69 | * @param hd_align Alignment for heading in column | |
70 | * @param col_align Data alignment | |
71 | * | |
72 | * @note alignment is of type TextTable::Align; values are | |
73 | * TextTable::LEFT, TextTable::CENTER, or TextTable::RIGHT | |
74 | * | |
75 | */ | |
76 | void define_column(const std::string& heading, Align hd_align, | |
77 | Align col_align); | |
78 | ||
79 | /** | |
80 | * Set indent for table. Only affects table output. | |
81 | * | |
82 | * @param i Number of spaces to indent | |
83 | */ | |
84 | void set_indent(int i) { indent = i; } | |
85 | ||
9f95a23c TL |
86 | /** |
87 | * Set column separation | |
88 | * | |
89 | * @param s String to separate columns | |
90 | */ | |
91 | void set_column_separation(const std::string& s) { | |
92 | column_separation = s; | |
93 | } | |
94 | ||
7c673cae FG |
95 | /** |
96 | * Add item to table, perhaps on new row. | |
97 | * table << val1 << val2 << TextTable::endrow; | |
98 | * | |
99 | * @param: value to output. | |
100 | * | |
101 | * @note: Numerics are output in decimal; strings are not truncated. | |
102 | * Output formatting choice is limited to alignment in define_column(). | |
103 | * | |
104 | * @return TextTable& for chaining. | |
105 | */ | |
106 | ||
107 | template<typename T> TextTable& operator<<(const T& item) | |
108 | { | |
109 | if (row.size() < currow + 1) | |
110 | row.resize(currow + 1); | |
111 | ||
112 | /** | |
113 | * col.size() is a good guess for how big row[currow] needs to be, | |
114 | * so just expand it out now | |
115 | */ | |
116 | if (row[currow].size() < col.size()) { | |
117 | row[currow].resize(col.size()); | |
118 | } | |
119 | ||
120 | // inserting more items than defined columns is a coding error | |
11fdf7f2 | 121 | ceph_assert(curcol + 1 <= col.size()); |
7c673cae FG |
122 | |
123 | // get rendered width of item alone | |
124 | std::ostringstream oss; | |
125 | oss << item; | |
126 | int width = oss.str().length(); | |
127 | oss.seekp(0); | |
128 | ||
129 | // expand column width if necessary | |
130 | if (width > col[curcol].width) { | |
131 | col[curcol].width = width; | |
132 | } | |
133 | ||
134 | // now store the rendered item with its proper width | |
135 | row[currow][curcol] = oss.str(); | |
136 | ||
137 | curcol++; | |
138 | return *this; | |
139 | } | |
140 | ||
141 | /** | |
142 | * Degenerate type/variable here is just to allow selection of the | |
143 | * following operator<< for "<< TextTable::endrow" | |
144 | */ | |
145 | ||
146 | struct endrow_t {}; | |
11fdf7f2 | 147 | static constexpr endrow_t endrow{}; |
7c673cae FG |
148 | |
149 | /** | |
150 | * Implements TextTable::endrow | |
151 | */ | |
152 | ||
153 | TextTable &operator<<(endrow_t) | |
154 | { | |
155 | curcol = 0; | |
156 | currow++; | |
157 | return *this; | |
158 | } | |
159 | ||
160 | /** | |
161 | * Render table to ostream (i.e. cout << table) | |
162 | */ | |
163 | ||
164 | friend std::ostream &operator<<(std::ostream &out, const TextTable &t); | |
165 | ||
166 | /** | |
167 | * clear: Reset everything in a TextTable except column defs | |
168 | * resize cols to heading widths, clear indent | |
169 | */ | |
170 | ||
171 | void clear(); | |
172 | }; | |
173 | ||
174 | #endif | |
175 |