casacore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Record.h
Go to the documentation of this file.
1 //# Record.h: A hierarchical collection of named fields of various types
2 //# Copyright (C) 1995,1996,1997,1998,2000,2001
3 //# Associated Universities, Inc. Washington DC, USA.
4 //#
5 //# This library is free software; you can redistribute it and/or modify it
6 //# under the terms of the GNU Library General Public License as published by
7 //# the Free Software Foundation; either version 2 of the License, or (at your
8 //# option) any later version.
9 //#
10 //# This library is distributed in the hope that it will be useful, but WITHOUT
11 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 //# License for more details.
14 //#
15 //# You should have received a copy of the GNU Library General Public License
16 //# along with this library; if not, write to the Free Software Foundation,
17 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 //#
19 //# Correspondence concerning AIPS++ should be addressed as follows:
20 //# Internet email: aips2-request@nrao.edu.
21 //# Postal address: AIPS++ Project Office
22 //# National Radio Astronomy Observatory
23 //# 520 Edgemont Road
24 //# Charlottesville, VA 22903-2475 USA
25 //#
26 //#
27 //# $Id$
28 
29 
30 #ifndef CASA_RECORD_H
31 #define CASA_RECORD_H
32 
33 //# Includes
34 #include <casacore/casa/aips.h>
40 
41 namespace casacore { //# NAMESPACE CASACORE - BEGIN
42 
43 //# Forward Declarations
44 class IPosition;
45 class AipsIO;
46 
47 
48 // <summary>
49 // A hierarchical collection of named fields of various types
50 // </summary>
51 
52 // <use visibility=export>
53 // <reviewed reviewer="Mark Wieringa" date="1996/04/15" tests="tRecord">
54 // </reviewed>
55 
56 // <prerequisite>
57 // <li> <linkto class="RecordDesc">RecordDesc</linkto>.
58 // <li> <linkto class="RecordInterface">RecordInterface</linkto>.
59 // <li> <linkto class="RecordFieldPtr">RecordFieldPtr</linkto>.
60 // </prerequisite>
61 
62 // <etymology>
63 // ``Record'' is a widely used term in both programming languages and data
64 // structures to denote an imhogeneous set of fields. An alternative would
65 // have been to name it <em>struct</em>ure, which would have perhaps been
66 // a clearer name for C++ programmers.
67 // </etymology>
68 
69 // <synopsis>
70 // Class <linkto class=RecordInterface>RecordInterface</linkto> decribes
71 // the fundamental properties of records.
72 // <br>
73 // The Record class is a particular type of a record class.
74 // The fields in Record may be of scalar type, array type, or a Record.
75 // The types are chosen to be compatible with the native
76 // types of the Table system, viz: Bool, uChar, Short, Int, uInt, float,
77 // double, Complex, DComplex, String.
78 // Arrays of all these types are also available.
79 // Note that a Record is not a space-efficient way of storing small objects.
80 // <p>
81 // The structure of a Record is defined by the <linkto class="RecordDesc">
82 // RecordDesc</linkto> class. The structure of the Record can be defined at
83 // construction time. It can thereafter be restructured. This has the
84 // effect, however, that any existing RecordFieldPtr objects become
85 // invalid (using the <linkto file="Notice.h">Notice</linkto> classes).
86 // <br>
87 // It is possible to add or remove fields once a Record is constructed.
88 // However, this is not possible when the Record is constructed with a
89 // fixed structure (i.e. with the fixedStructure flag set).
90 // <p>
91 // A Record is an hierarchical structure, because it can have fields
92 // containing Record's (as layed out in the RecordDesc). A subrecord
93 // has a variable structure, when its RecordDesc is empty (i.e. contains
94 // no fields). It is fixed when its RecordDesc contains fields.
95 // <p>
96 // A Record may be assigned to another only if they conform; that is if their
97 // fields have the identical type in the identical order.
98 // The field names do not need to be identical however, only the types.
99 // That is, the structure needs to be identical, but
100 // not the labels. Note that field order is significant,
101 // <src>[ifield(type=Int),ffield(type=float)]</src>
102 // is not the same as <src>[ffield(type=float),ifield(type=Int)]</src>
103 // <br>
104 // Conformance is checked recursively for fixed subrecords. That is, a
105 // variable structured subrecord is not checked, because any record
106 // can be assigned to it. A fixed structured subrecord has to
107 // conform the corresponding subrecord in the source.
108 // <p>
109 // Record uses copy-on-write semantics. This means that when a Record
110 // is copied, only the pointer to the underlying RecordRep object is copied.
111 // Only when the Record gets changed (i.e. when a non-const Record member
112 // function is called), the RecordRep object is copied.
113 // This results in a cheap copy behaviour.
114 // </synopsis>
115 
116 // <example>
117 // Suppose we wanted to create a records that describe the favorite example
118 // of the OO world - an employee:
119 // <srcBlock>
120 // RecordDesc employeeDesc;
121 // employeeDesc.addField ("name", TpString);
122 // employeeDesc.addField ("salary", TpDouble);
123 // </srcBlock>
124 // The above creates the description (structure) for some record objects.
125 // <srcBlock>
126 // Record employeeA(employeeDesc);
127 // Record employeeB(employeeDesc, False);
128 // </srcBlock>
129 // And these two lines create Record objects which share this common structure.
130 // The first Record has a fixed structure, the 2nd variable.
131 // <srcBlock>
132 // RecordFieldPtr<String> nameA(employeeA, 0);
133 // RecordFieldPtr<String> nameB(employeeB, 0);
134 // RecordFieldPtr<double> salaryA(employeeA, 1);
135 // RecordFieldPtr<double> salaryB(employeeB, "salary");
136 // </srcBlock>
137 // This shows how we can get access to the individual fields. The fields are
138 // fundamentally identified by number, but the number can be looked up through
139 // the use of the fieldNumber member function.
140 // <srcBlock>
141 // nameA.define ("Tim");
142 // nameB.define ("Brian");
143 // salaryA.define (1.0e+8);
144 // salaryB.define (1.0 / *salaryA);
145 // </srcBlock>
146 // Once obtained, the fields are readily manipulated, as shown above. Note
147 // that the field values are obtained through the dereference (<src>*</src>)
148 // operator. This is to identify that the field objects are <em>pointers</em>
149 // to the values in the underlying Record; that is
150 // <srcBlock>
151 // salaryA = salaryB;
152 // *salaryA = *salaryB;
153 // </srcBlock>
154 // Do very different things; the first line is a pointer copy; salaryA and
155 // salaryB now point to the same field in salaryB. The second line is a value
156 // copy.
157 //
158 // Whole records can be copied as long as their structures are compatible, so
159 // that <src> employeeA = employeeB </src> is a legal statement. However, if
160 // the structure is changed, assignment is no longer possible, and all of the
161 // field pointers are invalidated:
162 // <srcBlock>
163 // employeeB.define ("age", (Int)40);
164 // employeeA = employeeB; // exception - no longer conformant
165 // </srcBlock>
166 // </example>
167 
168 // <motivation>
169 // Collections of data with different types are frequently needed.
170 // Record makes it possible to hold such data in a flexible way.
171 // </motivation>
172 
173 // <todo asof="1996/03/12">
174 // <li> A record reference class, which contains some fields from another
175 // record, would likely be useful. This would be analagous to a
176 // subarray sliced from an existing array.
177 // </todo>
178 
179 
180 class Record : public RecordInterface
181 {
182 friend class RecordRep;
183 
184 public:
185  // Create a record with no fields.
186  // The record has a variable structure.
187  Record();
188 
189  // Create a record with no fields.
190  // The type determines if the record has a fixed or variable structure.
191  // The callback function is called when a field is added to the Record.
192  // That function can check the name and of data type of the new field
193  // (for instance, the Table system uses it to ensure that table columns
194  // and keywords have different names).
195  explicit Record (RecordType type,
196  CheckFieldFunction* = 0, const void* checkArgument = 0);
197 
198  // Create a record with the given description. If it is not possible to
199  // create all fields (for example, if a field with an unsupported data
200  // type is requested), an exception is thrown.
201  // The type determines if the record has a fixed or variable structure.
202  // All fields are checked by the field checking function (if defined)
203  // (for instance, the Table system uses it to ensure that table columns
204  // and keywords have different names).
205  explicit Record (const RecordDesc& description, RecordType type = Fixed,
206  CheckFieldFunction* = 0, const void* checkArgument = 0);
207 
208  // Create a copy of other using copy semantics.
209  Record (const Record& other);
210 
211  // Create a Record from another type of record using copy semantics.
212  // Subrecords are also converted to a Record.
213  Record (const RecordInterface& other);
214 
215  // Copy the data in the other record to this record.
216  // It can operate in 2 ways depending on the Record structure flag.
217  // <ul>
218  // <li> For variable structured records the existing fields are
219  // thrown away and replaced by the new fields.
220  // This means that RecordFieldPtr's using this record get invalidated.
221  // Because copy-on-write semantics are used, this kind of
222  // assignment is a very efficient operation.
223  // <li> For fixed structured records the existing values are replaced
224  // by the new values. This means that RecordFieldPtr's using this
225  // record remain valid.
226  // The structure of the other record has to conform this record
227  // or this record has to be empty, otherwise an exception is thrown.
228  // This assignment is less efficient, because it has to check the
229  // conformance and because each value has to be copied.
230  // </ul>
231  // <note role=warning>
232  // Attributes like fixed structure flag and check function will not
233  // be copied.
234  // </note>
235  Record& operator= (const Record& other);
236 
237  // Release resources associated with this object.
238  virtual ~Record();
239 
240  // Make a copy of this object.
241  virtual RecordInterface* clone() const;
242 
243  // Assign that RecordInterface object to this one.
244  // Unlike <src>operator=</src> it copies all data in the derived
245  // class.
246  virtual void assign (const RecordInterface& that);
247 
248  // Get the comment for this field.
249  virtual const String& comment (const RecordFieldId&) const;
250 
251  // Set the comment for this field.
252  virtual void setComment (const RecordFieldId&, const String& comment);
253 
254  // Describes the current structure of this Record.
255  const RecordDesc& description() const;
256 
257  // Change the structure of this Record to contain the fields in
258  // newDescription. After calling restructure, <src>description() ==
259  // newDescription</src>. Any existing RecordFieldPtr objects are
260  // invalidated (their <src>isAttached()</src> members return False) after
261  // this call.
262  // <br>When the new description contains subrecords, those subrecords
263  // will be restructured if <src>recursive=True</src> is given.
264  // Otherwise the subrecord is a variable empty record.
265  // Subrecords will be variable if their description is empty (i.e. does
266  // not contain any field), otherwise they are fixed. The 2nd form of
267  // the <src>restructure</src> function will overwrite those implicit
268  // record types with the given record type. The new type will also
269  // be given to this top record.
270  // <br>Restructuring is not possible and an exception is thrown
271  // if the Record has a fixed structure.
272  virtual void restructure (const RecordDesc& newDescription,
273  Bool recursive = True);
274 
275  // Returns True if this and other have the same RecordDesc, other
276  // than different names for the fields. That is, the number, type and the
277  // order of the fields must be identical (recursively for fixed
278  // structured sub-Records in this).
279  // <note role=caution>
280  // <src>thisRecord.conform(thatRecord) == True</src> does not imply
281  // <br><src>thatRecord.conform(thisRecord) == True</src>, because
282  // a variable record in one conforms a fixed record in that, but
283  // not vice-versa.
284  // </note>
285  Bool conform (const Record& other) const;
286 
287  // How many fields does this structure have? A convenient synonym for
288  // <src>description().nfields()</src>.
289  virtual uInt nfields() const;
290 
291  // Get the field number from the field name.
292  // -1 is returned if the field name is unknown.
293  virtual Int fieldNumber (const String& fieldName) const;
294 
295  // Get the data type of this field.
296  virtual DataType type (Int whichField) const;
297 
298  // Remove a field from the record.
299  // <note role=caution>
300  // Removing a field means that the field number of the fields following
301  // it will be decremented. Only the RecordFieldPtr's
302  // pointing to the removed field will be invalidated.
303  // </note>
304  void removeField (const RecordFieldId&);
305 
306  // Rename the given field.
307  void renameField (const String& newName, const RecordFieldId&);
308 
309  // Define a value for the given field containing a subrecord.
310  // When the field is unknown, it will be added to the record.
311  // The second version is meant for any type of record (e.g. Record,
312  // TableRecord, GlishRecord). It is converted to a Record using the
313  // Record constructor taking a RecordInterface object.
314  // <group>
315  void defineRecord (const RecordFieldId&, const Record& value,
317  virtual void defineRecord (const RecordFieldId&,
318  const RecordInterface& value,
319  RecordType = Variable);
320  // </group>
321 
322  // Get the subrecord from the given field.
323  // <note>
324  // The non-const version has a different name to prevent that the
325  // copy-on-write mechanism makes a copy when not necessary.
326  // </note>
327  // <group>
328  const Record& subRecord (const RecordFieldId&) const;
329  Record& rwSubRecord (const RecordFieldId&);
330  virtual const RecordInterface& asRecord (const RecordFieldId&) const;
331  virtual RecordInterface& asrwRecord (const RecordFieldId&);
332  // </group>
333 
334  // Get or define the value as a ValueHolder.
335  // This is useful to pass around a value of any supported type.
336  // <group>
337  virtual ValueHolder asValueHolder (const RecordFieldId&) const;
338  virtual void defineFromValueHolder (const RecordFieldId&,
339  const ValueHolder&);
340  // </group>
341 
342  // Merge a field from another record into this record.
343  // The DuplicatesFlag (as described in
344  // <linkto class=RecordInterface>RecordInterface</linkto>) determines
345  // what will be done in case the field name already exists.
346  void mergeField (const Record& other, const RecordFieldId&,
348 
349  // Merge all fields from the other record into this record.
350  // The DuplicatesFlag (as described in
351  // <linkto class=RecordInterface>RecordInterface</linkto>) determines
352  // what will be done in case a field name already exists.
353  // An exception will be thrown if other is the same as this
354  // (i.e. if merging the record itself).
355  void merge (const Record& other, DuplicatesFlag = ThrowOnDuplicates);
356 
357  // Write the Record to an output stream.
358  friend AipsIO& operator<< (AipsIO& os, const Record& rec);
359 
360  // Read the Record from an input stream.
361  friend AipsIO& operator>> (AipsIO& os, Record& rec);
362 
363  // Write the Record to an output stream.
364  // This is used to write a subrecord, whose description has
365  // not been written.
366  void putRecord (AipsIO& os) const;
367 
368  // Read the Record from an input stream.
369  // This is used to read a subrecord, whose description has
370  // not been read.
371  void getRecord (AipsIO& os);
372 
373  // Put the data of a record.
374  // This is used to write a subrecord, whose description has
375  // already been written.
376  void putData (AipsIO& os) const;
377 
378  // Read the data of a record.
379  // This is used to read a subrecord, whose description has
380  // already been read.
381  void getData (AipsIO& os, uInt version);
382 
383  // Make a unique record representation
384  // (to do copy-on-write in RecordFieldPtr).
385  virtual void makeUnique();
386 
387  // Print the contents of the record.
388  // Only the first <src>maxNrValues</src> of an array will be printed.
389  // A value < 0 means the entire array.
390  virtual void print (std::ostream&,
391  Int maxNrValues = 25,
392  const String& indent="") const;
393 
394 
395 protected:
396  // Used by the RecordField classes to attach in a type-safe way to the
397  // correct field.
398  // <group>
399  virtual void* get_pointer (Int whichField, DataType type) const;
400  virtual void* get_pointer (Int whichField, DataType type,
401  const String& recordType) const;
402  // </group>
403 
404  // Return a const reference to the underlying RecordRep.
405  const RecordRep& ref() const;
406 
407  // Return a non-const reference to the underlying RecordRep.
408  // When needed, the RecordRep will be copied and all RecordField
409  // objects will be notified.
410  RecordRep& rwRef();
411 
412  // Add a field to the record.
413  virtual void addDataField (const String& name, DataType type,
414  const IPosition& shape, Bool fixedShape,
415  const void* value);
416 
417  // Define a value in the given field.
418  virtual void defineDataField (Int whichField, DataType type,
419  const void* value);
420 
421 private:
422  // Get the description of this record.
423  virtual RecordDesc getDescription() const;
424 
425  // Create Record as a subrecord.
426  // When the description is empty, the record has a variable structure.
427  // Otherwise it is fixed.
428  // <group>
429  Record (RecordRep* parent, const RecordDesc& description);
430  Record (RecordRep* parent, RecordType type);
431  // </group>
432 
433  // The Record representation.
435  // The parent Record.
437 };
438 
439 
440 
441 inline const RecordRep& Record::ref() const
442 {
443  return rep_p.ref();
444 }
445 inline const RecordDesc& Record::description() const
446 {
447  return ref().description();
448 }
449 
450 inline Bool Record::conform (const Record& other) const
451 {
452  return ref().conform (other.ref());
453 }
454 
455 inline AipsIO& operator<< (AipsIO& os, const Record& rec)
456 {
457  rec.putRecord (os);
458  return os;
459 }
460 inline void Record::putData (AipsIO& os) const
461 {
462  ref().putData (os);
463 }
464 
465 inline AipsIO& operator>> (AipsIO& os, Record& rec)
466 {
467  rec.getRecord (os);
468  return os;
469 }
470 inline void Record::getData (AipsIO& os, uInt version)
471 {
472  rwRef().getData (os, version);
473 }
474 
475 
476 
477 
478 } //# NAMESPACE CASACORE - END
479 
480 #endif
const Record & subRecord(const RecordFieldId &) const
Get the subrecord from the given field.
friend AipsIO & operator<<(AipsIO &os, const Record &rec)
Write the Record to an output stream.
Definition: Record.h:455
RecordRep & rwRef()
Return a non-const reference to the underlying RecordRep.
A Vector of integers, for indexing into Array&lt;T&gt; objects.
Definition: IPosition.h:118
virtual void print(std::ostream &, Int maxNrValues=25, const String &indent="") const
Print the contents of the record.
Record & rwSubRecord(const RecordFieldId &)
virtual void makeUnique()
Make a unique record representation (to do copy-on-write in RecordFieldPtr).
const RecordDesc & description() const
Describes the current structure of this Record.
Definition: Record.h:445
int Int
Definition: aipstype.h:50
RecordType
Define the flag telling if a Record has a fixed or variable structure.
IPosition shape(const RecordFieldId &) const
Get the actual shape of this field.
void putRecord(AipsIO &os) const
Write the Record to an output stream.
void defineRecord(const RecordFieldId &, const Record &value, RecordType type=Variable)
Define a value for the given field containing a subrecord.
virtual void defineFromValueHolder(const RecordFieldId &, const ValueHolder &)
void renameField(const String &newName, const RecordFieldId &)
Rename the given field.
virtual void setComment(const RecordFieldId &, const String &comment)
Set the comment for this field.
Record & operator=(const Record &other)
Copy the data in the other record to this record.
void mergeField(const Record &other, const RecordFieldId &, DuplicatesFlag=ThrowOnDuplicates)
Merge a field from another record into this record.
void merge(const Record &other, DuplicatesFlag=ThrowOnDuplicates)
Merge all fields from the other record into this record.
AipsIO is the object persistency mechanism of Casacore.
Definition: AipsIO.h:168
RecordRep * parent_p
The parent Record.
Definition: Record.h:436
void removeField(const RecordFieldId &)
Remove a field from the record.
virtual DataType type(Int whichField) const
Get the data type of this field.
The representation of a Record.
Definition: RecordRep.h:100
const RecordRep & ref() const
Return a const reference to the underlying RecordRep.
Definition: Record.h:441
ostream & operator<<(ostream &os, const IComplex &)
Show on ostream.
virtual void defineDataField(Int whichField, DataType type, const void *value)
Define a value in the given field.
virtual const RecordInterface & asRecord(const RecordFieldId &) const
virtual RecordInterface & asrwRecord(const RecordFieldId &)
void getRecord(AipsIO &os)
Read the Record from an input stream.
virtual ValueHolder asValueHolder(const RecordFieldId &) const
Get or define the value as a ValueHolder.
virtual RecordDesc getDescription() const
Get the description of this record.
virtual uInt nfields() const
How many fields does this structure have? A convenient synonym for description().nfields().
Record()
Create a record with no fields.
virtual void restructure(const RecordDesc &newDescription, Bool recursive=True)
Change the structure of this Record to contain the fields in newDescription.
Record has a fixed structure; that is, no fields can be added or removed once the Record is created...
virtual RecordInterface * clone() const
Make a copy of this object.
virtual void assign(const RecordInterface &that)
Assign that RecordInterface object to this one.
virtual Int fieldNumber(const String &fieldName) const
Get the field number from the field name.
The identification of a record field.
Definition: RecordFieldId.h:91
Description of the fields in a record object.
Definition: RecordDesc.h:105
A holder for a value of any basic Casacore data type.
Definition: ValueHolder.h:68
Record has a variable structure; after Record creation fields can be added or removed at will...
Copy-On-Write-Pointer class - allows control of copy based on constness.
Definition: COWPtr.h:185
virtual const String & comment(const RecordFieldId &) const
Get the comment for this field.
DuplicatesFlag
Define the Duplicates flag for the function merge in the various record classes.
void putData(AipsIO &os) const
Put the data of a record.
A hierarchical collection of named fields of various types.
Definition: Record.h:180
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
virtual void addDataField(const String &name, DataType type, const IPosition &shape, Bool fixedShape, const void *value)
Add a field to the record.
Bool conform(const Record &other) const
Returns True if this and other have the same RecordDesc, other than different names for the fields...
Definition: Record.h:450
void getData(AipsIO &os, uInt version)
Read the data of a record.
Definition: Record.h:470
virtual void * get_pointer(Int whichField, DataType type) const
Used by the RecordField classes to attach in a type-safe way to the correct field.
friend AipsIO & operator>>(AipsIO &os, Record &rec)
Read the Record from an input stream.
Definition: Record.h:465
const RecordDesc & description() const
Describes the current structure of this Record.
Definition: RecordRep.h:308
RecordType & recordType()
Give access to the RecordType flag (write-access is needed when a record is read back).
String: the storage and methods of handling collections of characters.
Definition: String.h:225
COWPtr< RecordRep > rep_p
The Record representation.
Definition: Record.h:434
AipsIO & operator>>(AipsIO &os, Record &rec)
Definition: Record.h:465
Abstract base class for Record classes.
Bool CheckFieldFunction(const String &fieldName, DataType dataType, const void *extraArgument, String &message)
Define the signature of the add callback function.
virtual ~Record()
Release resources associated with this object.
Bool conform(const RecordRep &other) const
Returns True if this and other have the same RecordDesc, other than different names for the fields...
void putData(AipsIO &os) const
Put the data of a record.
Definition: Record.h:460
const Bool True
Definition: aipstype.h:43
void getData(AipsIO &os, uInt version)
Read the data of a record.
LatticeExprNode value(const LatticeExprNode &expr)
This function returns the value of the expression without a mask.
String name(const RecordFieldId &) const
Get the name of this field.
unsigned int uInt
Definition: aipstype.h:51