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 <casa/aips.h> 00035 #include <casa/Containers/RecordInterface.h> 00036 #include <tables/Tables/TableRecordRep.h> 00037 #include <casa/Containers/RecordDesc.h> 00038 #include <casa/Utilities/COWPtr.h> 00039 00040 namespace casa { //# NAMESPACE CASA - 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 // Get the comment for this field. 00256 virtual const String& comment (const RecordFieldId&) const; 00257 00258 // Set the comment for this field. 00259 virtual void setComment (const RecordFieldId&, const String& comment); 00260 00261 // Describes the current structure of this TableRecord. 00262 const RecordDesc& description() const; 00263 00264 // Change the structure of this TableRecord to contain the fields in 00265 // newDescription. After calling restructure, <src>description() == 00266 // newDescription</src>. Any existing RecordFieldPtr objects are 00267 // invalidated (their <src>isAttached()</src> members return False) after 00268 // this call. 00269 // <br>When the new description contains subrecords, those subrecords 00270 // will be restructured if <src>recursive=True</src> is given. 00271 // Otherwise the subrecord is a variable empty record. 00272 // Subrecords will be variable if their description is empty (i.e. does 00273 // not contain any field), otherwise they are fixed. 00274 // <br>Restructuring is not possible and an exception is thrown 00275 // if the Record has a fixed structure. 00276 virtual void restructure (const RecordDesc& newDescription, 00277 Bool recursive=True); 00278 00279 // Returns True if this and other have the same RecordDesc, other 00280 // than different names for the fields. That is, the number, type and the 00281 // order of the fields must be identical (recursively for fixed 00282 // structured sub-Records in this). 00283 // <note role=caution> 00284 // <src>thisRecord.conform(thatRecord) == True</src> does not imply 00285 // <br><src>thatRecord.conform(thisRecord) == True</src>, because 00286 // a variable record in one conforms a fixed record in that, but 00287 // not vice-versa. 00288 // </note> 00289 Bool conform (const TableRecord& other) const; 00290 00291 // How many fields does this structure have? A convenient synonym for 00292 // <src>description().nfields()</src>. 00293 virtual uInt nfields() const; 00294 00295 // Get the field number from the field name. 00296 // -1 is returned if the field name is unknown. 00297 virtual Int fieldNumber (const String& fieldName) const; 00298 00299 // Get the data type of this field. 00300 virtual DataType type (Int whichField) const; 00301 00302 // Remove a field from the record. 00303 // <note role=caution> 00304 // Removing a field means that the field number of the fields following 00305 // it will be decremented. Only the RecordFieldPtr's 00306 // pointing to the removed field will be invalidated. 00307 // </note> 00308 void removeField (const RecordFieldId&); 00309 00310 // Rename the given field. 00311 void renameField (const String& newName, const RecordFieldId&); 00312 00313 // Define a value for the given field. 00314 // When the field is unknown, it will be added to the record. 00315 // The second version is meant for any type of record (e.g. Record, 00316 // TableRecord, GlishRecord). It is converted to a TableRecord using the 00317 // TableRecord constructor taking a RecordInterface object. 00318 // <group> 00319 void defineRecord (const RecordFieldId&, const TableRecord& value, 00320 RecordType type = Variable); 00321 virtual void defineRecord (const RecordFieldId&, 00322 const RecordInterface& value, 00323 RecordType = Variable); 00324 void defineTable (const RecordFieldId&, const Table& value, 00325 RecordType type = Variable); 00326 // </group> 00327 00328 // Get the subrecord or table from the given field. 00329 // <note> 00330 // The non-const version has a different name to prevent that the 00331 // copy-on-write mechanism makes a copy when not necessary. 00332 // </note> 00333 // <group> 00334 const TableRecord& subRecord (const RecordFieldId&) const; 00335 TableRecord& rwSubRecord (const RecordFieldId&); 00336 virtual const RecordInterface& asRecord (const RecordFieldId&) const; 00337 virtual RecordInterface& asrwRecord (const RecordFieldId&); 00338 // </group> 00339 00340 // Get the table from the given field. 00341 // <group> 00342 Table asTable (const RecordFieldId&) const; 00343 Table asTable (const RecordFieldId&, const TableLock& lockOptions) const; 00344 // </group> 00345 00346 // Get the attributes of a table field. 00347 const TableAttr& tableAttributes (const RecordFieldId&) const; 00348 00349 // Merge a field from another record into this record. 00350 // The DuplicatesFlag (as described in 00351 // <linkto class=RecordInterface>RecordInterface</linkto>) determines 00352 // what will be done in case the field name already exists. 00353 void mergeField (const TableRecord& other, const RecordFieldId&, 00354 DuplicatesFlag = ThrowOnDuplicates); 00355 00356 // Merge all fields from the other record into this record. 00357 // The DuplicatesFlag (as described in 00358 // <linkto class=RecordInterface>RecordInterface</linkto>) determines 00359 // what will be done in case a field name already exists. 00360 // An exception will be thrown if other is the same as this 00361 // (i.e. if merging the record itself). 00362 void merge (const TableRecord& other, DuplicatesFlag = ThrowOnDuplicates); 00363 00364 // Close the table in the given field. 00365 // When accessed again, it will be opened automatically. 00366 // This can be useful to save memory usage. 00367 void closeTable (const RecordFieldId&) const; 00368 00369 // Close all open tables. 00370 // When accessed again, it will be opened automatically. 00371 // This can be useful to save memory usage. 00372 void closeTables() const; 00373 00374 // Flush all open subtables. 00375 void flushTables (Bool fsync=False) const; 00376 00377 // Rename the subtables with a path containing the old parent table name. 00378 void renameTables (const String& newParentName, 00379 const String& oldParentName); 00380 00381 // Are subtables used in other processes. 00382 Bool areTablesMultiUsed() const; 00383 00384 // Write the TableRecord to an output stream. 00385 friend AipsIO& operator<< (AipsIO& os, const TableRecord& rec); 00386 00387 // Read the TableRecord from an input stream. 00388 friend AipsIO& operator>> (AipsIO& os, TableRecord& rec); 00389 00390 // Put the data of a record. 00391 // This is used to write a subrecord, whose description has 00392 // not been written. 00393 void putRecord (AipsIO& os, const TableAttr&) const; 00394 00395 // Read a record. 00396 // This is used to read a subrecord, whose description has 00397 // not been read. 00398 void getRecord (AipsIO& os, const TableAttr&); 00399 00400 // Put the data of a record. 00401 // This is used to write a subrecord, whose description has 00402 // already been written. 00403 void putData (AipsIO& os, const TableAttr&) const; 00404 00405 // Read the data of a record. 00406 // This is used to read a subrecord, whose description has 00407 // already been read. 00408 void getData (AipsIO& os, uInt version, const TableAttr&); 00409 00410 // Print the contents of the record. 00411 // Only the first <src>maxNrValues</src> of an array will be printed. 00412 // A value < 0 means the entire array. 00413 virtual void print (std::ostream&, 00414 Int maxNrValues = 25, 00415 const String& indent="") const; 00416 00417 // Reopen possible tables in keywords as read/write. 00418 // Tables are not reopened if they are not writable. 00419 void reopenRW(); 00420 00421 // Set the attributes of subtables to te ones in the other record. 00422 // It is primarily a helper function for PlainTable::syncTable 00423 // and ColumnSet::syncColumns. 00424 void setTableAttr (const TableRecord& other, const TableAttr& defaultAttr); 00425 00426 // Make a unique record representation 00427 // (to do copy-on-write in RecordFieldPtr). 00428 virtual void makeUnique(); 00429 00430 00431 protected: 00432 // Used by the RecordField classes to attach in a type-safe way to the 00433 // correct field. 00434 // <group> 00435 virtual void* get_pointer (Int whichField, DataType type) const; 00436 virtual void* get_pointer (Int whichField, DataType type, 00437 const String& recordType) const; 00438 // </group> 00439 00440 // Return a const reference to the underlying TableRecordRep. 00441 const TableRecordRep& ref() const; 00442 00443 // Return a non-const reference to the underlying TableRecordRep. 00444 // When needed, the TableRecordRep will be copied and all RecordField 00445 // objects will be notified. 00446 TableRecordRep& rwRef(); 00447 00448 // Add a field to the record. 00449 virtual void addDataField (const String& name, DataType type, 00450 const IPosition& shape, Bool fixedShape, 00451 const void* value); 00452 00453 // Define a value in the given field. 00454 virtual void defineDataField (Int whichField, DataType type, 00455 const void* value); 00456 00457 private: 00458 // Get the description of this record. 00459 virtual RecordDesc getDescription() const; 00460 00461 // Create TableRecord as a subrecord. 00462 // When the description is empty, the record has a variable structure. 00463 // Otherwise it is fixed. 00464 // <group> 00465 TableRecord (TableRecordRep* parent, const RecordDesc& description); 00466 TableRecord (TableRecordRep* parent, RecordType type); 00467 // </group> 00468 00469 // Set the recordtype of this record and all its subrecords (recursively). 00470 void setRecordType (RecordType type); 00471 00472 // The TableRecord representation. 00473 COWPtr<TableRecordRep> rep_p; 00474 // The parent TableRecord. 00475 TableRecordRep* parent_p; 00476 }; 00477 00478 00479 00480 inline const TableRecordRep& TableRecord::ref() const 00481 { 00482 return rep_p.ref(); 00483 } 00484 inline const RecordDesc& TableRecord::description() const 00485 { 00486 return ref().description(); 00487 } 00488 00489 inline Bool TableRecord::conform (const TableRecord& other) const 00490 { 00491 return ref().conform (other.ref()); 00492 } 00493 00494 inline void TableRecord::putData (AipsIO& os, 00495 const TableAttr& parentAttr) const 00496 { 00497 ref().putData (os, parentAttr); 00498 } 00499 00500 inline void TableRecord::getData (AipsIO& os, uInt version, 00501 const TableAttr& parentAttr) 00502 { 00503 rwRef().getData (os, version, parentAttr); 00504 } 00505 00506 inline void TableRecord::reopenRW() 00507 { 00508 rwRef().reopenRW(); 00509 } 00510 00511 inline void TableRecord::closeTables() const 00512 { 00513 ref().closeTables(); 00514 } 00515 00516 inline void TableRecord::flushTables (Bool fsync) const 00517 { 00518 ref().flushTables (fsync); 00519 } 00520 00521 inline void TableRecord::renameTables (const String& newParentName, 00522 const String& oldParentName) 00523 { 00524 rwRef().renameTables (newParentName, oldParentName); 00525 } 00526 00527 inline Bool TableRecord::areTablesMultiUsed() const 00528 { 00529 return ref().areTablesMultiUsed(); 00530 } 00531 00532 00533 00534 } //# NAMESPACE CASA - END 00535 00536 #endif
1.5.1