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$
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

Generated on Mon Sep 1 22:33:30 2008 for NRAOCASA by  doxygen 1.5.1