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