casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
AipsIO.h
Go to the documentation of this file.
00001 //# AipsIO.h: AipsIO is the object persistency mechanism of AIPS++
00002 //# Copyright (C) 1993,1994,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 //# $Id: AipsIO.h 20615 2009-06-09 02:16:01Z Malte.Marquarding $
00027 
00028 #ifndef CASA_AIPSIO_H
00029 #define CASA_AIPSIO_H
00030 
00031 
00032 //# Includes
00033 #include <casa/aips.h>
00034 #include <casa/Containers/Block.h>
00035 #include <casa/BasicSL/String.h>
00036 #include <casa/BasicSL/Complex.h>
00037 #include <casa/IO/ByteIO.h>
00038 #include <casa/vector.h>
00039 
00040 namespace casa { //# NAMESPACE CASA - BEGIN
00041 
00042 //# Forward Declarations
00043 class TypeIO;
00044 class ByteIO;
00045 class RegularFileIO;
00046 
00047 
00048 // <summary> 
00049 // AipsIO is the object persistency mechanism of AIPS++.
00050 // </summary>
00051 
00052 // <use visibility=export>
00053 
00054 // <reviewed reviewer="ghunt" date="95Feb21" tests="" demos="">
00055 
00056 // <etymology>
00057 //  AipsIO is simply the conventional shorthand for "aips++ input/output".
00058 // </etymology>
00059 
00060 // <synopsis> 
00061 // AipsIO is a class designed to do I/O for objects.
00062 // It reads/writes the data using a class derived from
00063 // <linkto class=TypeIO>TypeIO</linkto>. For instance, class
00064 // <linkto class=CanonicalIO>CanonicalIO</linkto> can be used
00065 // to read/write the data in canonical format.
00066 // <p>
00067 // The TypeIO class in its turn uses a class derived from
00068 // <linkto class=ByteIO>ByteIO</linkto> to determine where the data
00069 // has to be written.
00070 // <p>
00071 // An object is written by writing all its data members.  It will be
00072 // preceeded by a header containing type and version.
00073 // The I/O can be done via de overloaded << and >> operators to write or
00074 // read a single item (e.g., an int or an object).  These operators are
00075 // already defined for all built-in data types and for Complex, DComplex,
00076 // String, and Bool.
00077 // Since each enumeration is a specific type, it is hard to handle them.
00078 // Casting to Bool (which is also an enumerated type) is a possibility,
00079 // but that assumes that each enumerated type has the same size (which
00080 // is probably true for all compilers).
00081 // Another possibility is to store it in an int when writing.  Reading
00082 // can be done the opposite way, although the ARM says that an int
00083 // cannot be assigned to an enumerated type.
00084 // <p>
00085 // There are also functions put, get and getnew to write or read an
00086 // array of values.  These functions are defined for the same data types
00087 // as << and >> (so one can write, for example, an array of Strings).
00088 // AipsIO.put (nr, arr) writes nr values from the given array.
00089 // AipsIO.get (nr, arr) reads nr values into the given user-supplied array.
00090 // AipsIO.getnew (&nr, &arr) reads the number of values written into
00091 // a new array allocated on the heap.  It returns the nr of values read
00092 // and a pointer to the array.
00093 // The data must be read back in the same order as it was written.
00094 // <p>
00095 // The functions <src>putstart(type,version)</src>
00096 // and <src>putend()</src> must be called
00097 // before resp. after writing all values of the object.
00098 // It stores the given type and version of the object.
00099 // Similarly <src>getstart(type)</src> and <src>getend()</src> must be called.
00100 // getstart checks the type and returns the version.  By using the version
00101 // the read function of the object can convert older versions of the
00102 // object (which may still reside on disk) to the latest version.
00103 // The function getNextType is available to get the type of the next
00104 // object stored. This can be used to check the type or to open (i.e.
00105 // issue a getstart) in the correct way.
00106 // <p>
00107 // When implementing a class, one should also define the operators << and >>
00108 // for the class to allow users to write or read an object in this
00109 // simple way (e.g., as  io >> obj;  to read an object).
00110 // One has to define the friend functions:
00111 // <srcblock>
00112 //      friend AipsIO& operator<< (AipsIO&, const YourClass&);
00113 //      friend AipsIO& operator>> (AipsIO&, YourClass&);
00114 // </srcblock>
00115 // since they cannot be stored in the class itself.
00116 // The type of an object is usually passed as the class name.
00117 // <srcblock>
00118 //      AipsIO& operator<< (AipsIO& ios, const YourClass& object) {
00119 //          ios.putstart ("YourClass", version);
00120 //          ios << ....;
00121 //          ios.putend ();
00122 //      }
00123 // </srcblock>
00124 //
00125 // The functions getpos() and setpos(offset) can be used to get and set
00126 // the offset in the file to a given point.  They can be used to point
00127 // to a position in the file where an object must be written or read.
00128 // Obviously these functions are to be used by a storage manager and
00129 // are not for public use.  Someday they should be made private with
00130 // a friend defined.
00131 // </synopsis> 
00132 
00133 // <example>
00134 // <srcblock>
00135 //     MyClass myObject(...);                   // some object
00136 //     AipsIO ios("file.name", ByteIO::New);    // create new file
00137 //     ios << myObject;                         // write object
00138 //     MyClass myObject2;
00139 //     ios >> myObject2;                        // read it back
00140 // </srcblock>
00141 // This example creates an object, writes it to AipsIO and reads it
00142 // back into another object.
00143 // The shift functions for MyClass could be defined as follows:
00144 // <srcblock>
00145 // AipsIO& operator<< (AipsIO& ios, const MyClass& myObject)
00146 // {
00147 //     ios.putstart ("MyClass", 1);    // MyClass version 1
00148 //     ios << ...;                     // write all data members
00149 //     ios.putend();
00150 // }
00151 // AipsIO& operator>> (AipsIO& ios, const MyClass& myObject)
00152 // {
00153 //     // If needed, delete current data members first.
00154 //     // Now read in the object.
00155 //     uInt version = ios.getstart ("MyClass");
00156 //     ios >> ...;                     // read all data members
00157 //     ios.getend();
00158 // }
00159 // </srcblock>
00160 // In this example the version is not used. In more complex objects
00161 // it will probably be used when data members get added or changed
00162 // in future versions of a software system.
00163 // </example>
00164 
00165 
00166 class AipsIO
00167 {
00168 public:
00169     // No file attached yet
00170     AipsIO();
00171 
00172     // Construct and open/create a file with the given name.
00173     // The actual IO is done via a CanonicalIO object using a filebuf
00174     // with a buffer of the given size.
00175     explicit AipsIO (const String& fileName,
00176                      ByteIO::OpenOption = ByteIO::Old,
00177                      uInt filebufSize=65536);
00179 
00180     // Construct and open/create a file with the given name.
00181     // This can for instance by used to use AipsIO on a file descriptor
00182     // for which a <linkto class=FilebufIO>FilebufIO</linkto>
00183     // object has been created.
00184     // The actual IO is done via a CanonicalIO object on top of it.
00185     explicit AipsIO (ByteIO*);
00186 
00187     // Construct and open by connecting to the given file descriptor.
00188     // The actual IO is done via a filebuf object with a buffer
00189     // of the given size.
00190     explicit AipsIO (TypeIO*);
00191 
00192     // Close if not done yet
00193     ~AipsIO();
00194 
00195     // Open/create file.
00196     // An exception is thrown if the object contains an already open file.
00197     void open (const String& fileName, ByteIO::OpenOption = ByteIO::Old,
00198                uInt filebufSize=65536);
00199 
00200     // Open by connecting to the given byte stream.
00201     // This can for instance by used to use AipsIO on a file descriptor
00202     // for which a <linkto class=FilebufIO>FilebufIO</linkto>
00203     // object has been created.
00204     // The actual IO is done via a CanonicalIO object on top of it.
00205     // An exception is thrown if the object contains an already open file.
00206     void open (ByteIO*);
00207 
00208     // Open by connecting to the given file descriptor.
00209     // An exception is thrown if the object contains an already open file.
00210     void open (TypeIO*);
00211 
00212     // Close file opened
00213     void close();
00214 
00215     // Return the file option.
00216     ByteIO::OpenOption fileOption() const;
00217 
00218     // Start putting an object.
00219     // This writes the object type and version. When reading back getstart
00220     // calls have to be done in the same way. Getstart
00221     // checks the type and returns the version. The user can use that to
00222     // correctly read back objects with different versions.
00223     // <br>
00224     // Data in the outermost object cannot be put before a putstart is done.
00225     // Data in nested objects can be put without an intermediate putstart.
00226     // However, for complex objects it is recommended to do a putstart
00227     // to have a better checking.
00228     // <br>
00229     // After all values (inclusing nested objects) of the object have
00230     // been put, a call to putend has to be done.
00231     // <group>
00232     uInt putstart (const String& objectType, uInt objectVersion);
00233     uInt putstart (const Char* objectType, uInt objectVersion);
00234     // </group>
00235 
00236     // Put a single value.
00237     // <group>
00238     AipsIO& operator<< (const Bool& value);
00239     AipsIO& operator<< (const Char& value);
00240     AipsIO& operator<< (const uChar& value);
00241     AipsIO& operator<< (const short& value);
00242     AipsIO& operator<< (const unsigned short& value);
00243     AipsIO& operator<< (const int& value);
00244     AipsIO& operator<< (const unsigned int& value);
00245     AipsIO& operator<< (const Int64& value);
00246     AipsIO& operator<< (const uInt64& value);
00247     AipsIO& operator<< (const float& value);
00248     AipsIO& operator<< (const double& value);
00249     AipsIO& operator<< (const Complex& value);
00250     AipsIO& operator<< (const DComplex& value);
00251     AipsIO& operator<< (const String& value);
00252     AipsIO& operator<< (const Char* value);
00253     // </group>
00254 
00255     // Put an array of values with the given number of values.
00256     // If the flag putNr is set, the number of values is put first.
00257     // <group>
00258     AipsIO& put (uInt nrval, const Bool* values, Bool putNR = True);
00259     AipsIO& put (uInt nrval, const Char* values, Bool putNR = True);
00260     AipsIO& put (uInt nrval, const uChar* values, Bool putNR = True);
00261     AipsIO& put (uInt nrval, const short* values, Bool putNR = True);
00262     AipsIO& put (uInt nrval, const unsigned short* values, Bool putNR = True);
00263     AipsIO& put (uInt nrval, const int* values, Bool putNR = True);
00264     AipsIO& put (uInt nrval, const unsigned int* values, Bool putNR = True);
00265     AipsIO& put (uInt nrval, const Int64* values, Bool putNR = True);
00266     AipsIO& put (uInt nrval, const uInt64* values, Bool putNR = True);
00267     AipsIO& put (uInt nrval, const float* values, Bool putNR = True);
00268     AipsIO& put (uInt nrval, const double* values, Bool putNR = True);
00269     AipsIO& put (uInt nrval, const Complex* values, Bool putNR = True);
00270     AipsIO& put (uInt nrval, const DComplex* values, Bool putNR = True);
00271     AipsIO& put (uInt nrval, const String* values, Bool putNR = True);
00272     // </group>
00273 
00274     // Put a vector as an array of values
00275     // For standard types it has the same result as put with putNR=True.
00276     template<typename T>
00277     AipsIO& put (const vector<T>& vec)
00278       { *this << uInt(vec.size());
00279         for (typename vector<T>::const_iterator iter=vec.begin();
00280              iter!=vec.end(); ++iter) {
00281           *this << *iter;
00282         }
00283         return *this;
00284       }
00285     //# Possibly specialize for standard types to make it faster.
00286     //# Specialize for a bool vector.
00287     AipsIO& put (const vector<Bool>& vec);
00288 
00289 
00290     // End putting an object. It returns the object length (including
00291     // possible nested objects).
00292     uInt putend();
00293 
00294     // Get and set file-offset.
00295     // <group>
00296     Int64 getpos ();
00297     Int64 setpos (Int64 offset);
00298     // </group>
00299 
00300     // Get the type of the next object stored.
00301     // This is not possible if a put is in progress.
00302     const String& getNextType();
00303 
00304     // Start reading an object. It will check if the given type matches
00305     // the one stored by putstart. It returns the object version which
00306     // can be used to read in older version of the object correctly.
00307     // <br>
00308     // After all values (inclusing nested objects) of the object have
00309     // been read, a call to getend has to be done.
00310     // <group>
00311     uInt getstart (const String& objectType);
00312     uInt getstart (const Char* objectType);
00313     // </group>
00314 
00315     // Get a single value.
00316     // <group>
00317     AipsIO& operator>> (Bool& value);
00318     AipsIO& operator>> (Char& value);
00319     AipsIO& operator>> (uChar& value);
00320     AipsIO& operator>> (short& value);
00321     AipsIO& operator>> (unsigned short& value);
00322     AipsIO& operator>> (int& value);
00323     AipsIO& operator>> (unsigned int& value);
00324     AipsIO& operator>> (Int64& value);
00325     AipsIO& operator>> (uInt64& value);
00326     AipsIO& operator>> (float& value);
00327     AipsIO& operator>> (double& value);
00328     AipsIO& operator>> (Complex& value);
00329     AipsIO& operator>> (DComplex& value);
00330     AipsIO& operator>> (String& value);
00331     // </group>
00332 
00333     // Read in nrval values into the user-supplied values buffer.
00334     // The buffer must be long enough.
00335     // <group>
00336     AipsIO& get (uInt nrval, Bool* values);
00337     AipsIO& get (uInt nrval, Char* values);
00338     AipsIO& get (uInt nrval, uChar* values);
00339     AipsIO& get (uInt nrval, short* values);
00340     AipsIO& get (uInt nrval, unsigned short* values);
00341     AipsIO& get (uInt nrval, int* values);
00342     AipsIO& get (uInt nrval, unsigned int* values);
00343     AipsIO& get (uInt nrval, Int64* values);
00344     AipsIO& get (uInt nrval, uInt64* values);
00345     AipsIO& get (uInt nrval, float* values);
00346     AipsIO& get (uInt nrval, double* values);
00347     AipsIO& get (uInt nrval, Complex* values);
00348     AipsIO& get (uInt nrval, DComplex* values);
00349     AipsIO& get (uInt nrval, String* values);
00350     // </group>
00351 
00352     // Get a vector as an array of values (similar to getnew).
00353     // It resizes the vector as needed.
00354     template<typename T>
00355     AipsIO& get (vector<T>& vec)
00356       { uInt sz;
00357         *this >> sz;
00358         vec.resize(sz);
00359         for (typename vector<T>::iterator iter=vec.begin();
00360              iter!=vec.end(); ++iter) {
00361           *this >> *iter;
00362         }
00363         return *this;
00364       }
00365     //# Specialize for a bool vector.
00366     AipsIO& get (vector<Bool>& vec);
00367 
00368 
00369     // Read in values as written by the function put.
00370     // It will read the number of values (into nrval), allocate a
00371     // values buffer of that length and read the values into that buffer.
00372     // A pointer to the buffer is returned into values.
00373     // <warn=caution> Although the buffer is allocated by this function,
00374     // the user has to delete it (using <src>delete [] values;</src>).
00375     // <group>
00376     AipsIO& getnew (uInt& nrval, Bool*& values);
00377     AipsIO& getnew (uInt& nrval, Char*& values);
00378     AipsIO& getnew (uInt& nrval, uChar*& values);
00379     AipsIO& getnew (uInt& nrval, short*& values);
00380     AipsIO& getnew (uInt& nrval, unsigned short*& values);
00381     AipsIO& getnew (uInt& nrval, int*& values);
00382     AipsIO& getnew (uInt& nrval, unsigned int*& values);
00383     AipsIO& getnew (uInt& nrval, Int64*& values);
00384     AipsIO& getnew (uInt& nrval, uInt64*& values);
00385     AipsIO& getnew (uInt& nrval, float*& values);
00386     AipsIO& getnew (uInt& nrval, double*& values);
00387     AipsIO& getnew (uInt& nrval, Complex*& values);
00388     AipsIO& getnew (uInt& nrval, DComplex*& values);
00389     AipsIO& getnew (uInt& nrval, String*& values);
00390     // </group>
00391 
00392     // End reading an object. It returns the object length (including
00393     // possible nested objects).
00394     // It checks if the entire object has been read (to keep the data
00395     // stream in sync). If not, an exception is thrown.
00396     uInt getend();
00397 
00398 private:
00399     // Initialize everything for the open.
00400     // It checks if there is no outstanding open file.
00401     void openInit (ByteIO::OpenOption);
00402 
00403     // Test if put is possible (throw exception if not).
00404     void testput();
00405 
00406     // Test if get is possible (throw exception if not).
00407     void testget();
00408 
00409     // Test if get did not exceed object.
00410     void testgetLength();
00411 
00412     // Throw exception for testput
00413     void testputerr();
00414 
00415     // Throw exception for testget
00416     void testgeterr();
00417 
00418     // Throw exception for testgetLength
00419     void testgeterrLength();
00420 
00421 
00422     //  1 = file was opened by AipsIO
00423     //  0 = file not opened
00424     // -1 = file opened by user (=fd passed)
00425     Int          opened_p;
00426     // File open option
00427     ByteIO::OpenOption fopt_p;
00428     // <0 = not opened for put
00429     //  0 = no putstart done
00430     // >0 = put is possible
00431     int          swput_p;
00432     // <0 = not opened for get
00433     //  0 = no getstart done
00434     // >0 = get is possible
00435     int          swget_p;
00436     // Nested object level
00437     uInt         level_p;
00438     // Current size of objlen and objptr
00439     uInt         maxlev_p;
00440     // Object length at each level
00441     Block<uInt>  objlen_p;
00442     // Object length to be read at each level
00443     Block<uInt>  objtln_p;
00444     // Offset of length at each level
00445     Block<Int64>  objptr_p;
00446     // True = the object type has already been read
00447     Bool         hasCachedType_p;
00448     // The cached object type.
00449     String       objectType_p;
00450     // The file object.
00451     RegularFileIO* file_p;
00452     // The actual IO object.
00453     TypeIO*      io_p;
00454     // Is the file is seekable?
00455     Bool         seekable_p;
00456     // magic value to check sync.
00457     static const uInt magicval_p;
00458 };
00459 
00460 
00461 
00462 // Return the file option.
00463 inline ByteIO::OpenOption AipsIO::fileOption() const
00464 { return fopt_p; }
00465 
00466 
00467 // testput tests if a put can be done; ie. if putstart has been done.
00468 // It throws an exception if not.
00469 // testget is similar to test if a get can be done.
00470 inline void AipsIO::testput()
00471 {
00472     if (swput_p <= 0) {
00473         testputerr();
00474     }
00475 }
00476 inline void AipsIO::testget()
00477 {
00478     if (swget_p <= 0) {
00479         testgeterr();
00480     }
00481 }
00482 inline void AipsIO::testgetLength()
00483 {
00484     if (objlen_p[level_p] > objtln_p[level_p]) {
00485         testgeterrLength();
00486     }
00487 }
00488 
00489 
00490 
00491 } //# NAMESPACE CASA - END
00492 
00493 #endif