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$ 00028 00029 00030 #ifndef CASA_RECORD_H 00031 #define CASA_RECORD_H 00032 00033 //# Includes 00034 #include <casacore/casa/aips.h> 00035 #include <casacore/casa/Containers/RecordInterface.h> 00036 #include <casacore/casa/Containers/RecordRep.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 00047 00048 // <summary> 00049 // A hierarchical collection of named fields of various types 00050 // </summary> 00051 00052 // <use visibility=export> 00053 // <reviewed reviewer="Mark Wieringa" date="1996/04/15" tests="tRecord"> 00054 // </reviewed> 00055 00056 // <prerequisite> 00057 // <li> <linkto class="RecordDesc">RecordDesc</linkto>. 00058 // <li> <linkto class="RecordInterface">RecordInterface</linkto>. 00059 // <li> <linkto class="RecordFieldPtr">RecordFieldPtr</linkto>. 00060 // </prerequisite> 00061 00062 // <etymology> 00063 // ``Record'' is a widely used term in both programming languages and data 00064 // structures to denote an imhogeneous set of fields. An alternative would 00065 // have been to name it <em>struct</em>ure, which would have perhaps been 00066 // a clearer name for C++ programmers. 00067 // </etymology> 00068 00069 // <synopsis> 00070 // Class <linkto class=RecordInterface>RecordInterface</linkto> decribes 00071 // the fundamental properties of records. 00072 // <br> 00073 // The Record class is a particular type of a record class. 00074 // The fields in Record may be of scalar type, array type, or a Record. 00075 // The types are chosen to be compatible with the native 00076 // types of the Table system, viz: Bool, uChar, Short, Int, uInt, float, 00077 // double, Complex, DComplex, String. 00078 // Arrays of all these types are also available. 00079 // Note that a Record is not a space-efficient way of storing small objects. 00080 // <p> 00081 // The structure of a Record is defined by the <linkto class="RecordDesc"> 00082 // RecordDesc</linkto> class. The structure of the Record 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 Record is constructed. 00088 // However, this is not possible when the Record is constructed with a 00089 // fixed structure (i.e. with the fixedStructure flag set). 00090 // <p> 00091 // A Record is an hierarchical structure, because it can have fields 00092 // containing Record'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 Record may be assigned to another only if they conform; that is if their 00097 // 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 // <p> 00109 // Record uses copy-on-write semantics. This means that when a Record 00110 // is copied, only the pointer to the underlying RecordRep object is copied. 00111 // Only when the Record gets changed (i.e. when a non-const Record member 00112 // function is called), the RecordRep object is copied. 00113 // This results in a cheap copy behaviour. 00114 // </synopsis> 00115 00116 // <example> 00117 // Suppose we wanted to create a records that describe the favorite example 00118 // of the OO world - an employee: 00119 // <srcBlock> 00120 // RecordDesc employeeDesc; 00121 // employeeDesc.addField ("name", TpString); 00122 // employeeDesc.addField ("salary", TpDouble); 00123 // </srcBlock> 00124 // The above creates the description (structure) for some record objects. 00125 // <srcBlock> 00126 // Record employeeA(employeeDesc); 00127 // Record employeeB(employeeDesc, False); 00128 // </srcBlock> 00129 // And these two lines create Record objects which share this common structure. 00130 // The first Record has a fixed structure, the 2nd variable. 00131 // <srcBlock> 00132 // RecordFieldPtr<String> nameA(employeeA, 0); 00133 // RecordFieldPtr<String> nameB(employeeB, 0); 00134 // RecordFieldPtr<double> salaryA(employeeA, 1); 00135 // RecordFieldPtr<double> salaryB(employeeB, "salary"); 00136 // </srcBlock> 00137 // This shows how we can get access to the individual fields. The fields are 00138 // fundamentally identified by number, but the number can be looked up through 00139 // the use of the fieldNumber member function. 00140 // <srcBlock> 00141 // nameA.define ("Tim"); 00142 // nameB.define ("Brian"); 00143 // salaryA.define (1.0e+8); 00144 // salaryB.define (1.0 / *salaryA); 00145 // </srcBlock> 00146 // Once obtained, the fields are readily manipulated, as shown above. Note 00147 // that the field values are obtained through the dereference (<src>*</src>) 00148 // operator. This is to identify that the field objects are <em>pointers</em> 00149 // to the values in the underlying Record; that is 00150 // <srcBlock> 00151 // salaryA = salaryB; 00152 // *salaryA = *salaryB; 00153 // </srcBlock> 00154 // Do very different things; the first line is a pointer copy; salaryA and 00155 // salaryB now point to the same field in salaryB. The second line is a value 00156 // copy. 00157 // 00158 // Whole records can be copied as long as their structures are compatible, so 00159 // that <src> employeeA = employeeB </src> is a legal statement. However, if 00160 // the structure is changed, assignment is no longer possible, and all of the 00161 // field pointers are invalidated: 00162 // <srcBlock> 00163 // employeeB.define ("age", (Int)40); 00164 // employeeA = employeeB; // exception - no longer conformant 00165 // </srcBlock> 00166 // </example> 00167 00168 // <motivation> 00169 // Collections of data with different types are frequently needed. 00170 // Record makes it possible to hold such data in a flexible way. 00171 // </motivation> 00172 00173 // <todo asof="1996/03/12"> 00174 // <li> A record reference class, which contains some fields from another 00175 // record, would likely be useful. This would be analagous to a 00176 // subarray sliced from an existing array. 00177 // </todo> 00178 00179 00180 class Record : public RecordInterface 00181 { 00182 friend class RecordRep; 00183 00184 public: 00185 // Create a record with no fields. 00186 // The record has a variable structure. 00187 Record(); 00188 00189 // Create a record with no fields. 00190 // The type determines if the record has a fixed or variable structure. 00191 // The callback function is called when a field is added to the Record. 00192 // That function can check the name and of data type of the new field 00193 // (for instance, the Table system uses it to ensure that table columns 00194 // and keywords have different names). 00195 explicit Record (RecordType type, 00196 CheckFieldFunction* = 0, const void* checkArgument = 0); 00197 00198 // Create a record with the given description. If it is not possible to 00199 // create all fields (for example, if a field with an unsupported data 00200 // type is requested), an exception is thrown. 00201 // The type determines if the record has a fixed or variable structure. 00202 // All fields are checked by the field checking function (if defined) 00203 // (for instance, the Table system uses it to ensure that table columns 00204 // and keywords have different names). 00205 explicit Record (const RecordDesc& description, RecordType type = Fixed, 00206 CheckFieldFunction* = 0, const void* checkArgument = 0); 00207 00208 // Create a copy of other using copy semantics. 00209 Record (const Record& other); 00210 00211 // Create a Record from another type of record using copy semantics. 00212 // Subrecords are also converted to a Record. 00213 Record (const RecordInterface& other); 00214 00215 // Copy the data in the other record to this record. 00216 // It can operate in 2 ways depending on the Record structure flag. 00217 // <ul> 00218 // <li> For variable structured records the existing fields are 00219 // thrown away and replaced by the new fields. 00220 // This means that RecordFieldPtr's using this record get invalidated. 00221 // Because copy-on-write semantics are used, this kind of 00222 // assignment is a very efficient operation. 00223 // <li> For fixed structured records the existing values are replaced 00224 // by the new values. This means that RecordFieldPtr's using this 00225 // record remain valid. 00226 // The structure of the other record has to conform this record 00227 // or this record has to be empty, otherwise an exception is thrown. 00228 // This assignment is less efficient, because it has to check the 00229 // conformance and because each value has to be copied. 00230 // </ul> 00231 // <note role=warning> 00232 // Attributes like fixed structure flag and check function will not 00233 // be copied. 00234 // </note> 00235 Record& operator= (const Record& other); 00236 00237 // Release resources associated with this object. 00238 ~Record(); 00239 00240 // Make a copy of this object. 00241 virtual RecordInterface* clone() const; 00242 00243 // Assign that RecordInterface object to this one. 00244 // Unlike <src>operator=</src> it copies all data in the derived 00245 // class. 00246 virtual void assign (const RecordInterface& that); 00247 00248 // Get the comment for this field. 00249 virtual const String& comment (const RecordFieldId&) const; 00250 00251 // Set the comment for this field. 00252 virtual void setComment (const RecordFieldId&, const String& comment); 00253 00254 // Describes the current structure of this Record. 00255 const RecordDesc& description() const; 00256 00257 // Change the structure of this Record to contain the fields in 00258 // newDescription. After calling restructure, <src>description() == 00259 // newDescription</src>. Any existing RecordFieldPtr objects are 00260 // invalidated (their <src>isAttached()</src> members return False) after 00261 // this call. 00262 // <br>When the new description contains subrecords, those subrecords 00263 // will be restructured if <src>recursive=True</src> is given. 00264 // Otherwise the subrecord is a variable empty record. 00265 // Subrecords will be variable if their description is empty (i.e. does 00266 // not contain any field), otherwise they are fixed. The 2nd form of 00267 // the <src>restructure</src> function will overwrite those implicit 00268 // record types with the given record type. The new type will also 00269 // be given to this top record. 00270 // <br>Restructuring is not possible and an exception is thrown 00271 // if the Record has a fixed structure. 00272 virtual void restructure (const RecordDesc& newDescription, 00273 Bool recursive = True); 00274 00275 // Returns True if this and other have the same RecordDesc, other 00276 // than different names for the fields. That is, the number, type and the 00277 // order of the fields must be identical (recursively for fixed 00278 // structured sub-Records in this). 00279 // <note role=caution> 00280 // <src>thisRecord.conform(thatRecord) == True</src> does not imply 00281 // <br><src>thatRecord.conform(thisRecord) == True</src>, because 00282 // a variable record in one conforms a fixed record in that, but 00283 // not vice-versa. 00284 // </note> 00285 Bool conform (const Record& other) const; 00286 00287 // How many fields does this structure have? A convenient synonym for 00288 // <src>description().nfields()</src>. 00289 virtual uInt nfields() const; 00290 00291 // Get the field number from the field name. 00292 // -1 is returned if the field name is unknown. 00293 virtual Int fieldNumber (const String& fieldName) const; 00294 00295 // Get the data type of this field. 00296 virtual DataType type (Int whichField) const; 00297 00298 // Remove a field from the record. 00299 // <note role=caution> 00300 // Removing a field means that the field number of the fields following 00301 // it will be decremented. Only the RecordFieldPtr's 00302 // pointing to the removed field will be invalidated. 00303 // </note> 00304 void removeField (const RecordFieldId&); 00305 00306 // Rename the given field. 00307 void renameField (const String& newName, const RecordFieldId&); 00308 00309 // Define a value for the given field containing a subrecord. 00310 // When the field is unknown, it will be added to the record. 00311 // The second version is meant for any type of record (e.g. Record, 00312 // TableRecord, GlishRecord). It is converted to a Record using the 00313 // Record constructor taking a RecordInterface object. 00314 // <group> 00315 void defineRecord (const RecordFieldId&, const Record& value, 00316 RecordType type = Variable); 00317 virtual void defineRecord (const RecordFieldId&, 00318 const RecordInterface& value, 00319 RecordType = Variable); 00320 // </group> 00321 00322 // Get the subrecord from the given field. 00323 // <note> 00324 // The non-const version has a different name to prevent that the 00325 // copy-on-write mechanism makes a copy when not necessary. 00326 // </note> 00327 // <group> 00328 const Record& subRecord (const RecordFieldId&) const; 00329 Record& rwSubRecord (const RecordFieldId&); 00330 virtual const RecordInterface& asRecord (const RecordFieldId&) const; 00331 virtual RecordInterface& asrwRecord (const RecordFieldId&); 00332 // </group> 00333 00334 // Get or define the value as a ValueHolder. 00335 // This is useful to pass around a value of any supported type. 00336 // <group> 00337 virtual ValueHolder asValueHolder (const RecordFieldId&) const; 00338 virtual void defineFromValueHolder (const RecordFieldId&, 00339 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 CASACORE - END 00479 00480 #endif