casacore
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>
35 #include <casacore/casa/Containers/RecordInterface.h>
36 #include <casacore/casa/Containers/RecordRep.h>
37 #include <casacore/casa/Containers/RecordDesc.h>
38 #include <casacore/casa/Utilities/COWPtr.h>
39 
40 namespace casacore { //# NAMESPACE CASACORE - BEGIN
41 
42 //# Forward Declarations
43 template<class T> class Array;
44 class IPosition;
45 class AipsIO;
46 class ValueHolder;
47 
48 
49 // <summary>
50 // A hierarchical collection of named fields of various types
51 // </summary>
52 
53 // <use visibility=export>
54 // <reviewed reviewer="Mark Wieringa" date="1996/04/15" tests="tRecord">
55 // </reviewed>
56 
57 // <prerequisite>
58 // <li> <linkto class="RecordDesc">RecordDesc</linkto>.
59 // <li> <linkto class="RecordInterface">RecordInterface</linkto>.
60 // <li> <linkto class="RecordFieldPtr">RecordFieldPtr</linkto>.
61 // </prerequisite>
62 
63 // <etymology>
64 // ``Record'' is a widely used term in both programming languages and data
65 // structures to denote an imhogeneous set of fields. An alternative would
66 // have been to name it <em>struct</em>ure, which would have perhaps been
67 // a clearer name for C++ programmers.
68 // </etymology>
69 
70 // <synopsis>
71 // Class <linkto class=RecordInterface>RecordInterface</linkto> decribes
72 // the fundamental properties of records.
73 // <br>
74 // The Record class is a particular type of a record class.
75 // The fields in Record may be of scalar type, array type, or a Record.
76 // The types are chosen to be compatible with the native
77 // types of the Table system, viz: Bool, uChar, Short, Int, uInt, float,
78 // double, Complex, DComplex, String.
79 // Arrays of all these types are also available.
80 // Note that a Record is not a space-efficient way of storing small objects.
81 // <p>
82 // The structure of a Record is defined by the <linkto class="RecordDesc">
83 // RecordDesc</linkto> class. The structure of the Record can be defined at
84 // construction time. It can thereafter be restructured. This has the
85 // effect, however, that any existing RecordFieldPtr objects become
86 // invalid (using the <linkto file="Notice.h">Notice</linkto> classes).
87 // <br>
88 // It is possible to add or remove fields once a Record is constructed.
89 // However, this is not possible when the Record is constructed with a
90 // fixed structure (i.e. with the fixedStructure flag set).
91 // <p>
92 // A Record is an hierarchical structure, because it can have fields
93 // containing Record's (as layed out in the RecordDesc). A subrecord
94 // has a variable structure, when its RecordDesc is empty (i.e. contains
95 // no fields). It is fixed when its RecordDesc contains fields.
96 // <p>
97 // A Record may be assigned to another only if they conform; that is if their
98 // fields have the identical type in the identical order.
99 // The field names do not need to be identical however, only the types.
100 // That is, the structure needs to be identical, but
101 // not the labels. Note that field order is significant,
102 // <src>[ifield(type=Int),ffield(type=float)]</src>
103 // is not the same as <src>[ffield(type=float),ifield(type=Int)]</src>
104 // <br>
105 // Conformance is checked recursively for fixed subrecords. That is, a
106 // variable structured subrecord is not checked, because any record
107 // can be assigned to it. A fixed structured subrecord has to
108 // conform the corresponding subrecord in the source.
109 // <p>
110 // Record uses copy-on-write semantics. This means that when a Record
111 // is copied, only the pointer to the underlying RecordRep object is copied.
112 // Only when the Record gets changed (i.e. when a non-const Record member
113 // function is called), the RecordRep object is copied.
114 // This results in a cheap copy behaviour.
115 // </synopsis>
116 
117 // <example>
118 // Suppose we wanted to create a records that describe the favorite example
119 // of the OO world - an employee:
120 // <srcBlock>
121 // RecordDesc employeeDesc;
122 // employeeDesc.addField ("name", TpString);
123 // employeeDesc.addField ("salary", TpDouble);
124 // </srcBlock>
125 // The above creates the description (structure) for some record objects.
126 // <srcBlock>
127 // Record employeeA(employeeDesc);
128 // Record employeeB(employeeDesc, False);
129 // </srcBlock>
130 // And these two lines create Record objects which share this common structure.
131 // The first Record has a fixed structure, the 2nd variable.
132 // <srcBlock>
133 // RecordFieldPtr<String> nameA(employeeA, 0);
134 // RecordFieldPtr<String> nameB(employeeB, 0);
135 // RecordFieldPtr<double> salaryA(employeeA, 1);
136 // RecordFieldPtr<double> salaryB(employeeB, "salary");
137 // </srcBlock>
138 // This shows how we can get access to the individual fields. The fields are
139 // fundamentally identified by number, but the number can be looked up through
140 // the use of the fieldNumber member function.
141 // <srcBlock>
142 // nameA.define ("Tim");
143 // nameB.define ("Brian");
144 // salaryA.define (1.0e+8);
145 // salaryB.define (1.0 / *salaryA);
146 // </srcBlock>
147 // Once obtained, the fields are readily manipulated, as shown above. Note
148 // that the field values are obtained through the dereference (<src>*</src>)
149 // operator. This is to identify that the field objects are <em>pointers</em>
150 // to the values in the underlying Record; that is
151 // <srcBlock>
152 // salaryA = salaryB;
153 // *salaryA = *salaryB;
154 // </srcBlock>
155 // Do very different things; the first line is a pointer copy; salaryA and
156 // salaryB now point to the same field in salaryB. The second line is a value
157 // copy.
158 //
159 // Whole records can be copied as long as their structures are compatible, so
160 // that <src> employeeA = employeeB </src> is a legal statement. However, if
161 // the structure is changed, assignment is no longer possible, and all of the
162 // field pointers are invalidated:
163 // <srcBlock>
164 // employeeB.define ("age", (Int)40);
165 // employeeA = employeeB; // exception - no longer conformant
166 // </srcBlock>
167 // </example>
168 
169 // <motivation>
170 // Collections of data with different types are frequently needed.
171 // Record makes it possible to hold such data in a flexible way.
172 // </motivation>
173 
174 // <todo asof="1996/03/12">
175 // <li> A record reference class, which contains some fields from another
176 // record, would likely be useful. This would be analagous to a
177 // subarray sliced from an existing array.
178 // </todo>
179 
180 
181 class Record : public RecordInterface
182 {
183 friend class RecordRep;
184 
185 public:
186  // Create a record with no fields.
187  // The record has a variable structure.
188  Record();
189 
190  // Create a record with no fields.
191  // The type determines if the record has a fixed or variable structure.
192  // The callback function is called when a field is added to the Record.
193  // That function can check the name and of data type of the new field
194  // (for instance, the Table system uses it to ensure that table columns
195  // and keywords have different names).
196  explicit Record (RecordType type,
197  CheckFieldFunction* = 0, const void* checkArgument = 0);
198 
199  // Create a record with the given description. If it is not possible to
200  // create all fields (for example, if a field with an unsupported data
201  // type is requested), an exception is thrown.
202  // The type determines if the record has a fixed or variable structure.
203  // All fields are checked by the field checking function (if defined)
204  // (for instance, the Table system uses it to ensure that table columns
205  // and keywords have different names).
206  explicit Record (const RecordDesc& description, RecordType type = Fixed,
207  CheckFieldFunction* = 0, const void* checkArgument = 0);
208 
209  // Create a copy of other using copy semantics.
210  Record (const Record& other);
211 
212  // Create a Record from another type of record using copy semantics.
213  // Subrecords are also converted to a Record.
214  Record (const RecordInterface& other);
215 
216  // Copy the data in the other record to this record.
217  // It can operate in 2 ways depending on the Record structure flag.
218  // <ul>
219  // <li> For variable structured records the existing fields are
220  // thrown away and replaced by the new fields.
221  // This means that RecordFieldPtr's using this record get invalidated.
222  // Because copy-on-write semantics are used, this kind of
223  // assignment is a very efficient operation.
224  // <li> For fixed structured records the existing values are replaced
225  // by the new values. This means that RecordFieldPtr's using this
226  // record remain valid.
227  // The structure of the other record has to conform this record
228  // or this record has to be empty, otherwise an exception is thrown.
229  // This assignment is less efficient, because it has to check the
230  // conformance and because each value has to be copied.
231  // </ul>
232  // <note role=warning>
233  // Attributes like fixed structure flag and check function will not
234  // be copied.
235  // </note>
236  Record& operator= (const Record& other);
237 
238  // Release resources associated with this object.
239  ~Record();
240 
241  // Make a copy of this object.
242  virtual RecordInterface* clone() const;
243 
244  // Assign that RecordInterface object to this one.
245  // Unlike <src>operator=</src> it copies all data in the derived
246  // class.
247  virtual void assign (const RecordInterface& that);
248 
249  // Get the comment for this field.
250  virtual const String& comment (const RecordFieldId&) const;
251 
252  // Set the comment for this field.
253  virtual void setComment (const RecordFieldId&, const String& comment);
254 
255  // Describes the current structure of this Record.
256  const RecordDesc& description() const;
257 
258  // Change the structure of this Record to contain the fields in
259  // newDescription. After calling restructure, <src>description() ==
260  // newDescription</src>. Any existing RecordFieldPtr objects are
261  // invalidated (their <src>isAttached()</src> members return False) after
262  // this call.
263  // <br>When the new description contains subrecords, those subrecords
264  // will be restructured if <src>recursive=True</src> is given.
265  // Otherwise the subrecord is a variable empty record.
266  // Subrecords will be variable if their description is empty (i.e. does
267  // not contain any field), otherwise they are fixed. The 2nd form of
268  // the <src>restructure</src> function will overwrite those implicit
269  // record types with the given record type. The new type will also
270  // be given to this top record.
271  // <br>Restructuring is not possible and an exception is thrown
272  // if the Record has a fixed structure.
273  virtual void restructure (const RecordDesc& newDescription,
274  Bool recursive = True);
275 
276  // Returns True if this and other have the same RecordDesc, other
277  // than different names for the fields. That is, the number, type and the
278  // order of the fields must be identical (recursively for fixed
279  // structured sub-Records in this).
280  // <note role=caution>
281  // <src>thisRecord.conform(thatRecord) == True</src> does not imply
282  // <br><src>thatRecord.conform(thisRecord) == True</src>, because
283  // a variable record in one conforms a fixed record in that, but
284  // not vice-versa.
285  // </note>
286  Bool conform (const Record& other) const;
287 
288  // How many fields does this structure have? A convenient synonym for
289  // <src>description().nfields()</src>.
290  virtual uInt nfields() const;
291 
292  // Get the field number from the field name.
293  // -1 is returned if the field name is unknown.
294  virtual Int fieldNumber (const String& fieldName) const;
295 
296  // Get the data type of this field.
297  virtual DataType type (Int whichField) const;
298 
299  // Remove a field from the record.
300  // <note role=caution>
301  // Removing a field means that the field number of the fields following
302  // it will be decremented. Only the RecordFieldPtr's
303  // pointing to the removed field will be invalidated.
304  // </note>
305  void removeField (const RecordFieldId&);
306 
307  // Rename the given field.
308  void renameField (const String& newName, const RecordFieldId&);
309 
310  // Define a value for the given field containing a subrecord.
311  // When the field is unknown, it will be added to the record.
312  // The second version is meant for any type of record (e.g. Record,
313  // TableRecord, GlishRecord). It is converted to a Record using the
314  // Record constructor taking a RecordInterface object.
315  // <group>
316  void defineRecord (const RecordFieldId&, const Record& value,
318  virtual void defineRecord (const RecordFieldId&,
319  const RecordInterface& value,
320  RecordType = Variable);
321  // </group>
322 
323  // Get the subrecord from the given field.
324  // <note>
325  // The non-const version has a different name to prevent that the
326  // copy-on-write mechanism makes a copy when not necessary.
327  // </note>
328  // <group>
329  const Record& subRecord (const RecordFieldId&) const;
330  Record& rwSubRecord (const RecordFieldId&);
331  virtual const RecordInterface& asRecord (const RecordFieldId&) const;
332  virtual RecordInterface& asrwRecord (const RecordFieldId&);
333  // </group>
334 
335  // Get or define the value as a ValueHolder.
336  // This is useful to pass around a value of any supported type.
337  // <group>
338  ValueHolder asValueHolder (const RecordFieldId&) const;
339  void defineFromValueHolder (const RecordFieldId&, 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<T> objects.
Definition: IPosition.h:119
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:47
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.
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
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 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.
ValueHolder asValueHolder(const RecordFieldId &) const
Get or define the value as a ValueHolder.
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
void defineFromValueHolder(const RecordFieldId &, const ValueHolder &)
A holder for a value of any basic Casacore data type.
Definition: ValueHolder.h:67
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:181
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:39
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:223
COWPtr< RecordRep > rep_p
The Record representation.
Definition: Record.h:434
~Record()
Release resources associated with this object.
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.
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:40
this file contains all the compiler specific defines
Definition: mainpage.dox:28
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:48