casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
SDDBlock.h
Go to the documentation of this file.
00001 //# SDDBlock.h: A Block<uChar> with some helpful functions for SDD files.
00002 //# Copyright (C) 1995,1999,2001
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //#
00027 //# $Id$
00028 
00029 #ifndef NRAO_SDDBLOCK_H
00030 #define NRAO_SDDBLOCK_H
00031 
00032 #include <casa/aips.h>
00033 #include <casa/Containers/Block.h>
00034 #include <casa/Exceptions/Error.h>
00035 
00036 #include <casa/namespace.h>
00037 //# Forward Declarations
00038 #include <casa/iosfwd.h>
00039 
00040 #include <casa/namespace.h>
00041 // <summary> 
00042 // SDDBlock handles the IO and value extraction from SDD records (blocks).
00043 // </summary>
00044 
00045 // <use visibility=local> 
00046 
00047 // <reviewed reviewer="" date="" tests="" demos="">
00048 
00049 // <prerequisite>
00050 // <li> SDDFile
00051 // <li> Block
00052 // <li> iostreams
00053 // <li> The SDD file format.
00054 // </prerequisite>
00055 //
00056 // <etymology>
00057 // SDD stands for Single Dish Data.  It is the data format that UniPOPS
00058 // understands.  It is also the on-line data format at the NRAO 12m.
00059 // SDD files are organized in records or blocks.  This class handles the
00060 // io to and from those blocks.  it is used by the other SDD classes.
00061 // </etymology>
00062 //
00063 // <synopsis> 
00064 // SDDBlock is used primarily to handle the IO to and from an SDD file
00065 // in units of an SDD record size.  The standard rccord size if 512
00066 // bytes although this class can handle arbitrarily sized records so
00067 // long as the size is an integer multiple of 8 bytes (the size of
00068 // and IEEE double precision floating point number).  The total size
00069 // of an SDDBlock is an integer multiple of the record size (i.e. no
00070 // fractional records are allowed).  This class also aids in extracting
00071 // values of different types from the block.  This is not likely to
00072 // be immediately portable.  However, by isolating that conversion here,
00073 // it should make any future ports easier.  Since SDD files will only
00074 // ever be written on Suns, its unlikely that this issue will be a
00075 // problem.
00076 //
00077 // The IO only involves iostreams and not fstream.  It is intended
00078 // that the public SDD classes handle all of the fstream specific
00079 // operations and that this class does not need to do any seeks.
00080 //
00081 // An SDDBlock is always at least 1 SDD record in size.
00082 // </synopsis> 
00083 //
00084 // <example>
00085 // This is a somewhat contrived example.
00086 // <srcblock>
00087 // // This istream would be initialized appropriately
00088 // istream in;
00089 // // construct an SDDBlock of 1 SDD record using the standard record size
00090 // SDDBlock block;
00091 // block.read(in, 1);
00092 // // Extract the 5th double from the record, which indicates the size
00093 // // of the full record to read in bytes, convert that to SDD records
00094 // // read it in.   This would need some additional checks if partial
00095 // // records might be indicated.
00096 // double fullSize = block.asdouble(4);
00097 // uInt nrecs = uInt(fullSize/block.bytesPerRecord());
00098 // // read the remaining records
00099 // block.read(in, (nrecs-1));
00100 // </srcblock>
00101 // </example>
00102 //
00103 // <motivation>
00104 // SDD files are organized into units that are integer number of
00105 // records (always of 512 bytes at this point in history, but they
00106 // could theoretically be of a different size).  It makes sense to
00107 // have a class that the other SDD classes could use to deal with
00108 // the data in those chunks.
00109 // </motivation>
00110 //
00111 // <thrown>
00112 // <li> indexError - by the asT functions but only when AIPS_ARRAY_INDEX_CHECK is on.
00113 // <li> AllocError - during construction
00114 // <li> AipsError - by read/write indicates an IO error
00115 // <li> AipsError - by copy and write if the indicated size is invalid
00116 // </thrown>
00117 //
00118 // <todo asof="">
00119 // </todo>
00120 
00121 class SDDBlock
00122 {
00123 public: 
00124     // SDD files have traditionally been composed of 512 byte records, but they are not
00125     // not really required to be.
00126     enum {STANDARD_RECORD_SIZE = 512};
00127 
00128     // An SDDBlock with the indicated number of SDD records, each record having
00129     // the indicated size in bytes, the whole thing filled with zeros.
00130     SDDBlock(uInt n = 1, uInt bytesPerRecord = STANDARD_RECORD_SIZE);
00131     // copy constructor, this makes a true copy.
00132     SDDBlock(const SDDBlock& other);
00133 
00134     ~SDDBlock();
00135         
00136     // assignment operator, this makes a true copy
00137     SDDBlock& operator=(const SDDBlock& other);
00138 
00139     // return the size in SDD records
00140     uInt nRecords() const {return cblk_p->nelements()/bytesPerRecord_p;}
00141     // return the number of bytes
00142     uInt nbytes() const { return cblk_p->nelements();}
00143     // return the number of bytes per record
00144     uInt bytesPerRecord() const { return bytesPerRecord_p;}
00145 
00146     // resize this block to the indicated number of SDD records
00147     // forceSmaller and copyElements work as with the Block class
00148     void resize(uInt nRecords, Bool forceSmaller = False,
00149                      Bool copyElements = False);
00150 
00151     // reshape is like resize, except that the number of bytes per record can also
00152     // change.  The number of bytesPerRecord must be a multiple of 8.
00153     void reshape(uInt nRecords, uInt bytesPerRecord,
00154                  Bool forceSmaller = False, Bool copyElements = False);
00155 
00156     // read from istream and fill until this SDDBlock is full or istream is exhausted
00157     // return the number of records actually read 
00158     uInt read(istream& in);
00159     // read nrecord records from istream, filling starting at the indicated record
00160     // stop if istream is exhausted, return the number of records actually read
00161     uInt read(istream& in, uInt nrecord, uInt startRecord = 0);
00162 
00163     // read the indicated number of bytes from in, starting at the optionally indicated
00164     // starting bytes offset, returns the number of bytes actually read
00165     uInt readBytes(istream& in, uInt nbytes, uInt startOffset = 0);
00166 
00167     // write the entire SDDBlock to ostream, return the number of records written
00168     uInt write(ostream& out) const;
00169     // write nrecord records to ostream, starting at the indicated record
00170     // return the number of records written
00171     uInt write(ostream& out, uInt nrecord, uInt startRecord = 0) const;
00172 
00173     // write the indicated number of bytes to out, starting at the optionally indicated
00174     // starting byte offset, returns the number of bytes actually written
00175     uInt writeBytes(ostream& out, uInt nbytes, uInt startOffset = 0) const;
00176 
00177     // copy ncopy character to another SDDBlock starting at outStart (characters) 
00178     // offset into and starting at inStart (characters) offset into this blcck
00179     void copy(SDDBlock& outBlock, uInt ncopy,
00180               uInt outStart = 0, uInt inStart = 0) const;
00181 
00182     // index into the block 
00183     Char& operator[](uInt index) {return (*cblk_p)[index];}
00184     const Char& operator[](uInt index) const {return (*cblk_p)[index];}
00185 
00186     // Index into the block as Shorts (0-based)
00187     Short& asShort(uInt index);
00188     const Short& asShort(uInt index) const;
00189     // Index into the block as Ints (0-based)
00190     Int& asInt(uInt location);
00191     const Int& asInt(uInt location) const;
00192     // Index into the block as floats (0-based)
00193     float& asfloat(uInt location);
00194     const float& asfloat(uInt location) const;
00195     // Index into the block as doubles (0-based)
00196     double& asdouble(uInt location);
00197     const double& asdouble(uInt location) const;
00198     
00199 private:
00200     Block<Char> *cblk_p;
00201     Short *sarray;
00202     Int *iarray;
00203     float *farray;
00204     double *darray;
00205 
00206     uInt bytesPerRecord_p;
00207 
00208     void set_pointers();
00209 };
00210 
00211 inline Short& SDDBlock::asShort(uInt index)
00212 {
00213 #if defined(AIPS_ARRAY_INDEX_CHECK)
00214     if ((cblk_p->nelements() == 0) || 
00215          (index > (cblk_p->nelements()/sizeof(Short)) - 1)) {
00216         throw(indexError<Short>(index, "SDDBlock::asShort(uInt index) - "
00217                                 "index out of range"));
00218     }
00219 #endif
00220     return sarray[index];
00221 }
00222 
00223 inline const Short& SDDBlock::asShort(uInt index) const
00224 {
00225 #if defined(AIPS_ARRAY_INDEX_CHECK)
00226     if ((cblk_p->nelements() == 0) || 
00227          (index > (cblk_p->nelements()/sizeof(Short)) - 1)) {
00228         throw(indexError<Short>(index, "SDDBlock::asShort(uInt index) - "
00229                                 "index out of range"));
00230     }
00231 #endif
00232     return sarray[index];
00233 }
00234 
00235 inline Int& SDDBlock::asInt(uInt index)
00236 {
00237 #if defined(AIPS_ARRAY_INDEX_CHECK)
00238     if ((cblk_p->nelements() == 0) || 
00239          (index > (cblk_p->nelements()/sizeof(Int)) - 1)) {
00240         throw(indexError<Int>(index, "SDDBlock::asInt(uInt index) - "
00241                               "index out of range"));
00242     }
00243 #endif
00244     return iarray[index];
00245 }
00246 
00247 inline const Int& SDDBlock::asInt(uInt index) const
00248 {
00249 #if defined(AIPS_ARRAY_INDEX_CHECK)
00250     if ((cblk_p->nelements() == 0) || 
00251          (index > (cblk_p->nelements()/sizeof(Int)) - 1)) {
00252         throw(indexError<Int>(index, "SDDBlock::asInt(uInt index) - "
00253                               "index out of range"));
00254     }
00255 #endif
00256     return iarray[index];
00257 }
00258 
00259 
00260 inline float& SDDBlock::asfloat(uInt index)
00261 {
00262 #if defined(AIPS_ARRAY_INDEX_CHECK)
00263     if ((cblk_p->nelements() == 0) || 
00264          (index > (cblk_p->nelements()/sizeof(float)) - 1)) {
00265         throw(indexError<float>(index, "SDDBlock::asfloat(uInt index) - "
00266                                 "index out of range"));
00267     }
00268 #endif
00269     return farray[index];
00270 }
00271 
00272 inline const float& SDDBlock::asfloat(uInt index) const
00273 {
00274 #if defined(AIPS_ARRAY_INDEX_CHECK)
00275     if ((cblk_p->nelements() == 0) || 
00276          (index > (cblk_p->nelements()/sizeof(float)) - 1)) {
00277         throw(indexError<float>(index, "SDDBlock::asfloat(uInt index) - "
00278                                 "index out of range"));
00279     }
00280 #endif
00281     return farray[index];
00282 }
00283 
00284 inline double& SDDBlock::asdouble(uInt index)
00285 {
00286 #if defined(AIPS_ARRAY_INDEX_CHECK)
00287     if ((cblk_p->nelements() == 0) || 
00288          (index > (cblk_p->nelements()/sizeof(double)) - 1)) {
00289         throw(indexError<double>(index, "SDDBlock::asdouble(uInt index) - "
00290                                  "index out of range"));
00291     }
00292 #endif
00293     return darray[index];
00294 }
00295 
00296 inline const double& SDDBlock::asdouble(uInt index) const
00297 {
00298 #if defined(AIPS_ARRAY_INDEX_CHECK)
00299     if ((cblk_p->nelements() == 0) || 
00300          (index > (cblk_p->nelements()/sizeof(double)) - 1)) {
00301         throw(indexError<double>(index, "SDDBlock::asdouble(uInt index) - "
00302                                  "index out of range"));
00303     }
00304 #endif
00305     return darray[index];
00306 }
00307 
00308 inline uInt SDDBlock::readBytes(istream& in, uInt nbytes, uInt startOffset)
00309 {
00310     // is a resize necessary, copy elements if it is necessary
00311     // this may be wastefull, if so, use SDDBlock::resize() first without copying
00312     if (nbytes + startOffset - 1 > cblk_p->nelements())
00313         resize(nbytes+startOffset-1, False, True);
00314 
00315     in.read((cblk_p->storage() + startOffset), nbytes);
00316     return in.gcount();
00317 }
00318 
00319 inline uInt SDDBlock::read(istream& in)
00320 {
00321     // attempt to read from istream until Block is full
00322     uInt nchars = readBytes(in, cblk_p->nelements());
00323     if (nchars%bytesPerRecord_p) {
00324         throw(AipsError("SDDBlock::read(istream& in) - partial record read"));
00325     }
00326     return nchars/bytesPerRecord_p;
00327 }
00328 
00329 inline uInt SDDBlock::read(istream& in, uInt nrecord, uInt startRecord)
00330 {
00331     uInt nchars = 
00332         readBytes(in, nrecord*bytesPerRecord_p, startRecord*bytesPerRecord_p);
00333 
00334     if (nchars%bytesPerRecord_p) {
00335         throw(AipsError("SDDBlock::read(istream& in, uInt nrecord, uInt startRecord) - "
00336                         "partial record read"));
00337     }
00338     return nchars/bytesPerRecord_p;
00339 }
00340 
00341 inline uInt SDDBlock::writeBytes(ostream& out, uInt nbytes, uInt startOffset) const
00342 {
00343     // make sure we have what has been requested
00344     if (nbytes+startOffset-1 > cblk_p->nelements()) {
00345         throw(AipsError("SDDBlock::write - request exceeds current size of SDDBlock"));
00346     }
00347     out.write(cblk_p->storage() + startOffset, nbytes);
00348     return nbytes;
00349 }
00350 
00351 inline uInt SDDBlock::write(ostream& out) const
00352 {
00353     // write all of Block to ostream
00354     return (writeBytes(out, cblk_p->nelements()))/bytesPerRecord_p;
00355 }
00356 
00357 inline uInt SDDBlock::write(ostream& out, uInt nrecord, uInt startRecord) const
00358 {
00359     writeBytes(out, nrecord*bytesPerRecord_p, startRecord*bytesPerRecord_p);
00360     return nrecord;
00361 }
00362 
00363 inline void SDDBlock::copy(SDDBlock& out, uInt ncopy, uInt outStart, uInt inStart) const
00364 {
00365     if ((outStart+ncopy-1) > out.nbytes() ||
00366         (inStart+ncopy-1) > nbytes()) {
00367         throw (AipsError("SDDBlock::copy(SDDBlock& out, uInt, uInt, uInt) - "
00368                          "copy would extend beyond end of one or both blocks"));
00369     }
00370     const Char* incptr = cblk_p->storage() + inStart;
00371     Char* outcptr = out.cblk_p->storage() + outStart;
00372     for (uInt i=0;i<ncopy;i++, incptr++, outcptr++) *outcptr = *incptr;
00373 }
00374 
00375 #endif