casa
$Rev:20696$
|
00001 //# Array.h: A templated N-D Array class with zero origin 00002 //# Copyright (C) 1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003 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: Array.h 21098 2011-06-24 07:42:37Z gervandiepen $ 00027 00028 #ifndef CASA_ARRAY_H 00029 #define CASA_ARRAY_H 00030 00031 //# Includes 00032 #include <casa/Arrays/ArrayBase.h> 00033 #include <casa/Containers/Block.h> 00034 #include <casa/Utilities/CountedPtr.h> 00035 #include <casa/Arrays/MaskLogiArrFwd.h> 00036 #include <casa/Arrays/IPosition.h> 00037 #include <casa/ostream.h> 00038 #include <iterator> 00039 #if defined(WHATEVER_VECTOR_FORWARD_DEC) 00040 WHATEVER_VECTOR_FORWARD_DEC; 00041 #else 00042 #include <casa/stdvector.h> 00043 #endif 00044 00045 namespace casa { //#Begin casa namespace 00046 //# Forward Declarations 00047 class AipsIO; 00048 class Slice; 00049 class Slicer; 00050 template<class T> class Matrix; 00051 template<class T> class ArrayIterator; 00052 template<class T> class MaskedArray; 00053 template<class Domain, class Range> class Functional; 00054 //template <class T, class U> class vector; 00055 00056 00057 // <summary> A templated N-D Array class with zero origin </summary> 00058 00059 // Array<T> is a templated, N-dimensional, Array class. The origin is zero, 00060 // but by default indices are zero-based. This Array class is the 00061 // base class for specialized Vector<T>, Matrix<T>, and Cube<T> classes. 00062 // 00063 // Indexing into the array, and positions in general, are given with IPosition 00064 // (essentially a vector of integers) objects. That is, an N-dimensional 00065 // array requires a length-N IPosition to define a position within the array. 00066 // Unlike C, indexing is done with (), not []. Also, the storage order 00067 // is the same as in FORTRAN, i.e. memory varies most rapidly with the first 00068 // index. 00069 // <srcblock> 00070 // // axisLengths = [1,2,3,4,5] 00071 // IPosition axisLengths(5, 1, 2, 3, 4, 5); 00072 // Array<Int> ai(axisLengths); // ai is a 5 dimensional array of 00073 // // integers; indices are 0-based 00074 // // => ai.nelements() == 120 00075 // Array<Int> ai2(axisLengths); // The first element is at index 0 00076 // IPosition zero(5); zero = 0; // [0,0,0,0,0] 00077 // //... 00078 // </srcblock> 00079 // Indexing into an N-dimensional array is relatively expensive. Normally 00080 // you will index into a Vector, Matrix, or Cube. These may be obtained from 00081 // an N-dimensional array by creating a reference, or by using an 00082 // ArrayIterator. The "shape" of the array is an IPosition which gives the 00083 // length of each axis. 00084 // 00085 // An Array may be standalone, or it may refer to another array, or to 00086 // part of another array (by refer we mean that if you change a pixel in 00087 // the current array, a pixel in the referred to array also changes, i.e. 00088 // they share underlying storage). 00089 // <note role=warning> 00090 // One way one array can reference another is through the copy 00091 // constructor. While this might be what you want, you should 00092 // probably use the reference() member function to make it explicit. 00093 // The copy constructor is used when arguments are passed by value; 00094 // normally functions should not pass Arrays by value, rather they 00095 // should pass a reference or a const reference. On the positive 00096 // side, returning an array from a function is efficient since no 00097 // copying need be done. 00098 // </note> 00099 // 00100 // Aside from the explicit reference() member function, a user will 00101 // most commonly encounter an array which references another array 00102 // when he takes an array slice (or section). A slice is a sub-region of 00103 // an array (which might also have a stride: every nth row, every mth column, 00104 // ...). 00105 // <srcblock> 00106 // IPosition lengths(3,10,20,30); 00107 // Array<Int> ai(lengths); // A 10x20x30 cube 00108 // Cube<Int> ci; 00109 // //... 00110 // ci.reference(ai1); // ci and ai now reference the same 00111 // // storage 00112 // ci(0,0,0) = 123; // Can use Cube indexing 00113 // ci.xyPlane(2) = 0; // and other member functions 00114 // IPosition zero(3,0,0,0); 00115 // assert(ai(zero) == 123); // True because ai, ci are references 00116 // //... 00117 // Array<Int> subArray; 00118 // IPosition blc(3,0,0,0), trc(3,5,5,5); 00119 // subArray.reference(ai(blc, trc)); 00120 // subArray = 10; // All of subArray, which is the 00121 // // subcube from 0,0,0 to 5,5,5 in 00122 // // ai, has the value 10. 00123 // </srcblock> 00124 // While the last example has an array slice referenced explicitly by another 00125 // array variable, normally the user will often only use the slice as 00126 // a temporary in an expresion, for example: 00127 // <srcblock> 00128 // Array<Complex> array; 00129 // IPosition blc, trc, offset; 00130 // //... 00131 // // Copy from one region of the array into another 00132 // array(blc, trc) = array(blc+offset, trc+offset); 00133 // </srcblock> 00134 // 00135 // The Array classes are intended to operate on relatively large 00136 // amounts of data. While they haven't been extensively tuned yet, 00137 // they are relatively efficient in terms of speed. Presently they 00138 // are not space efficient -- the overhead is about 15 words. While 00139 // this will be improved (probably to about 1/2 that), these array 00140 // classes are not appropriate for very large numbers of very small 00141 // arrays. The Block<T> class may be what you want in this circumstance. 00142 // 00143 // Element by element mathematical and logical operations are available 00144 // for arrays (defined in aips/ArrayMath.h and aips/ArrayLogical.h). 00145 // Because arithmetic and logical functions are split out, it is possible 00146 // to create an Array<T> (and hence Vector<T> etc) for any type T that has 00147 // a default constructor, assignment operator, and copy constructor. In 00148 // particular, Array<String> works. 00149 // 00150 // If compiled with the preprocessor symbol AIPS_DEBUG symbol, array 00151 // consistency ("invariants") will be checked in most member 00152 // functions, and indexing will be range-checked. This should not be 00153 // defined for production runs. 00154 // 00155 // A tutorial for the ArrayClasses is available in the "AIPS++ Programming 00156 // Manual." 00157 // 00158 // <note role=tip> 00159 // Most of the data members and functions which are "protected" should 00160 // likely become "private". 00161 // </note> 00162 // 00163 // <todo asof="1999/12/30"> 00164 // <li> Integrate into the Lattice hierarchy 00165 // <li> Factor out the common functions (shape etc) into a type-independent 00166 // base class. 00167 // </todo> 00168 00169 template<class T> class Array : public ArrayBase 00170 { 00171 public: 00172 00173 // Result has dimensionality of zero, and nelements is zero. 00174 Array(); 00175 00176 // Create an array of the given shape, i.e. after construction 00177 // array.ndim() == shape.nelements() and array.shape() == shape. 00178 // The origin of the Array is zero. 00179 explicit Array(const IPosition &shape); 00180 00181 // Create an array of the given shape and initialize it with the 00182 // initial value. 00183 Array(const IPosition &shape, const T &initialValue); 00184 00185 // After construction, this and other reference the same storage. 00186 Array(const Array<T> &other); 00187 00188 // Create an Array of a given shape from a pointer. 00189 Array(const IPosition &shape, T *storage, StorageInitPolicy policy = COPY); 00190 // Create an Array of a given shape from a pointer. Because the pointer 00191 // is const, a copy is always made. 00192 Array(const IPosition &shape, const T *storage); 00193 00194 // Frees up storage only if this array was the last reference to it. 00195 virtual ~Array(); 00196 00197 // Assign the other array to this array. 00198 // If the shapes mismatch, this array is resized. 00199 virtual void assign (const Array<T>& other); 00200 00201 // Set every element of the array to "value." Also could use the 00202 // assignment operator which assigns an array from a scalar. 00203 void set(const T &value); 00204 00205 // Apply the function to every element of the array. This modifies 00206 // the array in place. 00207 // <group> 00208 // This version takes a function which takes a T and returns a T. 00209 void apply(T (*function)(T)); 00210 // This version takes a function which takes a const T reference and 00211 // returns a T. 00212 void apply(T (*function)(const T &)); 00213 // This version applies a functional. 00214 void apply(const Functional<T,T> &function); 00215 // </group> 00216 00217 // After invocation, this array and other reference the same storage. That 00218 // is, modifying an element through one will show up in the other. The 00219 // arrays appear to be identical; they have the same shape. 00220 // <br>Please note that this function makes it possible to reference a 00221 // const Array, thus effectively it makes a const Array non-const. 00222 // Although this may seem undesirable at first sight, it is necessary to 00223 // be able to make references to temporary Array objects, in particular to 00224 // Array slices. Otherwise one first needs to use the copy constructor. 00225 //# The const has been introduced on 2005-Mar-31 because of the hassle 00226 //# involved in calling the copy ctor before reference. 00227 virtual void reference(const Array<T> &other); 00228 00229 // Copy the values in other to this. If the array on the left hand 00230 // side has no elements, then it is resized to be the same size as 00231 // as the array on the right hand side. Otherwise, the arrays must 00232 // conform (same shapes). 00233 // <srcblock> 00234 // IPosition shape(2,10,10); // some shape 00235 // Array<Double> ad(shape); 00236 // //... 00237 // Array<Double> ad2; // N.B. ad2.nelements() == 0 00238 // ad2 = ad; // ad2 resizes, then elements 00239 // // are copied. 00240 // shape = 20; 00241 // Array<Double> ad3(shape); 00242 // ad3 = ad; // Error: arrays do not conform 00243 // </srcblock> 00244 // Note that the assign function can be used to assign a 00245 // non-conforming array. 00246 virtual Array<T> &operator=(const Array<T> &other); 00247 00248 // Set every element of this array to "value". In other words, a scalar 00249 // behaves as if it were a constant conformant array. 00250 Array<T> &operator=(const T &value); 00251 00252 // Copy to this those values in marray whose corresponding elements 00253 // in marray's mask are True. 00254 // 00255 // <thrown> 00256 // <li> ArrayConformanceError 00257 // </thrown> 00258 // 00259 Array<T> &operator= (const MaskedArray<T> &marray); 00260 00261 // This makes a copy of the array and returns it. This can be 00262 // useful for, e.g. making working copies of function arguments 00263 // that you can write into. 00264 // <srcblock> 00265 // void someFunction(const Array<Int> &arg) 00266 // { 00267 // Array<Int> tmp(arg.copy()); 00268 // // ... 00269 // } 00270 // </srcblock> 00271 // Note that since the copy constructor makes a reference, if we just 00272 // created used to copy constructor, modifying "tmp" would also 00273 // modify "arg". Clearly another alternative would simply be: 00274 // <srcblock> 00275 // void someFunction(const Array<Int> &arg) 00276 // { 00277 // Array<Int> tmp; 00278 // tmp = arg; 00279 // // ... 00280 // } 00281 // </srcblock> 00282 // which likely would be simpler to understand. (Should copy() 00283 // be deprecated and removed?) 00284 Array<T> copy() const; // Make a copy of this 00285 00286 // This function copies the matching part of from array to this array. 00287 // The matching part is the part with the minimum size for each axis. 00288 // E.g. if this array has shape [4,5,6] and from array has shape [7,3], 00289 // the matching part has shape [4,3]. 00290 // <br>Note it is used by the resize function if 00291 // <src>copyValues==True</src>. 00292 void copyMatchingPart (const Array<T> &from); 00293 00294 // This ensures that this array does not reference any other storage. 00295 // <note role=tip> 00296 // When a section is taken of an array with non-unity strides, 00297 // storage can be wasted if the array, which originally contained 00298 // all the data, goes away. unique() also reclaims storage. This 00299 // is an optimization users don't normally need to understand. 00300 // 00301 // <srcblock> 00302 // IPosition shape(...), blc(...), trc(...), inc(...); 00303 // Array<Float> af(shape); 00304 // inc = 2; // or anything > 1 00305 // Array<Float> aSection.reference(af(blc, trc, inc)); 00306 // af.reference(anotherArray); 00307 // // aSection now references storage that has a stride 00308 // // in it, but nothing else is. Storage is wasted. 00309 // aSection.unique(); 00310 // </srcblock> 00311 // </note> 00312 void unique(); 00313 00314 // Create an STL vector from an Array. The created vector is a linear 00315 // representation of the Array memory. See 00316 // <linkto class=Vector>Vector</linkto> for 00317 // details of the operation and its reverse (i.e. creating a 00318 // <src>Vector</src> from a <src>vector</src>), and for details of 00319 // definition and instantiation. 00320 template <class U> 00321 void tovector(vector<T, U> &out) const; 00322 00323 // It is occasionally useful to have an array which access the same 00324 // storage appear to have a different shape. For example, 00325 // turning an N-dimensional array into a Vector. 00326 // <br>When the array data are contiguous, the array can be reshaped 00327 // to any form as long as the number of elements stays the same. 00328 // When not contiguous, it is only possible to remove or add axes 00329 // with length 1. 00330 // <srcblock> 00331 // IPosition squareShape(2,5,5); 00332 // Array<Float> square(squareShape); 00333 // IPosition lineShape(1,25); 00334 // Vector<Float> line(square.reform(lineShape)); 00335 // // "square"'s storage may now be accessed through Vector "line" 00336 // </srcblock> 00337 Array<T> reform(const IPosition &shape) const; 00338 00339 // These member functions remove degenerate (ie. length==1) axes from 00340 // Arrays. Only axes greater than startingAxis are considered (normally 00341 // one wants to remove trailing axes). The first two of these functions 00342 // return an Array reference with axes removed. The latter two functions 00343 // let this Array object reference the 'other' array with degenerated axes 00344 // removed. 00345 // <br> 00346 // Unless throwIfError is False, an exception will be thrown if 00347 // startingAxis exceeds the array's dimensionality. 00348 // <br> 00349 // The functions with argument <src>ignoreAxes</src> do 00350 // not consider the axes given in that argument. In this way it can be 00351 // achieved that degenerate axes are kept. 00352 // <note role=caution> When the two functions returning <src>void</src> 00353 // are invoked on a derived object (e.g. Matrix), an exception is 00354 // thrown if removing the degenerate axes from other does not result 00355 // in a correct number of axes. 00356 // </note> 00357 // <group> 00358 Array<T> nonDegenerate(uInt startingAxis=0, Bool throwIfError=True) const; 00359 Array<T> nonDegenerate(const IPosition& ignoreAxes) const; 00360 void nonDegenerate(const Array<T> &other, uInt startingAxis=0, 00361 Bool throwIfError=True); 00362 void nonDegenerate(const Array<T> &other, const IPosition &ignoreAxes) 00363 { doNonDegenerate (other, ignoreAxes); } 00364 // </group> 00365 00366 // Remove degenerate axes from this Array object. 00367 // Note it does not make sense to use these functions on a derived object 00368 // like Matrix, because it is not possible to remove axes from them. 00369 // <group> 00370 void removeDegenerate(uInt startingAxis=0, 00371 Bool throwIfError=True); 00372 void removeDegenerate(const IPosition &ignoreAxes); 00373 // </group> 00374 00375 // This member function returns an Array reference with the specified 00376 // number of extra axes, all of length one, appended to the end of the 00377 // Array. Note that the <src>reform</src> function can also be 00378 // used to add extra axes. 00379 // <group> 00380 const Array<T> addDegenerate(uInt numAxes) const; 00381 Array<T> addDegenerate(uInt numAxes); 00382 // </group> 00383 00384 // Make this array a different shape. If <src>copyValues==True</src> 00385 // the old values are copied over to the new array. 00386 // Copying is done on a per axis basis, thus a subsection with the 00387 // minimum of the old and new shape is copied. 00388 // <br>Resize without argument is equal to resize(IPosition()). 00389 // <br>It is important to note that if multiple Array objects 00390 // reference the same data storage, this Array object still references 00391 // the same data storage as the other Array objects if the shape does 00392 // not change. Otherwise this Array object references newly allocated 00393 // storage, while the other Array objects still reference the existing 00394 // data storage. 00395 // <br>If you want to be sure that the data storage of this Array object 00396 // is not referenced by other Array objects, the function unique should 00397 // be called first. 00398 // <group> 00399 virtual void resize(); 00400 virtual void resize(const IPosition &newShape, Bool copyValues=False); 00401 // </group> 00402 00403 // Access a single element of the array. This is relatively 00404 // expensive. Extensive indexing should be done through one 00405 // of the Array specializations (Vector, Matrix, Cube). If 00406 // AIPS_DEBUG is defined, index checking will be performed. 00407 // <group> 00408 T &operator()(const IPosition &); 00409 const T &operator()(const IPosition &) const; 00410 // </group> 00411 00412 // Get a reference to an array section extending 00413 // from start to end (inclusive). 00414 // <group> 00415 Array<T> operator()(const IPosition &start, 00416 const IPosition &end); 00417 const Array<T> operator()(const IPosition &start, 00418 const IPosition &end) const; 00419 // Along the ith axis, every inc[i]'th element is chosen. 00420 Array<T> operator()(const IPosition &start, 00421 const IPosition &end, 00422 const IPosition &inc); 00423 const Array<T> operator()(const IPosition &start, 00424 const IPosition &end, 00425 const IPosition &inc) const; 00426 // </group> 00427 00428 // Get a reference to an array section using a Slicer. 00429 // <group> 00430 Array<T> operator()(const Slicer&); 00431 const Array<T> operator()(const Slicer&) const; 00432 // </group> 00433 00434 // Get a reference to a section of an array. 00435 // This is the same as operator(). 00436 virtual ArrayBase* getSection (const Slicer&); 00437 00438 // Get the subset given by the i-th value of the last axis. So for a cube 00439 // it returns the i-th xy plane. For a Matrix it returns the i-th row. 00440 // The returned array references the original array data; its dimensionality 00441 // is one less. For a 1-dim array it still returns a 1-dim array. 00442 // <note>This function should not be used in tight loops as it is (much) 00443 // slower than iterating using begin() and end(), ArrayIter, or 00444 // ArrayAccessor.</note> 00445 Array<T> operator[] (uInt i) const; 00446 00447 00448 // The array is masked by the input LogicalArray. 00449 // This mask must conform to the array. 00450 // <group> 00451 const MaskedArray<T> operator() (const LogicalArray &mask) const; 00452 MaskedArray<T> operator() (const LogicalArray &mask); 00453 // </group> 00454 00455 // The array is masked by the input MaskedLogicalArray. 00456 // The mask is effectively the AND of the internal LogicalArray 00457 // and the internal mask of the MaskedLogicalArray. 00458 // The MaskedLogicalArray must conform to the array. 00459 // <group> 00460 const MaskedArray<T> operator() (const MaskedLogicalArray &mask) const; 00461 MaskedArray<T> operator() (const MaskedLogicalArray &mask); 00462 // </group> 00463 00464 // The number of references the underlying storage has assigned to it. 00465 // It is 1 unless there are outstanding references to the storage (e.g., 00466 // through a slice). Normally you have no need to do this since the 00467 // arrays handle all of the references for you. 00468 uInt nrefs() const; 00469 00470 // Check to see if the Array is consistent. This is about the same thing 00471 // as checking for invariants. If AIPS_DEBUG is defined, this is invoked 00472 // after construction and on entry to most member functions. 00473 virtual Bool ok() const; 00474 00475 // Are the shapes identical? 00476 // <group> 00477 Bool conform (const Array<T> &other) const 00478 { return conform2(other); } 00479 Bool conform (const MaskedArray<T> &other) const; 00480 // </group> 00481 00482 // Get a pointer to the beginning of the array. 00483 // Note that the array may not be contiguous. 00484 // <group> 00485 T* data() 00486 { return begin_p; } 00487 const T* data() const 00488 { return begin_p; } 00489 // </group> 00490 00491 // Generally use of this should be shunned, except to use a FORTRAN routine 00492 // or something similar. Because you can't know the state of the underlying 00493 // data layout (in particular, if there are increments) sometimes the 00494 // pointer returned will be to a copy, but often this won't be necessary. 00495 // A boolean is returned which tells you if this is a copy (and hence the 00496 // storage must be deleted). Note that if you don't do anything unusual, 00497 // getStorage followed by freeStorage or putStorage will do the deletion 00498 // for you (if required). e.g.: 00499 // <srcblock> 00500 // Array<Int> a(shape); ... 00501 // Bool deleteIt; Int *storage = a.getStorage(deleteIt); 00502 // foo(storage, a.nelements()); a.puStorage(storage, deleteIt); 00503 // // or a.freeStorage(storage, deleteIt) if a is const. 00504 // </srcblock> 00505 // NB: However, if you only use getStorage, you will have to delete the 00506 // pointer yourself using freeStorage(). 00507 // 00508 // It would probably be useful to have corresponding "copyin" "copyout" 00509 // functions that used a user supplied buffer. 00510 // Note that deleteIt is set in this function. 00511 // <group> 00512 T *getStorage(Bool &deleteIt); 00513 const T *getStorage(Bool &deleteIt) const; 00514 // </group> 00515 00516 // putStorage() is normally called after a call to getStorage() (cf). 00517 // The "storage" pointer is set to zero. 00518 void putStorage(T *&storage, Bool deleteAndCopy); 00519 00520 // If deleteIt is set, delete "storage". Normally freeStorage calls 00521 // will follow calls to getStorage. The reason the pointer is "const" 00522 // is because only const pointers are released from const arrays. 00523 // The "storage" pointer is set to zero. 00524 void freeStorage(const T *&storage, Bool deleteIt) const; 00525 00526 // Replace the data values with those in the pointer <src>storage</src>. 00527 // The results are undefined is storage does not point at nelements() or 00528 // more data elements. After takeStorage() is called, <src>unique()</src> 00529 // is True. 00530 // <group> 00531 virtual void takeStorage(const IPosition &shape, T *storage, 00532 StorageInitPolicy policy = COPY); 00533 // Since the pointer is const, a copy is always taken. 00534 virtual void takeStorage(const IPosition &shape, const T *storage); 00535 // </group> 00536 00537 00538 // Used to iterate through Arrays. Derived classes VectorIterator and 00539 // MatrixIterator are probably more useful. 00540 friend class ArrayIterator<T>; 00541 00542 // Create an ArrayIterator object of the correct type. 00543 virtual ArrayPositionIterator* makeIterator (uInt byDim); 00544 00545 // Needed to be a friend for Matrix<T>::reference() 00546 friend class Matrix<T>; 00547 00548 00549 // <group name=STL-iterator> 00550 // See the function begin() and end() for a detailed description 00551 // of the STL iterator capability. 00552 class BaseIteratorSTL 00553 { 00554 public: 00555 // Create the begin const_iterator object for an Array. 00556 explicit BaseIteratorSTL (const Array<T>&); 00557 // Create the end const_iterator object for an Array. 00558 // It also acts as the default constructor. 00559 explicit BaseIteratorSTL (const T* end = 0) 00560 : itsPos(end), itsLineEnd(0), itsLineIncr(0), itsLineAxis(0), 00561 itsArray(0), itsContig(False) {} 00562 00563 void nextElem() 00564 { 00565 itsPos++; 00566 if (!itsContig) { 00567 itsPos += itsLineIncr; 00568 if (itsPos > itsLineEnd) increment(); 00569 } 00570 } 00571 void nextLine() 00572 { 00573 itsPos = itsLineEnd; 00574 increment(); 00575 } 00576 00577 bool operator== (const BaseIteratorSTL& other) const 00578 { return itsPos == other.itsPos; } 00579 00580 bool operator!= (const BaseIteratorSTL& other) const 00581 { return itsPos != other.itsPos; } 00582 00583 T* getPos() 00584 { return const_cast<T*>(itsPos); } 00585 00586 friend ostream& operator<< (ostream& os, const BaseIteratorSTL& iter) 00587 { os << iter.itsPos; return os; } 00588 00589 protected: 00590 // Increment iterator for a non-contiguous array. 00591 void increment(); 00592 00593 const T* itsPos; 00594 const T* itsLineEnd; 00595 size_t itsLineIncr; 00596 uInt itsLineAxis; 00597 IPosition itsCurPos; 00598 IPosition itsLastPos; 00599 const Array<T>* itsArray; 00600 Bool itsContig; 00601 }; 00602 00603 class IteratorSTL: public BaseIteratorSTL 00604 { 00605 public: 00606 // <group name=STL-iterator-typedefs> 00607 typedef T value_type; 00608 typedef value_type* pointer; 00609 typedef value_type& reference; 00610 typedef std::size_t size_type; 00611 typedef ptrdiff_t difference_type; 00612 typedef std::forward_iterator_tag iterator_category; 00613 // </group> 00614 00615 // Create the begin iterator object for an Array. 00616 explicit IteratorSTL (Array<T>& arr) 00617 : BaseIteratorSTL (arr) {} 00618 // Create the end iterator object for an Array. 00619 // It also acts as the default constructor. 00620 explicit IteratorSTL (const T* end = 0) 00621 : BaseIteratorSTL (end) {} 00622 00623 const IteratorSTL& operator++() 00624 { 00625 this->nextElem(); 00626 return *this; 00627 } 00628 IteratorSTL operator++(int) 00629 { 00630 IteratorSTL old(*this); 00631 this->nextElem(); 00632 return old; 00633 } 00634 00635 T& operator*() 00636 { return *this->getPos(); } 00637 T* operator->() 00638 { return this->getPos(); } 00639 }; 00640 00641 class ConstIteratorSTL: public BaseIteratorSTL 00642 { 00643 public: 00644 // <group name=STL-iterator-typedefs> 00645 typedef T value_type; 00646 typedef const value_type* pointer; 00647 typedef const value_type& reference; 00648 typedef std::size_t size_type; 00649 typedef ptrdiff_t difference_type; 00650 typedef std::forward_iterator_tag iterator_category; 00651 // </group> 00652 00653 // Create the begin const_iterator object for an Array. 00654 explicit ConstIteratorSTL (const Array<T>& arr) 00655 : BaseIteratorSTL (arr) {} 00656 // Create the end const_iterator object for an Array. 00657 // It also acts as the default constructor. 00658 explicit ConstIteratorSTL (const T* end = 0) 00659 : BaseIteratorSTL (end) {} 00660 // Create from a non-const iterator. 00661 ConstIteratorSTL (const IteratorSTL& iter) 00662 : BaseIteratorSTL (iter) {} 00663 00664 const ConstIteratorSTL& operator++() 00665 { 00666 this->nextElem(); 00667 return *this; 00668 } 00669 ConstIteratorSTL operator++(int) 00670 { 00671 ConstIteratorSTL old(*this); 00672 this->nextElem(); 00673 return old; 00674 } 00675 00676 const T& operator*() const 00677 { return *this->itsPos; } 00678 const T* operator->() 00679 { return this->itsPos; } 00680 00681 const T* pos() const 00682 { return this->itsPos; } 00683 }; 00684 // </group> 00685 00686 // Define the STL-style iterator functions (only forward iterator). 00687 // It makes it possible to iterate through all data elements of an array 00688 // and to use it common STL functions. 00689 // The end() function is relatively expensive, so it should not be 00690 // used inside a for statement. It is much better to call it beforehand 00691 // as shown in the example below. Furthermore it is very important to 00692 // use <src>++iter</src>, because <src>iter++</src> is 4 times slower. 00693 // <srcblock> 00694 // Array<Int> arr(shape); 00695 // Array<Int>::iterator iterend(arr.end()); 00696 // for (Array<Int>::iterator iter=arr.begin(); iter!=iterend; ++iter) { 00697 // *iter += 1; 00698 // } 00699 // </srcblock> 00700 // The Array class supports random access, so in principle a random 00701 // iterator could be implemented, but its performance would not be great, 00702 // especially for non-contiguous arrays. 00703 // <br>Some other STL like functions exist for performance reasons. 00704 // If the array is contiguous, it is possible to use the 00705 // <src>cbegin</src> and <src>cend</src> functions which are 00706 // about 10% faster. 00707 // <group name=STL-iterator> 00708 // STL-style typedefs. 00709 // <group> 00710 typedef T value_type; 00711 typedef IteratorSTL iterator; 00712 typedef ConstIteratorSTL const_iterator; 00713 typedef T* contiter; 00714 typedef const T* const_contiter; 00715 // </group> 00716 // Get the begin iterator object for any array. 00717 // <group> 00718 iterator begin() 00719 { return iterator (*this); } 00720 const_iterator begin() const 00721 { return const_iterator (*this); } 00722 iterator end() 00723 { return iterator(end_p); } 00724 const_iterator end() const 00725 { return const_iterator(end_p); } 00726 // </group> 00727 00728 // Get the begin iterator object for a contiguous array. 00729 // <group> 00730 contiter cbegin() 00731 { return begin_p; } 00732 const_contiter cbegin() const 00733 { return begin_p; } 00734 contiter cend() 00735 { return end_p; } 00736 const_contiter cend() const 00737 { return end_p; } 00738 // </group> 00739 00740 // </group> 00741 00742 00743 protected: 00744 // Remove the degenerate axes from the Array object. 00745 // This is the implementation of the nonDegenerate functions. 00746 // It has a different name to be able to make it virtual without having 00747 // the "hide virtual function" message when compiling derived classes. 00748 virtual void doNonDegenerate(const Array<T> &other, 00749 const IPosition &ignoreAxes); 00750 00751 00752 // Reference counted block that contains the storage. 00753 CountedPtr<Block<T> > data_p; 00754 00755 // This pointer is adjusted to point to the first element of the array. 00756 // It is not necessarily the same thing as data->storage() since 00757 // this array might be a section, e.g. have a blc which shifts us forward 00758 // into the block. 00759 T *begin_p; 00760 00761 // The end for an STL-style iteration. 00762 T* end_p; 00763 00764 00765 // Fill the steps and the end for a derived class. 00766 void makeSteps() 00767 { baseMakeSteps(); this->setEndIter(); } 00768 00769 // Set the end iterator. 00770 void setEndIter() 00771 { end_p = (nels_p==0 ? 0 : (contiguous_p ? begin_p + nels_p : 00772 begin_p + size_t(length_p(ndim()-1)) * steps_p(ndim()-1))); } 00773 }; 00774 00775 }//#End casa namespace 00776 #ifndef CASACORE_NO_AUTO_TEMPLATES 00777 #include <casa/Arrays/Array.tcc> 00778 #endif //# CASACORE_NO_AUTO_TEMPLATES 00779 #endif