fork download
  1. // inspired by github.com/dattanchu/bprinter
  2.  
  3. //#pragma once
  4.  
  5. #include <map>
  6. #include <vector>
  7. #include <string>
  8. #include <algorithm>
  9. #include <numeric>
  10. #include <stdexcept>
  11. #include <sstream>
  12.  
  13. #ifdef auto_table_USE_SCOPED_COLOR
  14. #include "scoped_color.h"
  15. #endif
  16.  
  17. namespace auto_table {
  18.  
  19. template <typename K, typename V>
  20. struct sum_values {
  21. V operator()(V i, const std::pair<const K, V>& x) { return i + x.second; }
  22. };
  23.  
  24. struct endl {};
  25.  
  26. template <typename my_stream_t = std::stringstream>
  27. class auto_table {
  28. my_stream_t my_stream;
  29. typedef std::vector<std::string> row_t;
  30. typedef std::vector<row_t> rows_t;
  31. typedef std::map<size_t, size_t> column_widths_t;
  32. column_widths_t column_widths;
  33. rows_t rows;
  34. size_t header_every_nth_row;
  35. size_t horizontal_padding;
  36.  
  37. public:
  38. auto_table() : header_every_nth_row(0), horizontal_padding(0) {}
  39.  
  40. private:
  41. static size_t width(std::string const& s) { return s.length(); }
  42.  
  43. static size_t combine_width(size_t one_width, size_t another_width) {
  44. return std::max(one_width, another_width);
  45. }
  46.  
  47. private:
  48. template <typename stream_t>
  49. void print_horizontal_line(stream_t& stream) {
  50. stream << '+';
  51. size_t sum = std::accumulate(column_widths.begin(), column_widths.end(), 0,
  52. sum_values<size_t, size_t>());
  53. for (size_t i = 0;
  54. i < sum + column_widths.size() +
  55. 2 * column_widths.size() * horizontal_padding - 1;
  56. i++)
  57. stream << '-';
  58. stream << "+\n";
  59. }
  60.  
  61. std::string pad_column(std::string const& s, size_t column) {
  62. size_t s_width = width(s);
  63. size_t column_width = column_widths[column];
  64. if (s_width > column_width) return s;
  65.  
  66. return std::string(column_width - s_width + horizontal_padding, ' ') + s +
  67. std::string(horizontal_padding, ' ');
  68. }
  69.  
  70. template <typename stream_t>
  71. void print_row(size_t r, stream_t& stream, int color = 7) {
  72. size_t column_count = column_widths.size();
  73. row_t const& row = rows[r];
  74. size_t header_count = row.size();
  75.  
  76. for (size_t i = 0; i < header_count; i++) {
  77. stream << '|';
  78. #ifdef auto_table_USE_SCOPED_COLOR
  79. scoped_console_color col(color);
  80. #endif
  81. stream << pad_column(row[i], i);
  82. }
  83.  
  84. for (size_t i = header_count; i < column_count; i++)
  85. stream << '|' << pad_column("", i);
  86.  
  87. stream << "|\n";
  88. }
  89.  
  90. template <typename stream_t>
  91. void print_header(stream_t& stream) {
  92. print_horizontal_line(stream);
  93. if (rows.size() > 0) {
  94. print_row(0, stream, 10);
  95. print_horizontal_line(stream);
  96. }
  97. }
  98.  
  99. template <typename stream_t>
  100. void print_rows(stream_t& stream) {
  101. size_t row_count = rows.size();
  102.  
  103. if (row_count == 0) return;
  104.  
  105. for (size_t row = 1; row < row_count - 1; row++) {
  106. if (row > 1 && header_every_nth_row &&
  107. (row - 1) % header_every_nth_row == 0)
  108. print_header(stream);
  109.  
  110. print_row(row, stream, 15);
  111. }
  112.  
  113. if (rows[row_count - 1].size() > 0) print_row(row_count - 1, stream, 15);
  114. }
  115.  
  116. template <typename stream_t>
  117. void print_footer(stream_t& stream) {
  118. print_horizontal_line(stream);
  119. }
  120.  
  121. public:
  122. auto_table& add_column(std::string const& name, size_t min_width = 0) {
  123. size_t new_width = combine_width(width(name), min_width);
  124. column_widths[column_widths.size()] = new_width;
  125.  
  126. if (rows.size() < 1) rows.push_back(row_t());
  127.  
  128. rows.front().push_back(name);
  129. return *this;
  130. }
  131.  
  132. auto_table& with_header_every_nth_row(size_t n) {
  133. header_every_nth_row = n;
  134. return *this;
  135. }
  136.  
  137. auto_table& with_horizontal_padding(size_t n) {
  138. horizontal_padding = n;
  139. return *this;
  140. }
  141.  
  142. auto_table& operator<<(::auto_table::endl const& input) {
  143. rows.push_back(row_t());
  144. return *this;
  145. }
  146.  
  147. template <typename TPar>
  148. auto_table& operator<<(TPar const& input) {
  149. if (column_widths.size() == 0)
  150. throw std::runtime_error("no columns defined!");
  151.  
  152. if (rows.size() < 1) rows.push_back(row_t());
  153.  
  154. if (rows.back().size() >= column_widths.size()) rows.push_back(row_t());
  155.  
  156. my_stream << input;
  157. std::string entry(my_stream.str());
  158. size_t column = rows.back().size();
  159. size_t new_width = combine_width(width(entry), column_widths[column]);
  160. column_widths[column] = new_width;
  161.  
  162. rows.back().push_back(entry);
  163.  
  164. my_stream.str("");
  165.  
  166. return *this;
  167. }
  168.  
  169. template <typename stream_t>
  170. void print(stream_t& stream) {
  171. this->print_header(stream);
  172. this->print_rows(stream);
  173. this->print_footer(stream);
  174. }
  175.  
  176. my_stream_t& get_stream() { return my_stream; }
  177. };
  178.  
  179. typedef auto_table<> printer;
  180. }
  181.  
  182. #include <random>
  183. #include <iostream>
  184.  
  185. int main() {
  186. auto_table::printer tp;
  187. tp
  188. .add_column("Name")
  189. .add_column("Age")
  190. .add_column("Position")
  191. .add_column("Allowance")
  192. .with_header_every_nth_row(3)
  193. .with_horizontal_padding(1)
  194. ;
  195.  
  196. tp << "Dat Chu" << 25 << "Research Assistant" << -0.00000000001337;
  197. tp << "John Doe" << 26 << "Too much float" << 125456789.123456789;
  198. tp << "John Doe" << 26 << "Typical Int" << 1254;
  199. tp << "John Doe" << 26 << "Typical float" << 1254.36;
  200. tp << "John Doe" << 26 << "Too much negative" << -125456789.123456789;
  201. tp << "John Doe" << 26 << "Exact size int" << 125456789;
  202. tp << "John Doe" << 26 << "Exact size int" << -12545678;
  203. tp << "John Doe" << 26 << "Exact size float" << -1254567.8;
  204. tp << "John Doe" << 26 << "Negative Int" << -1254;
  205. tp << "Jane Doe" << auto_table::endl();
  206. tp << "Tom Doe" << 7 << "Student" << -3.14;
  207.  
  208. tp.print(std::cout);
  209.  
  210. tp
  211. .with_header_every_nth_row(0)
  212. .with_horizontal_padding(0)
  213. .print(std::cout)
  214. ;
  215.  
  216. }
  217.  
Success #stdin #stdout 0s 3308KB
stdin
Standard input is empty
stdout
+----------------------------------------------------+
|     Name | Age |           Position |    Allowance |
+----------------------------------------------------+
|  Dat Chu |  25 | Research Assistant |   -1.337e-11 |
| John Doe |  26 |     Too much float |  1.25457e+08 |
| John Doe |  26 |        Typical Int |         1254 |
+----------------------------------------------------+
|     Name | Age |           Position |    Allowance |
+----------------------------------------------------+
| John Doe |  26 |      Typical float |      1254.36 |
| John Doe |  26 |  Too much negative | -1.25457e+08 |
| John Doe |  26 |     Exact size int |    125456789 |
+----------------------------------------------------+
|     Name | Age |           Position |    Allowance |
+----------------------------------------------------+
| John Doe |  26 |     Exact size int |    -12545678 |
| John Doe |  26 |   Exact size float | -1.25457e+06 |
| John Doe |  26 |       Negative Int |        -1254 |
+----------------------------------------------------+
|     Name | Age |           Position |    Allowance |
+----------------------------------------------------+
| Jane Doe |     |                    |              |
|  Tom Doe |   7 |            Student |        -3.14 |
+----------------------------------------------------+
+--------------------------------------------+
|    Name|Age|          Position|   Allowance|
+--------------------------------------------+
| Dat Chu| 25|Research Assistant|  -1.337e-11|
|John Doe| 26|    Too much float| 1.25457e+08|
|John Doe| 26|       Typical Int|        1254|
|John Doe| 26|     Typical float|     1254.36|
|John Doe| 26| Too much negative|-1.25457e+08|
|John Doe| 26|    Exact size int|   125456789|
|John Doe| 26|    Exact size int|   -12545678|
|John Doe| 26|  Exact size float|-1.25457e+06|
|John Doe| 26|      Negative Int|       -1254|
|Jane Doe|   |                  |            |
| Tom Doe|  7|           Student|       -3.14|
+--------------------------------------------+