00001 //# TableRecord.h: A hierarchical collection of named fields of various types 00002 //# Copyright (C) 1996,1997,1998,2000,2001,2002 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 //# 00027 //# $Id$ 00028 00029 00030 #ifndef TABLES_TABLERECORD_H 00031 #define TABLES_TABLERECORD_H 00032 00033 //# Includes 00034 #include <casacore/casa/aips.h> 00035 #include <casacore/casa/Containers/RecordInterface.h> 00036 #include <casacore/tables/Tables/TableRecordRep.h> 00037 #include <casacore/casa/Containers/RecordDesc.h> 00038 #include <casacore/casa/Utilities/COWPtr.h> 00039 00040 namespace casacore { //# NAMESPACE CASACORE - BEGIN 00041 00042 //# Forward Declarations 00043 template<class T> class Array; 00044 class IPosition; 00045 class AipsIO; 00046 class TableLock; 00047 00048 00049 // <summary> 00050 // A hierarchical collection of named fields of various types 00051 // </summary> 00052 00053 // <use visibility=export> 00054 // <reviewed reviewer="Mark Wieringa" date="1996/04/15" tests="tTableRecord"> 00055 // </reviewed> 00056 00057 // <prerequisite> 00058 // <li> <linkto class="RecordDesc">RecordDesc</linkto>. 00059 // <li> <linkto class="RecordFieldPtr">RecordFieldPtr</linkto>. 00060 // </prerequisite> 00061 // 00062 // <etymology> 00063 // TableRecord is a Record to be used in the Table system. 00064 // </etymology> 00065 // 00066 // <synopsis> 00067 // Class <linkto class=RecordInterface>RecordInterface</linkto> describes 00068 // the fundamental properties of records. 00069 // <br> 00070 // The TableRecord class is a particular type of a record class. 00071 // The fields in TableRecord may be of scalar type, array type, a Table 00072 // or a TableRecord. 00073 // The types are chosen to be compatible with the native 00074 // types of the Table system, viz: Bool, uChar, Short, Int, uInt, Float, 00075 // Double, Complex, DComplex, String. 00076 // Arrays of all these types are also available. 00077 // Note that a TableRecord is not a space-efficient way of storing 00078 // small objects. 00079 // <p> 00080 // The structure of a TableRecord is defined by the 00081 // <linkto class="RecordDesc">RecordDesc</linkto> class. 00082 // The structure of the TableRecord can be defined at 00083 // construction time. It can thereafter be restructured. This has the 00084 // effect, however, that any existing RecordFieldPtr objects become 00085 // invalid (using the <linkto file="Notice.h">Notice</linkto> classes). 00086 // <br> 00087 // It is possible to add or remove fields once a TableRecord is constructed. 00088 // However, this is not possible when the TableRecord is constructed with a 00089 // fixed structure (i.e. with the fixedStructure flag set). 00090 // <p> 00091 // A TableRecord is an hierarchical structure, because it can have fields 00092 // containing TableRecord's (as layed out in the RecordDesc). A subrecord 00093 // has a variable structure, when its RecordDesc is empty (i.e. contains 00094 // no fields). It is fixed when its RecordDesc contains fields. 00095 // <p> 00096 // A TableRecord may be assigned to another only if they conform; that is if 00097 // their fields have the identical type in the identical order. 00098 // The field names do not need to be identical however, only the types. 00099 // That is, the structure needs to be identical, but 00100 // not the labels. Note that field order is significant, 00101 // <src>[ifield(type=Int),ffield(type=Float)]</src> 00102 // is not the same as <src>[ffield(type=Float),ifield(type=Int)]</src> 00103 // <br> 00104 // Conformance is checked recursively for fixed subrecords. That is, a 00105 // variable structured subrecord is not checked, because any record 00106 // can be assigned to it. A fixed structured subrecord has to 00107 // conform the corresponding subrecord in the source. 00108 // <br> A Table field is conforming when the name of the table 00109 // description of the source table matches the table description name 00110 // defined in the RecordDesc field. When that name is blank, every 00111 // table matches. In fact, defining a table description name is identical 00112 // to defining an array shape.. 00113 // <p> 00114 // When a TableRecord is read back, possible Tables contained in fields 00115 // are only opended and read back when they are accessed for the first time. 00116 // In that way no needless table opens are done. 00117 // When a table has been opened, it is possible to close it. This 00118 // can be useful to save memory usage. 00119 // <p> 00120 // TableRecord uses copy-on-write semantics. This means that when a 00121 // TableRecord is copied, only the pointer to the underlying 00122 // TableRecordRep object is copied. 00123 // Only when the TableRecord gets changed (i.e. when a non-const 00124 // TableRecord member function is called), the TableRecordRep object is copied. 00125 // This results in a cheap copy behaviour. 00126 // </synopsis> 00127 // 00128 // <example> 00129 // <srcblock> 00130 // { 00131 // TableDesc td ("td", TableDesc::Scratch); 00132 // td.addColumn (ScalarColumnDesc<Int> ("col1")); 00133 // td.addColumn (ScalarColumnDesc<float> ("col2")); 00134 // SetupNewTable newtab ("tTableRecord_tmp.tab1", td1, Table::New); 00135 // Table tab (newtab, 10); 00136 // RecordDesc rd; 00137 // rd.addTable ("tab1", "td"); // with description name 00138 // rd.addField ("tab2", TpTable); // without description name 00139 // TableRecord rec (rd, RecordInterface::Variable); 00140 // // Both define's are possible. 00141 // // The first one because the table description name matches. 00142 // // The second one because that field has no table description name, 00143 // // thus every table description matches. 00144 // rec.defineTable (rec.fieldNumber("tab1"), tab1); 00145 // rec.defineTable (rec.fieldNumber("tab2"), tab1); 00146 // Table t1 = rec.asTable ("tab1"); 00147 // AlwaysAssertExit (t1.nrow() == 10 && t1.tableDesc().ncolumn() == 2); 00148 // Table t2 = rec.asTable ("tab2"); 00149 // AlwaysAssertExit (t2.nrow() == 10 && t2.tableDesc().ncolumn() == 2); 00150 // AipsIO aos ("file.name", ByteIO::New); 00151 // aos << rec; 00152 // } 00153 // // Note that he above is put in a separate scope to be sure that 00154 // // all objects are deleted and tables are written. 00155 // { 00156 // TableRecord rec; 00157 // AipsIO aos ("file.name"); 00158 // aos >> rec; 00159 // // At this point the record is read back, but the tables are not opened. 00160 // // The next statement accesses the table resulting in its open. 00161 // Table t1 = rec.asTable ("tab1"); 00162 // // The following statement closes it again. 00163 // rec.closeTable ("tab1"); 00164 // </srcblock> 00165 // </example> 00166 // 00167 // <motivation> 00168 // In principle the class Record could also support data type Table. 00169 // However, this would have had the big disadvantage that all the 00170 // Table code would have be linked in when only a simple Record is needed. 00171 // It was decided that for that reason it was better to support tables 00172 // in a separate class. 00173 // </motivation> 00174 // 00175 // <todo asof="1995/08/22"> 00176 // <li> A record reference class, which contains some fields from another 00177 // record, would likely be useful. This would be analagous to a 00178 // subarray sliced from an existing array. 00179 // </todo> 00180 00181 00182 class TableRecord : public RecordInterface 00183 { 00184 friend class TableRecordRep; 00185 00186 public: 00187 // Create a record with no fields. 00188 // The record has a variable structure. 00189 TableRecord(); 00190 00191 // Create a record with no fields. 00192 // The type determines if the record has a fixed or variable structure. 00193 // The callback function is called when a field is added to the Record. 00194 // That function can check the name and of data type of the new field 00195 // (for instance, the Table system uses it to ensure that table columns 00196 // and keywords have different names). 00197 explicit TableRecord (RecordType type, 00198 CheckFieldFunction* = 0, 00199 const void* checkArgument = 0); 00200 00201 // Create a record with the given description. If it is not possible to 00202 // create all fields (for example, if a field with an unsupported data 00203 // type is requested), an exception is thrown. 00204 // The type determines if the record has a fixed or variable structure. 00205 // All fields are checked by the field checking function (if defined) 00206 // (for instance, the Table system uses it to ensure that table columns 00207 // and keywords have different names). 00208 explicit TableRecord (const RecordDesc& description, 00209 RecordType type = Fixed, 00210 CheckFieldFunction* = 0, 00211 const void* checkArgument = 0); 00212 00213 // Create a copy of other using copy semantics. 00214 TableRecord (const TableRecord& other); 00215 00216 // Create a TableRecord from another type of record. 00217 // It uses copy-on-write semantics if possible (i.e. if 00218 // <src>other</src> is a TableRecord), otherwise each field is copied. 00219 // Subrecords are also copied and converted to TableRecords if needed. 00220 TableRecord (const RecordInterface& other); 00221 00222 // Copy the data in the other record to this record. 00223 // It can operate in 2 ways depending on the TableRecord structure flag. 00224 // <ul> 00225 // <li> For variable structured records the existing fields are 00226 // thrown away and replaced by the new fields. 00227 // This means that RecordFieldPtr's using this record get invalidated. 00228 // Because copy-on-write semantics are used, this kind of 00229 // assignment is a very efficient operation. 00230 // <li> For fixed structured records the existing values are replaced 00231 // by the new values. This means that RecordFieldPtr's using this 00232 // record remain valid. 00233 // The structure of the other record has to conform this record 00234 // or this record has to be empty, otherwise an exception is thrown. 00235 // This assignment is less efficient, because it has to check the 00236 // conformance and because each value has to be copied. 00237 // </ul> 00238 // <note role=warning> 00239 // Attributes like fixed structure flag and check function will not 00240 // be copied. 00241 // </note> 00242 TableRecord& operator= (const TableRecord& other); 00243 00244 // Release resources associated with this object. 00245 ~TableRecord(); 00246 00247 // Make a copy of this object. 00248 virtual RecordInterface* clone() const; 00249 00250 // Assign that RecordInterface object to this one. 00251 // If <src>that</src> is a TableRecord, copy-on-write is used. 00252 // Otherwise each individual field is copied. 00253 virtual void assign (const RecordInterface& that); 00254 00255 // Convert the TableRecord to a Record (recursively). 00256 // A possible Table object is converted to a string containing 00257 // the table name preceeded by 'Table: ' (as used by TableProxy). 00258 Record toRecord() const; 00259 00260 // Fill the TableRecord from the given Record. 00261 // The fields are appended to the TableRecord. 00262 // It is the opposite of toRecord, so a String containg 'Table: ' 00263 // is handled as a Table (if it exists). 00264 void fromRecord (const Record& rec); 00265 00266 // Get or define the value as a ValueHolder. 00267 // This is useful to pass around a value of any supported type. 00268 // <group> 00269 virtual ValueHolder asValueHolder (const RecordFieldId&) const; 00270 virtual void defineFromValueHolder (const RecordFieldId&, 00271 const ValueHolder&); 00272 // </group> 00273 00274 // Get the comment for this field. 00275 virtual const String& comment (const RecordFieldId&) const; 00276 00277 // Set the comment for this field. 00278 virtual void setComment (const RecordFieldId&, const String& comment); 00279 00280 // Describes the current structure of this TableRecord. 00281 const RecordDesc& description() const; 00282 00283 // Change the structure of this TableRecord to contain the fields in 00284 // newDescription. After calling restructure, <src>description() == 00285 // newDescription</src>. Any existing RecordFieldPtr objects are 00286 // invalidated (their <src>isAttached()</src> members return False) after 00287 // this call. 00288 // <br>When the new description contains subrecords, those subrecords 00289 // will be restructured if <src>recursive=True</src> is given. 00290 // Otherwise the subrecord is a variable empty record. 00291 // Subrecords will be variable if their description is empty (i.e. does 00292 // not contain any field), otherwise they are fixed. 00293 // <br>Restructuring is not possible and an exception is thrown 00294 // if the Record has a fixed structure. 00295 virtual void restructure (const RecordDesc& newDescription, 00296 Bool recursive=True); 00297 00298 // Returns True if this and other have the same RecordDesc, other 00299 // than different names for the fields. That is, the number, type and the 00300 // order of the fields must be identical (recursively for fixed 00301 // structured sub-Records in this). 00302 // <note role=caution> 00303 // <src>thisRecord.conform(thatRecord) == True</src> does not imply 00304 // <br><src>thatRecord.conform(thisRecord) == True</src>, because 00305 // a variable record in one conforms a fixed record in that, but 00306 // not vice-versa. 00307 // </note> 00308 Bool conform (const TableRecord& other) const; 00309 00310 // How many fields does this structure have? A convenient synonym for 00311 // <src>description().nfields()</src>. 00312 virtual uInt nfields() const; 00313 00314 // Get the field number from the field name. 00315 // -1 is returned if the field name is unknown. 00316 virtual Int fieldNumber (const String& fieldName) const; 00317 00318 // Get the data type of this field. 00319 virtual DataType type (Int whichField) const; 00320 00321 // Remove a field from the record. 00322 // <note role=caution> 00323 // Removing a field means that the field number of the fields following 00324 // it will be decremented. Only the RecordFieldPtr's 00325 // pointing to the removed field will be invalidated. 00326 // </note> 00327 void removeField (const RecordFieldId&); 00328 00329 // Rename the given field. 00330 void renameField (const String& newName, const RecordFieldId&); 00331 00332 // Define a value for the given field. 00333 // When the field is unknown, it will be added to the record. 00334 // The second version is meant for any type of record (e.g. Record, 00335 // TableRecord, GlishRecord). It is converted to a TableRecord using the 00336 // TableRecord constructor taking a RecordInterface object. 00337 // <group> 00338 void defineRecord (const RecordFieldId&, const TableRecord& value, 00339 RecordType type = Variable); 00340 virtual void defineRecord (const RecordFieldId&, 00341 const RecordInterface& value, 00342 RecordType = Variable); 00343 void defineTable (const RecordFieldId&, const Table& value, 00344 RecordType type = Variable); 00345 // </group> 00346 00347 // Get the subrecord or table from the given field. 00348 // <note> 00349 // The non-const version has a different name to prevent that the 00350 // copy-on-write mechanism makes a copy when not necessary. 00351 // </note> 00352 // <group> 00353 const TableRecord& subRecord (const RecordFieldId&) const; 00354 TableRecord& rwSubRecord (const RecordFieldId&); 00355 virtual const RecordInterface& asRecord (const RecordFieldId&) const; 00356 virtual RecordInterface& asrwRecord (const RecordFieldId&); 00357 // </group> 00358 00359 // Get the table from the given field. 00360 // By default the read/write option and lock options are inherited 00361 // from the parent table. 00362 // If openWritable=True, the table is still opened as readonly if the file 00363 // permissions do not permit write access. 00364 // <group> 00365 Table asTable (const RecordFieldId&) const; 00366 Table asTable (const RecordFieldId&, const TableLock& lockOptions) const; 00367 // </group> 00368 00369 // Get the attributes of a table field. 00370 const TableAttr& tableAttributes (const RecordFieldId&) const; 00371 00372 // Merge a field from another record into this record. 00373 // The DuplicatesFlag (as described in 00374 // <linkto class=RecordInterface>RecordInterface</linkto>) determines 00375 // what will be done in case the field name already exists. 00376 void mergeField (const TableRecord& other, const RecordFieldId&, 00377 DuplicatesFlag = ThrowOnDuplicates); 00378 00379 // Merge all fields from the other record into this record. 00380 // The DuplicatesFlag (as described in 00381 // <linkto class=RecordInterface>RecordInterface</linkto>) determines 00382 // what will be done in case a field name already exists. 00383 // An exception will be thrown if other is the same as this 00384 // (i.e. if merging the record itself). 00385 void merge (const TableRecord& other, DuplicatesFlag = ThrowOnDuplicates); 00386 00387 // Close the table in the given field. 00388 // When accessed again, it will be opened automatically. 00389 // This can be useful to save memory usage. 00390 void closeTable (const RecordFieldId&) const; 00391 00392 // Close all open tables. 00393 // When accessed again, it will be opened automatically. 00394 // This can be useful to save memory usage. 00395 void closeTables() const; 00396 00397 // Flush all open subtables. 00398 void flushTables (Bool fsync=False) const; 00399 00400 // Rename the subtables with a path containing the old parent table name. 00401 void renameTables (const String& newParentName, 00402 const String& oldParentName); 00403 00404 // Are subtables used in other processes. 00405 Bool areTablesMultiUsed() const; 00406 00407 // Write the TableRecord to an output stream. 00408 friend AipsIO& operator<< (AipsIO& os, const TableRecord& rec); 00409 00410 // Read the TableRecord from an input stream. 00411 friend AipsIO& operator>> (AipsIO& os, TableRecord& rec); 00412 00413 // Put the data of a record. 00414 // This is used to write a subrecord, whose description has 00415 // not been written. 00416 void putRecord (AipsIO& os, const TableAttr&) const; 00417 00418 // Read a record. 00419 // This is used to read a subrecord, whose description has 00420 // not been read. 00421 void getRecord (AipsIO& os, const TableAttr&); 00422 00423 // Put the data of a record. 00424 // This is used to write a subrecord, whose description has 00425 // already been written. 00426 void putData (AipsIO& os, const TableAttr&) const; 00427 00428 // Read the data of a record. 00429 // This is used to read a subrecord, whose description has 00430 // already been read. 00431 void getData (AipsIO& os, uInt version, const TableAttr&); 00432 00433 // Print the contents of the record. 00434 // Only the first <src>maxNrValues</src> of an array will be printed. 00435 // A value < 0 means the entire array. 00436 virtual void print (std::ostream&, 00437 Int maxNrValues = 25, 00438 const String& indent="") const; 00439 00440 // Reopen possible tables in keywords as read/write. 00441 // Tables are not reopened if they are not writable. 00442 void reopenRW(); 00443 00444 // Recursively set the attributes of subtables to the ones in the other 00445 // record for matching subtable field names. Otherwise set it to defaultAttr. 00446 // The name attribute is not changed. 00447 // It is primarily a helper function for PlainTable::syncTable 00448 // and ColumnSet::syncColumns. 00449 // <br>However, it can also be used to achieve that all subtables of a 00450 // read/write table are opened as readonly. E.g.: 00451 // <srcblock> 00452 // TableAttr newAttr(String(), False, mainTable.lockOptions()); 00453 // mainTable.keywordSet().setTableAttr (TableRecord(), newAttr); 00454 // </srcblock> 00455 void setTableAttr (const TableRecord& other, const TableAttr& defaultAttr); 00456 00457 // Make a unique record representation 00458 // (to do copy-on-write in RecordFieldPtr). 00459 virtual void makeUnique(); 00460 00461 00462 protected: 00463 // Used by the RecordField classes to attach in a type-safe way to the 00464 // correct field. 00465 // <group> 00466 virtual void* get_pointer (Int whichField, DataType type) const; 00467 virtual void* get_pointer (Int whichField, DataType type, 00468 const String& recordType) const; 00469 // </group> 00470 00471 // Return a const reference to the underlying TableRecordRep. 00472 const TableRecordRep& ref() const; 00473 00474 // Return a non-const reference to the underlying TableRecordRep. 00475 // When needed, the TableRecordRep will be copied and all RecordField 00476 // objects will be notified. 00477 TableRecordRep& rwRef(); 00478 00479 // Add a field to the record. 00480 virtual void addDataField (const String& name, DataType type, 00481 const IPosition& shape, Bool fixedShape, 00482 const void* value); 00483 00484 // Define a value in the given field. 00485 virtual void defineDataField (Int whichField, DataType type, 00486 const void* value); 00487 00488 private: 00489 // Get the description of this record. 00490 virtual RecordDesc getDescription() const; 00491 00492 // Create TableRecord as a subrecord. 00493 // When the description is empty, the record has a variable structure. 00494 // Otherwise it is fixed. 00495 // <group> 00496 TableRecord (TableRecordRep* parent, const RecordDesc& description); 00497 TableRecord (TableRecordRep* parent, RecordType type); 00498 // </group> 00499 00500 // Set the recordtype of this record and all its subrecords (recursively). 00501 void setRecordType (RecordType type); 00502 00503 // The TableRecord representation. 00504 COWPtr<TableRecordRep> rep_p; 00505 // The parent TableRecord. 00506 TableRecordRep* parent_p; 00507 }; 00508 00509 00510 00511 inline const TableRecordRep& TableRecord::ref() const 00512 { 00513 return rep_p.ref(); 00514 } 00515 inline const RecordDesc& TableRecord::description() const 00516 { 00517 return ref().description(); 00518 } 00519 00520 inline Bool TableRecord::conform (const TableRecord& other) const 00521 { 00522 return ref().conform (other.ref()); 00523 } 00524 00525 inline void TableRecord::putData (AipsIO& os, 00526 const TableAttr& parentAttr) const 00527 { 00528 ref().putData (os, parentAttr); 00529 } 00530 00531 inline void TableRecord::getData (AipsIO& os, uInt version, 00532 const TableAttr& parentAttr) 00533 { 00534 rwRef().getData (os, version, parentAttr); 00535 } 00536 00537 inline void TableRecord::reopenRW() 00538 { 00539 rwRef().reopenRW(); 00540 } 00541 00542 inline void TableRecord::closeTables() const 00543 { 00544 ref().closeTables(); 00545 } 00546 00547 inline void TableRecord::flushTables (Bool fsync) const 00548 { 00549 ref().flushTables (fsync); 00550 } 00551 00552 inline void TableRecord::renameTables (const String& newParentName, 00553 const String& oldParentName) 00554 { 00555 rwRef().renameTables (newParentName, oldParentName); 00556 } 00557 00558 inline Bool TableRecord::areTablesMultiUsed() const 00559 { 00560 return ref().areTablesMultiUsed(); 00561 } 00562 00563 00564 00565 } //# NAMESPACE CASACORE - END 00566 00567 #endif