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