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