casa  $Rev:20696$
Array.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines