FBB::CSVTable - sequentially fills tables row-wise
#include <bobcat/csvtable>
Linking option: -lbobcat
FBB::CSVTable is used to fill tables row-wise. By default
the table’s elements are comma-separated. The elements may contain
any type of data that can also be inserted into std::ostreams, as may
also contain horizontal lines (optionally spanning multiple columns).
Before inserting elements into the table the widths, alignment
types and precisions of the table’s columns are defined. By default
values are right-aligned. While inserting table elements the alignment types
and precisions may be altered for specific elements, optionally spanning
multiple columns. When inserting values whose representations require more
characters than the current widths of the columns receiving those values
then those larger widths take precedence over the defined column widths.
Different from tables defined by FBB::Table(3bobcat) all
data inserted into CSVTables do not have to be completely available
before the table is inserted into a destination std::ostream. As the
table’s column formats are known before entering the data the
CSVTable knows which format to use for which column. These column
format specifications may be defined in multiple ways, e.g., by using text
labels and values. CSVTable objects always use the widest column
specifications and alignment types that were specified last.
When inserting elements into CSVTables the standard
C++ IO manipulators can also be used. Table rows do not automatically
end after the table’s last column has been filled. But when inserting
elements beyond the last column they are inserted as-is (but then the
standard I/O format specifications can optionally be used).
Table column definitions and table rows end at the end of
insertion statements (see below at the descriptions of the various
operator<< functions).
CSVTable uses two support classes handling, respectively,
the definitions of the characteristics of the table’s columns and
inserting values into the table’s elements. CSVTabDef handles
the table’s column definitions, CSVTabIns handles insertions
into the table elements. Their main characteristics are various insertion
operators which are described below.
Constructing tables normally consists of two steps: first the
characteristics of the columns are defined, then values are inserted into
the table’s elements. This sequence is not enforced by
CSVTable: after inserting values into the table column definitions
may be updated, whereafter additional values may be inserted into the table
which then use the updated column definitions.
FBB
All constructors, members, operators and manipulators, mentioned in this
man-page, are defined in the namespace FBB.
FMT objects are returned by several free functions (like
left, described below in section FREE FUNCTIONS), and
FMT defines the enumeration Align (see the next section)
specifying alignment types. FMT objects are internally used by
CSVTable objects. A FMT object specifies the width, the
precision when floating point numbers are inserted, the column’s
alignment type (left, right or centered), and the number of table columns to
use.
FMT objects can be inserted into std::ostream
objects showing its characteristics. In addition it offers the following
(const) accessors:
- o
- FMT::Align align():
the alignment value;
- o
- unsigned nCols():
the number of occupied columns;
- o
- unsigned precision():
the precision used when inserting a floating point value (~0U (= -1
as int) is returned if precision is not used). The insertion
operator shows precision: -1 when precision is ~0U;
- o
- unsigned width():
the width in number of characters;
The static member char const *FMT::align(FMT::Align value)
returns the textual label corresponding to value.
The enum FMT::Align defines the following values indicating
the alignment types of the columns of the table:
- o
- FMT::Align::CENTER:
The information inserted in the column is centered;
- o
- FMT::Align::LEFT:
The information inserted in the column is left-aligned;
- o
- FMT::Align::RIGHT:
The information inserted in the column is right-aligned (this is the
alignment used by default);
In addition, when inserting horizontal lines, the value
FMT::Align::HLINE is used.
- o
- CSVTable(std::ostream &out = std::cout, std::string const
&sep = ", "):
This constructor by default writes its table to std::cout and uses a
comma followed by a space character as column separator. During the
table’s construction the stream to write the table to can be
altered using the stream members, and the separator can be changed
using the sep member, but the separator can also be changed while
filling the table’s elements (see below). When the CSVTable
object goes out of scope the stream’s original configuration is
restored;
- o
- CSVTable(std::ofstream &&tmp, std::string const &sep =
", "):
This constructor by default uses the same separator to separate the
column’s elements as the first constructor, but writes the table to
the ofstream tmp, which is grabbed by CSVTable;
- o
- CSVTable(std::string const &fname, std::string const
&sep = ", "), std::ios::openmode mode = ios::out:
This constructor by default uses the same separator to separate the
column’s elements as the first constructor, but writes the table to
the file having (path)name fname, by default (re)writing the file.
If the file already exists and CSVTable should start writing at the
file’s end use, e.g., ios::ate | ios::in. An exception is
thrown if the specified file cannot be opened.
The move constructor and assignment operator are available; the
copy constructor and assignment operator are not available.
In the provided examples tab refers to an existing
CSVTable object. Each insertion statement (note: not insertion
expression) either defines or updates the table columns’
definitions or fills the next row of the table with data.
Defining column characteristics
The return types and left-hand side operands of the following
insertion operators are specified as CSVTabDef. The member
fmt() (cf. section MEMBER FUNCTIONS) returns a
CSVTabDef object which is then used in combination with the following
insertion operators to define the characteristics of the table’s
columns.
- o
- CSVTabDef &operator<<(CSVTabDef &tab, FMT const
&fmt):
This insertion operator defines the characteristics of the next table
column. FMT objects inserted into CSVTabDef objects must
have been returned by center, left or right (see section
FREE FUNCTIONS, below), or an exception will be thrown. When
redefining column specifications (e.g., when inserting FMT objects
for previously defined columns) then the width of the wider column is
used. Example:
// left align using 10 char. positions:
tab.fmt() << FBB::left(10);
// 1st col now right aligned, but its
// width remains 10
tab.fmr() << FBB::right(4);
- o
- CSVTabDef &operator<<(CSVTabDef &tab, Insertable const
&value):
This operator is defined for the template type Insertable parameter
value, where value’s type must be insertable in
std::ostreams. The (trimmed) width of value when inserted
into an ostream defines the width of the next column, which is
right-aligned. As width the previous insertion operator: if a previous
definition specified a larger width, then that width is kept. Example:
// 2 columns, having widths 2 and 5:
tab.fmt() << 12 << "hello";
Inserting the table’s elements
In addition to the insertion operator actually inserting a value
into the next table’s column(s) several format modifying insertion
operators are available. When a series of specifications are inserted before
the actual value is inserted then the specification inserted just before
inserting the table’s value is used, overruling that column’s
default specification. Format specifications other than those provided by
the standard I/O manipulators are ignored when used beyond the
table’s last column.
The return types and left-hand side operands of the following
insertion operators use CSVTabIns objects. CSVTable’s
conversion operator operator CSVTabIns() described below returns a
CSVTabIns object which is used by the following insertion operators
to insert values into the table.
- o
- CSVTabIns &operator<<(CSVTabIns &tab, FMT::hline):
This operator inserts a horizontal line in the table’s next column
element. It is ignored when used beyond the table’s last
column;
- o
- CSVTabIns &operator<<(CSVTabIns &tab,
(*FMT::hline)(unsigned nColumns)):
This operator inserts a horizontal line spanning the next nColumns
columns of the table. If the argument nColumns is omitted then a
horizontal line is inserted spanning all of the table’s remaining
columns. When covering multiple columns no separators are used between the
columns containing horizontal lines but one continuous horizontal line is
used instead. The horizontal line is never written beyond the
table’s last column.
- o
- CSVTabIns &operator<<(CSVTabIns &tab, Insertable const
&value):
This operator is defined for the template type Insertable parameter
value, where value’s type must be insertable in
std::ostreams. The value is inserted into the next table column,
using the format specification that’s active for that column.
However, the specifications may be altered just before inserting the
value. Values inserted beyond the table’s last column are inserted
as-is (although standard I/O manipulators can still be used);
- o
- CSVTabIns &operator<<(CSVTabIns &tab, FMT const
&fmt):
FMT objects are returned by several free functions defined in the
FBB namespace (i.e., center, left, or right,
described below in section FREE FUNCTIONS). Example:
// left align using precision 2. E.g.,
// e.g., ’12.13 ’
tab << left(2) << 12.1278;
- o
- CSVTabIns &operator<<(CSVTabIns &tab, FMT::Align
align):
The alignment argument can be FMT::CENTER, FMT::LEFT or
FMT::RIGHT. Example:
// centers ’12’ in its column,
// e.g., ’ 12 ’
tab << FMT::CENTER << 12;
- o
- void operator<<(CSVTabIns &tab, std::ios_base
&(*func)(std::ios_base &)):
This insertion operator accepts manipulators like std::left and
std::right. When inserting these manipulators the next value to
insert into the table is manipulated accordingly, overruling the next
column’s default specification. Example:
// ’hi’ is left-aligned, using the
// using the default width and precision
tab << std::left << "hi";
- o
- CSVTabIns &operator<<(CSVTabIns &tab, Sep const
&sep):
The separator used when starting to insert values into the table’s
next row is changed to the separator specified by sep. It remains
active for the table’s current row, also when inserting values
beyond the table’s last column. Example:
// writes, e.g., ’one, hi there’
tab << "one" << FMT::Sep{" "} << "hi" << "there";
- o
- operator CSVTabIns():
The conversion operator returns a CSVTabIns object which is used in
combination with the above insertion operators to insert values into the
next row of the table. Normally insertions start at column 1, but when
called after calling tab.more (see below) then insertions continue
after the last element that was inserted into tab.more. Each time
this conversion operator is used another row is added to the table.
Insertions beyond the table’s last column are processed, but
CSVTabIns’s insertion operators are ignored, inserting
values as-is. However, in that case the standard std::ostream
manipulators can also be used.
- o
- void operator()(std::string const &text):
Calls text, 0 to insert the trimmed comma-separated elements of
text into the table’s next row;
- o
- FMT const &operator[](unsigned idx) const:
Returns the default FMT specification of column idx (see also
the description of the member size() below).
In the provided examples tab refers to an existing
CSVTable object.
- o
- std::vector<FMT> const &columns() const:
Returns a reference to the vector containing the format specifications of
the table managed by CSVTable;
- o
- CSVTabDef &fmt(unsigned idx = 0):
The elements inserted into the CSVTabDef object returned by
fmt() define the specifications of the table’s columns.
Specifications start at column offset idx, using 0 if not specified
(its argument may not exceed the number of already defined columns or an
exception is thrown). When called repeatedly for already specified columns
then the widths of existing columns are kept if they exceed the widths of
the corresponding inserted FMT elements. Repeated fmt calls
may specify more columns than previous calls, in which case new columns
are added to the table.
- o
- void fmt(std::string const &colSpecs, unsigned idx = 0):
The comma-separated space-trimmed words of colSpecs define the widths
of right-aligned table columns, starting at column index idx, using
0 if not specified (its argument may not exceed the number of already
defined columns or an exception is thrown). When called repeatedly for
already specified columns then the widths of existing columns are kept if
they exceed the lengths of the corresponding trimmed words. Repeated calls
may specify more columns than previous calls, in which case additional
columns are added to the table. Example:
// Define three right-aligned columns,
// having widths of 3, 3 and 5.
tab.fmt("one, two, three");
// add columns 4 thru 6
tab.fmt("one, two, three", 3);
- o
- unsigned idx() const:
The index of the column that will be used at the next insertion is returned.
When inserting more values than the number of defined table columns then
the return value of the member size is returned;
- o
- CSVTabIns more(unsigned idx = ~0U):
When the default idx argument is used then values that are inserted
into the returned CSVTabIns object are inserted beyond the
last-used column of the table’s current row (which may be the
row’s first element).
- When using another argument then insertions start in column idx. If
dx exceeds the last-used column index then intermediate columns
remain empty.
- If idx is less than the column index that is used at the next
insertion an exception is thrown.
- Insertions beyond the table’s last column are processed, but then
CSVTabIns’s insertion operators are ignored, inserting
values as-is. However, in that case the standard std::ostream
manipulators can also be used;
- Following more the current row doesn’t end, but values
inserted next are inserted into the same row. Example:
// a row containing one element:
tab << 1;
// the next row contains 2 elements:
tab.more() << 1 << 2;
// now containing 4 elements
// (element at idx 2 remains empty):
tab.more(3) << 4;
// completes the row, now having
// 5 elements:
tab << 5;
- Following more calls the current row ends at the next
tab.row call. If following more calls the current row should
merely end then simply use tab.row();
- o
- void more(std::string const &text, unsigned idx = ~0U):
This member’s idx parameter is handled as described at the
previous member.
- The trimmed comma-separated elements of text are inserted into the
current row, without ending the current row;
- o
- CSVTabIns row(unsigned idx = ~0U):
This member’s idx parameter and insertions into the returned
CSVTabIns object are handled as described at the first more
member, but the current row ends at the end of the statement. Example:
// a row containing one element:
tab << 1;
// the next row contains 2 elements:
tab.more() << 1 << 2;
// the now contains 4 elements
// (element at idx 2 remains empty):
tab.row(3) << 4;
- o
- void row(std::string const &text, unsigned idx = ~0U):
This member’s idx parameter is handled as described at the
first more member.
- The trimmed comma-separated elements of text are inserted into the
current row, whereafter the row ends;
- o
- void stream(std::ostream &out):
After calling tab.stream(out) the table’s construction
continues at the next row using the stream out;
- o
- void stream(std::ofstream &&tmp):
After calling this member the table’s construction continues at the
next row using the ofstream tmp, whih is grabbed by
CSVTable;
- o
- void stream(std::string const &fname, std::ios::openmode
mode = std::ios::out):
After calling this member the table’s construction continues at the
next row using the (path)name fname, by default (re)writing the
file. If the file already exists and CSVTable should start writing
at the file’s end use, e.g., ios::ate | ios::in. An
exception is thrown if the specified file cannot be opened;
- o
- std::ostream &stream():
A reference to the currently used stream is returned;
- o
- std::string const &sep() const:
Returns the currently used default column separator;
- o
- void sep(std::string const &separator):
Changes the currently used default column separator to
separator.
- o
- unsigned size() const:
The number of defined columns is returned;
In the following examples tab.fmt() refers to a
CSVTabDef object.
next examples tab refers to a CSVTable object (using
its conversion to a CSVTabIns object) and
Defining Column Characteristics
The following functions are used to specify the alignment, width
and optional precision of columns. The first argument of these functions
specifies the column’s width, the second argument is optional and
specifies the column’s precision (used when inserting floating point
values). The precision is only used if its value is less than the
column’s width.
- o
- FMT center(unsigned width, unsigned precision = ~0U):
When inserting this function’s return value into tab.fmt() the
values inserted into its column are centered in fields of width
characters wide. Example:
// values are centered in fields of 10
// characters wide, floating point values
// use 3 digit behind the decimal point:
tab.fmt() << center(10, 3);
- o
- FMT center(std::string const &str, unsigned precision = ~0U):
A convenience function calling str.length(), precision
;
- o
- FMT left(unsigned width, unsigned precision = ~0U):
When inserting this function’s return value into tab.fmt() the
values inserted into its column are left-aligned in fields of width
characters wide. Example:
// values are left-aligned in fields
// of 5 characters wide.
tab.fmt() << left(5);
- o
- FMT left(std::string const &str, unsigned precision = ~0U):
A convenience function calling left(str.length(), precision);
- o
- FMT right(unsigned width, unsigned precision = ~0U):
When inserting this function’s return value into tab.fmt() the
values inserted into its column are right-aligned in fields of
width characters wide. Example:
// values are right-aligned in fields
// of 5 characters wide.
tab.fmt() << right(5);
Right-alignment is also used when using CSVTab’s
fmt(std::string) member or when directly inserting values into
CSVTabDef objects.
- o
- FMT right(std::string const &str, unsigned precision = ~0U):
A convenience function calling right(str.length(), precision);
Inserting Table Elements
In the following examples tab refers to a CSVTable
object returning a CSVTabIns object using its conversion
operator.
Except for the function hline the following functions are
used to alter the column’s default alignment and precision. The
precision is only used if its value is less than the column’s width.
By specifying ~0U the precision is ignored. If only the default
alignment should be overruled then inserting the corresponding
FMT::Align value suffices.
Altering the default alignment of individual columns:
- o
- FMT precision :
After inserting this function’s return value into tab the
value inserted next is centered, using precision when inserting
floating point values.
// centers 9.87 in column 1
tab << center(2) << 9.876";
- o
- FMT left(precision):
After inserting this function’s return value into tab the
value inserted next is left-aligned, using precision when inserting
floating point values.
// left-aligns 9.87 in column 1
tab << left(2) << 9.876";
- o
- FMT right(precision):
When inserting this function’s return value into tab the value
inserted next is right-aligned, using precision when inserting
floating point values.
// right-aligns 9.87 in column 1
tab << right(2) << 9.876";
By default CSVTable uses right-alignment.
Joining columns:
Alignments specifications may span multiple columns. This is
realized through the join functions. When inserting a value after
inserting the return value of a join member then that value is
inserted occupying all the columns and using the alignment type specified
when calling join. If necessary the number of columns is reduced to
avoid exceeding the table’s last column.
- o
- FMT join(unsigned nCols, FMT::Align align, unsigned precision =
~0U):
A value that’s inserted into the table after inserting
join’s return value occupies nCols columns, using
alignment type align, and optionally using precision when
inserting floating point values. The alignment specification must be
FMT::CENTER, FMT::LEFT or FMT::RIGHT. Example:
// writes (assuming columns 2 and 3 occupy
// 10 characters):
// left, mid , right
tab << "left" << join(2, FMT::CENTER) << "mid" << "right"";
- o
- FMT join(FMT::Align align, unsigned precision = ~0U):
Same effect as the previous join function, but this function occupies
all remaining columns of the table’s current row (this can also be
accomplished by calling the first join function specifying
~0U as its first argument).
Inserting horizontal lines:
If a single table element should contain a horizontal line then
simply inserting Align::HLINE works fine. The hline functions
are used to insert horizontal lines spanning one or more table columns.
- o
- FMT hline(unsigned nCols = ~0U):
When inserting this function’s return value into a CSVTabIns
object a horizontal line spanning nCols columns is inserted into
the table. If necessary nCols is reduced so that the horizontal
line does not exceed the table’s last column. When spanning
multiple columns no column separated are used between the spanned columns:
a single uninterrupted horizontal line is inserted. Example:
// columns 1 and 2: a horizontal line, column 3:
// contains ’hi’ (preceded by the column separator)
tab << hline(2) << "hi";
#include <bobcat/csvtable>
using namespace FBB;
int main()
{
CSVTable tab;
tab.fmt() << "case" << right("length", 2) << right("weight", 1) <<
right("length", 2) << right("weight", 1);
tab.sep(" ");
tab << hline();
tab << "" << join(4, FMT::CENTER) << "Gender";
tab << "" << hline();
tab << "" << join(2, FMT::CENTER) << "Female" <<
join(2, FMT::CENTER) << "Male";
tab << "" << hline(2) << hline(2);
tab << "Case" << "Length" << "Weight" << "Length" << "Weight";
tab << hline();
tab << 1 << 1.744 << 55.345 << 1.7244 << 64.801;
tab << 2 << 1.58 << 57.545 << 1.8174 << 81.451;
tab << 3 << 1.674 << 62.125 << 1.8244 << 80.201;
tab << hline();
}
This program writes the following table to std::cout:
------------------------------------
Gender
------------------------------
Female Male
-------------- --------------
Case Length Weight Length Weight
------------------------------------
1 1.74 55.3 1.72 64.8
2 1.58 57.5 1.82 81.5
3 1.67 62.1 1.82 80.2
------------------------------------
bobcat/csvtable - defines the class interface
- o
- https://fbb-git.gitlab.io/bobcat/: gitlab project page;
- o
- bobcat_5.07.00-x.dsc: detached signature;
- o
- bobcat_5.07.00-x.tar.gz: source archive;
- o
- bobcat_5.07.00-x_i386.changes: change log;
- o
- libbobcat1_5.07.00-x_*.deb: debian package containing the
libraries;
- o
- libbobcat1-dev_5.07.00-x_*.deb: debian package containing the
libraries, headers and manual pages;
Bobcat is an acronym of `Brokken’s Own Base Classes And
Templates’.
This is free software, distributed under the terms of the GNU
General Public License (GPL).
Frank B. Brokken (f.b.brokken@rug.nl).