Basic Interface

Creating RDB objects for reading or writing

The RDB library allows the user to read or write RDB formatted data. Users may attach an RDB object to either a file or a C++ stream. The object may be associated with a file or stream either at the time it is created, via the constructors RDB::RDB, or after the object is created, via the RDB::open methods.

    // Open for input, using explicit open mode.
    RDB irdb( "input.rdb", ios::in );

    // Open for input, using default open mode.
    RDB irdb( "input.rdb" );

    // Open for input, using a pointer to an istream.
    RDB irdb( &cin );

    // Open for output.  The explicit open mode is required, otherwise
    //   it will default to open for input.
    RDB ordb( "output.rdb", ios::out );

    // Create the object with no file or stream specified.
    RDB ordb;
    // Specify the stream via the RDB::open(ostream) method.
    ordb.open( &cout );
    // Or, specify the file via the RDB::open(string,ios::openmode) method.
    ordb.open( "output.rdb", ios::out );

RDB header and table information

Information about the number of comments, columns, and rows are available using the RDB::nComments, RDB::nColumns(), and RDB::nRows methods. It is important to note that the first two are trivial queries, but determining the number of rows involves reading the entire table.

    irdb.open( &cin );

    for ( size_t idx = 0; idx < irdb.nColumns( ); idx++ ) {
      cout << idx << ":  " << irdb.getColumn( idx )->getName( ) << endl;

    }

    // This could take awhile...
    cout << "There are " << irdb.nRows( ) << " rows" << endl;    

Accessing comments and columns

An RDB object allows the user to add comments and columns as well as access existing comments and columns. When an RDB object is opened for reading, the RDB header is parsed for comments and columns. Any comment or column found is placed in the RDB object. When an RDB object is opened for writing, no comments or columns are present in the object.

To access an existing comment or column the user may reference the comment or column by index. Comments/Columns are indexed beginning at 0. If the user is requesting an index beyond the range of comments/columns contained in the RDB object, an RDBErrNotFound object is thrown or RDB::_errno is set. If the user is adding a comment/column and specifies an index beyond the range contained in the RDB object, the comment/column is added to the end of the list.

It is important to note that comments are returned as references to the underlying object while columns are returned as pointers to the underlying object. This is to allow columns of different datatypes to be stored in the same RDB object container.

    // Foreach column...
    for ( size_t idx = 0; idx < irdb.nColumns( ); idx++ ) {
      // Print the name and definition.
      cout << irdb.getColumn( idx )->getName( ) << " | "
           << irdb.getColumn( idx )->getDef( )  << endl;

           // Note the use of the '->', pointer dereference, operator.

    }

    // Set the error handling behavior to throw exceptions.
    irdb.setThrow( true );
    try {
      // Ask for on comment beyond what we have.
      irdb.getComment( irdb.nComments( ) );

           // NOTE:  the use of the '.', dot, operator.

    } catch ( RDBErr& rdberr ) {
      // Catch the exception that will be thrown.
      cerr << "This will fail because comment indices start at 0." << endl;

    }

    // Here we check how many comments there are and then add one to
    //   the end.
    size_t ncomments_before = irdb.nComments( );
    irdb.setComment( "Add one comment to the end..." );
    if ( ncomments_before != irdb.nComments( ) ) {
      cout << "Now there's one more comment..." << endl;

    }

It is also possible to access an existing comment/column or add a new comment/column by specifying the comment keyword/column name. Once, again if the comment/column is being added and no matching keyword/name is found, a new comment/column is added to the end of the list. If the comment/column is being returned and not matching keyword/name is found, an RDBErrNotFound object is thrown or RDB::_errno is set.

    RDBColumn* col = irdb.getColumn( "x_err" );

Comments and columns are stored in RDBComment and RDBColumn objects respectively. The RDB object provides access to the RDBComment and RDBColumn objects it contains. For access to the constituent parts of either a comment or a column, the user may use the respective class interfaces.

    // To access a column name, first get the column then ask it for
    //   its name...
    irdb.getColumn( 3 )->getName( );

    // To reset a comment header variable, first get the comment then
    //   set its value...
    irdb.getComment( "foo" ).setValue( "Not bar" );

Table I/O

Table input and output are handled by the RDB::read and RDB::write methods. For input, RDB::read reads one row from the table, parsing it into the RDB object's columns. It checks to ensure the proper number of columns are found on each row,

Rewinding tables

With RDB objects, the user has the possibility of rewinding the RDB table. The object remebers the location of the first element of the first row or data. At any point, the object may be rewound, with the RDB::rewind method, to that point. RDBColumn::rewind is called on all columns associated with the RDB object.

It is important to note that if the RDB object was opened with a stream, rather than a filename, the stream must the ability to seek. Rewinding an RDB object opened with cin or cout will fail.

Automatic indexing for column data

Group columns

RDB objects use the RDB::newGroup method to monitor RDBColumns which have grouping activated. RDB::newGroup scans the RDBColumns associated with the object and calls RDBColumn::newGroup on each column. If any column returns true, RDB::newGroup returns true.

    double sum;
    int cnt;
    string group;

    irdb.getColumn( "break" )->setGroup( true );

    while ( irdb.read( ) ) {
      if ( irdb.newGroup( ) ) {
        if ( irdb.getColumn( "_NR" )->getDataLong( ) ) {
          // Write out old group's stats...
          cout << "Avg for group " << group << " == " << sum / cnt << endl;

        }

        // Reset accumulators...
        sum   = 0.0;
        cnt   = 0;
        group = irdb.getColumn( "break" )->getDataString( );
        
      }
      
      // Accumulate statistics on other columns...
      sum += irdb.getColumn( "data" )->getDataDouble( );
      cnt++;

    }

Creating RDB objects

RDB objects are created using any of the class constructors, RDB::RDB(const string&, const ios::open_mode), RDB::RDB(istream) or RDB::RDB(const RDB&). The filename constructor doubles as the default constructor for the class. If no filename is specifed, an object is created but no stream is attached to it. The RDB::open() method must be called to attach the object to a stream.

If the filename constructor is used with a filename specified, then the default is to open the file for reading. The user may explicitly set the open mode for output though.

The copy constructor does a shallow copy of the object provided as an argument. The new object is linked to the argument. Modification to the first objects RDBColumns will show up in the second objects RDBColumns.

Header and table size

Information about the number of comments, columns, rows are available using the RDB::nComments(), RDB::nColumns(), or RDB::nRows() methods.

Comment initializers

Various initialization functions are provided to set or add comments to an RDB. They methods allow the user to set or add entire RDBComment objects, or parts of RDBComments such as the keyword or value.

Each method allows the user to either specify the comment index, thereby replacing the existing RDBComment, or to leave out the index, thereby appending a new RDBComment to the end of the header.

Examples

Here an entire RDBComment object is added to the header.
  RDBComment comment( "#: comment_variable = comment value" );
  rdb.setComment( comment );

Here we overwrite the second comment with a new one.

  rdb.setComment( comment, 2 );

Comment accessors

Comment accessors allow the user to retrieve all or part of the RDBComment. Once again there is a seperate method for each part of the RDBComment.

Each method has two signatures. The first signature allows the user to specify which comment to act upon by its index in the header. The second signature allows the user to specify which comment to act upon via keyword. It should be noted that if the comment does not explicityly contain a keyword = value construct no keyword is stored for the comment.

Each signature throws an exception if a comment matching either the index or keyword is not found. For functions specifying the index, an IndexOutOfRangeException is thrown. For the functions specifying the keyword, a KeyNotFoundException is thrown.

Column initializers

Various initialization functions are provided to set or add columns to an RDB. They methods allow the user to set or add entire RDBColumn objects, or parts of RDBColumns such as the name, definition, or value.

Each method allows the user to either specify either the column index or the column name. The user may provide an entire RDBColumn object, as is the case with the RDB::setColumn() methods. If the index is out of range or the name is not the name of an existing column, the RDBColumn object is added to the RDB. Otherwise, the RDBColumn object replaces the existing object.

Each in turn throws an exception if the column is not found. In the case of columns specified by index, an IndexOutOfRangeException is thrown. In the cass of columns specified by name, a KeyNotFoundException is thrown. The methods which provide a column definition can also throw BadHeaderException if the definition is not of the proper form.

Column accessors

Column accessors allow the user to retrieve all or part of the RDBColumn. Once again there is a seperate method for each part of the RDBColumn.

Each method allows the user to either specify either the column index or the column name.

Each in turn throws an exception if the column is not found. In the case of columns specified by index, an IndexOutOfRangeException is thrown. In the cass of columns specified by name, a KeyNotFoundException is thrown.

Examples

Here's a neat trick. You can link input and output tables by sharing RDBColumns. In this example the input is passed to the output. However, after linking the two RDB objects, the user doesn't have to explicitly set the values on the output table. The output will just use the values from the latest read from the input.

  RDB irdb(&cin);
  RDB ordb(&cout);

  // This part takes a pointer to the column from input and gives it
  //   to the output.  Now they point at the same RDBColumn...
  for ( int i = 0; i < input.nColumns( ); i++ )
    ordb.setColumn( irdb.getColumn( i ) );

  ordb.writeHeader( );

  // Because the two tables share pointers to the same RDBColumns, a
  //   call to read sets the values of the data in the output as well
  //   as the input.  So now, a call to write will write the values
  //   from the read.
  while ( irdb.read( ) )
    ordb.write( );

Generated on Tue Sep 15 11:07:16 2009 for rdbxx by  doxygen 1.5.6