casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
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 21130 2011-10-18 07:39:05Z 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     vector<T> tovector() 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 functions
00344     // return an Array reference with axes removed. The latter two functions
00345     // let this Array object reference the 'other' array with degenerated axes
00346     // removed.
00347     // <br>
00348     // Unless throwIfError is False, an exception will be thrown if
00349     // startingAxis exceeds the array's dimensionality.
00350     // <br>
00351     // The functions with argument <src>ignoreAxes</src> do
00352     // not consider the axes given in that argument. In this way it can be
00353     // achieved that degenerate axes are kept.
00354     // <note role=caution> When the two functions returning <src>void</src>
00355     // are invoked on a derived object (e.g. Matrix), an exception is
00356     // thrown if removing the degenerate axes from other does not result
00357     // in a correct number of axes.
00358     // </note>
00359     // <group>
00360     Array<T> nonDegenerate(uInt startingAxis=0, Bool throwIfError=True) const;
00361     Array<T> nonDegenerate(const IPosition& ignoreAxes) const;
00362     void nonDegenerate(const Array<T> &other, uInt startingAxis=0,
00363                        Bool throwIfError=True);
00364     void nonDegenerate(const Array<T> &other, const IPosition &ignoreAxes)
00365         { doNonDegenerate (other, ignoreAxes); }
00366     // </group> 
00367 
00368     // Remove degenerate axes from this Array object.
00369     // Note it does not make sense to use these functions on a derived object
00370     // like Matrix, because it is not possible to remove axes from them.
00371     // <group>
00372     void removeDegenerate(uInt startingAxis=0,
00373                           Bool throwIfError=True);
00374     void removeDegenerate(const IPosition &ignoreAxes);
00375     // </group>
00376 
00377     // This member function returns an Array reference with the specified
00378     // number of extra axes, all of length one, appended to the end of the
00379     // Array. Note that the <src>reform</src> function can also be
00380     // used to add extra axes.
00381     // <group>
00382     const Array<T> addDegenerate(uInt numAxes) const;
00383     Array<T> addDegenerate(uInt numAxes);
00384     // </group>
00385 
00386     // Make this array a different shape. If <src>copyValues==True</src>
00387     // the old values are copied over to the new array.
00388     // Copying is done on a per axis basis, thus a subsection with the
00389     // minimum of the old and new shape is copied.
00390     // <br>Resize without argument is equal to resize(IPosition()).
00391     // <br>It is important to note that if multiple Array objects
00392     // reference the same data storage, this Array object still references
00393     // the same data storage as the other Array objects if the shape does
00394     // not change. Otherwise this Array object references newly allocated
00395     // storage, while the other Array objects still reference the existing
00396     // data storage.
00397     // <br>If you want to be sure that the data storage of this Array object
00398     // is not referenced by other Array objects, the function unique should
00399     // be called first.
00400     // <group>
00401     virtual void resize();
00402     virtual void resize(const IPosition &newShape, Bool copyValues=False);
00403     // </group>
00404 
00405     // Access a single element of the array. This is relatively
00406     // expensive. Extensive indexing should be done through one
00407     // of the Array specializations (Vector, Matrix, Cube). If
00408     // AIPS_DEBUG is defined, index checking will be performed.
00409     // <group>
00410     T &operator()(const IPosition &);
00411     const T &operator()(const IPosition &) const;
00412     // </group>
00413 
00414     // Get a reference to an array section extending
00415     // from start to end (inclusive).
00416     // <group>
00417     Array<T> operator()(const IPosition &start,
00418                         const IPosition &end);
00419     const Array<T> operator()(const IPosition &start,
00420                               const IPosition &end) const;
00421     // Along the ith axis, every inc[i]'th element is chosen.
00422     Array<T> operator()(const IPosition &start,
00423                         const IPosition &end,
00424                         const IPosition &inc);
00425     const Array<T> operator()(const IPosition &start,
00426                               const IPosition &end,
00427                               const IPosition &inc) const;
00428     // </group>
00429 
00430     // Get a reference to an array section using a Slicer.
00431     // <group>
00432     Array<T> operator()(const Slicer&);
00433     const Array<T> operator()(const Slicer&) const;
00434     // </group>
00435 
00436     // Get a reference to a section of an array.
00437     // This is the same as operator().
00438     virtual ArrayBase* getSection (const Slicer&);
00439 
00440     // Get the subset given by the i-th value of the last axis. So for a cube
00441     // it returns the i-th xy plane. For a Matrix it returns the i-th row.
00442     // The returned array references the original array data; its dimensionality
00443     // is one less. For a 1-dim array it still returns a 1-dim array.
00444     // <note>This function should not be used in tight loops as it is (much)
00445     // slower than iterating using begin() and end(), ArrayIter, or
00446     // ArrayAccessor.</note>
00447     Array<T> operator[] (uInt i) const;
00448 
00449 
00450     // The array is masked by the input LogicalArray.
00451     // This mask must conform to the array.
00452     // <group>
00453     const MaskedArray<T> operator() (const LogicalArray &mask) const;
00454     MaskedArray<T> operator() (const LogicalArray &mask);
00455     // </group>
00456 
00457     // The array is masked by the input MaskedLogicalArray.
00458     // The mask is effectively the AND of the internal LogicalArray
00459     // and the internal mask of the MaskedLogicalArray.
00460     // The MaskedLogicalArray must conform to the array.
00461     // <group>
00462     const MaskedArray<T> operator() (const MaskedLogicalArray &mask) const;
00463     MaskedArray<T> operator() (const MaskedLogicalArray &mask);
00464     // </group>
00465 
00466     // The number of references the underlying storage has assigned to it.
00467     // It is 1 unless there are outstanding references to the storage (e.g.,
00468     // through a slice). Normally you have no need to do this since the
00469     // arrays handle all of the references for you.
00470     uInt nrefs() const;
00471 
00472     // Check to see if the Array is consistent. This is about the same thing
00473     // as checking for invariants. If AIPS_DEBUG is defined, this is invoked
00474     // after construction and on entry to most member functions.
00475     virtual Bool ok() const;
00476 
00477     // Are the shapes identical?
00478     // <group>
00479     Bool conform (const Array<T> &other) const
00480       { return conform2(other); }
00481     Bool conform (const MaskedArray<T> &other) const;
00482     // </group>
00483 
00484     // Get a pointer to the beginning of the array.
00485     // Note that the array may not be contiguous.
00486     // <group>
00487     T* data()
00488       { return begin_p; }
00489     const T* data() const
00490       { return begin_p; }
00491     // </group>
00492 
00493     // Generally use of this should be shunned, except to use a FORTRAN routine
00494     // or something similar. Because you can't know the state of the underlying
00495     // data layout (in particular, if there are increments) sometimes the
00496     // pointer returned will be to a copy, but often this won't be necessary.
00497     // A boolean is returned which tells you if this is a copy (and hence the
00498     // storage must be deleted). Note that if you don't do anything unusual,
00499     // getStorage followed by freeStorage or putStorage will do the deletion
00500     // for you (if required). e.g.:
00501     // <srcblock>
00502     // Array<Int> a(shape); ...
00503     // Bool deleteIt; Int *storage = a.getStorage(deleteIt);
00504     // foo(storage, a.nelements()); a.puStorage(storage, deleteIt);
00505     // // or a.freeStorage(storage, deleteIt) if a is const.
00506     // </srcblock>
00507     // NB: However, if you only use getStorage, you will have to delete the
00508     // pointer yourself using freeStorage().
00509     //
00510     // It would probably be useful to have corresponding "copyin" "copyout"
00511     // functions that used a user supplied buffer.
00512     // Note that deleteIt is set in this function.
00513     // <group>
00514     T *getStorage(Bool &deleteIt);
00515     const T *getStorage(Bool &deleteIt) const;
00516     // </group>
00517 
00518     // putStorage() is normally called after a call to getStorage() (cf).
00519     // The "storage" pointer is set to zero.
00520     void putStorage(T *&storage, Bool deleteAndCopy);
00521 
00522     // If deleteIt is set, delete "storage". Normally freeStorage calls
00523     // will follow calls to getStorage. The reason the pointer is "const"
00524     // is because only const pointers are released from const arrays.
00525     // The "storage" pointer is set to zero.
00526     void freeStorage(const T *&storage, Bool deleteIt) const;
00527 
00528     // Replace the data values with those in the pointer <src>storage</src>.
00529     // The results are undefined is storage does not point at nelements() or
00530     // more data elements. After takeStorage() is called, <src>unique()</src>
00531     // is True.
00532     // <group>
00533     virtual void takeStorage(const IPosition &shape, T *storage,
00534                      StorageInitPolicy policy = COPY);
00535     // Since the pointer is const, a copy is always taken.
00536     virtual void takeStorage(const IPosition &shape, const T *storage);
00537     // </group>
00538 
00539 
00540     // Used to iterate through Arrays. Derived classes VectorIterator and
00541     // MatrixIterator are probably more useful.
00542     friend class ArrayIterator<T>;
00543 
00544     // Create an ArrayIterator object of the correct type.
00545     virtual ArrayPositionIterator* makeIterator (uInt byDim);
00546 
00547     // Needed to be a friend for Matrix<T>::reference()
00548     friend class Matrix<T>;
00549 
00550 
00551     // <group name=STL-iterator>
00552     // See the function begin() and end() for a detailed description
00553     // of the STL iterator capability.
00554     class BaseIteratorSTL
00555     {
00556     public:
00557       // Create the begin const_iterator object for an Array.
00558       explicit BaseIteratorSTL (const Array<T>&);
00559       // Create the end const_iterator object for an Array.
00560       // It also acts as the default constructor.
00561       explicit BaseIteratorSTL (const T* end = 0)
00562         : itsPos(end), itsLineEnd(0), itsLineIncr(0), itsLineAxis(0),
00563           itsArray(0), itsContig(False) {}
00564 
00565       void nextElem()
00566       {
00567         itsPos++;
00568         if (!itsContig) {
00569           itsPos += itsLineIncr;
00570           if (itsPos > itsLineEnd) increment();
00571         }
00572       }
00573       void nextLine()
00574       {
00575         itsPos = itsLineEnd;
00576         increment();
00577       }
00578 
00579       bool operator== (const BaseIteratorSTL& other) const
00580         { return itsPos == other.itsPos; }
00581 
00582       bool operator!= (const BaseIteratorSTL& other) const
00583         { return itsPos != other.itsPos; }
00584 
00585       T* getPos()
00586         { return const_cast<T*>(itsPos); }
00587 
00588       friend ostream& operator<< (ostream& os, const BaseIteratorSTL& iter)
00589         { os << iter.itsPos; return os; }
00590 
00591     protected:
00592       // Increment iterator for a non-contiguous array.
00593       void increment();
00594 
00595       const T*  itsPos;
00596       const T*  itsLineEnd;
00597       size_t    itsLineIncr;
00598       uInt      itsLineAxis;
00599       IPosition itsCurPos;
00600       IPosition itsLastPos;
00601       const Array<T>* itsArray; 
00602       Bool      itsContig;
00603     };
00604 
00605     class IteratorSTL: public BaseIteratorSTL
00606     {
00607     public:
00608       // <group name=STL-iterator-typedefs>
00609       typedef T                 value_type;
00610       typedef value_type*       pointer;
00611       typedef value_type&       reference;
00612       typedef std::size_t       size_type;
00613       typedef ptrdiff_t         difference_type;
00614       typedef std::forward_iterator_tag iterator_category;
00615       // </group>
00616 
00617       // Create the begin iterator object for an Array.
00618       explicit IteratorSTL (Array<T>& arr)
00619         : BaseIteratorSTL (arr) {}
00620       // Create the end iterator object for an Array.
00621       // It also acts as the default constructor.
00622       explicit IteratorSTL (const T* end = 0)
00623         : BaseIteratorSTL (end) {}
00624 
00625       const IteratorSTL& operator++()
00626       {
00627         this->nextElem();
00628         return *this;
00629       }
00630       IteratorSTL operator++(int)
00631       {
00632         IteratorSTL old(*this);
00633         this->nextElem();
00634         return old;
00635       }
00636 
00637       T& operator*()
00638         { return *this->getPos(); }
00639       T* operator->()
00640         { return this->getPos(); }
00641     };
00642 
00643   class ConstIteratorSTL: public BaseIteratorSTL
00644     {
00645     public:
00646       // <group name=STL-iterator-typedefs>
00647       typedef T                 value_type;
00648       typedef const value_type* pointer;
00649       typedef const value_type& reference;
00650       typedef std::size_t       size_type;
00651       typedef ptrdiff_t         difference_type;
00652       typedef std::forward_iterator_tag iterator_category;
00653       // </group>
00654 
00655       // Create the begin const_iterator object for an Array.
00656       explicit ConstIteratorSTL (const Array<T>& arr)
00657         : BaseIteratorSTL (arr) {}
00658       // Create the end const_iterator object for an Array.
00659       // It also acts as the default constructor.
00660       explicit ConstIteratorSTL (const T* end = 0)
00661         : BaseIteratorSTL (end) {}
00662       // Create from a non-const iterator.
00663       ConstIteratorSTL (const IteratorSTL& iter)
00664         : BaseIteratorSTL (iter) {}
00665 
00666       const ConstIteratorSTL& operator++()
00667       {
00668         this->nextElem();
00669         return *this;
00670       }
00671       ConstIteratorSTL operator++(int)
00672       {
00673         ConstIteratorSTL old(*this);
00674         this->nextElem();
00675         return old;
00676       }
00677 
00678       const T& operator*() const
00679         { return *this->itsPos; }
00680       const T* operator->()
00681         { return this->itsPos; }
00682 
00683       const T* pos() const
00684         { return this->itsPos; }
00685     };
00686     // </group>
00687 
00688     // Define the STL-style iterator functions (only forward iterator).
00689     // It makes it possible to iterate through all data elements of an array
00690     // and to use it common STL functions.
00691     // The end() function is relatively expensive, so it should not be
00692     // used inside a for statement. It is much better to call it beforehand
00693     // as shown in the example below. Furthermore it is very important to
00694     // use <src>++iter</src>, because <src>iter++</src> is 4 times slower.
00695     // <srcblock>
00696     //  Array<Int> arr(shape);
00697     //  Array<Int>::iterator iterend(arr.end());
00698     //  for (Array<Int>::iterator iter=arr.begin(); iter!=iterend; ++iter) {
00699     //    *iter += 1;
00700     //  }
00701     // </srcblock>
00702     // The Array class supports random access, so in principle a random
00703     // iterator could be implemented, but its performance would not be great,
00704     // especially for non-contiguous arrays.
00705     // <br>Some other STL like functions exist for performance reasons.
00706     // If the array is contiguous, it is possible to use the
00707     // <src>cbegin</src> and <src>cend</src> functions which are
00708     // about 10% faster.
00709     // <group name=STL-iterator>
00710     // STL-style typedefs.
00711     // <group>
00712     typedef T                value_type;
00713     typedef IteratorSTL      iterator;
00714     typedef ConstIteratorSTL const_iterator;
00715     typedef T*               contiter;
00716     typedef const T*         const_contiter;
00717     // </group>
00718     // Get the begin iterator object for any array.
00719     // <group>
00720     iterator begin()
00721         { return iterator (*this); }
00722     const_iterator begin() const
00723         { return const_iterator (*this); }
00724     iterator end()
00725         { return iterator(end_p); }
00726     const_iterator end() const
00727         { return const_iterator(end_p); }
00728     // </group>
00729 
00730     // Get the begin iterator object for a contiguous array.
00731     // <group>
00732     contiter cbegin()
00733         { return begin_p; }
00734     const_contiter cbegin() const
00735         { return begin_p; }
00736     contiter cend()
00737         { return end_p; }
00738     const_contiter cend() const
00739         { return end_p; }
00740     // </group>
00741 
00742     // </group>
00743 
00744 
00745 protected:
00746     // Remove the degenerate axes from the Array object.
00747     // This is the implementation of the nonDegenerate functions.
00748     // It has a different name to be able to make it virtual without having
00749     // the "hide virtual function" message when compiling derived classes.
00750     virtual void doNonDegenerate(const Array<T> &other,
00751                                  const IPosition &ignoreAxes);
00752 
00753 
00754     // Reference counted block that contains the storage.
00755     CountedPtr<Block<T> > data_p;
00756 
00757     // This pointer is adjusted to point to the first element of the array.
00758     // It is not necessarily the same thing as data->storage() since
00759     // this array might be a section, e.g. have a blc which shifts us forward
00760     // into the block.
00761     T *begin_p;
00762 
00763     // The end for an STL-style iteration.
00764     T* end_p;
00765 
00766 
00767     // Fill the steps and the end for a derived class.
00768     void makeSteps()
00769       { baseMakeSteps(); this->setEndIter(); }
00770 
00771     // Set the end iterator.
00772     void setEndIter()
00773       { end_p = (nels_p==0 ? 0 : (contiguous_p  ?  begin_p + nels_p :
00774                    begin_p + size_t(length_p(ndim()-1)) * steps_p(ndim()-1))); }
00775 };
00776 
00777 }//#End casa namespace
00778 #ifndef CASACORE_NO_AUTO_TEMPLATES
00779 #include <casa/Arrays/Array.tcc>
00780 #endif //# CASACORE_NO_AUTO_TEMPLATES
00781 #endif