class ref name: matrix_dbag
category-group: dbag
layer: 3

synopsis.
The matrix databag object ( matrix_dbag_o ) is a child class of the "list" databag ( list_dbag_o ), which is top-level class (eg has no parent class). It is used to hold a "matrix" (eg, "table" or "grid") of information. A matrix databag can be embedded in a recursive databag (this is common).

It is highly recommended that you read the databag intro page prior to looking at any specific databag object reference page, in order to familirize yourself with the over-all mechanics of databags.

description.
Databags can be used wherever data stored in strings, is needed. Common usage can be found in networks (transmitting data), databases (mapping data to database tables), or as "background classes" for all sorts of objects. If you have a class X, you can store X's data directly into it by subclassing it from a recursive databag (see the example on this page).

Each row in the matrix databag is implemented as an array databag, so rows must conform to the syntax rules of an array databag. Each row must start with '<' and end with '>'. Each element in the array must be a simple "word" (contain only numbers, letters, and/or '_'), or else be enclosed in quotes (either single- or double-; single-quotes are recommended for data enclosed in C-syntax character buffers, for readability). The basic syntax for a matrix databag can be deduced from this example string:

char *my_standard_matrix_dbag =
"dbag_name \n\
columns \n\
[ \
    <column1  column2  column3  column4  column5  column6> \n\
    <row1     row1col2 row1col3 row1col4 row1col5 row1col6> \n\
    <row2col1 row3col2 row3col3 row3col4 row3col5 row3col6> \n\
    < r3col1  row3col2 row3col3 row3col4 row3col5 r1col6  > \n\
]";

The placement of whitespace in this string, including the newlines ("\n"), is completely under user control. Notice in the 3rd data row (starting with "row3col1"), the enclosing angle-brackets are separated from the data by a single blank. This is optional. We recommend it to improve readability, it may help you catch errors. Also, in the string above each line is terminated by a new-line. This is also optional but recommented for readability. The data bag must have a name (in this case "dbag_name"). Any name will do. The matrix (eg table) section starts with the keyword "columns" and is followed by an opening square bracket, and ends with a closing square bracket. These are mandatory - the opening square bracket tells the databag parsing engine that a matrix databag is about to begin. Each row must have the same number of columns. The very first row, after the "[", is not data but an array databag containing the names of the columns. This too, is required.

getting data. The primary member function / operation is to "get()" a value by [column, row]. Think of referencing the item as a mathematical point on an x-y grid. Thus, the first argument to the "get()" group of functions is the column number (or name!), and the second argument is the row.

adding data. You can add a row of data or a column of data at a time via member functions. append_column() and append_row().

As with all databags, matrix databags can be stored in other types of databags (usually inside recursive databags).

member functions (primary)

matrix_dbag_o()
SIGNATURE: matrix_dbag_o ()
SYNOPSIS:
creates a a new matrix_dbag object, completely devoid of contents. The object has no internal structure - no string has been given to it to define any data structure.
 

matrix_dbag_o(matrix_dbag_o)
SIGNATURE: matrix_dbag_o (const matrix_dbag_o &that)
SYNOPSIS: copy constructor: creates a a new matrix databag object which is an exact image of the copied matrix databag object "that".
 

operator = (matrix_dbag_o)
SIGNATURE: const matrix_dbag_o &operator = (const matrix_dbag_o &rhs)
SYNOPSIS:
copies exactly the RHS object ("rhs"), to the existing matrix databag object instance. The resultant matrix databag instance is the same as if the copy constructor was used.
RETURNS: a reference to the current object
 

destructor
SIGNATURE: ~matrix_dbag_o ()
SYNOPSIS: virtual destructor. The databag instance is wiped out and all contents are reinitialized to the at-construction state.
 

matrix_dbag_o(<args>)
SIGNATURE: matrix_dbag_o (const string_o &s)
SYNOPSIS:
create a new matrix databag object. The matrix databag is loaded according to the contents of the input parameter string "s", which must be of valid matrix databag format, in order for the load to succeed.
 

clone()
SIGNATURE: dbag_o *clone () const
SYNOPSIS:
Allocates a new matrix databag, copies the current object into it, and returns a pointer to a new matrix databag instance. The pointer is upcasted to the top-level parent class dbag_o.
 

bad_reference()
SIGNATURE: const matrix_dbag_o &bad_reference ()
SYNOPSIS:
returns a reference to a static global matrix databag that is used to indicate failure by functions (such as assignment operator) that return references.
TRAITS: this is static; call it without an attached object.
 

operator ==()
SIGNATURE: int operator == (const dbag_o &rhs) const
SYNOPSIS:
tell if the current matrix databag is the same as 'rhs'. 'rhs' must be of the same sub-type (ie, matrix) as the current object (if not, 0 is returned)
RETURNS:
1: the [matrix] databags are the same (equivalent)
0: the databags are different (possibly different subtypes)
 

operator ==()
SIGNATURE: int operator == (const matrix_dbag_o &rhs) const
SYNOPSIS:
tell if the current matrix databag is the same as 'rhs'. the converse of directory_o::operator != (rhs). Two matrix databag are equivalent if they have the same number of rows and columns, and if each datum (entry for any given row and column) matches. If both databag are empty (have no data at all), they will be considered equal.
RETURNS:
1: matrix databag are the same (equivalent)
0: matrix databag are different
 

operator !=()
SIGNATURE: int operator != (const matrix_dbag_o &rhs) const
SYNOPSIS:
This operator member function tests if the current matrix databag is different from the "rhs" variable. This is the inverse of "==" operator - if the databag are not equal (see the "==" operator for the precise definition of equality), they are different, and hence this operator function will return 1.
RETURNS:
1: the matrix databags are different
0: the matrix databags are equivalent
 

num_rows()
SIGNATURE: count_t num_rows () const
SYNOPSIS: returns the number of rows in the current matrix databag object. If the object has not been initialized, 0 is returned.
RETURNS: n >= 0: number of rows in the matrix databag object
 

num_columns()
SIGNATURE: count_t num_columns () const
SYNOPSIS: returns the number of columns in the current matrix databag object. If the object has not been initialized, 0 is returned.
RETURNS: n >= 0: number of columns in the matrix databag object
 

column_names()
SIGNATURE: array_dbag_o *column_names () const
SYNOPSIS:
returns a pointer to the array databag holding the names of the columns. If the matrix databag has not been initialized to a string representing matrix data, NULL is returned
RETURNS: pointer to internal array databag that holds item's column names
 

set_column_names()
SIGNATURE: void set_column_names (const array_dbag_o *new_cols)
SYNOPSIS:
sets (or resets) the array databag that contain the column names. note that if there is data currently in the object, the number of columns (as given by the number of elements in "new_cols") does not need to match the existing number of columns. If "new_cols" is NULL, the function will do nothing (use "reset()" to empty out the object).
 

mod_setall()
SIGNATURE: int mod_setall (boolean ison = TRUE)
SYNOPSIS: this function turns on the "is-modified" flag/property for each databag contained within the current object.
DESCRIPTION:
this function is like set_modified(), but only in that it turns the "is-modified" flag on. This function is a reimplementation of the virtual function in the base class dbag_o. For this class, since it is derived from list_dbag_o, this function forwards the operation to list_dbag_o::mod_setall(). Each list databag object (contained within) will have its "is-modified" flag/property set on (or off, if 'ison' is FALSE). This corresponds to each row in the matrix.
See the discussion in the main databag group page for more information.
 

get()
SIGNATURE: const string_o &get (count_t col, count_t row, int *pi = NULL) const
SYNOPSIS:
gets a single element (eg entry) in the matrix databag object. The element is returned as a string object (the same way it is stored). The databag must have been loaded prior in order for this function to successfully return the element. If the element fails to get fetched (either by out-of-bounds row or column values, or the object was not initialized), the string returned will be the string_o classe's "bad string" reference - that is, a call to string_o::bad_reference(), which is a placeholder for functions that return references, and the output 'error indicator' variable "pi" will be set to non-zero.
PARAMETERS

  • col: "integer" type variable ("countable") referencing the column number for the desired item-element. The first column has value 0. If the value given by "col" is out of bounds, the output parameter "pi" is set to 1.
  • row: "integer" type variable ("countable") referencing the row number for the desired item-element. The first row has value 0. If the value given by "row" is out of bounds, the output parameter "pi" is set to 1.
  • pi: optional [output] error indicator variable. This is set to 0 if the desired item has been found and successfully returned. If the item is not found, this is set to 1.
RETURNS: [string_o] reference to the string object found at the target position, or string_o::bad_reference(), if the element is not found.
 

get()
SIGNATURE: const string_o &get (const string_o &colname, count_t row, int *pi = NULL) const
SYNOPSIS:
gets a single element (eg entry) in the matrix databag object. The element is returned as a string object. The element is located by the column and row position specified by the first two [input] parameters, "colname" and "row". This function is analogous to the "get (count_t, count_t, int *)" member function. The only difference is that the column is referenced by its column name, instead of the column's position value.
PARAMETERS

  • colname: string object containing the column name referencing the column of the desired item-element. The case must match, eg, the name of the column to find must be exact. If the column specified by "colname" is not found, the output parameter "pi" is set to 1.
  • row: "integer" type variable ("countable") referencing the row number for the desired item-element. The first row has value 0. If the value given by "row" is out of bounds, the output parameter "pi" is set to 1.
  • pi: optional [output] error indicator variable. This is set to 0 if the desired item has been found and successfully returned. If the item is not found, this is set to 1.
RETURNS: [string_o] reference to the string object found at the target position, or string_o::bad_reference(), if the element is not found.
 

get()
SIGNATURE: const string_o &get (count_t col, const string_o &rowname, int *pi = NULL) const
SYNOPSIS:
gets a single element ('entry') in the matrix databag object. The element is returned as a string object. The element is located by the column and row position specified by the first two [input] parameters, "col" and "rowname". This function is analogous to the "get (count_t, count_t, int *)" member function. The only difference is that the row is referenced by its "row name", instead of the row's position value.
PARAMETERS

  • col: "integer" type variable ("countable") referencing the column number for the desired item-element. The first column has value 0. If the value given by "col" is out of bounds, the output parameter "pi" is set to 1.
  • rowname: string object containing the row name referencing the row of the desired item-element. The case must match, eg, the name of the row to find must be exact. If the row specified by "rowname" is not found, the output parameter "pi" is set to 1.
  • pi: optional [output] error indicator variable. This is set to 0 if the desired item has been found and successfully returned. If the item is not found, this is set to 1.
RETURNS: [string_o] reference to the string object found at the target position, or string_o::bad_reference(), if the element is not found.
TRAITS: the concept of a row having a name may be phased out in future releases. Hence, usage of this function is discouraged.
 

get_idx()
SIGNATURE: count_t get_idx (const string_o &nam, count_t idx, count_t start= 0) const
SYNOPSIS: finds a row in table, where column index is 'idx' and value = name
RETURNS: -1
TRAITS: this function is marked for termination and should be avoided.
 

get_idx()
SIGNATURE: count_t get_idx (const string_o &name, const string_o &value, count_t start_psn = 0, int *pi = NULL) const
SYNOPSIS: this returns the row count of the item given by the column named by 'name', and value matches the value found in 'value'.
PARAMETERS

  • name: name of the column to inspect (eg, for column 0, the name is "name"; for column 1, the name is "type", etc)
  • value: the value of the item in the column specified by 'name' to look for. Thus, given rows named "url", "email", and "zip", if the column to search is "name" (eg, parameter name value is "name"), and value is "zip", the return value is 2.
  • start_psn: which row to start looking from. This parameter is of dubious value.
  • pi: [output] error indicator variable. values:
    0: successfully fetched
    zErr_NotInitialized: the object is not properly initialized ("columns" is NULL)
    zErr_NotFound: not found
RETURNS: -1
TRAITS: this function is marked for termination and should be avoided.
 

get_row()
SIGNATURE: const array_dbag_o &get_row (count_t i, int *pi = NULL) const
SYNOPSIS: returns the ith row from the object, as an array databag.
PARAMETERS

  • i: index number of the row to retrieve. if i is not in [0..size()], an error occurs
  • pi: [output] error indicator variable. values:
    0: successfully fetched
    zErr_Index_OutofBounds: 'i' not a valid value
DESCRIPTION:
since rows of data in the matrix databag are stored as array databags, that is the return type. The return value is a reference to the actual array databag object. If an error occurs (meaning 'i' is out of bounds), array_dbag_o::bad_reference() is the returned value. Since, in case of error, the application may well likely ignore checking the addrss of the returned reference, checking the value of 'pi' is the de-facto way to ascertain if there was an error.
 

row_number()
SIGNATURE: count_t row_number (const string_o &colnam, const string_o &nam, count_t start = 0, int *pi = NULL) const
SYNOPSIS: ..
PARAMETERS

  • colnam: ..
  • nam: ..
  • start: ..
  • pi: [output] error indicator variable. values:
    0: successfully fetched
    zErr_NotInitialized: the object is not properly initialized ("columns" is NULL)
    zErr_NotFound: not found; column name is incorrect
 

reset()
SIGNATURE: int reset ()
SYNOPSIS:
This function resets the object to its degenerate, at-construction state. "reset()" is called by the destructor; it can also be called at any time directly by the client (application code). All base class "reset()" operations are invoked.
zErr_NotInitialized: the object is not properly initialized ("columns" is NULL)
RETURNS: 0
 

empty_out()
SIGNATURE: int empty_out ()
SYNOPSIS:
"empties out" the current object. This will delete all of the object's rows inside (except the header row). The object's name is unaffected. Internal data remains, so that new rows can be added immediately afterwards.
DESCRIPTION:
This member function "empties out" all data rows of the matrix databag. The object's structure is intact, allowing rows of similar size to be added to the object afterwards.
 

load()
SIGNATURE: int load (const string_o &s)
SYNOPSIS:
this function parses the string "s" and loads its data into the object. The resultant set of data consists of a set of string objects, one for each data element in the grid of data found in "s".
PARAMETERS

  • s: multi-line string containing string representation of a matrix databag (see examples on this page for a description of its syntax).
  • RETURNS:
    0: "s" successfully parsed. the matrix databag object's data is set, to the contents found in "s".
    -1: error occured in processing (likely caused by incorrsct syntax)
     

    unload()
    SIGNATURE: int unload (int * = NULL)
    SYNOPSIS:
    "Unloads" the data from the matrix databag object. All data elements are deleted. The object's structure (if set) is preserved (the table header column remains). This is akin to a "partial reset".
     

    put()
    SIGNATURE: int put (count_t col, const string_o &val, boolean force = FALSE, int *pi = NULL)
    SYNOPSIS: puts the value given in 'val' into the array indexed by 'col'.
     

    put()
    SIGNATURE: int put (count_t y, count_t x, const string_o &val, boolean force = FALSE, int *pi = NULL)
    SYNOPSIS: this "puts" the value 'val' into the (x,y) location in the object's internal data matrix.
    PARAMETERS

    • y: the row (array number, starting at 0) to access
    • x: the column (index into the array) to access
    • value: the value of the item to store
    • force: if TRUE, the object is designated as having been modified. if FALSE (the default), the "is-modified" status depends on whether the updated value has changed.
    • pi: [output] error indicator variable. values:
      0: value successfully put
      zErr_Index_OutofBounds: invalid row or column index
     

    put()
    SIGNATURE: int put (const string_o &colnam, count_t row, const string_o &val, boolean force = FALSE, int *pi = NULL)
    SYNOPSIS:
    puts the value given by 'val' into matrix location specified by 'colnam' and 'row'. This function relies on the fact that columns in a matrix databag have names
    PARAMETERS

    • colnam: the name of the column to access (array name)
    • row: the row (index into the array) to access
    • value: the value of the item to store
    • force: if TRUE, the object is designated as having been modified. if FALSE (the default), the "is-modified" status depends on whether the updated value has changed.
    • pi: [output] error indicator variable. values:
      0: value successfully put
      zErr_Index_OutofBounds: invalid row or column index
     

    append_column()
    SIGNATURE: int append_column (const string_o &name) const
    SYNOPSIS: Adds an empty column to the object's internal table.
     

    append_row()
    SIGNATURE: int append_row (const array_dbag_o &a)
    SYNOPSIS:
    Adds a row to the object's internal table. The row is in the form of an array databag found in parameter 'a'. The number of columns in 'a' must match the number of columns in the object.
    RETURNS:
    0: row successfully added to the current object
    -1: error occurred; "a" not aggregated to the current object. Either the object has no data loaded or the number of columns in "a" and the object do not match.
     

    delete_row()
    SIGNATURE: int delete_row (count_t i)
    SYNOPSIS: deletes the "ith" row of data, where "i" is the row number (starting from 0).
     

    merge_dbag()
    SIGNATURE: int merge_dbag (const dbag_o &that, int *pi = NULL)
    SYNOPSIS: appends the rows from matrix databag "that" to the current object.
    DESCRIPTION:
    Although the input parameter "that" is of type dbag_o, it must be a matrix databag in order for this function to succeed (each databag holds a 'type code' that can be readily accesed by calling function dbag_type()). Both databags must have data loaded and have exactly the same columns - both the number of columns must match, and each column name must match up.
     

    PARAMETERS

    • that: a matrix databag object. It must have data. The columns of "that" must match with those of the current object.
    • pi: [output] error indicator. values:
      0: operation succeeded. Data bags are merged.
      1: "that" is a databag, but not of type matrix
      3: number of columns are not the same in source and target databags
      4: either or both source and target databags are not loaded
      5: column values are not the same (1 or more column names do not match)
     

    iprint()
    SIGNATURE: const string_o &iprint (string_o &, const count_t) const
    SYNOPSIS: [WIP]
     

    note.
    The term "matrix" has been selected as it is more precise than, say "table" (which can be used to denote furniture or components in a database. Also [from wiki], a "table" can be a parliamentary procedure, a type of diamond cut, a game, or a geographic formation).

    examples.
    The following example presents some elements found in the periodic table, stored in the matrix_dbag object "xe". An error has been deliberately introduced into this table, erronously setting atomic number 80 to Krypton instead of Mercury. This is to show usage of the put() member function in correcting the error.

    Various matrix databag member functions are used in this example, including: get(), get_idx(), put(), iprint(), append_column(), and append_row().

    #include "stdafx.h"
    #include "z_func.h"
    #include "z_strsubs.h"
    #include "z_dbag_recurs.h"
    
    static const char *PEdata =
    "elements \
    ( \
        current_element (name hydrogen ID 1) \
    columns \
    [ \
      <number name    abbrev  is_RA   C_melt  C_boil  rarity > \
      < 1     Hydrogen H      NO  '-259.14' '-252.87' common > \
      <26     Iron    Fe      NO      1538    2862    common > \
      <27     Cobalt  Co      NO      1495    2927    uncommon > \
      <80     Krypton Me      NO  '-38.83' '356.73'   'semi-common' > \
      <79     Gold    Au      NO      '1064.18' 2856  'semi-rare' > \
      <92     Uranium U       YES     '1132.2'  4131  'semi-rare' > \
    ] \
    )";
    
    class Elem : public rec_dbag_o
    {
    public:
        Elem () : rec_dbag_o(PEdata) { }
        Elem (const string_o &s) : rec_dbag_o(s) { }
        /* ... */
    };
    
    static void dump_all (const matrix_dbag_o &);
    static void dump_row (const matrix_dbag_o &, count_t);
    static void dump_aligned (const string_o, int);
    
    //----------------------------------------------------------------------
    int main (int argc, char *argv[])
    {
        int ie = 0, ie2, ie3, ie4, ie5;
        count_t i, nr, nc;
    
        z_start();
    
        string_o s;
        Elem xe;
    
        string_o curr_elem = xe.get ("current_element name");
        matrix_dbag_o the_matrix;
        dbag_o &my_matrix = xe.get_dbag ("columns", &ie);
        if (!ie)
        {
            the_matrix = (matrix_dbag_o &) my_matrix;
            nr = the_matrix.num_rows();
            nc = the_matrix.num_columns();
        }
    
        std::cout << "Class name .....: \"" << xe.dbag_name() << "\"\n";
        std::cout << "Current element : \"" << curr_elem << "\"\n";
        std::cout << "# of elements in our periodic table: \"" << nr << "\"\n";
        dump_all (the_matrix);
    
        // fix the error - "Mercury", not "Krypton"
        the_matrix.put("name", 3, "Mercury", &ie2);    // row 3 (4th row), 2nd col
        the_matrix.put(2,      3, "Hg");               // abbrev: 4th row, 3rd col
    
        std::cout << "Fixed the error of row 3. Now it looks like this:\n";
        dump_row (the_matrix, 3);
    
        std::cout << "here's \"iprint()\":\n";
        the_matrix.iprint(s, 0);                    // USAGE OF "iprint()"
        std::cout << s << std::endl;
    
        std::cout << "\"get_idx(abbrev, Au)\" retuerns: ";
        the_matrix.iprint(s, 0);                    // USAGE OF "iprint()"
        i = the_matrix.get_idx("abbrev", "Au", 0);  // "get_idx(string, string)"
        std::cout << i << std::endl;
    
        std::cout << "\"get_idx(Iron, 1)\" returns: ";
        i = the_matrix.get_idx("Iron", 1, 0);       // "get_idx(string, count)"
        std::cout << i << std::endl;
    
        std::cout << "DOING 3 THINGS:\n\t\"put(0, 3, 'YES')\"\n";
        std::cout << "\t\"add_column(EXTRA)\"\n\t\"append_row()\"\n";
        std::cout << "now the grid looks liks this:\n";
    
        array_dbag_o my_array ("another_item", 8, "Plutonium", "Pu", "YES",
            "639", "3228", "rare", "more_Shit");
    
        i = the_matrix.append_column ("EXTRA");     // USAGE OF "append_column()"
        i = the_matrix.put(0, 3, string_o("YES"), &ie2);
        i = the_matrix.append_row (my_array);       // USAGE OF "append_row()"
        dump_all (the_matrix);
    
        z_finish();
        exit(ie);
        return 0;
    }
    
    //----------------------------------------------------------------------
    static void dump_all (const matrix_dbag_o &me)
    {
        count_t i, nr = me.num_rows(), nc = me.num_columns();
        for (i = 0; i < nr; i++)
           dump_row (me, i);
    }
    
    //----------------------------------------------------------------------
    // dump_row() prints the contents in nicely aligned columns.
    // the abbreviation is either 1 char ("H", "U") or 2 ("Fe", "Xe")
    //----------------------------------------------------------------------
    static void dump_row (const matrix_dbag_o &my_mat, count_t i)
    {
        char b[800];
        int ie2, ie3, ie4, ie5;
    
        dump_aligned (my_mat.get(2, i, &ie2), 2);
        std::cout << " (atomic #: ";
        dump_aligned (my_mat.get(0, i, &ie2), 2);
    
        z_strcpy (b, (my_mat.get(1, i, &ie4)).data());
        z_pad_blanks_right(b, 20);
        std::cout << "; name: "
                << b << "| is radioactive?: "
                << my_mat.get(3, i, &ie5) << ")" << std::endl;
    }
    
    //----------------------------------------------------------------------
    static void dump_aligned (const string_o s, int colwidth)
    {
        std::cout << s;
        int i;
        for (i = s.size(); i < colwidth; i++)
            std::cout << " ";
    }
    

    bugs.
    Matrix databags, like other types of databags, can go into an infinite loop if the syntax of the data in its string to be parsed is not correct. It is the responsibility of the application to ensure that the data going into creating or loading a databag is correct. One way for the parsing to fail (and hence, never return is to use non-"word" data. For example, in the case of the matrix presented on this page, if the single-quotes are removed:

    columns \
    [ \
      <number name    abbrev  is_RA   C_melt  C_boil  rarity > \
      < 1     Hydrogen H      NO     -259.14 -252.87  common > \
      <92     Uranium U       YES     1132.2  4131    semi-rare > \
    ] \
    
    The parse will fail and never return upon hitting the minus sign or the dot (decimal point) for the 5th and 6th columns in the first (and second) row ("Hydrogen"). It will also fail due to the embedded dash of "semi-rare".

    history.

    ??? 08/18/1997: new parsing syntax implemented {--GeG}
    Fri 10/31/1997: bug: list databag's "reset()", "columns" got wiped out
    ??? 08/23/1998: phased out using a string to reference rows {--GeG}
    ??? 11/16/1998: matrix_dbag_o::operator == () created
    Thu 05/30/2002: new #define naming conventions ("zos_", "zcc_")
    Sat 09/13/2003: overhauling get(), get_row() param list order {--GeG}
    Mon 04/30/2012: source code file clean-up