Record.h

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1