casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
RecordDesc.h
Go to the documentation of this file.
00001 //# RecordDesc.h: Description of the fields in a record object
00002 //# Copyright (C) 1995,1996,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: RecordDesc.h 20551 2009-03-25 00:11:33Z Malte.Marquarding $
00028 
00029 
00030 #ifndef CASA_RECORDDESC_H
00031 #define CASA_RECORDDESC_H
00032 
00033 
00034 //# Includes
00035 #include <casa/Containers/RecordDescRep.h>
00036 #include <casa/Containers/RecordInterface.h>
00037 #include <casa/Utilities/COWPtr.h>
00038 #include <casa/iosfwd.h>
00039 
00040 namespace casa { //# NAMESPACE CASA - BEGIN
00041 
00042 //# Forward Declarations
00043 class AipsIO;
00044 
00045 
00046 // <summary>
00047 // Description of the fields in a record object
00048 // </summary>
00049 
00050 // <use visibility=export>
00051 // <reviewed reviewer="Mark Wieringa" date="1996/04/15" tests="tRecordDesc">
00052 // </reviewed>
00053 
00054 // <prerequisite>
00055 //   <li> <linkto group="DataType.h#DataType">DataType</linkto>
00056 //   <li> <linkto class="Record">Record</linkto>
00057 // </prerequisite>
00058 //
00059 // <etymology>
00060 // RecordStructure would perhaps have been the clearest possible name. However
00061 // it was decided to name it ``RecordDesc'' to use a compatible naming
00062 // convention with other classes in the system, such as TableDesc. This class
00063 // <em>Desc</em>ribes the structure of a Record.
00064 // </etymology>
00065 //
00066 // <synopsis>
00067 // RecordDesc describes the structure of <linkto class="Record">Record</linkto>
00068 // objects. A Record consists of a number of fields. A RecordDesc describes 
00069 // those fields by assigning to each one:
00070 // <ul>
00071 //    <li> A name for the field.
00072 //    <li> A type from the <linkto group="DataType.h#DataType">DataType</linkto>
00073 //         enum.
00074 //    <li> A shape if the field is an array.
00075 //    <li> A RecordDesc if the field is itself a Record (the Record is an
00076 //         hierarchical structure).
00077 // </ul>
00078 // Only one field with a given name is allowed (although fields in subrecords
00079 // may have the same name as a field in a parent or child Record).
00080 //
00081 // Field indices are zero relative, i.e. they range from 0 to 
00082 // <src>nfields()-1</src>.
00083 // </synopsis>
00084 //
00085 // <example>
00086 // See the example in the description of the 
00087 // <linkto class="Record:example">Record</linkto> class.
00088 // </example>
00089 //
00090 // <motivation>
00091 // It is useful to be able to create many new objects with the same structure
00092 // as some other, without necessarily cloning it by copying all the values.
00093 // A ``Description'' type is necessary to do this (e.g., shape for an Array).
00094 // </motivation>
00095 //
00096 //
00097 // <todo asof="1995/06/01">
00098 //   <li> Should the strategy wrt. field names be changed (not used in
00099 //        field description equality, must be unique at a given level?).
00100 //   <li> Perhaps we should be able to more conveniently change the description
00101 //        of an existing field.
00102 // </todo>
00103 
00104 class RecordDesc
00105 {
00106 public:
00107     // Writes/reads the RecordDesc to/from an output stream.
00108     // <group name=io>
00109     friend ostream& operator<< (ostream& os, const RecordDesc& desc);
00110     friend AipsIO& operator<< (AipsIO& os, const RecordDesc& desc);
00111     friend AipsIO& operator>> (AipsIO& os, RecordDesc& desc);
00112     // </group>
00113 
00114     // Create a description with no fields.
00115     RecordDesc();
00116 
00117     // Create a description which is a copy of other.
00118     RecordDesc (const RecordDesc& other);
00119 
00120     // Replace this description with other.
00121     RecordDesc& operator= (const RecordDesc& other);
00122 
00123     ~RecordDesc();
00124 
00125     // Add scalar, array, sub-record, or table field.
00126     // If of array type, the shape is set to [-1], which indicates a
00127     // variable sized array.
00128     // If of sub-record type, the sub-record is free format.
00129     // Returns the number of fields in the description.
00130     uInt addField (const String& fieldName, DataType dataType);
00131 
00132     // Add an array field of the indicated type. The DataType is promoted
00133     // from a scalar type to an array type if necessary, e.g., 
00134     // <src>TpInt ->TpArrayInt</src>.  Returns the number of fields in
00135     // the description.
00136     // A shape of [-1] indicates a variable shape.
00137     uInt addField (const String& fieldName, DataType scalarOrArrayType,
00138                    const IPosition& shape);
00139 
00140     // Add a Record field to the description. This allows hierarchical
00141     // descriptions to be developed. Returns the number of fields in the
00142     // description.
00143     uInt addField (const String& fieldName, const RecordDesc& subDesc);
00144 
00145     // Add a Table field to the description. The Table description has the
00146     // given name. Returns the number of fields in the description.
00147     // <br>
00148     // When a table is put in a record field, it is checked if the name
00149     // of its description matches this name. If this name is empty, it
00150     // matches any table description.
00151     // <note role=warning>
00152     // Note that not all record types are able to instantiate a table field.
00153     // E.g. <linkto class=TableRecord>TableRecord</linkto> can instantiate
00154     // it, while <linkto class=Record>Record</linkto> cannot and throws an
00155     // exception when a record description containing a table field is used.
00156     // </note>
00157     uInt addTable (const String& fieldName, const String& tableDescName);
00158 
00159     // Get the comment for this field.
00160     const String& comment (Int whichField) const;
00161 
00162     // Set the comment for this field.
00163     void setComment (Int whichField, const String& comment);
00164 
00165     // Set the shape for this field.
00166     // An exception will be thrown if the field is no array.
00167     void setShape (Int whichField, const IPosition& shape);
00168 
00169     // Merge a single field from other.  If allowDuplicates is True, silently
00170     // throw away fields if one with the same name and type already exists,
00171     // otherwise an exception is thrown.  Conflicting types always cause an
00172     // exception. Returns the number of fields in the description.
00173     uInt mergeField (const RecordDesc& other, Int whichFieldFromOther,
00174                      RecordInterface::DuplicatesFlag DuplicateAction
00175                                        = RecordInterface::ThrowOnDuplicates);
00176 
00177     // Add all the fields from another RecordDesc to the current objects.
00178     // It returns the new number of fields.
00179     uInt merge (const RecordDesc& other, 
00180                 RecordInterface::DuplicatesFlag DuplicateAction
00181                                        = RecordInterface::ThrowOnDuplicates);
00182     
00183     // Remove the given field from the description.
00184     // It returns the new number of fields.
00185     uInt removeField (Int whichField);
00186 
00187     // Rename the given field.
00188     void renameField (const String& newName, Int whichField);
00189 
00190     // Returns the index of the field named fieldName. Returns -1 if fieldName
00191     // does not exist.
00192     Int fieldNumber (const String& fieldName) const;
00193 
00194     // Number of fields in the description.
00195     uInt nfields() const;
00196 
00197     // What is the type of the given field. Returns TpRecord if the field is
00198     // a sub-Record.
00199     DataType type (Int whichField) const;
00200 
00201     // What is the name of the given field.
00202     const String& name (Int whichField) const;
00203 
00204     // Create a name for a field defined by index as *i (similar to glish).
00205     // It takes care that the resulting name is unique by adding a suffix _j
00206     // when needed.
00207     String makeName (Int whichField) const;
00208 
00209     // Make the given name unique by adding a suffix _j when needed.
00210     // j is the minimal number needed to make it unique.
00211     String uniqueName (const String& name) const;
00212 
00213     // Returns True if whichField is an array.
00214     Bool isArray (Int whichField) const;
00215 
00216     // Returns True if whichField is a scalar.
00217     Bool isScalar (Int whichField) const;
00218 
00219     // Returns True if whichField is a sub-record.
00220     Bool isSubRecord (Int whichField) const;
00221 
00222     // Returns True if whichField is a table.
00223     Bool isTable (Int whichField) const;
00224 
00225     // What is the shape of the given field. Returns [1] if the field is a
00226     // scalar, table or, sub-record, [-1] if it is a variable length array,
00227     // and the actual shape for a fixed length array.
00228     const IPosition& shape (Int whichField) const;
00229 
00230     // What is the name of the table description.
00231     // Returns an empty string when the field is no table.
00232     const String& tableDescName (Int whichField) const;
00233 
00234     // If whichField is a sub-record return its description.
00235     // Otherwise an exception is thrown.
00236     // The non-const version is named differently to prevent accidental
00237     // use of the non-const version.
00238     // <group>
00239     const RecordDesc& subRecord (Int whichField) const;
00240     RecordDesc& rwSubRecord (Int whichField);
00241     // </group>
00242 
00243     // This and other compare equal if the field types and shapes are identical
00244     // (recursively if there are described sub-records).
00245     // The field names are not used.
00246     // <br>Use function isEqual if names are important, but order is not.
00247     // <group>
00248     Bool operator== (const RecordDesc& other) const;
00249     Bool operator!= (const RecordDesc& other) const;
00250     // </group>
00251 
00252     // Test if this description conforms the other.
00253     // It is NOT doing it recursively, thus is does not check if
00254     // sub-records are conforming.
00255     // <br>This is used by Record, to see if another record can be assigned
00256     // to this record.
00257     Bool conform (const RecordDesc& other) const;
00258 
00259     // Test if this description equals another one.
00260     // It is equal if the number of fields is equal and all field names in
00261     // this description occur in the other too. The order of the fields
00262     // is not important.
00263     // <br>The flag equalDataTypes is set to True if the data types
00264     // of all fields match.
00265     // <br>Use function operator== if order and types are important,
00266     // but names are not.
00267     Bool isEqual (const RecordDesc& other, Bool& equalDataTypes) const;
00268 
00269     // Test if this description is a subset of another one.
00270     // It is similar to isEqual above.
00271     Bool isSubset (const RecordDesc& other, Bool& equalDataTypes) const;
00272 
00273     // Test if this description is a strict subset of another one, thus
00274     // if it is a subset and not equal.
00275     Bool isStrictSubset (const RecordDesc& other, Bool& equalDataTypes) const;
00276 
00277     // Test if this description is a superset of another one.
00278     Bool isSuperset (const RecordDesc& other, Bool& equalDataTypes) const;
00279 
00280     // Test if this description is a strict superset of another one, thus
00281     // if it is a superset and not equal.
00282     Bool isStrictSuperset (const RecordDesc& other,
00283                            Bool& equalDataTypes) const;
00284 
00285     // Test if the set of field names in this and other record description
00286     // is disjoint (i.e. if they do not share names).
00287     Bool isDisjoint (const RecordDesc& other) const;
00288 
00289 
00290 private:
00291     // Writes/reads the RecordDesc to/from an output stream.
00292     // <group>
00293     ostream& put (ostream& os) const;
00294     AipsIO& put (AipsIO& os) const;
00295     AipsIO& get (AipsIO& os);
00296     // </group>
00297 
00298     // Use a copy-on-write pointer to the RecordDescRep.
00299     COWPtr<RecordDescRep> desc_p;
00300 };
00301 
00302 
00303 
00304 inline RecordDesc::RecordDesc()
00305 : desc_p (new RecordDescRep)
00306 {}
00307 
00308 inline RecordDesc::RecordDesc (const RecordDesc& other)
00309 : desc_p (other.desc_p)
00310 {}
00311 
00312 inline RecordDesc& RecordDesc::operator= (const RecordDesc& other)
00313 {
00314     if (this != &other) {
00315         desc_p = other.desc_p;
00316     }
00317     return *this;
00318 }
00319 
00320 inline RecordDesc::~RecordDesc()
00321 {}
00322 
00323 inline uInt RecordDesc::addField (const String& fieldName, DataType dataType)
00324 {
00325     return desc_p.rwRef().addField (fieldName, dataType);
00326 }
00327 
00328 inline uInt RecordDesc::addField (const String& fieldName,
00329                                   DataType scalarOrArrayType,
00330                                   const IPosition& shape)
00331 {
00332     return desc_p.rwRef().addArray (fieldName, scalarOrArrayType, shape);
00333 }
00334 
00335 inline uInt RecordDesc::addField (const String& fieldName,
00336                                   const RecordDesc& subDesc)
00337 {
00338     return desc_p.rwRef().addRecord (fieldName, subDesc);
00339 }
00340 
00341 inline uInt RecordDesc::addTable (const String& fieldName,
00342                                   const String& tableDescName)
00343 {
00344     return desc_p.rwRef().addTable (fieldName, tableDescName);
00345 }
00346 
00347 inline const String& RecordDesc::comment (Int whichField) const
00348 {
00349     return desc_p.ref().comment (whichField);
00350 }
00351 
00352 inline void RecordDesc::setComment (Int whichField, const String& comment)
00353 {
00354     desc_p.rwRef().setComment (whichField, comment);
00355 }
00356 
00357 inline void RecordDesc::setShape (Int whichField, const IPosition& shape)
00358 {
00359     desc_p.rwRef().setShape (whichField, shape);
00360 }
00361 
00362 inline uInt RecordDesc::mergeField (const RecordDesc& other,
00363                                Int whichFieldFromOther,
00364                                RecordInterface::DuplicatesFlag duplicateAction)
00365 {
00366     return desc_p.rwRef().mergeField (other.desc_p.ref(), whichFieldFromOther,
00367                                       duplicateAction);
00368 }
00369 
00370 inline uInt RecordDesc::merge (const RecordDesc& other,
00371                                RecordInterface::DuplicatesFlag duplicateAction)
00372 {
00373     return desc_p.rwRef().merge (other.desc_p.ref(), duplicateAction);
00374 }
00375     
00376 inline uInt RecordDesc::removeField (Int whichField)
00377 {
00378     return desc_p.rwRef().removeField (whichField);
00379 }
00380 
00381 inline void RecordDesc::renameField (const String& newName, Int whichField)
00382 {
00383     desc_p.rwRef().renameField (newName, whichField);
00384 }
00385  
00386 inline Int RecordDesc::fieldNumber (const String& fieldName) const
00387 {
00388     return desc_p.ref().fieldNumber (fieldName);
00389 }
00390 
00391 inline uInt RecordDesc::nfields() const
00392 {
00393     return desc_p.ref().nfields();
00394 }
00395 
00396 inline DataType RecordDesc::type (Int whichField) const
00397 {
00398     return desc_p.ref().type (whichField);
00399 }
00400 
00401 inline String RecordDesc::uniqueName (const String& name) const
00402 {
00403     return desc_p.ref().uniqueName (name);
00404 }
00405 
00406 inline String RecordDesc::makeName (Int whichField) const
00407 {
00408     return desc_p.ref().makeName (whichField);
00409 }
00410 
00411 inline const String& RecordDesc::name (Int whichField) const
00412 {
00413     return desc_p.ref().name (whichField);
00414 }
00415 
00416 inline Bool RecordDesc::isArray (Int whichField) const
00417 {
00418     return desc_p.ref().isArray (whichField);
00419 }
00420 
00421 inline Bool RecordDesc::isScalar (Int whichField) const
00422 {
00423     return desc_p.ref().isScalar (whichField);
00424 }
00425 
00426 inline Bool RecordDesc::isSubRecord (Int whichField) const
00427 {
00428     return desc_p.ref().isSubRecord (whichField);
00429 }
00430 
00431 inline Bool RecordDesc::isTable (Int whichField) const
00432 {
00433     return desc_p.ref().isTable (whichField);
00434 }
00435 
00436 inline const IPosition& RecordDesc::shape (Int whichField) const
00437 {
00438     return desc_p.ref().shape (whichField);
00439 }
00440 
00441 inline const String& RecordDesc::tableDescName (Int whichField) const
00442 {
00443     return desc_p.ref().tableDescName (whichField);
00444 }
00445 
00446 inline const RecordDesc& RecordDesc::subRecord (Int whichField) const
00447 {
00448     return desc_p.ref().subRecord (whichField);
00449 }
00450 
00451 inline RecordDesc& RecordDesc::rwSubRecord (Int whichField)
00452 {
00453     return desc_p.rwRef().subRecord (whichField);
00454 }
00455 
00456 inline Bool RecordDesc::operator== (const RecordDesc& other) const
00457 {
00458     return desc_p.ref() == other.desc_p.ref();
00459 }
00460 
00461 inline Bool RecordDesc::operator!= (const RecordDesc& other) const
00462 {
00463     return desc_p.ref() != other.desc_p.ref();
00464 }
00465 inline Bool RecordDesc::conform (const RecordDesc& other) const
00466 {
00467     return desc_p.ref().conform (other.desc_p.ref());
00468 }
00469 
00470 inline Bool RecordDesc::isEqual (const RecordDesc& other,
00471                                  Bool& equalDataTypes) const
00472 {
00473     return desc_p.ref().isEqual (other.desc_p.ref(), equalDataTypes);
00474 }
00475 inline Bool RecordDesc::isSubset (const RecordDesc& other,
00476                                   Bool& equalDataTypes) const
00477 {
00478     return desc_p.ref().isSubset (other.desc_p.ref(), equalDataTypes);
00479 }
00480 inline Bool RecordDesc::isStrictSubset (const RecordDesc& other,
00481                                         Bool& equalDataTypes) const
00482 {
00483     return desc_p.ref().isStrictSubset (other.desc_p.ref(), equalDataTypes);
00484 }
00485 inline Bool RecordDesc::isSuperset (const RecordDesc& other,
00486                                     Bool& equalDataTypes) const
00487 {
00488     return other.desc_p.ref().isSubset (desc_p.ref(), equalDataTypes);
00489 }
00490 inline Bool RecordDesc::isStrictSuperset (const RecordDesc& other,
00491                                           Bool& equalDataTypes) const
00492 {
00493     return other.desc_p.ref().isStrictSubset (desc_p.ref(), equalDataTypes);
00494 }
00495 inline Bool RecordDesc::isDisjoint (const RecordDesc& other) const
00496 {
00497     return desc_p.ref().isDisjoint (other.desc_p.ref());
00498 }
00499 
00500 
00501 inline ostream& operator<< (ostream& os, const RecordDesc& desc)
00502 {
00503     return desc.put (os);
00504 }
00505 inline AipsIO& operator<< (AipsIO& os, const RecordDesc& desc)
00506 {
00507     return desc.put (os);
00508 }
00509 inline AipsIO& operator>> (AipsIO& os, RecordDesc& desc)
00510 {
00511     return desc.get (os);
00512 }
00513 
00514 
00515 
00516 
00517 
00518 } //# NAMESPACE CASA - END
00519 
00520 #endif