FBB::CSVTable(3bobcat)
π FBB::CSVTable π
okay bestie, so this is FBB::CSVTable(3bobcat) β it lives under the "Table Construction" energy of the bobcat manual, and it is literally here to make your tables pop off row by row. no cap.
β¨ NAME β¨
FBB::CSVTable β Sequentially fills tables row-wise. she's organized, she's sequential, she fills rows like it's her main character moment π
β¨ SYNOPSIS β¨
#include <bobcat/csvtable>
Linking option: -lbobcat
β¨ DESCRIPTION β¨
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, and they may also contain horizontal lines (optionally spanning multiple columns). yes bestie, horizontal lines too. iconic behavior.
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. the table is not gonna squish your data, periodt.
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. so the last word wins, lowkey.
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 still 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). E.g.,
CSVTable tab;
...
tab << 1 << 2; // two elements in this row
tab << "one" << "two" << 3; // three elements in this row
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. They offer 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. so you can change your mind mid-build. we love flexibility π«Ά
β¨ NAMESPACE β¨
FBB
All constructors, members, operators and manipulators, mentioned in this man-page, are defined in the namespace FBB.
β¨ INHERITS FROM β¨
-
β¨ FMT β¨
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. FMT provides the following (const) accessors:
FMT::Align align()β the alignment value;unsigned nCols()β the number of occupied columns;unsigned precision()β the precision used when inserting a floating point value (~0U(=-1as int) is returned if precision is not used). The insertion operator shows precision:-1when precision is~0U;unsigned width()β the field width in number of characters;
The static member char const *FMT::align(FMT::Align value) returns the textual label corresponding to value.
β¨ ALIGN ENUM β¨
The enum FMT::Align defines values indicating the alignment types of the table's columns:
FMT::Align::CENTERβ The inserted information in the column is centered;FMT::Align::LEFTβ The inserted information is left-aligned;FMT::Align::RIGHTβ The inserted information is right-aligned (used by default);
In addition, when inserting horizontal lines, the value FMT::Align::HLINE is used.
β¨ CONSTRUCTORS β¨
CSVTable(std::ostream &out = std::cout, std::string const &sep = ", ")β This constructor by default writes its table tostd::coutand uses a comma followed by a space character as column separator. During the table's construction the stream receiving the table can be altered using stream members, and the separator can be changed using thesepmember, but the separator can also be changed while filling the table's elements (see below). When theCSVTableobject goes out of scope the stream's original configuration is restored;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 toofstreamtmp, which is grabbed byCSVTable;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 andCSVTableshould 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 move assignment operator are available; the copy constructor and assignment operator are not available.
β¨ OVERLOADED OPERATORS β¨
Okay so, in all the examples down here, tab is a CSVTable object that already exists. And listen β every insertion statement (bestie, a statement, not an insertion expression, the page is being very specific about this π) either defines or updates the table columns' definitions, or it fills up the next row of the table with data. That's it. That's the whole job description. π
πΈ Defining column characteristics πΈ
The return types and the left-hand side operands of these insertion operators are all specified as CSVTabDef. The member fmt() (peep the MEMBER FUNCTIONS section, it's iconic) hands you back a CSVTabDef object, and you use that object together with the operators below to define the characteristics of your table's columns. Very demure, very mindful. π
CSVTabDef &operator<<(CSVTabDef &tab, FMT const &fmt)β this one defines the characteristics of the next table column. FMT objects inserted into CSVTabDef objects must have been returned bycenter,leftorright(see section FREE FUNCTIONS, below) β otherwise an exception gets thrown, no cap π« . When you're redefining column specifications (like, inserting FMT objects for columns you already defined), the width of the wider column wins. 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);
CSVTabDef &operator<<(CSVTabDef &tab, Type const &value)β this operator is defined for the template typeTypeparametervalue, whereTypevalues must be insertable instd::ostreams. The (trimmed) width ofvaluewhen it's inserted into an ostream is what defines the width of the next column, and that column is right-aligned. Same width rules as the previous insertion operator, fr fr: 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 table elements π
Besides the insertion operator that actually inserts a value into the next table's column(s), there are several format-modifying insertion operators available. And here's the tea β: when you insert a whole series of specifications before the actual value goes in, the specification inserted just before you insert the table's value is the one that's used β it overrules that column's default specification. Format specifications that aren't the ones provided by the standard I/O manipulators get ignored when used beyond the table's last column. Noted. π
The return types and left-hand side operands of these insertion operators use CSVTabIns objects. CSVTable's conversion operator operator CSVTabIns() (described below) returns a CSVTabIns object, and that's what these insertion operators use to insert values into the table. π«Ά
CSVTabIns &operator<<(CSVTabIns &tab, FMT::hline)β inserts a horizontal line in the table's next column element. It's ignored if you use it beyond the table's last column.CSVTabIns &operator<<(CSVTabIns &tab, (*FMT::hline)(unsigned nColumns))β inserts a horizontal line spanning the nextnColumnscolumns of the table. If you leave thenColumnsargument out, then the horizontal line spans all of the table's remaining columns. When it's covering multiple columns, no separators are used between the columns containing horizontal lines β instead it's one continuous horizontal line. And that line is never written beyond the table's last column. Boundaries, gorgeous. π§CSVTabIns &operator<<(CSVTabIns &tab, Type const &value)β this operator is defined for the template typeTypeparametervalue, whereTypevalues must be insertable instd::ostreams. The value gets inserted into the next table column using the format specification that's active for that column. That said, the specifications can be altered right before you insert the value. Values inserted beyond the table's last column are inserted as-is (although standard I/O manipulators can still be used).CSVTabIns &operator<<(CSVTabIns &tab, FMT const &fmt)β FMT objects are returned by several free functions defined in theFBBnamespace (that'scenter,left, orright, all described below in section FREE FUNCTIONS). Example:
// left align using precision 2. E.g.,
// e.g., '12.13 '
tab << left(2) << 12.1278;
CSVTabIns &operator<<(CSVTabIns &tab, FMT::Align align)β the alignment argument can beFMT::CENTER,FMT::LEFTorFMT::RIGHT. Example:
// centers '12' in its column,
// e.g., ' 12 '
tab << FMT::CENTER << 12;
void operator<<(CSVTabIns &tab, std::ios_base &(*func)(std::ios_base &))β this insertion operator accepts manipulators likestd::leftandstd::right. When you insert these manipulators, the next value you 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";
CSVTabIns &operator<<(CSVTabIns &tab, Sep const &sep)β the separator used when you start inserting values into the table's next row gets changed to the separator specified bysep. It stays active for the table's current row, including when you're inserting values beyond the table's last column. Staying power πͺ. Example:
// writes, e.g., 'one, hi there'
tab << "one" << FMT::Sep{" "} << "hi" << "there";
operator CSVTabIns()β the conversion operator returns aCSVTabInsobject, 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 it's called after callingtab.more(see below) then insertions continue after the last element that was inserted intotab.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 and the values are inserted as-is. In that case, though, the standardstd::ostreammanipulators can also be used. π₯void operator()(std::string const &text)β Callstext,0to insert the trimmed comma-separated elements oftextinto the table's next row.FMT const &operator[](unsigned idx) constβ returns the default FMT specification of columnidx(also check out the description of the membersize()below, it's related).
π«Ά MEMBER FUNCTIONS π«Ά
okay bestie, this is the whole toolbox. everywhere down below, tab means an existing CSVTable object β like, the one you already made π
std::vector<FMT> const &columns() constβ hands you back a reference to the vector holding the format specifications of the table thatCSVTableis managing. that's it, that's the whole vibe.CSVTabDef &fmt(unsigned idx = 0)β whatever you insert into theCSVTabDefobject this returns becomes the spec for the table's columns. the specifications start at column offsetidx, or0if you didn't specify it (and fr fr, that argument may not exceed the number of already-defined columns, or an exception gets thrown at you π). if you call this again for columns you already specified, the widths of the existing columns are kept whenever they're bigger than the widths of the correspondingFMTelements you just inserted. and repeatedfmtcalls can totally specify more columns than previous calls did β those new columns just get added to the table. growth mindset β¨void fmt(std::string const &colSpecs, unsigned idx = 0)β the comma-separated, space-trimmed words insidecolSpecsset the widths of right-aligned table columns, starting at column indexidx, or0if you didn't specify (again: that arg may not exceed the number of already-defined columns or it's exception city π¨). call it repeatedly on columns you already set and the widths of the existing columns stick around as long as they're wider than the lengths of the corresponding trimmed words. repeated calls may also specify more columns than previous calls, and those extra columns get added to the table. example time:
// 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);
unsigned idx() constβ tells you the index of the column that's gonna be used at the next insertion. and if you're inserting more values than there are defined table columns, you get back whatever the membersizereturns. cute.CSVTabIns more(unsigned idx = ~0U)β with the defaultidxargument, the values you insert into the returnedCSVTabInsobject land beyond the last-used column of the table's current row (which could be the row's very first element, no pressure). pass a different argument and insertions start at columnidx. if that goes past the last-used column index, the columns in between just stay empty (ghost columns π»). ifidxis less than the column index used at the next insertion β exception, thrown, over. insertions beyond the table's last column still get processed, but thenCSVTabIns's insertion operators are ignored and the values are inserted as-is β however, in that case you can use the standardstd::ostreammanipulators too. also important: aftermorethe current row does not end, the values you insert next go 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 you just want the current row to end, simply use tab.row(); π«‘
void more(std::string const &text, unsigned idx = ~0U)β this member'sidxparameter is handled exactly like the previous member's. the trimmed comma-separated elements oftextget inserted into the current row, and the current row does not end. cozy.CSVTabIns row(unsigned idx = ~0U)β this member'sidxparameter and the insertions into the returnedCSVTabInsobject are handled like at the firstmoremember, except 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;
void row(std::string const &text, unsigned idx = ~0U)β this member'sidxparameter is handled like at the firstmoremember. the trimmed comma-separated elements oftextget inserted into the current row, and after that the row ends. bye bestie πvoid stream(std::ostream &out)β after callingtab.stream(out), the table's construction keeps going at the next row, using the streamout.void stream(std::ofstream &&tmp)β after calling this member, the table's construction continues at the next row using theofstreamtmp, which is grabbed byCSVTable(it's hers now, she claimed it π).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)namefname, and by default it (re)writes the file. if the file already exists andCSVTableshould start writing at the file's end, use, e.g.,ios::ate | ios::in. an exception is thrown if the file you named can't be opened π€std::ostream &stream()β returns a reference to the stream that's currently in use.std::string const &sep() constβ returns the currently used default column separator.void sep(std::string const &separator)β changes the currently used default column separator toseparator.unsigned size() constβ returns the number of defined columns.
β¨π FREE FUNCTIONS πβ¨
ok so in every single example down here, whenever you see tab.fmt(), just know it's a CSVTabDef object bestie, that's the vibe π
πΈ Defining Column Characteristics πΈ
these functions are THE moment for telling a column how it should look: its alignment, its width, and optionally its precision. the first argument is always the column's width, and the second one is optional and sets the column's precision (that's the one that matters when you're inserting floating point values). and listen β the precision only actually gets used if it's less than the column's width. no exceptions, that's the rule. π
FMT center(unsigned width, unsigned precision = ~0U)β when you insert this function's return value intotab.fmt(), everything you put in that column gets centered inside fields that arewidthcharacters 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);
FMT center(std::string const &str, unsigned precision = ~0U)β the cozy little convenience version that just callsstr.length(), precisionfor you π«ΆFMT left(unsigned width, unsigned precision = ~0U)β insert this return value intotab.fmt()and the values in that column go hard left, left-aligned inside fieldswidthcharacters wide. example:
// values are left-aligned in fields
// of 5 characters wide.
tab.fmt() << left(5);
FMT left(std::string const &str, unsigned precision = ~0U)β the convenience twin, callingleft(str.length(), precision);πFMT right(unsigned width, unsigned precision = ~0U)β insert this return value intotab.fmt()and the column's values are right-aligned inside fieldswidthcharacters wide. example:
// values are right-aligned in fields
// of 5 characters wide.
tab.fmt() << right(5);
alsooo, right-alignment is the default you get when you use CSVTab's fmt(std::string) member, or when you directly insert values into CSVTabDef objects. she's the default for a reason β¨
FMT right(std::string const &str, unsigned precision = ~0U)β yep, the convenience one, callingright(str.length(), precision).π
π Inserting Table Elements π
in the examples below, tab is a CSVTable object that's returning a CSVTabIns object through its conversion operator. main character energy tbh π
with one exception β hline β these functions are here to alter the column's default alignment and precision. again: the precision only gets used if it's less than the column's width. pass ~0U and the precision is just... ignored, not even invited. and if all you wanna do is overrule the default alignment? just inserting the matching FMT::Align value is enough, periodt.
π¦ Altering the default alignment of individual columns
FMT precisionβ once you insert this function's return value intotab, the next value you insert gets centered, and precision is used when inserting floating point values.
// centers 9.87 in column 1
tab << center(2) << 9.876";
FMT left(precision)β after inserting this return value intotab, the next value inserted is left-aligned, with precision used for floating point values.
// left-aligns 9.87 in column 1
tab << left(2) << 9.876";
FMT right(precision)β insert this return value intotaband the next value inserted is right-aligned, precision used when inserting floating point values.
// right-aligns 9.87 in column 1
tab << right(2) << 9.876";
fyi, CSVTable uses right-alignment by default. it's giving consistent π
π§ Joining columns
alignment specs can totally span multiple columns, and that's literally what the join functions are for. when you insert a value right after inserting the return value of a join member, that value occupies all the columns and uses the alignment type you named when calling join. and if things get spicy, the number of columns is reduced when necessary so you never exceed the table's last column. no overflow in this house π«
FMT join(unsigned nCols, FMT::Align align, unsigned precision = ~0U)β a value inserted into the table afterjoin's return value occupiesnColscolumns, using alignment typealign, and optionally using precision when inserting floating point values. the alignment specification must beFMT::CENTER,FMT::LEFTorFMT::RIGHT. example:
// writes (assuming columns 2 and 3 occupy
// 10 characters):
// left, mid , right
tab << "left" << join(2, FMT::CENTER) << "mid" << "right"";
FMT join(FMT::Align align, unsigned precision = ~0U)β same energy as the previousjoin, except this one occupies all the remaining columns of the table's current row (you can also pull this off by calling the firstjoinfunction with~0Uas its first argument π).
β Inserting horizontal lines
if a single table element just needs a horizontal line, inserting Align::HLINE is all it takes, easy. but the hline functions are the ones for lines that span one or more table columns π
FMT hline(unsigned nCols = ~0U)β when you insert this function's return value into aCSVTabInsobject, a horizontal line spanningnColscolumns gets inserted into the table. if necessary,nColsis reduced so that the line doesn't run past the table's last column. and when it spans multiple columns, no column separators are used between the spanned columns β it's one single uninterrupted horizontal line. example:
// columns 1 and 2: a horizontal line, column 3:
// contains βhiβ (preceded by the column separator)
tab << hline(2) << "hi";
π₯ EXAMPLE π₯
ok bestie this is the whole thing, look at her go:
#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();
}
and 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
------------------------------------
π FILES π
bobcat/csvtableβ this is the one that defines the class interface π
π SEE ALSO π
π BUGS π
None Reported. (she's flawless, no notes π)
π BOBCAT PROJECT FILES π
- https://fbb-git.gitlab.io/bobcat/: the gitlab project page;
Debian Bobcat project files:
libbobcat6: the debian package containing the shared library, changelog and copyright note;libbobcat-dev: the debian package containing the static library, headers, manual pages, and developer info;
π BOBCAT π
Bobcat is an acronym of `Brokkenβs Own Base Classes And Templatesβ. iconic name behavior honestly β¨
π COPYRIGHT π
This is free software, distributed under the terms of the GNU General Public License (GPL).
π AUTHOR π
Frank B. Brokken (f.b.brokken@rug.nl).
and that's a wrap on the whole page bestie!! π«Ά this came from the Bobcat project β the version is libbobcat-dev_6.15.01, dated 2005-2026, and the page itself is FBB::CSVTable(3bobcat). go forth and make the prettiest little tables, you've absolutely got this π
πΈπ¦
π¦ where this page comes from
- ubuntu stonking: libbobcat-dev 6.15.01-1 Β· GPL-3.0-or-later WITH OpenSSL exception
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms