Evo C++ Library v0.5.1
fmt.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_fmt_h
9 #define INCL_evo_fmt_h
10 
11 #include "substring.h"
12 
13 namespace evo {
16 
18 
20 namespace impl {
21  template<class T> struct FmtFieldType {
22  typedef typename T::FmtFieldType Type;
23  };
24  template<> struct FmtFieldType<String> {
25  typedef FmtString Type;
26  };
27 }
30 
45 struct FmtTable {
47  enum Type {
49  tMARKDOWN
50  };
51 
53  struct Column {
56  int width;
57 
59  Column() : align(fLEFT), width(0) {
60  }
61 
67  Column(const SubString& name, FmtAlign align, int width=0) : name(name), align(align), width(width) {
68  }
69 
76  Column(const SubString& name, int width=0) : name(name), align(fLEFT), width(width) {
77  }
78 
82  Column(const Column& src) : name(src.name), align(src.align), width(src.width) {
83  }
84 
89  Column& operator=(const Column& src) {
90  name = src.name;
91  align = src.align;
92  width = src.width;
93  return *this;
94  }
95  };
96 
98 
101  }
102 
107  FmtTable(const Column* cols, SizeT size) {
108  add_columns(cols, size);
109  }
110 
118  FmtTable(const StringBase* names, SizeT size, int minwidth=0, FmtAlign align=fLEFT) {
119  add_columns(names, size, minwidth, align);
120  }
121 
125  FmtTable(const FmtTable& src) : columns(src.columns) {
126  }
127 
132  FmtTable& operator=(const FmtTable& src) {
133  columns = src.columns;
134  return *this;
135  }
136 
141  FmtTable& add_column(const Column& column) {
142  Column& newcol = *(columns.add(column).lastM());
143  if (newcol.width < 0 || (SizeT)newcol.width < newcol.name.size())
144  newcol.width = (int)newcol.name.size();
145  return *this;
146  }
147 
154  FmtTable& add_column(const StringBase& name, FmtAlign align=fLEFT, int width=0) {
155  if (width < 0 || (SizeT)width < name.size_)
156  width = (int)name.size_;
157  columns.add(Column(name, align, width));
158  return *this;
159  }
160 
166  FmtTable& add_column(const StringBase& name, int width) {
167  if (width < 0 || (SizeT)width < name.size_)
168  width = (int)name.size_;
169  columns.add(Column(name, width));
170  return *this;
171  }
172 
178  FmtTable& add_columns(const Column* cols, SizeT size) {
179  if (cols != NULL) {
180  if (size == 0) {
181  for (SizeT i = 0; cols[i].name.size_ > 0; ++i)
182  add_column(cols[i]);
183  } else {
184  columns.reserve(size);
185  for (SizeT i = 0; i < size; ++i)
186  add_column(cols[i]);
187  }
188  }
189  return *this;
190  }
191 
199  FmtTable& add_columns(const StringBase* names, SizeT size, int minwidth=0, FmtAlign align=fLEFT) {
200  if (names != NULL) {
201  if (size == 0) {
202  for (SizeT i = 0; names[i].size_ > 0; ++i)
203  add_column(names[i], align, minwidth);
204  } else {
205  columns.reserve(size);
206  for (SizeT i = 0; i < size; ++i)
207  add_column(names[i], align, minwidth);
208  }
209  }
210  return *this;
211  }
212 
221  if (index < columns.size())
222  columns(index).align = align;
223  return *this;
224  }
225 
234  FmtTable& column_minsize(SizeT index, int width) {
235  if (index < columns.size()) {
236  int& col_width = columns(index).width;
237  if (width > col_width)
238  col_width = width;
239  }
240  return *this;
241  }
242 
247  for (List<Column>::IterM iter(columns); iter; ++iter) {
248  Column& col = *iter;
249  col.align = fLEFT;
250  col.width = (int)col.name.size();
251  }
252  return *this;
253  }
254 
260  struct Writer {
265  bool started;
266 
271  Writer(FmtTable& table, Type type=tTEXT) : table(table), type(type), column_index(0), rows(0), started(false) {
272  }
273 
281  template<class T>
282  T& write_header(T& out) {
283  const SizeT sz = table.columns.size();
284  if (sz > 0) {
285  started = true;
286  if (type == tMARKDOWN)
287  out.writebin("| ", 2);
288 
289  for (SizeT i = 0; i < sz; ++i) {
290  if (i > 0) {
291  if (type == tMARKDOWN)
292  out.writebin(" | ", 3);
293  else
294  out.writebin(" ", 2);
295  }
296  const Column& col = table.columns[i];
297  out << FmtString(col.name, col.align, col.width, ' ');
298  }
299 
300  if (type == tMARKDOWN) {
301  out.writebin(" |", 2);
302  out << NL;
303  out.writebin("| ", 2);
304  for (SizeT i = 0; i < sz; ++i) {
305  if (i > 0)
306  out.writebin(" | ", 3);
307  const Column& col = table.columns[i];
308  switch (col.align) {
309  case fRIGHT:
310  out.writechar('-', table.columns[i].width - 1);
311  out.writechar(':');
312  break;
313  case fCENTER:
314  out.writechar(':');
315  out.writechar('-', table.columns[i].width - 2);
316  out.writechar(':');
317  break;
318  default:
319  out.writechar('-', table.columns[i].width);
320  break;
321  }
322  }
323  out.writebin(" |", 2);
324  }
325  out << NL;
326  }
327  return out;
328  }
329 
339  template<class T, class U>
340  T& write_value(T& out, const U& fmtval) {
341  const SizeT col_sz = table.columns.size();
342  if (started && col_sz > 0) {
343  assert( column_index < table.columns.size() );
344  const Column& col = table.columns[column_index];
345  typename impl::FmtFieldType<U>::Type v(fmtval, col.align, col.width);
346  if (type == tMARKDOWN) {
347  if (column_index == 0) {
348  out.writebin("| ", 2);
349  out << v;
350  ++column_index;
351  } else if (++column_index >= col_sz) {
352  ++rows;
353  column_index = 0;
354  out.writebin(" | ", 3);
355  out << v;
356  out.writebin(" |", 2);
357  out << NL;
358  } else {
359  out.writebin(" | ", 3);
360  out << v;
361  }
362  } else {
363  if (column_index > 0)
364  out.writebin(" ", 2);
365  out << v;
366  if (++column_index >= col_sz) {
367  column_index = 0;
368  ++rows;
369  out << NL;
370  }
371  }
372  }
373  return out;
374  }
375 
383  template<class T>
384  T& write_endrow(T& out) {
385  if (started && column_index > 0) {
386  if (type == tMARKDOWN) {
387  for (SizeT sz = table.columns.size(); column_index < sz; ++column_index) {
388  out.writebin(" | ", 3);
389  out.writechar(' ', table.columns[column_index].width);
390  }
391  out.writebin(" |", 2);
392  }
393  column_index = 0;
394  ++rows;
395  out << NL;
396  }
397  return out;
398  }
399 
407  template<class T>
408  T& write_finished(T& out) {
409  if (started) {
410  write_endrow(out);
411  if (rows == 0 && table.columns.size() > 0) {
412  if (type == tMARKDOWN) {
413  out.writebin("| ", 2);
414  out.writechar(' ', table.columns[0].width);
415  for (SizeT i = 1, sz = table.columns.size(); i < sz; ++i) {
416  out.writebin(" | ", 3);
417  out.writechar(' ', table.columns[i].width);
418  }
419  out.writebin(" |", 2);
420  }
421  out << NL;
422  }
423  column_index = 0;
424  rows = 0;
425  started = false;
426  }
427  return out;
428  }
429  };
430 
437  struct CachedWriter {
439 
442  StringList* current_row;
443  bool started;
444 
446  CachedWriter(FmtTable& table, Type type=tTEXT) : writer(table, type), current_row(NULL) {
447  }
448 
450  template<class T>
451  T& write_header(T& out) {
452  started = true;
453  return out;
454  }
455 
457  template<class T, class U>
458  T& write_value(T& out, const U& fmtval) {
459  const SizeT col_sz = writer.table.columns.size();
460  if (started && col_sz > 0) {
461  if (current_row == NULL) {
462  current_row = rowcache.addnew().lastM();
463  current_row->reserve(writer.table.columns.size());
464  }
465  const SizeT i = current_row->size();
466  if (i >= col_sz) {
467  current_row = rowcache.addnew().lastM();
468  current_row->reserve(writer.table.columns.size());
469  }
470 
471  String& val = *(current_row->addnew().lastM());
472  val.clear() << fmtval;
473  writer.table.column_minsize(i, (int)val.size());
474  }
475  return out;
476  }
477 
479  template<class T>
480  T& write_endrow(T& out) {
481  if (started) {
482  current_row = NULL;
483  writer.write_endrow(out);
484  }
485  return out;
486  }
487 
489  template<class T>
490  T& write_finished(T& out) {
491  if (started) {
492  writer.write_header(out);
493  for (SizeT i = 0, i_sz = rowcache.size(); i < i_sz; ++i) {
494  const StringList& row = rowcache[i];
495  for (SizeT j = 0, j_sz = row.size(); j < j_sz; ++j)
496  writer.write_value(out, row[j]);
497  writer.write_endrow(out);
498  }
499  writer.write_finished(out);
500  rowcache.clear();
501  started = false;
502  }
503  return out;
504  }
505  };
506 };
507 
509 
534 
538  FmtTableAttribs(FmtTable& table) : table(table), column_index(0) {
539  }
540 
546  const SizeT col_sz = table.columns.size();
547  if (col_sz > 0) {
548  table.columns(column_index).align = align;
549  if (++column_index >= col_sz)
550  column_index = 0;
551  }
552  return *this;
553  }
554 
561  FmtTableAttribs& operator<<(int minwidth) {
562  const SizeT col_sz = table.columns.size();
563  if (col_sz > 0) {
564  int& width = table.columns(column_index).width;
565  if (minwidth > width)
566  width = minwidth;
567  if (++column_index >= col_sz)
568  column_index = 0;
569  }
570  return *this;
571  }
572 
580  const SizeT col_sz = table.columns.size();
581  if (col_sz > 0) {
582  FmtTable::Column& col = table.columns(column_index);
583  col.align = field.align;
584  int& width = col.width;
585  if (field.width > width)
586  width = field.width;
587  if (++column_index >= col_sz)
588  column_index = 0;
589  }
590  return *this;
591  }
592 
597  column_index = 0;
598  return *this;
599  }
600 };
601 
603 
613 template<class T, class W=FmtTable::CachedWriter>
614 struct FmtTableOut {
616  W writer;
617  T& out;
618 
624  FmtTableOut(T& out, FmtTable& table, FmtTable::Type type=FmtTable::tTEXT) : writer(table, type), out(out)
625  { writer.write_header(out); }
626 
631  { writer.write_finished(out); }
632 
637  This& operator<<(char val)
638  { writer.write_value(out, FmtChar(val, 1)); return *this; }
639 
641  This& operator<<(const FmtChar& val)
642  { writer.write_value(out, val); return *this; }
643 
645  This& operator<<(const char* val)
646  { writer.write_value(out, FmtString(val)); return *this; }
647 
649  This& operator<<(const StringBase& val)
650  { writer.write_value(out, FmtString(val)); return *this; }
651 
653  This& operator<<(const FmtString& val)
654  { writer.write_value(out, val); return *this; }
655 
657  This& operator<<(short val)
658  { writer.write_value(out, FmtShort(val)); return *this; }
659 
661  This& operator<<(int val)
662  { writer.write_value(out, FmtInt(val)); return *this; }
663 
665  This& operator<<(long val)
666  { writer.write_value(out, FmtLong(val)); return *this; }
667 
669  This& operator<<(longl val)
670  { writer.write_value(out, FmtLongL(val)); return *this; }
671 
673  This& operator<<(ushort val)
674  { writer.write_value(out, FmtUShort(val)); return *this; }
675 
677  This& operator<<(uint val)
678  { writer.write_value(out, FmtUInt(val)); return *this; }
679 
681  This& operator<<(ulong val)
682  { writer.write_value(out, FmtULong(val)); return *this; }
683 
685  This& operator<<(ulongl val)
686  { writer.write_value(out, FmtULongL(val)); return *this; }
687 
689  This& operator<<(float val)
690  { writer.write_value(out, FmtFloat(val)); return *this; }
691 
693  This& operator<<(double val)
694  { writer.write_value(out, FmtFloatD(val)); return *this; }
695 
697  This& operator<<(ldouble val)
698  { writer.write_value(out, FmtFloatL(val)); return *this; }
699 
705  template<class V>
706  This& operator<<(const FmtIntT<V>& val)
707  { writer.write_value(out, val); return *this; }
708 
714  template<class V>
715  This& operator<<(const FmtFloatT<V>& val)
716  { writer.write_value(out, val); return *this; }
717 
725  template<class V>
726  This& operator<<(const IntegerT<V>& val) {
727  if (val.null())
728  writer.write_value(out, String("", 0));
729  else
730  writer.write_value(out, FmtIntT<V>(*val));
731  return *this;
732  }
733 
741  template<class V>
742  This& operator<<(const FloatT<V>& val) {
743  if (val.null())
744  writer.write_value(out, String("", 0));
745  else
746  writer.write_value(out, FmtFloatT<V>(*val));
747  return *this;
748  }
749 
758  { writer.write_endrow(out); return *this; }
759 
765  { writer.write_finished(out); return *this; }
766 };
767 
769 
782 template<class T>
784  return FmtTableOut<T,FmtTable::CachedWriter>(out, table, type);
785 }
786 
799 template<class T>
801  return FmtTableOut<T,FmtTable::Writer>(out, table, type);
802 }
803 
805 
806 }
807 #endif
ListType & add(const Item *data, Size size)
Append new items copied from data pointer (modifier).
Definition: list.h:2019
Size size() const
Get size.
Definition: list.h:759
SubString name
Column name
Definition: fmt.h:54
FmtTableOut(T &out, FmtTable &table, FmtTable::Type type=FmtTable::tTEXT)
Constructor.
Definition: fmt.h:624
FmtFloatT< float > FmtFloat
Explicitly format a floating pointer number.
Definition: str.h:3192
List< StringList > rowcache
List of cached rows.
Definition: fmt.h:441
T & write_header(T &out)
Write header output.
Definition: fmt.h:282
T & write_endrow(T &out)
Write end to current row.
Definition: fmt.h:480
Evo SubString container.
T & write_endrow(T &out)
Write end to current row.
Definition: fmt.h:384
This & operator<<(char val)
Write value for current column in current row and move to next column.
Definition: fmt.h:637
This & operator<<(const FmtString &val)
Write value for current column in current row and move to next column.
Definition: fmt.h:653
Helper for adjusting FmtTable column attributes.
Definition: fmt.h:531
FmtTable & column_align(SizeT index, FmtAlign align)
Set align value for column at given index.
Definition: fmt.h:220
Column(const SubString &name, int width=0)
Constructor.
Definition: fmt.h:76
FmtTableOut< T, FmtTable::CachedWriter > fmt_table(T &out, FmtTable &table, FmtTable::Type type=FmtTable::tTEXT)
Create cached FmtTableOut paired with given string/stream to write to.
Definition: fmt.h:783
This & operator<<(long val)
Write value for current column in current row and move to next column.
Definition: fmt.h:665
This & operator<<(Newline)
End current row.
Definition: fmt.h:757
FmtTableAttribs & operator<<(Newline)
Reset by moving back to first column.
Definition: fmt.h:596
This & operator<<(const FmtChar &val)
Write value for current column in current row and move to next column.
Definition: fmt.h:641
T & write_header(T &out)
Write header output.
Definition: fmt.h:451
FmtIntT< uint > FmtUInt
Explicitly format an integer.
Definition: str.h:3116
int width
Column width, default: 0
Definition: fmt.h:56
ListType & reserve(Size size, bool prefer_realloc=false)
Reserve capacity for additional items (modifier).
Definition: list.h:1703
Random access iterator.
Definition: iter.h:904
T & write_value(T &out, const U &fmtval)
Write next value.
Definition: fmt.h:458
Column(const SubString &name, FmtAlign align, int width=0)
Constructor.
Definition: fmt.h:67
bool started
True when writing has started, false when finished.
Definition: fmt.h:265
Used to write formatted output (used internally).
Definition: fmt.h:260
T & write_finished(T &out)
Finish writing table.
Definition: fmt.h:490
Text table formatter.
Definition: fmt.h:45
Newline
Newline type.
Definition: sys.h:748
FmtIntT< ushort > FmtUShort
Explicitly format an integer.
Definition: str.h:3115
This & operator<<(int val)
Write value for current column in current row and move to next column.
Definition: fmt.h:661
FmtFloatT< double > FmtFloatD
Explicitly format a floating pointer number.
Definition: str.h:3193
CachedWriter(FmtTable &table, Type type=tTEXT)
Constructor.
Definition: fmt.h:446
String & clear()
Clear by removing all items.
Definition: string.h:4975
Output interface for writing text table to stream/string.
Definition: fmt.h:614
Column & operator=(const Column &src)
Assignment operator.
Definition: fmt.h:89
FmtTableOut< T, W > This
This type.
Definition: fmt.h:615
This & operator<<(const char *val)
Write value for current column in current row and move to next column.
Definition: fmt.h:645
FmtTable & add_columns(const StringBase *names, SizeT size, int minwidth=0, FmtAlign align=fLEFT)
Add multiple columns to table.
Definition: fmt.h:199
SizeT column_index
Current column index.
Definition: fmt.h:263
FmtTable & column_reset()
Reset column information to defaults.
Definition: fmt.h:246
FmtTableAttribs(FmtTable &table)
Constructor.
Definition: fmt.h:538
Size size() const
Get size.
FmtTable & add_column(const StringBase &name, int width)
Add column to table.
Definition: fmt.h:166
Used to write formatted output with caching (used internally).
Definition: fmt.h:437
This & operator<<(float val)
Write value for current column in current row and move to next column.
Definition: fmt.h:689
StringList * current_row
Pointer to current row, NULL if about to start a new row.
Definition: fmt.h:442
List< String > StringList
List of String values.
Definition: fmt.h:438
FmtAlign
Formatting alignment.
Definition: str.h:2356
T & write_value(T &out, const U &fmtval)
Write next value.
Definition: fmt.h:340
FmtIntT< long > FmtLong
Explicitly format an integer.
Definition: str.h:3108
String container.
Definition: string.h:674
Type type
Formatting type.
Definition: fmt.h:262
FmtIntT< int > FmtInt
Explicitly format an integer.
Definition: str.h:3107
FmtTable & add_column(const StringBase &name, FmtAlign align=fLEFT, int width=0)
Add column to table.
Definition: fmt.h:154
FmtTable(const StringBase *names, SizeT size, int minwidth=0, FmtAlign align=fLEFT)
Constructor calling add_columns().
Definition: fmt.h:118
FmtIntT< short > FmtShort
Explicitly format an integer.
Definition: str.h:3106
W writer
Writer to use with FmtTable.
Definition: fmt.h:616
Flush
Signals an output stream to flush pending data.
Definition: sys.h:739
FmtTableAttribs & operator<<(int minwidth)
Update minimum width of current column and move to next column.
Definition: fmt.h:561
FmtTableAttribs & operator<<(FmtAlign align)
Set alignment for current column and move to next column.
Definition: fmt.h:545
Writer(FmtTable &table, Type type=tTEXT)
Constructor.
Definition: fmt.h:271
SizeT column_index
Current column index.
Definition: fmt.h:533
ListType & addnew(Size size=1)
Append new items (modifier).
Definition: list.h:1996
Align center by adding filler on left and right sides.
Definition: str.h:2359
FmtIntT< ulongl > FmtULongL
Explicitly format an integer.
Definition: str.h:3118
Explicitly format an integer.
Definition: str.h:3065
This & operator<<(ushort val)
Write value for current column in current row and move to next column.
Definition: fmt.h:673
FmtTable & table
Table info used.
Definition: fmt.h:261
ListType & clear()
Clear by removing all items.
Definition: list.h:574
Writer writer
Writer for actual writing.
Definition: fmt.h:440
FmtAlign align
Field alignment type (default: fLEFT)
Definition: str.h:2482
static const NewlineDefault & NL
Default newline type.
Definition: sys.h:785
T & write_finished(T &out)
Finish writing table.
Definition: fmt.h:408
FmtTable & column_minsize(SizeT index, int width)
Update minimum width for column at given index.
Definition: fmt.h:234
This & operator<<(const StringBase &val)
Write value for current column in current row and move to next column.
Definition: fmt.h:649
SizeT rows
Number of rows written.
Definition: fmt.h:264
Type
Formatting type to use.
Definition: fmt.h:47
FmtTable & add_columns(const Column *cols, SizeT size)
Add multiple columns to table.
Definition: fmt.h:178
Item * lastM()
Get last item (mutable).
Definition: list.h:1503
bool started
True when writing has started, false when finished.
Definition: fmt.h:443
Evo C++ Library namespace.
Definition: alg.h:11
List< Column > columns
Column information
Definition: fmt.h:97
This & operator<<(short val)
Write value for current column in current row and move to next column.
Definition: fmt.h:657
Explicitly format a string.
Definition: str.h:2931
This & operator<<(longl val)
Write value for current column in current row and move to next column.
Definition: fmt.h:669
T & out
Paired output string/stream to write to.
Definition: fmt.h:617
This & operator<<(double val)
Write value for current column in current row and move to next column.
Definition: fmt.h:693
FmtTable & add_column(const Column &column)
Add column to table.
Definition: fmt.h:141
This & operator<<(ulong val)
Write value for current column in current row and move to next column.
Definition: fmt.h:681
Column(const Column &src)
Copy constructor.
Definition: fmt.h:82
FmtAlign align
Column alignment type, default: fLEFT
Definition: fmt.h:55
Basic text table using whitespace to line up columns.
Definition: fmt.h:48
This & operator<<(ulongl val)
Write value for current column in current row and move to next column.
Definition: fmt.h:685
Explicitly format a repeated character.
Definition: str.h:2914
Align left by adding filler on right side.
Definition: str.h:2358
Column()
Constructor using default values.
Definition: fmt.h:59
FmtIntT< longl > FmtLongL
Explicitly format an integer.
Definition: str.h:3109
FmtTable & table
Paired table to update.
Definition: fmt.h:532
TSize size_
Data size as item count, 0 if empty or null.
Definition: sys.h:980
Sequential list container with random access.
Definition: list.h:240
FmtTable(const FmtTable &src)
Copy constructor.
Definition: fmt.h:125
int width
Field width to align in (default: 0)
Definition: str.h:2483
FmtTable & operator=(const FmtTable &src)
Assignment operator.
Definition: fmt.h:132
~FmtTableOut()
Destructor to finish writing table.
Definition: fmt.h:630
FmtTable()
Constructor.
Definition: fmt.h:100
Align right by adding filler on left side.
Definition: str.h:2360
FmtTableOut< T, FmtTable::Writer > fmt_table_nocache(T &out, FmtTable &table, FmtTable::Type type=FmtTable::tTEXT)
Create cached FmtTableOut paired with given string/stream to write to.
Definition: fmt.h:800
FmtIntT< ulong > FmtULong
Explicitly format an integer.
Definition: str.h:3117
uint32 SizeT
Default Evo container size type.
Definition: sys.h:729
Reference and access existing string data.
Definition: substring.h:229
FmtFloatT< ldouble > FmtFloatL
Explicitly format a floating pointer number.
Definition: str.h:3194
Base for all Evo list types (used internally).
Definition: sys.h:976
Explicitly format a floating pointer number.
Definition: str.h:3148
This & operator<<(Flush)
Flush any cached output.
Definition: fmt.h:764
Holds field and alignment formatting attributes.
Definition: str.h:2481
This & operator<<(uint val)
Write value for current column in current row and move to next column.
Definition: fmt.h:677
Column information.
Definition: fmt.h:53
This & operator<<(ldouble val)
Write value for current column in current row and move to next column.
Definition: fmt.h:697
FmtTableAttribs & operator<<(const FmtSetField &field)
Update column alignment and minimum width together and move to next column.
Definition: fmt.h:579
FmtTable(const Column *cols, SizeT size)
Constructor calling add_columns().
Definition: fmt.h:107