casa
$Rev:20696$
|
00001 //# TableRow.h: Access to a table row 00002 //# Copyright (C) 1996,1999,2001 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: TableRow.h 21298 2012-12-07 14:53:03Z gervandiepen $ 00027 00028 #ifndef TABLES_TABLEROW_H 00029 #define TABLES_TABLEROW_H 00030 00031 //# Includes 00032 #include <casa/aips.h> 00033 #include <tables/Tables/Table.h> 00034 #include <tables/Tables/TableRecord.h> 00035 #include <casa/Containers/Block.h> 00036 #include <casa/BasicSL/String.h> 00037 00038 namespace casa { //# NAMESPACE CASA - BEGIN 00039 00040 //# Forward Declarations 00041 class TableColumn; 00042 template<class T> class Vector; 00043 00044 00045 // <summary> 00046 // Readonly access to a table row 00047 // </summary> 00048 00049 // <use visibility=export> 00050 00051 // <reviewed reviewer="Paul Shannon" date="1996/05/10" tests="tTableRow.cc"> 00052 // </reviewed> 00053 00054 // <prerequisite> 00055 // <li> <linkto class=Table>Table</linkto> 00056 // <li> <linkto class=TableRecord>TableRecord</linkto> 00057 // </prerequisite> 00058 00059 // <synopsis> 00060 // This class provides easy access to the contents of a table, 00061 // one row at a time. 'Normal' access to a table is by columns, each of 00062 // which contains values of the same type. 00063 // A table row, by contrast, will be a collection 00064 // of heterogeneous data, similar to a C struct. For 00065 // this reason, the TableRow classes (ROTableRow and TableRow) are built 00066 // around and provide access to the class 00067 // <linkto class=TableRecord> TableRecord </linkto>. 00068 // The TableRow delegates much of its behaviour to the TableRecord class. 00069 // For example: 00070 // <srcblock> 00071 // Table table ("some.table"); 00072 // ROTableRow row (table); // construct TableRow object 00073 // cout << row.record().description(); // show its description 00074 // // Get the values in row 17. 00075 // const TableRecord& record = row.get (17); 00076 // // column name is "Title", and automatically becomes the record 00077 // // key for this field of the record: 00078 // String row17title = record.asString ("Title"); 00079 // Int row17count = record.asInt ("Count"); 00080 // </srcblock> 00081 // The simplest constructor will include all columns in the TableRow object 00082 // (although columns with a non-standard data type will be excluded, 00083 // because they cannot be represented in a TableRecord). 00084 // However, it is possible to be more selective and to include only 00085 // some columns in the TableRow object. The various constructors show 00086 // how this can be done. 00087 // <p> 00088 // It is possible to have multiple TableRow objects for the same table. 00089 // They can contain different columns or they can share columns. 00090 // 00091 // <p> 00092 // On construction an internal <linkto class=TableRecord>TableRecord</linkto> 00093 // object is created containing the required fields. The contents of this 00094 // record will be changed with each get call, but the structure of it is 00095 // fixed. This means that <linkto class=RORecordFieldPtr>RORecordFieldPtr 00096 // </linkto> objects can be constructed once and used many times. 00097 // This results in potentially faster access to the record, because it avoids 00098 // unnecessary name lookups. 00099 // </synopsis> 00100 00101 // <example> 00102 // <srcblock> 00103 // // Open the table as readonly and define a row object containing 00104 // // the given columns. 00105 // // Note that the function stringToVector is a very convenient 00106 // // way to construct a Vector<String>. 00107 // // Show the description of the fields in the row. 00108 // Table table("Some.table"); 00109 // ROTableRow row (table, stringToVector("col1,col2,col3")); 00110 // cout << row.record().description(); 00111 // // Loop through all rows and get their values. 00112 // for (uInt i=0; i<table.nrow(); i++) { 00113 // const TableRecord& values = row.get (i); 00114 // someString = values.asString ("col1"); 00115 // somedouble = values.asdouble ("col2"); 00116 // someArrayInt = values.asArrayInt ("col3"); 00117 // } 00118 // 00119 // // Provided the structure of the record is known, the RecordFieldPtr 00120 // // objects could be used as follows. 00121 // // This is faster than the previous method, because it avoids a name 00122 // // lookup for each iteration. 00123 // RORecordFieldPtr<String> col1(row.record(), "col1"); 00124 // RORecordFieldPtr<double> col2(row.record(), "col2"); 00125 // RORecordFieldPtr<Array<Int> > col3(row.record(), "col3"); 00126 // for (uInt i=0; i<table.nrow(); i++) { 00127 // row.get (i); 00128 // someString = *col1; 00129 // somedouble = *col2; 00130 // someArrayInt = *col3; 00131 // } 00132 // </srcblock> 00133 // Please note that the TableRecord& returned by the get() function is the 00134 // same as returned by the record() function. Therefore the RORecordField 00135 // objects can be created in advance. 00136 // </example> 00137 00138 class ROTableRow 00139 { 00140 public: 00141 // Create a detached ROTableRow object. 00142 // This means that no Table, etc. is contained in it. 00143 // Function isAttached will return False for it. 00144 // <br> 00145 // This constructor should normally not be used, because it does not 00146 // result in a valid object. It should only be used when really needed 00147 // (e.g. when an array of objects has to be used). 00148 ROTableRow(); 00149 00150 // Create a ROTableRow object for the given Table. 00151 // Its TableRecord will contain all columns except columns with 00152 // datatype TpOther (i.e. non-standard data types). 00153 // <br> 00154 // If the flag <src>storedColumnsOnly</src> is True, only the 00155 // columns actually stored by a storage manager will be selected. 00156 // This is useful when the contents of an entire row have to be copied. 00157 // Virtual columns are calculated on-the-fly (often using stored columns), 00158 // thus it makes no sense to copy their data. 00159 // <note role=caution> 00160 // If the table contains columns with large arrays, it may 00161 // be better not to use this constructor. Each get will read in 00162 // all data in the row, thus also the large data array(s). 00163 // In that case it is better to use the constructor which 00164 // includes selected columns only. 00165 // </note> 00166 explicit ROTableRow (const Table& table, Bool storedColumnsOnly = True); 00167 00168 // Create a ROTableRow object for the given Table. 00169 // Its TableRecord will contain all columns given in the Vector. 00170 // An exception is thrown if an unknown column name is given. 00171 // <br> 00172 // When exclude=True, all columns except the given columns are taken. 00173 // In that case an unknown name does not result in an exception. 00174 ROTableRow (const Table& table, const Vector<String>& columnNames, 00175 Bool exclude = False); 00176 00177 // Copy constructor (copy semantics). 00178 ROTableRow (const ROTableRow&); 00179 00180 ~ROTableRow(); 00181 00182 // Assignment (copy semantics). 00183 ROTableRow& operator= (const ROTableRow&); 00184 00185 // Test if a Table is attached to this object. 00186 Bool isAttached() const; 00187 00188 // Get the Table used for this object. 00189 const Table& table() const; 00190 00191 // Get the record containing all fields. 00192 const TableRecord& record() const; 00193 00194 // Get the number of the last row read. 00195 // -1 is returned when no Table is attached or no row has been read yet. 00196 Int rowNumber() const; 00197 00198 // Get a vector consisting of all columns names. 00199 // This can, for instance, be used to construct a TableRow object 00200 // with the same columns in another table. 00201 Vector<String> columnNames() const; 00202 00203 // Get the values of all columns used from the given row. 00204 // When the given row number equals the current one, nothing 00205 // will be read unless the alwaysRead flag is set to True. 00206 // <br>The TableRecord& returned is the same one as returned by the 00207 // record() function. So one can ignore the return value of get(). 00208 const TableRecord& get (uInt rownr, Bool alwaysRead = False) const; 00209 00210 // Get the block telling for each column if its value in the row 00211 // was indefined in the table. 00212 // Note that array values might be undefined in the table, but in 00213 // the record they will be represented as empty arrays. 00214 const Block<Bool>& getDefined() const; 00215 00216 protected: 00217 // Copy that object to this object. 00218 // The writable flag determines if writable or readonly 00219 // TableColumn objects will be created. 00220 void copy (const ROTableRow& that); 00221 00222 // Create the record, column, and field objects 00223 // for all columns in the table. 00224 // The writable flag determines if writable or readonly 00225 // TableColumn objects will be created. 00226 void create (const Table& table, Bool storedColumnsOnly, Bool writable); 00227 00228 // Create the record, column, and field objects for the given columns. 00229 // The writable flag determines if writable or readonly 00230 // TableColumn objects will be created. 00231 void create (const Table& table, const Vector<String>& columnNames, 00232 Bool exclude, Bool writable); 00233 00234 // Put the values found in the internal TableRecord at the given row. 00235 // This is a helper function for class TableRow. 00236 void putRecord (uInt rownr); 00237 00238 // Put a value in the given field in the TableRecord into the 00239 // given row and column. 00240 // This is a helper function for class TableRow. 00241 void putField (uInt rownr, const TableRecord& record, 00242 Int whichColumn, Int whichField); 00243 00244 // Set the switch to reread when the current row has been put. 00245 void setReread (uInt rownr); 00246 00247 //# The record of all fields. 00248 TableRecord* itsRecord; 00249 //# The table used. 00250 Table itsTable; 00251 //# The following block is actually a Block<TableColumn*>. 00252 //# However, using void* (and appropriate casts) saves on template 00253 //# instantiations. 00254 Block<void*> itsTabCols; 00255 //# The following block is actually a Block<Scalar/ArrayColumn<T>>. 00256 Block<void*> itsColumns; 00257 //# The following block is actually a block of RecordFieldPtr<T>*. 00258 //# These are used for fast access to the record. 00259 Block<void*> itsFields; 00260 //# Block to tell if the corresponding column value is defined. 00261 mutable Block<Bool> itsDefined; 00262 //# A cache for itsRecord.nfields() 00263 uInt itsNrused; 00264 //# The last rownr read (-1 is nothing read yet). 00265 //# This is via a pointer to keep the get function const. 00266 Int* itsLastRow; 00267 //# A switch to indicate that the last row has to be reread. 00268 //# This is the case when it has been put after being read. 00269 Bool* itsReread; 00270 00271 private: 00272 // Initialize the object. 00273 void init(); 00274 00275 // Make a RecordDesc from the table with some excluded column names. 00276 void makeDescExclude (RecordDesc& description, 00277 const Vector<String>& columnNames, 00278 Bool writable); 00279 00280 // Add a column to the record. 00281 // When skipOther is True, columns with a non-standard data type 00282 // will be silently skipped. 00283 void addColumnToDesc (RecordDesc& description, 00284 const TableColumn& column, Bool skipOther); 00285 00286 // Make the required objects. These are the TableRecord and for 00287 // each column a TableColumn and RecordFieldPtr. 00288 void makeObjects (const RecordDesc& description); 00289 00290 // Delete all objects. 00291 void deleteObjects(); 00292 }; 00293 00294 00295 00296 00297 // <summary> 00298 // Read/write access to a table row 00299 // </summary> 00300 00301 // <use visibility=export> 00302 00303 // <reviewed reviewer="Paul Shannon" date="1995/05/10" tests="tTableRow.cc"> 00304 // </reviewed> 00305 00306 // <prerequisite> 00307 // <li> <linkto class=ROTableRow>ROTableRow</linkto> 00308 // </prerequisite> 00309 00310 // <synopsis> 00311 // The class TableRow is derived from ROTableRow and as an extra it 00312 // provides write-access to a row in a table. 00313 // With the put function, all values in the TableRecord object will 00314 // be put in the corresponding columns in the table row. 00315 // There is, however, an extra consideration: 00316 // <ul> 00317 // <li> Constructing a TableRow object fails if the table is not 00318 // writable. Non-writable columns will not be part of the object. 00319 // If an explicitly given column is non-writable, the construction 00320 // will also fail. 00321 // </ul> 00322 // There are effectively 3 ways of writing data. 00323 // <ol> 00324 // <li> The function 00325 // <srcblock> 00326 // put (rownr, tableRecord); 00327 // </srcblock> 00328 // can be used to put all values from the given TableRecord, 00329 // which has to be conforming (i.e. matching order and names). 00330 // Optionally the conformance is checked. 00331 // This put function is capable of data type promotion. 00332 // For instance, if column COL1 is float, the corresponding 00333 // field in the TableRecord can be Int. 00334 // <li> A faster way is using the functions <src>record</src> 00335 // and <src>put</src>. It is possible to use <linkto class=RecordFieldPtr> 00336 // RecordFieldPtr</linkto> objects to get direct access to the 00337 // fields in the record (provided the structure of the record 00338 // is known). 00339 // E.g. 00340 // <srcblock> 00341 // TableRow row (someTable, stringToVector("col1,col2,col3")); 00342 // RecordFieldPtr<String> col1(row.record(), "col1"); 00343 // RecordFieldPtr<double> col2(row.record(), "col2"); 00344 // RecordFieldPtr<Array<Int> > col3(row.record(), "col3"); 00345 // for (uInt i=0; i<n; i++) { 00346 // *col1 = someString; 00347 // *col2 = somedouble; 00348 // *col3 = someArrayInt; 00349 // row.put (i); 00350 // } 00351 // </srcblock> 00352 // <li> 00353 // <li> The function 00354 // <srcblock> 00355 // putMatchingFields (rownr, tableRecord); 00356 // </srcblock> 00357 // can be used to put some fields from the given TableRecord. 00358 // Only fields having a corresponding name in the TableRow object 00359 // will be put. Similar to the first way data type promotion will 00360 // be applied for numeric scalars. 00361 // <br>E.g.: Suppose the TableRow object has columns A, C, and B, 00362 // and the given TableRecord has fields B, D, and C. Only fields B and C 00363 // will be put. As the example shows, the order of the fields is not 00364 // important. 00365 // <br> 00366 // This way is (much) slower than the other 2, because a name 00367 // lookup is involved for each field. It can, however, be more 00368 // convenient to use. 00369 // </ol> 00370 // </synopsis> 00371 00372 // <example> 00373 // <srcblock> 00374 // // Open the new table (with 10 rows) and define a row object containing 00375 // // values from the given column. 00376 // // Note that the function stringToVector is a very convenient 00377 // // way to construct a Vector<String>. 00378 // SetupNewTable newtab(tableDesc, Table::new); 00379 // Table table(newtab, 10); 00380 // TableRow row (table, stringToVector("col1,col2,col3,col4")); 00381 // // Loop through all rows and get their values. 00382 // for (uInt i=0; i<table.nrow(); i++) { 00383 // // Some magic filler function returns a filled TableRecord 00384 // // (with the correct fields in the correct order). 00385 // TableRecord record = fillerFunction(); 00386 // row.put (i, record); 00387 // } 00388 // </srcblock> 00389 // </example> 00390 00391 class TableRow : public ROTableRow 00392 { 00393 public: 00394 // Create a detached TableRow object. 00395 // This means that no Table, etc. is contained in it. 00396 // Function isAttached (in the base class) will return False for it. 00397 // <br> 00398 // This constructor should normally not be used, because it does not 00399 // result in a valid object. It should only be used when really needed 00400 // (e.g. when an array of objects has to be used). 00401 TableRow(); 00402 00403 // Create a TableRow object for the given Table. 00404 // Its TableRecord will contain all columns except columns with 00405 // datatype TpOther and columns which are not writable. 00406 // <br> 00407 // If the flag <src>storedColumnsOnly</src> is True, only the 00408 // columns actually stored by a storage manager will be selected. 00409 // This is useful when the contents of an entire row have to be copied. 00410 // Virtual columns are calculated on-the-fly (often using stored columns), 00411 // thus it makes no sense to copy their data. 00412 // <note role=caution> 00413 // If the table contains columns with large arrays, it may 00414 // be better not to use this constructor. Each get will read in 00415 // all data in the row, thus also the large data array(s). 00416 // In that case it is better to use the next constructor which 00417 // works selectively. 00418 // </note> 00419 explicit TableRow (const Table& table, Bool storedColumnsOnly = True); 00420 00421 // Create a TableRow object for the given Table. 00422 // Its TableRecord will contain all columns given in the Vector. 00423 // An exception is thrown if an unknown column name is given 00424 // or if a column is given which is not writable. 00425 // <br> 00426 // When exclude=True, all columns except the given columns are taken. 00427 // In that case an unknown name does not result in an exception 00428 // and non-writable columns are simply skipped. 00429 TableRow (const Table& table, const Vector<String>& columnNames, 00430 Bool exclude = False); 00431 00432 // Copy constructor (copy semantics). 00433 TableRow (const TableRow&); 00434 00435 ~TableRow(); 00436 00437 // Assignment (copy semantics). 00438 TableRow& operator= (const TableRow&); 00439 00440 // Get non-const access to the TableRecord in this object. 00441 // This can be used to change values in it which can thereafter 00442 // be put using the function <src>put(rownr)</src>. 00443 // <note> The returned TableRecord has a fixed structure, so it is 00444 // not possible to add or remove fields. It is only possible 00445 // to change values. 00446 // </note> 00447 TableRecord& record(); 00448 00449 // Put into the last row read. 00450 // An exception is thrown if no row has been read yet. 00451 // The values in the TableRecord contained in this object are put. 00452 // This TableRecord can be accessed and updated using the 00453 // function <src>record</src>. 00454 void put(); 00455 00456 // Put into the given row. 00457 // The values in the TableRecord contained in this object are put. 00458 // This TableRecord can be accessed and updated using the 00459 // function <src>record</src>. 00460 void put (uInt rownr); 00461 00462 // Put the values found in the TableRecord in the appropriate columns 00463 // in the given row. 00464 // The names and order of the fields in the TableRecord must conform 00465 // those of the description of the TableRow. The data types of numeric 00466 // scalars do not need to conform exactly; they can be promoted 00467 // (e.g. an Int value in the record may correspond to a float column). 00468 // If not conforming, an exception is thrown. 00469 // <note> For performance reasons it is optional to check 00470 // the name order conformance. 00471 // </note> 00472 // The <src>valuesDefined</src> block tells if the value in the 00473 // corresponding field in the record is actually defined. 00474 // If not, nothing will be written. 00475 // It is meant for array values which might be undefined in a table. 00476 // <group> 00477 void put (uInt rownr, const TableRecord& record, 00478 Bool checkConformance = True); 00479 void put (uInt rownr, const TableRecord& record, 00480 const Block<Bool>& valuesDefined, 00481 Bool checkConformance = True); 00482 // </group> 00483 00484 // Put the values found in the TableRecord. Only fields with a matching 00485 // name in the TableRow object will be put. 00486 // This makes it possible to put fields in a selective way. 00487 // <br>E.g.: If the TableRow contains columns A and B, and the 00488 // record contains fields B and C, only field B will be put. 00489 // <br>In principle the data types of the matching fields must match, 00490 // but data type promotion of numeric scalars will be applied. 00491 void putMatchingFields (uInt rownr, const TableRecord& record); 00492 00493 private: 00494 // Check if the names of the given record match this row. 00495 Bool namesConform (const TableRecord& that) const; 00496 }; 00497 00498 00499 inline Bool ROTableRow::isAttached() const 00500 { 00501 return (itsRecord != 0); 00502 } 00503 inline const Table& ROTableRow::table() const 00504 { 00505 return itsTable; 00506 } 00507 inline Int ROTableRow::rowNumber() const 00508 { 00509 return *itsLastRow; 00510 } 00511 inline const TableRecord& ROTableRow::record() const 00512 { 00513 return *itsRecord; 00514 } 00515 inline const Block<Bool>& ROTableRow::getDefined() const 00516 { 00517 return itsDefined; 00518 } 00519 inline TableRecord& TableRow::record() 00520 { 00521 return *itsRecord; 00522 } 00523 inline void TableRow::put (uInt rownr) 00524 { 00525 putRecord (rownr); 00526 } 00527 00528 00529 00530 } //# NAMESPACE CASA - END 00531 00532 #endif