casa
$Rev:20696$
|
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