casa
$Rev:20696$
|
00001 //# Record.h: A hierarchical collection of named fields of various types 00002 //# Copyright (C) 1995,1996,1997,1998,2000,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 //# 00027 //# $Id: Record.h 20551 2009-03-25 00:11:33Z Malte.Marquarding $ 00028 00029 00030 #ifndef CASA_RECORD_H 00031 #define CASA_RECORD_H 00032 00033 //# Includes 00034 #include <casa/aips.h> 00035 #include <casa/Containers/RecordInterface.h> 00036 #include <casa/Containers/RecordRep.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 ValueHolder; 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="tRecord"> 00055 // </reviewed> 00056 00057 // <prerequisite> 00058 // <li> <linkto class="RecordDesc">RecordDesc</linkto>. 00059 // <li> <linkto class="RecordInterface">RecordInterface</linkto>. 00060 // <li> <linkto class="RecordFieldPtr">RecordFieldPtr</linkto>. 00061 // </prerequisite> 00062 00063 // <etymology> 00064 // ``Record'' is a widely used term in both programming languages and data 00065 // structures to denote an imhogeneous set of fields. An alternative would 00066 // have been to name it <em>struct</em>ure, which would have perhaps been 00067 // a clearer name for C++ programmers. 00068 // </etymology> 00069 00070 // <synopsis> 00071 // Class <linkto class=RecordInterface>RecordInterface</linkto> decribes 00072 // the fundamental properties of records. 00073 // <br> 00074 // The Record class is a particular type of a record class. 00075 // The fields in Record may be of scalar type, array type, or a Record. 00076 // The types are chosen to be compatible with the native 00077 // types of the Table system, viz: Bool, uChar, Short, Int, uInt, float, 00078 // double, Complex, DComplex, String. 00079 // Arrays of all these types are also available. 00080 // Note that a Record is not a space-efficient way of storing small objects. 00081 // <p> 00082 // The structure of a Record is defined by the <linkto class="RecordDesc"> 00083 // RecordDesc</linkto> class. The structure of the Record can be defined at 00084 // construction time. It can thereafter be restructured. This has the 00085 // effect, however, that any existing RecordFieldPtr objects become 00086 // invalid (using the <linkto file="Notice.h">Notice</linkto> classes). 00087 // <br> 00088 // It is possible to add or remove fields once a Record is constructed. 00089 // However, this is not possible when the Record is constructed with a 00090 // fixed structure (i.e. with the fixedStructure flag set). 00091 // <p> 00092 // A Record is an hierarchical structure, because it can have fields 00093 // containing Record's (as layed out in the RecordDesc). A subrecord 00094 // has a variable structure, when its RecordDesc is empty (i.e. contains 00095 // no fields). It is fixed when its RecordDesc contains fields. 00096 // <p> 00097 // A Record may be assigned to another only if they conform; that is if their 00098 // fields have the identical type in the identical order. 00099 // The field names do not need to be identical however, only the types. 00100 // That is, the structure needs to be identical, but 00101 // not the labels. Note that field order is significant, 00102 // <src>[ifield(type=Int),ffield(type=float)]</src> 00103 // is not the same as <src>[ffield(type=float),ifield(type=Int)]</src> 00104 // <br> 00105 // Conformance is checked recursively for fixed subrecords. That is, a 00106 // variable structured subrecord is not checked, because any record 00107 // can be assigned to it. A fixed structured subrecord has to 00108 // conform the corresponding subrecord in the source. 00109 // <p> 00110 // Record uses copy-on-write semantics. This means that when a Record 00111 // is copied, only the pointer to the underlying RecordRep object is copied. 00112 // Only when the Record gets changed (i.e. when a non-const Record member 00113 // function is called), the RecordRep object is copied. 00114 // This results in a cheap copy behaviour. 00115 // </synopsis> 00116 00117 // <example> 00118 // Suppose we wanted to create a records that describe the favorite example 00119 // of the OO world - an employee: 00120 // <srcBlock> 00121 // RecordDesc employeeDesc; 00122 // employeeDesc.addField ("name", TpString); 00123 // employeeDesc.addField ("salary", TpDouble); 00124 // </srcBlock> 00125 // The above creates the description (structure) for some record objects. 00126 // <srcBlock> 00127 // Record employeeA(employeeDesc); 00128 // Record employeeB(employeeDesc, False); 00129 // </srcBlock> 00130 // And these two lines create Record objects which share this common structure. 00131 // The first Record has a fixed structure, the 2nd variable. 00132 // <srcBlock> 00133 // RecordFieldPtr<String> nameA(employeeA, 0); 00134 // RecordFieldPtr<String> nameB(employeeB, 0); 00135 // RecordFieldPtr<double> salaryA(employeeA, 1); 00136 // RecordFieldPtr<double> salaryB(employeeB, "salary"); 00137 // </srcBlock> 00138 // This shows how we can get access to the individual fields. The fields are 00139 // fundamentally identified by number, but the number can be looked up through 00140 // the use of the fieldNumber member function. 00141 // <srcBlock> 00142 // nameA.define ("Tim"); 00143 // nameB.define ("Brian"); 00144 // salaryA.define (1.0e+8); 00145 // salaryB.define (1.0 / *salaryA); 00146 // </srcBlock> 00147 // Once obtained, the fields are readily manipulated, as shown above. Note 00148 // that the field values are obtained through the dereference (<src>*</src>) 00149 // operator. This is to identify that the field objects are <em>pointers</em> 00150 // to the values in the underlying Record; that is 00151 // <srcBlock> 00152 // salaryA = salaryB; 00153 // *salaryA = *salaryB; 00154 // </srcBlock> 00155 // Do very different things; the first line is a pointer copy; salaryA and 00156 // salaryB now point to the same field in salaryB. The second line is a value 00157 // copy. 00158 // 00159 // Whole records can be copied as long as their structures are compatible, so 00160 // that <src> employeeA = employeeB </src> is a legal statement. However, if 00161 // the structure is changed, assignment is no longer possible, and all of the 00162 // field pointers are invalidated: 00163 // <srcBlock> 00164 // employeeB.define ("age", (Int)40); 00165 // employeeA = employeeB; // exception - no longer conformant 00166 // </srcBlock> 00167 // </example> 00168 00169 // <motivation> 00170 // Collections of data with different types are frequently needed. 00171 // Record makes it possible to hold such data in a flexible way. 00172 // </motivation> 00173 00174 // <todo asof="1996/03/12"> 00175 // <li> A record reference class, which contains some fields from another 00176 // record, would likely be useful. This would be analagous to a 00177 // subarray sliced from an existing array. 00178 // </todo> 00179 00180 00181 class Record : public RecordInterface 00182 { 00183 friend class RecordRep; 00184 00185 public: 00186 // Create a record with no fields. 00187 // The record has a variable structure. 00188 Record(); 00189 00190 // Create a record with no fields. 00191 // The type determines if the record has a fixed or variable structure. 00192 // The callback function is called when a field is added to the Record. 00193 // That function can check the name and of data type of the new field 00194 // (for instance, the Table system uses it to ensure that table columns 00195 // and keywords have different names). 00196 explicit Record (RecordType type, 00197 CheckFieldFunction* = 0, const void* checkArgument = 0); 00198 00199 // Create a record with the given description. If it is not possible to 00200 // create all fields (for example, if a field with an unsupported data 00201 // type is requested), an exception is thrown. 00202 // The type determines if the record has a fixed or variable structure. 00203 // All fields are checked by the field checking function (if defined) 00204 // (for instance, the Table system uses it to ensure that table columns 00205 // and keywords have different names). 00206 explicit Record (const RecordDesc& description, RecordType type = Fixed, 00207 CheckFieldFunction* = 0, const void* checkArgument = 0); 00208 00209 // Create a copy of other using copy semantics. 00210 Record (const Record& other); 00211 00212 // Create a Record from another type of record using copy semantics. 00213 // Subrecords are also converted to a Record. 00214 Record (const RecordInterface& other); 00215 00216 // Copy the data in the other record to this record. 00217 // It can operate in 2 ways depending on the Record structure flag. 00218 // <ul> 00219 // <li> For variable structured records the existing fields are 00220 // thrown away and replaced by the new fields. 00221 // This means that RecordFieldPtr's using this record get invalidated. 00222 // Because copy-on-write semantics are used, this kind of 00223 // assignment is a very efficient operation. 00224 // <li> For fixed structured records the existing values are replaced 00225 // by the new values. This means that RecordFieldPtr's using this 00226 // record remain valid. 00227 // The structure of the other record has to conform this record 00228 // or this record has to be empty, otherwise an exception is thrown. 00229 // This assignment is less efficient, because it has to check the 00230 // conformance and because each value has to be copied. 00231 // </ul> 00232 // <note role=warning> 00233 // Attributes like fixed structure flag and check function will not 00234 // be copied. 00235 // </note> 00236 Record& operator= (const Record& other); 00237 00238 // Release resources associated with this object. 00239 ~Record(); 00240 00241 // Make a copy of this object. 00242 virtual RecordInterface* clone() const; 00243 00244 // Assign that RecordInterface object to this one. 00245 // Unlike <src>operator=</src> it copies all data in the derived 00246 // class. 00247 virtual void assign (const RecordInterface& that); 00248 00249 // Get the comment for this field. 00250 virtual const String& comment (const RecordFieldId&) const; 00251 00252 // Set the comment for this field. 00253 virtual void setComment (const RecordFieldId&, const String& comment); 00254 00255 // Describes the current structure of this Record. 00256 const RecordDesc& description() const; 00257 00258 // Change the structure of this Record to contain the fields in 00259 // newDescription. After calling restructure, <src>description() == 00260 // newDescription</src>. Any existing RecordFieldPtr objects are 00261 // invalidated (their <src>isAttached()</src> members return False) after 00262 // this call. 00263 // <br>When the new description contains subrecords, those subrecords 00264 // will be restructured if <src>recursive=True</src> is given. 00265 // Otherwise the subrecord is a variable empty record. 00266 // Subrecords will be variable if their description is empty (i.e. does 00267 // not contain any field), otherwise they are fixed. The 2nd form of 00268 // the <src>restructure</src> function will overwrite those implicit 00269 // record types with the given record type. The new type will also 00270 // be given to this top record. 00271 // <br>Restructuring is not possible and an exception is thrown 00272 // if the Record has a fixed structure. 00273 virtual void restructure (const RecordDesc& newDescription, 00274 Bool recursive = True); 00275 00276 // Returns True if this and other have the same RecordDesc, other 00277 // than different names for the fields. That is, the number, type and the 00278 // order of the fields must be identical (recursively for fixed 00279 // structured sub-Records in this). 00280 // <note role=caution> 00281 // <src>thisRecord.conform(thatRecord) == True</src> does not imply 00282 // <br><src>thatRecord.conform(thisRecord) == True</src>, because 00283 // a variable record in one conforms a fixed record in that, but 00284 // not vice-versa. 00285 // </note> 00286 Bool conform (const Record& other) const; 00287 00288 // How many fields does this structure have? A convenient synonym for 00289 // <src>description().nfields()</src>. 00290 virtual uInt nfields() const; 00291 00292 // Get the field number from the field name. 00293 // -1 is returned if the field name is unknown. 00294 virtual Int fieldNumber (const String& fieldName) const; 00295 00296 // Get the data type of this field. 00297 virtual DataType type (Int whichField) const; 00298 00299 // Remove a field from the record. 00300 // <note role=caution> 00301 // Removing a field means that the field number of the fields following 00302 // it will be decremented. Only the RecordFieldPtr's 00303 // pointing to the removed field will be invalidated. 00304 // </note> 00305 void removeField (const RecordFieldId&); 00306 00307 // Rename the given field. 00308 void renameField (const String& newName, const RecordFieldId&); 00309 00310 // Define a value for the given field containing a subrecord. 00311 // When the field is unknown, it will be added to the record. 00312 // The second version is meant for any type of record (e.g. Record, 00313 // TableRecord, GlishRecord). It is converted to a Record using the 00314 // Record constructor taking a RecordInterface object. 00315 // <group> 00316 void defineRecord (const RecordFieldId&, const Record& value, 00317 RecordType type = Variable); 00318 virtual void defineRecord (const RecordFieldId&, 00319 const RecordInterface& value, 00320 RecordType = Variable); 00321 // </group> 00322 00323 // Get the subrecord from the given field. 00324 // <note> 00325 // The non-const version has a different name to prevent that the 00326 // copy-on-write mechanism makes a copy when not necessary. 00327 // </note> 00328 // <group> 00329 const Record& subRecord (const RecordFieldId&) const; 00330 Record& rwSubRecord (const RecordFieldId&); 00331 virtual const RecordInterface& asRecord (const RecordFieldId&) const; 00332 virtual RecordInterface& asrwRecord (const RecordFieldId&); 00333 // </group> 00334 00335 // Get or define the value as a ValueHolder. 00336 // This is useful to pass around a value of any supported type. 00337 // <group> 00338 ValueHolder asValueHolder (const RecordFieldId&) const; 00339 void defineFromValueHolder (const RecordFieldId&, const ValueHolder&); 00340 // </group> 00341 00342 // Merge a field from another record into this record. 00343 // The DuplicatesFlag (as described in 00344 // <linkto class=RecordInterface>RecordInterface</linkto>) determines 00345 // what will be done in case the field name already exists. 00346 void mergeField (const Record& other, const RecordFieldId&, 00347 DuplicatesFlag = ThrowOnDuplicates); 00348 00349 // Merge all fields from the other record into this record. 00350 // The DuplicatesFlag (as described in 00351 // <linkto class=RecordInterface>RecordInterface</linkto>) determines 00352 // what will be done in case a field name already exists. 00353 // An exception will be thrown if other is the same as this 00354 // (i.e. if merging the record itself). 00355 void merge (const Record& other, DuplicatesFlag = ThrowOnDuplicates); 00356 00357 // Write the Record to an output stream. 00358 friend AipsIO& operator<< (AipsIO& os, const Record& rec); 00359 00360 // Read the Record from an input stream. 00361 friend AipsIO& operator>> (AipsIO& os, Record& rec); 00362 00363 // Write the Record to an output stream. 00364 // This is used to write a subrecord, whose description has 00365 // not been written. 00366 void putRecord (AipsIO& os) const; 00367 00368 // Read the Record from an input stream. 00369 // This is used to read a subrecord, whose description has 00370 // not been read. 00371 void getRecord (AipsIO& os); 00372 00373 // Put the data of a record. 00374 // This is used to write a subrecord, whose description has 00375 // already been written. 00376 void putData (AipsIO& os) const; 00377 00378 // Read the data of a record. 00379 // This is used to read a subrecord, whose description has 00380 // already been read. 00381 void getData (AipsIO& os, uInt version); 00382 00383 // Make a unique record representation 00384 // (to do copy-on-write in RecordFieldPtr). 00385 virtual void makeUnique(); 00386 00387 // Print the contents of the record. 00388 // Only the first <src>maxNrValues</src> of an array will be printed. 00389 // A value < 0 means the entire array. 00390 virtual void print (std::ostream&, 00391 Int maxNrValues = 25, 00392 const String& indent="") const; 00393 00394 00395 protected: 00396 // Used by the RecordField classes to attach in a type-safe way to the 00397 // correct field. 00398 // <group> 00399 virtual void* get_pointer (Int whichField, DataType type) const; 00400 virtual void* get_pointer (Int whichField, DataType type, 00401 const String& recordType) const; 00402 // </group> 00403 00404 // Return a const reference to the underlying RecordRep. 00405 const RecordRep& ref() const; 00406 00407 // Return a non-const reference to the underlying RecordRep. 00408 // When needed, the RecordRep will be copied and all RecordField 00409 // objects will be notified. 00410 RecordRep& rwRef(); 00411 00412 // Add a field to the record. 00413 virtual void addDataField (const String& name, DataType type, 00414 const IPosition& shape, Bool fixedShape, 00415 const void* value); 00416 00417 // Define a value in the given field. 00418 virtual void defineDataField (Int whichField, DataType type, 00419 const void* value); 00420 00421 private: 00422 // Get the description of this record. 00423 virtual RecordDesc getDescription() const; 00424 00425 // Create Record as a subrecord. 00426 // When the description is empty, the record has a variable structure. 00427 // Otherwise it is fixed. 00428 // <group> 00429 Record (RecordRep* parent, const RecordDesc& description); 00430 Record (RecordRep* parent, RecordType type); 00431 // </group> 00432 00433 // The Record representation. 00434 COWPtr<RecordRep> rep_p; 00435 // The parent Record. 00436 RecordRep* parent_p; 00437 }; 00438 00439 00440 00441 inline const RecordRep& Record::ref() const 00442 { 00443 return rep_p.ref(); 00444 } 00445 inline const RecordDesc& Record::description() const 00446 { 00447 return ref().description(); 00448 } 00449 00450 inline Bool Record::conform (const Record& other) const 00451 { 00452 return ref().conform (other.ref()); 00453 } 00454 00455 inline AipsIO& operator<< (AipsIO& os, const Record& rec) 00456 { 00457 rec.putRecord (os); 00458 return os; 00459 } 00460 inline void Record::putData (AipsIO& os) const 00461 { 00462 ref().putData (os); 00463 } 00464 00465 inline AipsIO& operator>> (AipsIO& os, Record& rec) 00466 { 00467 rec.getRecord (os); 00468 return os; 00469 } 00470 inline void Record::getData (AipsIO& os, uInt version) 00471 { 00472 rwRef().getData (os, version); 00473 } 00474 00475 00476 00477 00478 } //# NAMESPACE CASA - END 00479 00480 #endif