]>
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> | |
7c673cae FG |
20 | #include "include/assert.h" |
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() {} | |
48 | TextTableColumn(std::string h, int w, Align ha, Align ca) : | |
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 | |
56 | ||
57 | protected: | |
58 | std::vector<std::vector<std::string> > row; // row data array | |
59 | ||
60 | public: | |
61 | TextTable(): curcol(0), currow(0), indent(0) {} | |
62 | ~TextTable() {} | |
63 | ||
64 | /** | |
65 | * Define a column in the table. | |
66 | * | |
67 | * @param heading Column heading string (or "") | |
68 | * @param hd_align Alignment for heading in column | |
69 | * @param col_align Data alignment | |
70 | * | |
71 | * @note alignment is of type TextTable::Align; values are | |
72 | * TextTable::LEFT, TextTable::CENTER, or TextTable::RIGHT | |
73 | * | |
74 | */ | |
75 | void define_column(const std::string& heading, Align hd_align, | |
76 | Align col_align); | |
77 | ||
78 | /** | |
79 | * Set indent for table. Only affects table output. | |
80 | * | |
81 | * @param i Number of spaces to indent | |
82 | */ | |
83 | void set_indent(int i) { indent = i; } | |
84 | ||
85 | /** | |
86 | * Add item to table, perhaps on new row. | |
87 | * table << val1 << val2 << TextTable::endrow; | |
88 | * | |
89 | * @param: value to output. | |
90 | * | |
91 | * @note: Numerics are output in decimal; strings are not truncated. | |
92 | * Output formatting choice is limited to alignment in define_column(). | |
93 | * | |
94 | * @return TextTable& for chaining. | |
95 | */ | |
96 | ||
97 | template<typename T> TextTable& operator<<(const T& item) | |
98 | { | |
99 | if (row.size() < currow + 1) | |
100 | row.resize(currow + 1); | |
101 | ||
102 | /** | |
103 | * col.size() is a good guess for how big row[currow] needs to be, | |
104 | * so just expand it out now | |
105 | */ | |
106 | if (row[currow].size() < col.size()) { | |
107 | row[currow].resize(col.size()); | |
108 | } | |
109 | ||
110 | // inserting more items than defined columns is a coding error | |
111 | assert(curcol + 1 <= col.size()); | |
112 | ||
113 | // get rendered width of item alone | |
114 | std::ostringstream oss; | |
115 | oss << item; | |
116 | int width = oss.str().length(); | |
117 | oss.seekp(0); | |
118 | ||
119 | // expand column width if necessary | |
120 | if (width > col[curcol].width) { | |
121 | col[curcol].width = width; | |
122 | } | |
123 | ||
124 | // now store the rendered item with its proper width | |
125 | row[currow][curcol] = oss.str(); | |
126 | ||
127 | curcol++; | |
128 | return *this; | |
129 | } | |
130 | ||
131 | /** | |
132 | * Degenerate type/variable here is just to allow selection of the | |
133 | * following operator<< for "<< TextTable::endrow" | |
134 | */ | |
135 | ||
136 | struct endrow_t {}; | |
137 | static endrow_t endrow; | |
138 | ||
139 | /** | |
140 | * Implements TextTable::endrow | |
141 | */ | |
142 | ||
143 | TextTable &operator<<(endrow_t) | |
144 | { | |
145 | curcol = 0; | |
146 | currow++; | |
147 | return *this; | |
148 | } | |
149 | ||
150 | /** | |
151 | * Render table to ostream (i.e. cout << table) | |
152 | */ | |
153 | ||
154 | friend std::ostream &operator<<(std::ostream &out, const TextTable &t); | |
155 | ||
156 | /** | |
157 | * clear: Reset everything in a TextTable except column defs | |
158 | * resize cols to heading widths, clear indent | |
159 | */ | |
160 | ||
161 | void clear(); | |
162 | }; | |
163 | ||
164 | #endif | |
165 |