ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
formatter.h
Go to the documentation of this file.
1
8#ifndef FORMATTER_H
9#define FORMATTER_H
10
11#include <string>
12#include <iostream>
13#include <type_traits>
14#include <utility>
15#include <cstdio>
16#include <numeric>
17#include "source_base/ndarray.h"
28{
29public:
30 FmtCore(const std::string& fmt): fmt_(fmt) {};
40 template<typename... Ts>
41 static inline std::string format(const char* fmt, const Ts&... args)
42 {
43 const int size = snprintf(nullptr, 0, fmt, FmtCore::filter(args)...) + 1;
44 std::string dst(size, ' ');
45 const int size_filled = snprintf(&dst[0], size, fmt, FmtCore::filter(args)...);
46 dst.resize(size_filled);
47 return dst;
48 }
56 template<typename... Ts>
57 std::string format(const Ts&... args) { return FmtCore::format(fmt_.c_str(), args...); }
63 void reset(const std::string& fmt = "") { fmt_ = fmt; }
69 const std::string& fmt() { return fmt_; }
79 static std::vector<std::string> split(const std::string& in, const std::string& delim)
80 {
81 std::vector<std::string> dst;
82 std::string::size_type beg = 0, end;
83 while((end = in.find(delim, beg)) != std::string::npos)
84 {
85 dst.push_back(in.substr(beg, end - beg));
86 beg = end + delim.size();
87 }
88 dst.push_back(in.substr(beg));
89 return dst;
90 }
97 static std::vector<std::string> split(const std::string& in)
98 {
99 std::vector<std::string> dst;
100 std::string::size_type beg = 0, end = 0;
101 while((beg = in.find_first_not_of(" ", end)) != std::string::npos)
102 {
103 end = in.find_first_of(" ", beg);
104 dst.push_back(in.substr(beg, end - beg));
105 }
106 return dst;
107 }
108 static bool startswith(const std::string& in, const std::string& prefix)
109 {
110 return (in.size() >= prefix.size()) && (in.substr(0, prefix.size()) == prefix);
111 }
112 static bool endswith(const std::string& in, const std::string& suffix)
113 {
114 return (in.size() >= suffix.size()) && (in.substr(in.size() - suffix.size()) == suffix);
115 }
116 static std::string strip(const std::string& in, const std::string& chars = " ")
117 {
118 std::string::size_type beg = in.find_first_not_of(chars);
119 return (beg == std::string::npos)? "": in.substr(beg, in.find_last_not_of(chars) - beg + 1);
120 }
121 static std::string center(const std::string& in, const size_t& width, const char& fillchar = ' ')
122 {
123 if (in.size() >= width) {
124 return in;
125 }
126 const size_t nwhitespaces = width - in.size();
127 const size_t nleft = nwhitespaces / 2;
128 const size_t nright = nwhitespaces - nleft;
129 return std::string(nleft, fillchar) + in + std::string(nright, fillchar);
130 }
131 static std::string replace(const std::string& in, const std::string& old, const std::string& new_)
132 {
133 std::string dst = in;
134 std::string::size_type pos = dst.find(old);
135 while(pos != std::string::npos)
136 {
137 dst.replace(pos, old.size(), new_);
138 pos = dst.find(old, pos + new_.size());
139 }
140 return dst;
141 }
142 static std::string join(const std::string& delim, const std::vector<std::string>& src)
143 {
144 return (src.empty())? "": std::accumulate(src.begin() + 1, src.end(), src[0],
145 [&delim](const std::string& acc, const std::string& s) { return acc + delim + s; });
146 }
147
148 static std::string upper(const std::string& in)
149 {
150 std::string dst = in;
151 std::transform(dst.begin(), dst.end(), dst.begin(), ::toupper);
152 return dst;
153 }
154
155 static std::string lower(const std::string& in)
156 {
157 std::string dst = in;
158 std::transform(dst.begin(), dst.end(), dst.begin(), ::tolower);
159 return dst;
160 }
161
162private:
163 std::string fmt_;
164 template<typename T>
165 static typename std::enable_if<std::is_same<T, std::string>::value, const char*>::type filter(const T& s) { return s.c_str(); }
166 template<typename T>
167 static typename std::enable_if<!std::is_same<T, std::string>::value, const T&>::type filter(const T& s) { return s; }
168};
169
171{
172public:
173 enum class Align{LEFT, RIGHT, CENTER};
174private:
175 typedef FmtCore core;
177 Alignments(const Align& val = Align::RIGHT, const Align& title = Align::CENTER): val_(val), title_(title) {};
178 Align val_, title_; // value and title alignments
180 struct Frames{
181 Frames(char up = '-', char mid = '-', char dw = '-', char l = ' ', char r = ' '): up_(up), mid_(mid), dw_(dw), l_(l), r_(r) {};
182 char up_, mid_ , dw_, l_, r_; // up, middle, down, left, right frames. up: the frame above title, middle: the one between title and data
183 } frames_; // down: the frame below data, left: the frame at left, right: the frame at right
185 Delimiters(char h = '-', char v = ' '): h_(h), v_(v) {};
186 char h_, v_; // horizontal and vertical delimiters
188public:
200 FmtTable(const std::vector<std::string>& titles,
201 const size_t nrows,
202 const std::vector<std::string>& fmts,
203 const size_t indent = 0,
204 const Alignments& aligns = {},
205 const Frames& frames = {},
206 const Delimiters& delimiters = {}):
207 titles_(titles), data_(nrows, titles.size()), // data
208 fmts_(fmts), indent_(indent), aligns_(aligns), frames_(frames), delimiters_(delimiters) // styles
209 { assert(titles.size() == fmts.size()||titles.size() == 0); };
218 template<typename T>
219 FmtTable& operator<<(const std::vector<T>& src)
220 {
221 // create a copy of source data, then format
222 std::vector<std::string> data(src.size());
223 for(size_t i = 0UL; i < src.size(); i++) { data[i] = core::format(fmts_[j_].c_str(), src[i]); }
224 set_value(0, j_, 'v', data);
225 j_ = (j_ + 1) % titles_.size();
226 return *this;
227 }
236 template<typename T>
237 void set_value(const size_t& i, const size_t& j, const T& value) { data_(i, j) = core::format(fmts_[j].c_str(), value); }
247 std::vector<std::string> relax_col_width(const std::vector<std::string>& col,
248 const std::string& title = "",
249 const Align valign = Align::RIGHT, // because enum type would be the smallest integral type, so it is safe to pass by value
250 const Align talign = Align::CENTER)
251 {
252 size_t max_width = title.size();
253 for(const std::string& s : col) { max_width = std::max(max_width, s.size()); }
254 std::vector<std::string> new_col(col.size() + 1); // the first is column title
255 for(size_t i = 0; i < col.size() + 1; i++)
256 {
257 new_col[i] = (i == 0)? FmtCore::strip(title): FmtCore::strip(col[i - 1]);
258 const size_t nwhitespaces = max_width - new_col[i].size();
259 switch((i == 0)? talign: valign)
260 {
261 case Align::RIGHT: new_col[i] = std::string(nwhitespaces, ' ') + new_col[i]; break;
262 case Align::LEFT: new_col[i] += std::string(nwhitespaces, ' '); break;
263 case Align::CENTER: new_col[i] = FmtCore::center(new_col[i], max_width); break;
264 }
265 }
266 return new_col;
267 }
268
275 std::string concat_title(const std::vector<std::string>& titles) const
276 {
277 std::string dst = "";
278 // first sum width of all titles
279 size_t width = std::accumulate(titles.begin(), titles.end(), 0, [](const size_t& acc, const std::string& s) { return acc + s.size(); });
280 // add width of delimiters
281 width += titles.size() - 1;
282 // add width of left and right frames
283 width += 2;
284 dst += std::string(indent_, ' ') + std::string(width, frames_.up_) + "\n"; // first line: the upper frame
285 dst += std::string(indent_, ' ') + std::string(1, frames_.l_); // second line: the left frame + titles + right frame
286 for(size_t i = 0; i < titles.size(); i++)
287 {
288 dst += titles[i];
289 if (i != titles.size() - 1) {
290 dst += delimiters_.v_;
291 }
292 }
293 dst += std::string(1, frames_.r_) + "\n";
294 dst += std::string(indent_, ' ') + std::string(width, frames_.mid_) + "\n"; // third line: the middle frame
295 return dst;
296 }
304 std::string concat_row(const std::vector<std::string>& row, const char& pos) const
305 {
306 std::string dst = "";
307 // first sum width of all elements of the row
308 size_t width = std::accumulate(row.begin(), row.end(), 0, [](const size_t& acc, const std::string& s) { return acc + s.size(); });
309 // for the delimiters
310 width += row.size() - 1;
311 // for the left and right frame
312 width += 2;
313 if (pos == 't') { // 't' for top
314 dst += std::string(indent_, ' ') + std::string(width, frames_.up_) + "\n";
315 }
316 dst += std::string(indent_, ' ') + std::string(1, frames_.l_);
317 for(size_t i = 0; i < row.size(); i++)
318 {
319 dst += row[i];
320 if (i != row.size() - 1) {
321 dst += delimiters_.v_;
322 }
323 }
324 dst += std::string(1, frames_.r_) + "\n";
325 if (pos == 'b') { // 'b' for bottom
326 dst += std::string(indent_, ' ') + std::string(width, frames_.dw_) + "\n"; // the last line
327 }
328 return dst;
329 }
335 std::string str()
336 {
337 std::string dst = "";
338 const size_t nrows = data_.shape()[0];
339 const size_t ncols = data_.shape()[1];
340 // if not all titles are empty, then with_title boolean will be true
341 bool with_title = false;
342 for (auto& title: titles_) {
343 if (!title.empty()) {
344 with_title = true;
345 break;
346 }
347 }
348 // first to relax each column
349 for(size_t j = 0UL; j < ncols; j++)
350 {
351 std::vector<std::string> col(nrows);
352 for (size_t i = 0UL; i < nrows; i++) {
353 col[i] = data_(i, j);
354 }
356 titles_[j] = col[0UL];
357 std::vector<std::string> col_new(col.begin() + 1, col.end());
358 set_value(0UL, j, 'v', col_new);
359 }
360 // then print titles
361 if (with_title) {
362 dst += concat_title(titles_);
363 }
364 // then print contents
365 for(size_t i = 0UL; i < nrows; i++)
366 {
367 std::vector<std::string> row(ncols);
368 for (size_t j = 0; j < ncols; j++) {
369 row[j] = data_(i, j);
370 }
371 dst += concat_row(row, ((i == 0UL)&&!with_title)? 't': (i == nrows - 1)? 'b': 'n');
372 }
373 return dst;
374 }
375 void str(const std::string& s) {};
376 // reuse
377 void iter_set(const size_t val) { j_ = val; }
378private:
388 template<typename T>
389 void set_value(const size_t& i, const size_t& j, const char& dir, const std::vector<T>& src)
390 {
391 if (dir == 'v') {
392 for (size_t k = 0UL; k < src.size(); k++) {
393 data_(i + k, j) = src[k];
394 }
395 } else if (dir == 'h') {
396 for (size_t k = 0UL; k < src.size(); k++) {
397 data_(j, i + k) = src[k];
398 }
399 }
400 }
401 // iterator support indices
402 size_t j_ = 0;
403
404 std::vector<std::string> titles_;
406 std::vector<std::string> fmts_; // format strings for each column
407 size_t indent_ = 0; // indent for each column
408};
409
410#endif
In C++20, the std::format library is introduced. However, it is not supported under restriction of AB...
Definition formatter.h:28
static std::string join(const std::string &delim, const std::vector< std::string > &src)
Definition formatter.h:142
FmtCore(const std::string &fmt)
Definition formatter.h:30
const std::string & fmt()
get the format string
Definition formatter.h:69
std::string format(const Ts &... args)
std::string overload of the varadic template function
Definition formatter.h:57
~FmtCore()
Definition formatter.h:31
static std::string lower(const std::string &in)
Definition formatter.h:155
static bool endswith(const std::string &in, const std::string &suffix)
Definition formatter.h:112
static std::string replace(const std::string &in, const std::string &old, const std::string &new_)
Definition formatter.h:131
static bool startswith(const std::string &in, const std::string &prefix)
Definition formatter.h:108
static std::string upper(const std::string &in)
Definition formatter.h:148
static std::enable_if< std::is_same< T, std::string >::value, constchar * >::type filter(const T &s)
Definition formatter.h:165
void reset(const std::string &fmt="")
reset the format string (std::string overloads)
Definition formatter.h:63
static std::vector< std::string > split(const std::string &in)
split a string with a delimiter, return only non-empty elements
Definition formatter.h:97
static std::enable_if<!std::is_same< T, std::string >::value, constT & >::type filter(const T &s)
Definition formatter.h:167
static std::string format(const char *fmt, const Ts &... args)
static function to format data
Definition formatter.h:41
static std::vector< std::string > split(const std::string &in, const std::string &delim)
split a string with a delimiter, return uncollapse vector
Definition formatter.h:79
static std::string center(const std::string &in, const size_t &width, const char &fillchar=' ')
Definition formatter.h:121
static std::string strip(const std::string &in, const std::string &chars=" ")
Definition formatter.h:116
std::string fmt_
Definition formatter.h:163
Definition formatter.h:171
std::string str()
to get the table as a string
Definition formatter.h:335
struct FmtTable::Alignments aligns_
Align
Definition formatter.h:173
std::string concat_row(const std::vector< std::string > &row, const char &pos) const
concatenate a row into a string
Definition formatter.h:304
void set_value(const size_t &i, const size_t &j, const T &value)
Set the value object.
Definition formatter.h:237
std::vector< std::string > titles_
Definition formatter.h:404
size_t j_
Definition formatter.h:402
std::vector< std::string > fmts_
Definition formatter.h:406
FmtTable(const std::vector< std::string > &titles, const size_t nrows, const std::vector< std::string > &fmts, const size_t indent=0, const Alignments &aligns={}, const Frames &frames={}, const Delimiters &delimiters={})
Construct a new Fmt Table object.
Definition formatter.h:200
struct FmtTable::Delimiters delimiters_
void set_value(const size_t &i, const size_t &j, const char &dir, const std::vector< T > &src)
Set the value object from std::vector.
Definition formatter.h:389
struct FmtTable::Frames frames_
size_t indent_
Definition formatter.h:407
std::vector< std::string > relax_col_width(const std::vector< std::string > &col, const std::string &title="", const Align valign=Align::RIGHT, const Align talign=Align::CENTER)
adjust the width of each column
Definition formatter.h:247
void str(const std::string &s)
Definition formatter.h:375
FmtCore core
Definition formatter.h:175
~FmtTable()
Definition formatter.h:210
std::string concat_title(const std::vector< std::string > &titles) const
concatenate titles into a string
Definition formatter.h:275
FmtTable & operator<<(const std::vector< T > &src)
import data from std::vector
Definition formatter.h:219
NDArray< std::string > data_
Definition formatter.h:405
void iter_set(const size_t val)
Definition formatter.h:377
under the restriction of C++11, a simple alternative to std::vector<T> + std::mdspan....
Definition ndarray.h:31
const std::vector< size_t > & shape() const
Definition ndarray.h:153
#define T
Definition exp.cpp:237
Definition formatter.h:176
Alignments(const Align &val=Align::RIGHT, const Align &title=Align::CENTER)
Definition formatter.h:177
Align val_
Definition formatter.h:178
Align title_
Definition formatter.h:178
Definition formatter.h:184
char v_
Definition formatter.h:186
char h_
Definition formatter.h:186
Delimiters(char h='-', char v=' ')
Definition formatter.h:185
Definition formatter.h:180
char up_
Definition formatter.h:182
Frames(char up='-', char mid='-', char dw='-', char l=' ', char r=' ')
Definition formatter.h:181
char dw_
Definition formatter.h:182
char mid_
Definition formatter.h:182
char l_
Definition formatter.h:182
char r_
Definition formatter.h:182