]>
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> | |
20 | #include <iomanip> | |
21 | #include <string> | |
22 | #include "include/assert.h" | |
23 | ||
24 | /** | |
25 | * TextTable: | |
26 | * Manage tabular output of data. Caller defines heading of each column | |
27 | * and alignment of heading and column data, | |
28 | * then inserts rows of data including tuples of | |
29 | * length (ncolumns) terminated by TextTable::endrow. When all rows | |
30 | * are inserted, caller asks for output with ostream << | |
31 | * which sizes/pads/dumps the table to ostream. | |
32 | * | |
33 | * Columns autosize to largest heading or datum. One space is printed | |
34 | * between columns. | |
35 | */ | |
36 | ||
37 | class TextTable { | |
38 | ||
39 | public: | |
40 | enum Align {LEFT = 1, CENTER, RIGHT}; | |
41 | ||
42 | private: | |
43 | struct TextTableColumn { | |
44 | std::string heading; | |
45 | int width; | |
46 | Align hd_align; | |
47 | Align col_align; | |
48 | ||
49 | TextTableColumn() {} | |
50 | TextTableColumn(std::string h, int w, Align ha, Align ca) : | |
51 | heading(h), width(w), hd_align(ha), col_align(ca) { } | |
52 | ~TextTableColumn() {} | |
53 | }; | |
54 | ||
55 | std::vector<TextTableColumn> col; // column definitions | |
56 | unsigned int curcol, currow; // col, row being inserted into | |
57 | unsigned int indent; // indent width when rendering | |
58 | ||
59 | protected: | |
60 | std::vector<std::vector<std::string> > row; // row data array | |
61 | ||
62 | public: | |
63 | TextTable(): curcol(0), currow(0), indent(0) {} | |
64 | ~TextTable() {} | |
65 | ||
66 | /** | |
67 | * Define a column in the table. | |
68 | * | |
69 | * @param heading Column heading string (or "") | |
70 | * @param hd_align Alignment for heading in column | |
71 | * @param col_align Data alignment | |
72 | * | |
73 | * @note alignment is of type TextTable::Align; values are | |
74 | * TextTable::LEFT, TextTable::CENTER, or TextTable::RIGHT | |
75 | * | |
76 | */ | |
77 | void define_column(const std::string& heading, Align hd_align, | |
78 | Align col_align); | |
79 | ||
80 | /** | |
81 | * Set indent for table. Only affects table output. | |
82 | * | |
83 | * @param i Number of spaces to indent | |
84 | */ | |
85 | void set_indent(int i) { indent = i; } | |
86 | ||
87 | /** | |
88 | * Add item to table, perhaps on new row. | |
89 | * table << val1 << val2 << TextTable::endrow; | |
90 | * | |
91 | * @param: value to output. | |
92 | * | |
93 | * @note: Numerics are output in decimal; strings are not truncated. | |
94 | * Output formatting choice is limited to alignment in define_column(). | |
95 | * | |
96 | * @return TextTable& for chaining. | |
97 | */ | |
98 | ||
99 | template<typename T> TextTable& operator<<(const T& item) | |
100 | { | |
101 | if (row.size() < currow + 1) | |
102 | row.resize(currow + 1); | |
103 | ||
104 | /** | |
105 | * col.size() is a good guess for how big row[currow] needs to be, | |
106 | * so just expand it out now | |
107 | */ | |
108 | if (row[currow].size() < col.size()) { | |
109 | row[currow].resize(col.size()); | |
110 | } | |
111 | ||
112 | // inserting more items than defined columns is a coding error | |
113 | assert(curcol + 1 <= col.size()); | |
114 | ||
115 | // get rendered width of item alone | |
116 | std::ostringstream oss; | |
117 | oss << item; | |
118 | int width = oss.str().length(); | |
119 | oss.seekp(0); | |
120 | ||
121 | // expand column width if necessary | |
122 | if (width > col[curcol].width) { | |
123 | col[curcol].width = width; | |
124 | } | |
125 | ||
126 | // now store the rendered item with its proper width | |
127 | row[currow][curcol] = oss.str(); | |
128 | ||
129 | curcol++; | |
130 | return *this; | |
131 | } | |
132 | ||
133 | /** | |
134 | * Degenerate type/variable here is just to allow selection of the | |
135 | * following operator<< for "<< TextTable::endrow" | |
136 | */ | |
137 | ||
138 | struct endrow_t {}; | |
139 | static endrow_t endrow; | |
140 | ||
141 | /** | |
142 | * Implements TextTable::endrow | |
143 | */ | |
144 | ||
145 | TextTable &operator<<(endrow_t) | |
146 | { | |
147 | curcol = 0; | |
148 | currow++; | |
149 | return *this; | |
150 | } | |
151 | ||
152 | /** | |
153 | * Render table to ostream (i.e. cout << table) | |
154 | */ | |
155 | ||
156 | friend std::ostream &operator<<(std::ostream &out, const TextTable &t); | |
157 | ||
158 | /** | |
159 | * clear: Reset everything in a TextTable except column defs | |
160 | * resize cols to heading widths, clear indent | |
161 | */ | |
162 | ||
163 | void clear(); | |
164 | }; | |
165 | ||
166 | #endif | |
167 |