casa
$Rev:20696$
|
00001 //# Block.h: Simple templated array classes 00002 //# Copyright (C) 1993-1997,2000,2002,2005 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: Block.h 21090 2011-06-01 10:01:28Z gervandiepen $ 00027 00028 #ifndef CASA_BLOCK_H 00029 #define CASA_BLOCK_H 00030 00031 #include <casa/aips.h> 00033 #include <casa/Utilities/Copy.h> 00034 00035 //# For index checking 00036 #if defined(AIPS_ARRAY_INDEX_CHECK) 00037 #include <casa/Exceptions/Error.h> 00038 #endif 00039 00040 #include <stddef.h> // for ptrdiff_t 00041 00042 namespace casa { //# NAMESPACE CASA - BEGIN 00043 00044 // <summary>simple 1-D array</summary> 00045 // <use visibility=export> 00046 // 00047 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos=""> 00048 // </reviewed> 00049 // 00050 // <etymology> 00051 // This should be viewed as a <em>block</em> of memory without sophisticated 00052 // manipulation functions. Thus it is called <src>Block</src>. 00053 // </etymology> 00054 // 00055 // <synopsis> 00056 // <src>Block<T></src> is a simple templated 1-D array class. Indices are always 00057 // 0-based. For efficiency reasons, no index checking is done unless the 00058 // preprocessor symbol <src>AIPS_ARRAY_INDEX_CHECK</src> is defined. 00059 // <src>Block<T></src>'s may be assigned to and constructed from other 00060 // <src>Block<T></src>'s. 00061 // As no reference counting is done this can be an expensive operation, however. 00062 // 00063 // The net effect of this class is meant to be unsurprising to users who think 00064 // of arrays as first class objects. The name "Block" is intended to convey 00065 // the concept of a solid "chunk" of things without any intervening "fancy" 00066 // memory management, etc. This class was written to be 00067 // used in the implementations of more functional Vector, Matrix, etc. classes, 00068 // although it is expected <src>Block<T></src> will be useful on its own. 00069 // 00070 // The Block class should be efficient. You should normally use <src>Block</src>. 00071 // 00072 // <note role=warning> If you use the assignment operator on an element of this 00073 // class, you may leave dangling references to pointers released from 00074 // <src>storage()</src>. 00075 // Resizing the array will also have this effect if the underlying storage 00076 // is actually affected. 00077 // </note> 00078 // 00079 // If index checking is turned on, an out-of-bounds index will 00080 // generate an <src>indexError<uInt></src> exception. 00081 // </synopsis> 00082 // 00083 // <example> 00084 // <srcblock> 00085 // Block<Int> a(100,0); // 100 ints initialized to 0 00086 // Block<Int> b; // 0-length Block 00087 // // ... 00088 // b = a; // resize b and copy a into it 00089 // for (size_t i=0; i < a.nelements(); i++) { 00090 // a[i] = i; // Generate a sequence 00091 // // with Vectors, could simply say "indgen(myVector);" 00092 // } 00093 // b.set(-1); // All positions in b have the value -1 00094 // b.resize(b.nelements()*2); // Make b twice as long, by default the old 00095 // // elements are copied over, although this can 00096 // // be defeated. 00097 // some_c_function(b.storage()); // Use a fn that takes an 00098 // // <src>Int *</src> pointer 00099 // </srcblock> 00100 // </example> 00101 // 00102 template<class T> class Block { 00103 public: 00104 // Create a zero-length Block. Note that any index into this Block 00105 // is an error. 00106 Block() : npts(0), array(0), destroyPointer(True) {} 00107 // Create a Block with the given number of points. The values in Block 00108 // are uninitialized. Note that indices range between 0 and n-1. 00109 explicit Block(size_t n) : npts(n), array(n>0 ? new T[n] : 0), destroyPointer(True) 00110 {} 00111 // Create a Block of the given length, and initialize (via operator= for 00112 // objects of type T) with the provided value. 00113 Block(size_t n, T val) : npts(n), array(n > 0 ? new T[n] : 0), destroyPointer(True) 00114 { objset(array, val, n); } 00115 00116 // Create a <src>Block</src> from a C-array (i.e. pointer). If 00117 // <src>takeOverStorage</src> is <src>True</src>, The Block assumes that 00118 // it owns the pointer, i.e. that it is safe to <src>delet[]</src> it when 00119 // the Block is destructed, otherwise the actual storage is not destroyed. 00120 // If true, <src>storagePointer</src> is set to <src>0</src>. 00121 Block(size_t n, T *&storagePointer, Bool takeOverStorage = True) 00122 : npts(n), array(storagePointer), destroyPointer(takeOverStorage) 00123 { if (destroyPointer) storagePointer = 0;} 00124 00125 // Copy the other block into this one. Uses copy, not reference, semantics. 00126 Block(const Block<T> &other) 00127 : npts(other.npts), array(npts > 0 ? new T[npts] : 0), destroyPointer(True) 00128 { objcopy(array, other.array, npts); } 00129 00130 // Assign other to this. this resizes itself to the size of other, so after 00131 // the assignment, this->nelements() == other.elements() always. 00132 Block<T> &operator=(const Block<T> &other) { 00133 if (&other != this) { 00134 this->resize(other.npts, True, False); 00135 objcopy(array, other.array, npts); 00136 }; 00137 return *this; } 00138 00139 // Frees up the storage pointed contained in the Block. 00140 ~Block() { if (array && destroyPointer) { delete [] array; array = 0;} } 00141 00142 // Resizes the Block. If <src>n == nelements()</src> resize just returns. If 00143 // a larger size is requested (<src>n > nelements()</src>) the Block always 00144 // resizes. If the requested size is smaller (<src>n < nelements()</src>), 00145 // by default the Block does not resize smaller, although it can be 00146 // forced to with <src>forceSmaller</src>. The reasoning behind this is that 00147 // often the user will just want a buffer of at least a certain size, 00148 // and won't want to pay the cost of multiple resizings. 00149 // <srcblock> 00150 // Block<float> bf(100, 0.0); 00151 // bf.resize(10); // bf.nelements() == 100 00152 // bf.resize(10, True) // bf.nelements() == 10 00153 // bf.resize(200) // bf.nelements() == 200 00154 // </srcblock> 00155 // Normally the old elements are copied over (although if the 00156 // Block is lengthened the trailing elements will have undefined 00157 // values), however this can be turned off by setting copyElements to 00158 // False. 00159 // 00160 // This is written as three functions because default parameters do 00161 // not always work properly with templates. 00162 // <group> 00163 void resize(size_t n, Bool forceSmaller=False, Bool copyElements=True) { 00164 if (!(n == npts || (n < npts && forceSmaller == False))) { 00165 T *tp = n > 0 ? new T[n] : 0; 00166 if (copyElements) { 00167 size_t nmin = npts < n ? npts : n; // Don't copy too much! 00168 objcopy(tp, array, nmin); 00169 }; 00170 if (array && destroyPointer) { // delete... 00171 delete [] array; 00172 array = 0; 00173 }; 00174 npts = n; 00175 destroyPointer = True; 00176 array = tp; // ... and swap pointer 00177 }; 00178 } 00179 // </group> 00180 00181 // Remove a single element from the Block. If forceSmaller is True this 00182 // will resize the Block and hence involve new memory allocations. This is 00183 // relatively expensive so setting forceSmaller to False is preferred. When 00184 // forcesmaller is False the Block is not resized but the elements with an 00185 // index above the removed element are shuffled down by one. For backward 00186 // compatibility forceSmaller is True by default. 00187 // <group> 00188 void remove(size_t whichOne, Bool forceSmaller=True) { 00189 if (whichOne >= npts) { 00190 #if defined(AIPS_ARRAY_INDEX_CHECK) 00191 throw(indexError<uInt>(whichOne, "Block::remove() - " 00192 "index out of range")); 00193 #else 00194 return; 00195 #endif 00196 }; 00197 if (forceSmaller == True) { 00198 T *tp = new T[npts - 1]; 00199 objcopy(tp, array, whichOne); 00200 objcopy(tp+whichOne, array + whichOne + 1, npts - whichOne - 1); 00201 if (array && destroyPointer) { 00202 delete [] array; 00203 array = 0; 00204 }; 00205 npts--; 00206 array = tp; 00207 destroyPointer = True; 00208 } else objmove(array+whichOne, array + whichOne + 1, npts - whichOne - 1); 00209 } 00210 // </group> 00211 00212 // Replace the internal storage with a C-array (i.e. pointer). 00213 // If <src>takeOverStorage</src> is True, The Block assumes that it 00214 // owns the pointer, i.e. that it is safe to <src>delete[]</src> it when the 00215 // <src>Block</src>is destructed, otherwise the actual storage is not destroyed. 00216 // If true, storagePointer is set to <src>NULL</src>. 00217 void replaceStorage(size_t n, T *&storagePointer, Bool takeOverStorage=True) { 00218 if (array && destroyPointer) { 00219 delete [] array; 00220 array = 0; 00221 }; 00222 npts = n; 00223 array = storagePointer; 00224 destroyPointer = takeOverStorage; 00225 if (destroyPointer) storagePointer = 0; 00226 }; 00227 00228 // Index into the block (0-based). If the preprocessor symbol 00229 // <src>AIPS_ARRAY_INDEX_CHECK</src> is defined, index checking will be done 00230 // and an out-of-bounds index will cause an <src>indexError<uInt></src> to be 00231 // thrown. Note that valid indices range between 0 and <src>nelements()-1</src>. 00232 // <thrown> 00233 // <li> indexError 00234 // </thrown> 00235 // <group> 00236 T &operator[](size_t index) { 00237 #if defined(AIPS_ARRAY_INDEX_CHECK) 00238 // Write it this way to avoid casts; remember index and npts are 00239 // unsigned. 00240 if ((npts == 0) || (index > npts - 1)) { 00241 throw(indexError<uInt>(index, "Block::operator[] - " 00242 "index out of range")); 00243 }; 00244 #endif 00245 return array[index]; 00246 } 00247 const T &operator[](size_t index) const { 00248 #if defined(AIPS_ARRAY_INDEX_CHECK) 00249 if ((npts == 0) || (index > npts - 1)) { 00250 throw(indexError<uInt>(index, "Block::operator[] const - " 00251 "index out of range")); 00252 }; 00253 #endif 00254 return array[index]; 00255 } 00256 // </group> 00257 00258 // Set all values in the block to "val". 00259 // <group> 00260 Block<T> &operator=(const T &val) 00261 { T tmp=val; objset(array, tmp, npts); return *this;} 00262 void set(const T &val) { *this = val; } 00263 // </group> 00264 00265 // If you really, really, need a "raw" pointer to the beginning of the 00266 // storage area this will give it to you. This may leave dangling pointers 00267 // if the block is destructed or if the assignment operator or resize 00268 // is used. Returns a null pointer if <src>nelements() == 0</src>. 00269 // It is best to only use this if you completely control the extent and 00270 // lifetime of the <src>Block</src>. 00271 // <h3> Examples of misuse </h3> <srcblock> 00272 // Block<Int> *bp = new Block<Int>(100); 00273 // Int *ip = bp->storage(); 00274 // delete bp; // Oops, ip is now dangling 00275 // Block<Int> a(100),b(100); 00276 // Int *ip = a.storage(); 00277 // a = b; // Likewise 00278 // </srcblock> 00279 // <group> 00280 T *storage() {return array;} 00281 const T *storage() const {return array;} 00282 // </group> 00283 00284 // The number of elements contained in this <src>Block<T></src>. 00285 // <group> 00286 size_t nelements() const {return npts;} 00287 size_t size() const {return npts;} 00288 // </group> 00289 00290 // Is the block empty (i.e. no elements)? 00291 Bool empty() const {return npts == 0;} 00292 00293 // Define the STL-style iterators. 00294 // It makes it possible to iterate through all data elements. 00295 // <srcblock> 00296 // Block<Int> bl(100,0); 00297 // for (Block<Int>::iterator iter=bl.begin(); iter!=bl.end(); iter++) { 00298 // *iter += 1; 00299 // } 00300 // </srcblock> 00301 // <group name=STL-iterator> 00302 // STL-style typedefs. 00303 // <group> 00304 typedef T value_type; 00305 typedef T* iterator; 00306 typedef const T* const_iterator; 00307 typedef value_type* pointer; 00308 typedef const value_type* const_pointer; 00309 typedef value_type& reference; 00310 typedef const value_type& const_reference; 00311 typedef size_t size_type; 00312 typedef ptrdiff_t difference_type; 00313 // </group> 00314 // Get the begin and end iterator object for this block. 00315 // <group> 00316 iterator begin() 00317 { return array; } 00318 const_iterator begin() const 00319 { return array; } 00320 iterator end() 00321 { return array + npts; } 00322 const_iterator end() const 00323 { return array + npts; } 00324 // </group> 00325 // </group> 00326 00327 private: 00328 // The number of points in the vector 00329 size_t npts; 00330 // The actual storage 00331 T *array; 00332 // Can we delete the storage upon destruction? 00333 Bool destroyPointer; 00334 }; 00335 00336 // <summary> 00337 // A drop-in replacement for <src>Block<T*></src>. 00338 // </summary> 00339 00340 // <use visibility=export> 00341 // <prerequisite> 00342 // <li> <linkto class=Block>Block</linkto> 00343 // </prerequisite> 00344 00345 // <synopsis> 00346 // <src>PtrBlock<T*></src> has exactly the same interface as <src>Block<T*></src> 00347 // and should be used in preference to the latter. It's purpose is solely to 00348 // reduce the number of template instantiations. 00349 // </synopsis> 00350 00351 // <todo asof="1996/05/01"> 00352 // <li> Partial template specialization is another implementation choice that 00353 // will be possible eventually. 00354 // <li> It might be useful to have functions that know the templte parameter 00355 // is a pointer, e.g. that delete all the non-null pointers. 00356 // </todo> 00357 00358 template<class T> class PtrBlock { 00359 public: 00360 PtrBlock() : block_p() {} 00361 explicit PtrBlock(size_t n) : block_p(n) {} 00362 PtrBlock(size_t n, T val) : block_p(n, (void *)val) {} 00363 PtrBlock(size_t n, T *&storagePointer, Bool takeOverStorage = True) 00364 : block_p(n, (void **&)storagePointer, takeOverStorage) {} 00365 PtrBlock(const PtrBlock<T> &other) : block_p(other.block_p) {} 00366 PtrBlock<T> &operator=(const PtrBlock<T> &other) 00367 { block_p = other.block_p; return *this;} 00368 ~PtrBlock() {} 00369 void resize(size_t n, Bool forceSmaller, Bool copyElements) 00370 { block_p.resize(n,forceSmaller, copyElements); } 00371 void resize(size_t n) {block_p.resize(n);} 00372 void resize(size_t n, Bool forceSmaller) {block_p.resize(n, forceSmaller);} 00373 void remove(size_t whichOne, Bool forceSmaller) { 00374 block_p.remove(whichOne, forceSmaller);} 00375 void remove(size_t whichOne) {block_p.remove(whichOne);} 00376 void replaceStorage(size_t n, T *&storagePointer, 00377 Bool takeOverStorage=True) 00378 {block_p.replaceStorage(n, (void **&)storagePointer, takeOverStorage);} 00379 T &operator[](size_t index) {return (T &)block_p[index];} 00380 const T &operator[](size_t index) const {return (const T &)block_p[index];} 00381 void set(const T &val) {block_p.set((void *const &)val);} 00382 PtrBlock<T> &operator=(const T &val) {set(val); return *this;} 00383 T *storage() {return (T *)block_p.storage();} 00384 const T *storage() const {return (const T *)block_p.storage();} 00385 size_t nelements() const {return block_p.nelements();} 00386 size_t size() const {return block_p.size();} 00387 Bool empty() const {return block_p.empty();} 00388 private: 00389 Block<void*> block_p; 00390 }; 00391 00392 00393 } //# NAMESPACE CASA - END 00394 00395 #endif