casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
IPosition.h
Go to the documentation of this file.
00001 //# IPosition.h: A vector of integers, used to index into arrays.
00002 //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2002
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: IPosition.h 21285 2012-11-14 15:36:59Z gervandiepen $
00027 
00028 #ifndef CASA_IPOSITION_H
00029 #define CASA_IPOSITION_H
00030 
00031 //# Includes
00032 #include <casa/aips.h>
00033 #include <casa/iosfwd.h>
00034 #include <casa/BasicSL/String.h>
00035 #include <vector>
00036 #include <cstddef>                  // for ptrdiff_t
00037 #include <sys/types.h>
00038 
00039 namespace casa { //# NAMESPACE CASA - BEGIN
00040 
00041 //# Forward Declarations
00042 class AipsIO;
00043 class LogIO;
00044 template<class T> class Array;
00045 template<class T> class Vector;
00046 
00047 // <summary> A Vector of integers, for indexing into Array<T> objects. </summary>
00048 
00049 // <use visibility=export>
00050 
00051 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="">
00052 // </reviewed>
00053 
00054 //# <prerequisite>
00055 //# Classes you should understand before using this one.
00056 //# </prerequisite>
00057 
00058 // <etymology>
00059 // IPosition is an Index Position in an n-dimensional array.
00060 // </etymology>
00061 
00062 // <synopsis> 
00063 // IPosition is "logically" a Vector<Int> constrained so that its origin
00064 // is zero-based, and in fact that used to be the way it was implemented.
00065 // It was split out into a separate class to make the inheritance from
00066 // Arrays simpler (since Arrays use IPositions). The
00067 // template instantiation mechanism is complicated enough that this
00068 // simplification was felt to be a good idea.
00069 // <p>
00070 // IPosition objects are normally used to index into, and define the shapes
00071 // of, multi-dimensional arrays. For example, if you have a 5 dimensional
00072 // array, you need an IPosition of length 5 to index into the array (or
00073 // to define its shape, etc.).
00074 // <p>
00075 // Unlike Vectors, IPositions always use copy semantics.
00076 // <srcblock>
00077 // IPosition ip1(5);                         // An IPosition of length 5
00078 // ip1(0) = 11; ip1(1) = 5; ... ip1(4) = 6;  // Indices 0-based
00079 // IPosition ip2(ip1);                       // Copy constructor; a COPY
00080 // </srcblock>
00081 //
00082 // Binary operations must take place either with a conformnat (same size)
00083 // IPosition or with an integer, which behaves as if it was an IPosition
00084 // of the same size (i.e., length). All the usual binary arithmetic
00085 // operations are available, as well as logical operations, which return
00086 // Booleans. These all operate "element-by-element".
00087 // <p>
00088 // All non-inlined member functions of IPosition check invariants if the
00089 // preprocessor symbol AIPS_DEBUG is defined.
00090 // That is, the member functions check that ok() is true (constructors
00091 // check after construction, other functions on entry to the function).
00092 // If these tests fail, an AipsError exception is thrown; its message
00093 // contains the line number and source file of the failure (it is thrown
00094 // by the lAssert macro defined in aips/Assert.h).
00095 //
00096 // Constructors and functions exist to construct an IPosition directly from
00097 // a Vector or std::vector object or to convert to it. Furthermore the
00098 // <src>fill</src> and <src>copy</src> can be used to fill from or copy to
00099 // any STL-type iterator.
00100 //
00101 // <example>
00102 // <srcblock>
00103 // IPosition blc(5), trc(5,1,2,3,4,5);
00104 // blc = 0;            // OR IPosition blc(5,0);
00105 // //...
00106 // if (blc > trc) {
00107 //    IPosition tmp;
00108 //    tmp = trc;       // Swap
00109 //    trc = blc;
00110 //    blc = tmp;
00111 // }
00112 // //...
00113 // trc += 5;           // make the box 5 larger in all dimensions
00114 // std::vector<Int> vec(trc.toStdVector());
00115 // </srcblock>
00116 // </example>
00117 
00118 
00119 class IPosition
00120 {
00121 public:
00122     enum {MIN_INT = -2147483647};
00123     // A zero-length IPosition.
00124     IPosition();
00125 
00126     // An IPosition of size "length." The values in the object are undefined.
00127     explicit IPosition(uInt length);
00128 
00129     // An IPosition of size "length." The values in the object get
00130     // initialized to val.
00131     IPosition(uInt length, ssize_t val);
00132 
00133     // An IPosition of size "length" with defined values. You need to supply
00134     // a value for each element of the IPosition (up to 10). [Unfortunately
00135     // varargs might not be sufficiently portable.]
00136     IPosition (uInt length, ssize_t val0, ssize_t val1, ssize_t val2=MIN_INT, 
00137                ssize_t val3=MIN_INT, ssize_t val4=MIN_INT, ssize_t val5=MIN_INT,
00138                ssize_t val6=MIN_INT, ssize_t val7=MIN_INT, ssize_t val8=MIN_INT,
00139                ssize_t val9=MIN_INT);
00140 
00141     // Makes a copy (copy, NOT reference, semantics) of other.
00142     IPosition(const IPosition& other);
00143     
00144     ~IPosition();
00145 
00146     // Makes this a copy of other. "this" and "other" must either be conformant
00147     // (same size) or this must be 0-length, in which case it will
00148     // resize itself to be the same length as other.
00149     IPosition& operator=(const IPosition& other);
00150 
00151     // Copy "value" into every position of this IPosition.
00152     IPosition& operator=(ssize_t value);
00153 
00154     // Construct a default axis path consisting of the values 0 .. nrdim-1.
00155     static IPosition makeAxisPath (uInt nrdim);
00156 
00157     // Construct a full axis path from a (partially) given axis path.
00158     // It fills the path with the non-given axis.
00159     // It is checked if the given axis path is valid (i.e. if the axis are
00160     // < nrdim and if they are not doubly defined).
00161     // E.g.: in the 4D case an axis path [0,2] is returned as [0,2,1,3].
00162     static IPosition makeAxisPath (uInt nrdim, const IPosition& partialPath);
00163 
00164     // Make a list of axes which are the axes not given in <src>axes</src>
00165     // up to the given dimension
00166     static IPosition otherAxes (uInt nrdim, const IPosition& axes);
00167 
00168     // Convert an IPosition to and from an Array<Int>. In either case, the
00169     // array must be one dimensional.
00170     // <group>
00171     IPosition(const Array<Int>& other);
00172     Vector<Int> asVector() const;
00173     // </group>
00174 
00175     // Convert an IPosition to and from an Array<Int>. In either case, the
00176     // array must be one dimensional.
00177     // <group>
00178     IPosition(const std::vector<Int>& other);
00179     std::vector<Int> asStdVector() const;
00180     // </group>
00181 
00182     // Resize and fill this IPosition object.
00183     template<typename InputIterator>
00184     void fill (uInt size, InputIterator iter)
00185     {
00186       resize (size);
00187       for (uInt i=0; i<size; ++i, ++iter) {
00188         data_p[i] = *iter;
00189       }
00190     }
00191 
00192     // Copy the contents of this IPosition object to the output iterator.
00193     // The size of the output must be sufficient.
00194     template<typename OutputIterator>
00195     void copy (OutputIterator iter) const
00196     {
00197       for (uInt i=0; i<size_p; ++i, ++iter) {
00198         *iter = data_p[i];
00199       }
00200     }
00201   
00202 
00203     // This member functions return an IPosition which has
00204     // degenerate (length==1) axes removed and the dimensionality reduced 
00205     // appropriately.
00206     // Only axes greater than startingAxis are considered (normally one 
00207     // wants to remove trailing axes.
00208     // <br>
00209     // The functions with argument <src>ignoreAxes</src> do
00210     // not consider the axes given in that argument.
00211     // <group>
00212     IPosition nonDegenerate(uInt startingAxis=0) const;
00213     IPosition nonDegenerate(const IPosition& ignoreAxes) const;
00214     // </group>
00215 
00216     // Old values are copied on resize if copy==True.
00217     // If the size increases, values beyond the former size are undefined.
00218     void resize(uInt newSize, Bool copy=True);
00219 
00220     // Index into the IPosition. Indices are zero-based. If the preprocessor
00221     // symbol AIPS_ARRAY_INDEX_CHECK is defined, operator() will check
00222     // "index" to ensure it is not out of bounds. If this check fails, an
00223     // AipsError will be thrown.
00224     // <group>
00225     ssize_t& operator[] (uInt index);
00226     ssize_t operator[]  (uInt index) const;
00227     ssize_t& operator() (uInt index);
00228     ssize_t operator()  (uInt index) const;
00229     // </group>
00230 
00231     // Make an IPosition by using only the specified elements of the current
00232     // IPosition. All values of <src>axes</src> must be less than
00233     // the number of elements of the current object.
00234     // <example>
00235     // IPosition ipos(4, 11, 12, 13, 14);
00236     // // ex1 is IPosition(3, 11, 12, 13);
00237     // IPosition ex1 = ipos(IPosition(3,0,1,2);
00238     // // ex2 is IPosition(3, 12, 11)
00239     // IPosition ex2 = ipos(IPosition(2,2,1);
00240     // // ex3 is IPosition(4,14,14,14,14)
00241     // IPosition ex3 = ipos(IPosition(4,3,3,3,3);
00242     // </example>
00243     IPosition operator() (const IPosition& axes) const;
00244 
00245     // Index into the IPosition from the end.
00246     // By default the last value is returned.
00247     // If the preprocessor symbol AIPS_ARRAY_INDEX_CHECK is defined, it will
00248     // check if the index is not out of bounds.
00249     // <group>
00250     ssize_t& last (uInt index=0);
00251     ssize_t last (uInt index=0) const;
00252     // </group>
00253 
00254     // Get the storage.
00255     const ssize_t *storage() const;
00256 
00257     // Append this IPosition with another one (causing a resize).
00258     void append (const IPosition& other);
00259 
00260     // Prepend this IPosition with another one (causing a resize).
00261     void prepend (const IPosition& other);
00262 
00263     // Return an IPosition as the concetanation of this and another IPosition.
00264     IPosition concatenate (const IPosition& other) const;
00265 
00266     // Set the first values of this IPosition to another IPosition.
00267     // An exception is thrown if the other IPosition is too long.
00268     void setFirst (const IPosition& other);
00269 
00270     // Set the last values of this IPosition to another IPosition.
00271     // An exception is thrown if the other IPosition is too long.
00272     void setLast (const IPosition& other);
00273 
00274     // Construct an IPosition from the first <src>n</src> values of this
00275     // IPosition.
00276     // An exception is thrown if <src>n</src> is too high.
00277     IPosition getFirst (uInt n) const;
00278 
00279     // Construct an IPosition from the last <src>n</src> values of this
00280     // IPosition.
00281     // An exception is thrown if <src>n</src> is too high.
00282     IPosition getLast (uInt n) const;
00283 
00284     // Return an IPosition where the given axes are reoved.
00285     IPosition removeAxes (const IPosition& axes) const;
00286 
00287     // Return an IPosition containing the given axes only.
00288     IPosition keepAxes (const IPosition& axes) const;
00289 
00290     // The number of elements in this IPosition. Since IPosition
00291     // objects use zero-based indexing, the maximum available index is
00292     // nelements() - 1.
00293     // <group>
00294     uInt nelements() const;
00295     uInt size() const;
00296     // </group>
00297 
00298     // Is the IPosition empty (i.e. no elements)?
00299     Bool empty() const;
00300 
00301     // conform returns true if nelements() == other.nelements().
00302     Bool conform(const IPosition& other) const;
00303 
00304     // Element-by-element arithmetic.
00305     // <group>
00306     void operator += (const IPosition& other);
00307     void operator -= (const IPosition& other);
00308     void operator *= (const IPosition& other);
00309     void operator /= (const IPosition& other);
00310     void operator += (ssize_t val);
00311     void operator -= (ssize_t val);
00312     void operator *= (ssize_t val);
00313     void operator /= (ssize_t val);
00314     // </group>
00315 
00316     // Returns 0 if nelements() == 0, otherwise it returns the product of
00317     // its elements.
00318     Int64 product() const;
00319 
00320     // Are all elements equal to 1?
00321     // Useful to check if a given stride is really a stride.
00322     Bool allOne() const;
00323 
00324     // Element-by-element comparison for equality.
00325     // It returns True if the lengths and all elements are equal.
00326     // <br>
00327     // Note that an important difference between this function and operator==()
00328     // is that if the two IPositions have different lengths, this function
00329     // returns False, instead of throwing an exception as operator==() does.
00330     Bool isEqual (const IPosition& other) const;
00331 
00332     // Element-by-element comparison for equality.
00333     // It returns True if all elements are equal.
00334     // When <src>skipDegeneratedAxes</src> is True, axes with
00335     // length 1 are skipped in both operands.
00336     Bool isEqual (const IPosition& other, Bool skipDegeneratedAxes) const;
00337 
00338     // Element-by-element comparison for (partial) equality.
00339     // It returns True if the lengths and the first <src>nrCompare</src>
00340     // elements are equal.
00341     Bool isEqual (const IPosition& other, uInt nrCompare) const;
00342 
00343     // Is the other IPosition a subset of (or equal to) this IPosition?
00344     // It is a subset if zero or more axes of this IPosition do not occur
00345     // or are degenerated in the other and if the remaining axes are
00346     // in the same order.
00347     Bool isSubSet (const IPosition& other) const;
00348 
00349     // Write the IPosition into a String.
00350     String toString() const;
00351 
00352     // Write an IPosition to an ostream in a simple text form.
00353     friend std::ostream& operator<<(std::ostream& os, const IPosition& ip);
00354 
00355     // Write an IPosition to an AipsIO stream in a binary format.
00356     friend AipsIO& operator<<(AipsIO& aio, const IPosition& ip);
00357 
00358     // Write an IPosition to a LogIO stream.
00359     friend LogIO& operator<<(LogIO& io, const IPosition& ip);
00360 
00361     // Read an IPosition from an AipsIO stream in a binary format.
00362     // Will throw an AipsError if the current IPosition Version does not match
00363     // that of the one on disk.
00364     friend AipsIO& operator>>(AipsIO& aio, IPosition& ip);
00365 
00366     // Is this IPosition consistent?
00367     Bool ok() const;
00368 
00369     // Define the STL-style iterators.
00370     // It makes it possible to iterate through all data elements.
00371     // <srcblock>
00372     //  IPosition shp(2,0);
00373     //  for (IPosition::iterator iter=shp.begin(); iter!=shp.end(); iter++) {
00374     //    *iter += 1;
00375     //  }
00376     // </srcblock>
00377     // <group name=STL-iterator>
00378     // STL-style typedefs.
00379     // <group>
00380     typedef ssize_t               value_type;
00381     typedef ssize_t*              iterator;
00382     typedef const ssize_t*        const_iterator;
00383     typedef value_type*       pointer;
00384     typedef const value_type* const_pointer; 
00385     typedef value_type&       reference;
00386     typedef const value_type& const_reference;
00387     typedef size_t            size_type;
00388     typedef ptrdiff_t         difference_type;
00389     // </group>
00390     // Get the begin and end iterator object for this object.
00391     // <group>
00392     iterator begin()
00393       { return data_p; }
00394     const_iterator begin() const
00395       { return data_p; }
00396     iterator end()
00397       { return data_p + size_p; }
00398     const_iterator end() const
00399       { return data_p + size_p; }
00400     // </group>
00401     // </group>
00402 
00403 private:
00404     // Allocate a buffer with length size_p.
00405     void allocateBuffer();
00406 
00407     // Throw an index error exception.
00408     void throwIndexError() const;
00409 
00410     enum { BufferLength = 4 };
00411     uInt size_p;
00412     ssize_t buffer_p[BufferLength];
00413     // When the iposition is length BufferSize or less data is just buffer_p,
00414     // avoiding calls to new and delete.
00415     ssize_t *data_p;
00416 };
00417 
00418 // <summary>Arithmetic Operations for IPosition's</summary>
00419 // Element by element arithmetic on IPositions.
00420 // <group name="IPosition Arithmetic">
00421 // Each operation is done on corresponding elements of the IPositions. The
00422 // two IPositions must have the same number of elements otherwise an
00423 // exception (ArrayConformanceError) will be thrown.
00424 // <group>
00425 IPosition operator + (const IPosition& left, const IPosition& right);
00426 IPosition operator - (const IPosition& left, const IPosition& right);
00427 IPosition operator * (const IPosition& left, const IPosition& right);
00428 IPosition operator / (const IPosition& left, const IPosition& right);
00429 // </group>
00430 // Each operation is done by appliying the integer argument to all elements
00431 // of the IPosition argument. 
00432 // <group>
00433 IPosition operator + (const IPosition& left, ssize_t val);
00434 IPosition operator - (const IPosition& left, ssize_t val);
00435 IPosition operator * (const IPosition& left, ssize_t val);
00436 IPosition operator / (const IPosition& left, ssize_t val);
00437 // </group>
00438 // Same functions as above but with with the Int argument on the left side.
00439 // <group>
00440 IPosition operator + (ssize_t val, const IPosition& right);
00441 IPosition operator - (ssize_t val, const IPosition& right);
00442 IPosition operator * (ssize_t val, const IPosition& right);
00443 IPosition operator / (ssize_t val, const IPosition& right);
00444 // </group>
00445 
00446 // Returns the element by element minimum or maximum.
00447 // <group>
00448 IPosition max (const IPosition& left, const IPosition& right);
00449 IPosition min (const IPosition& left, const IPosition& right);
00450 // </group>
00451 // </group>
00452 
00453 // <summary>Logical operations for IPosition's</summary>
00454 // Element by element boolean operations on IPositions. The result is true
00455 // only if the operation yields true for every element of the IPosition.
00456 // <group name="IPosition Logical">
00457 // Each operation is done on corresponding elements of the IPositions. The
00458 // two IPositions must have the same number of elements otherwise an
00459 // exception (ArrayConformanceError) will be thrown.
00460 // <group>
00461 Bool operator == (const IPosition& left, const IPosition& right);
00462 Bool operator != (const IPosition& left, const IPosition& right);
00463 Bool operator <  (const IPosition& left, const IPosition& right);
00464 Bool operator <= (const IPosition& left, const IPosition& right);
00465 Bool operator >  (const IPosition& left, const IPosition& right);
00466 Bool operator >= (const IPosition& left, const IPosition& right);
00467 // </group>
00468 // Each operation is done by appliying the integer argument to all elements
00469 // <group>
00470 Bool operator == (const IPosition& left, ssize_t val);
00471 Bool operator != (const IPosition& left, ssize_t val);
00472 Bool operator <  (const IPosition& left, ssize_t val);
00473 Bool operator <= (const IPosition& left, ssize_t val);
00474 Bool operator >  (const IPosition& left, ssize_t val);
00475 Bool operator >= (const IPosition& left, ssize_t val);
00476 // </group>
00477 // Same functions as above but with with the Int argument on the left side.
00478 // <group>
00479 Bool operator == (ssize_t val, const IPosition& right);
00480 Bool operator != (ssize_t val, const IPosition& right);
00481 Bool operator <  (ssize_t val, const IPosition& right);
00482 Bool operator <= (ssize_t val, const IPosition& right);
00483 Bool operator >  (ssize_t val, const IPosition& right);
00484 Bool operator >= (ssize_t val, const IPosition& right);
00485 // </group>
00486 // </group>
00487 
00488 // <summary>Indexing functions for IPosition's</summary>
00489 // Convert between IPosition and offset in an array.
00490 //
00491 // The offset of an element in an array is the number of elements from the
00492 // origin that the element would be if the array were arranged linearly.
00493 // The origin of the array has an offset equal to 0, while the
00494 // "top right corner" of the array has an offset equal to one less than the
00495 // total number of elements in the array.
00496 //
00497 // Two examples of offset would be the index in a carray and the seek position
00498 // in a file.
00499 
00500 // <group name="IPosition Indexing">
00501 // Convert from offset to IPosition in an array.
00502 IPosition toIPositionInArray (Int64 offset, const IPosition& shape);
00503 
00504 // Convert from IPosition to offset in an array.
00505 Int64 toOffsetInArray (const IPosition& iposition, const IPosition& shape);
00506 
00507 // Determine if the given offset or IPosition is inside the array. Returns
00508 // True if it is inside the Array.
00509 // <thrown>
00510 //   <li> ArrayConformanceError: If all the IPositions are not the same length
00511 // </thrown>
00512 // <group>
00513 Bool isInsideArray (const Int64 offset, const IPosition& shape);
00514 Bool isInsideArray (const IPosition& iposition, const IPosition& shape);
00515 // </group>
00516 // </group>
00517 
00518 
00519     
00520 //# Inlined member functions for IPosition
00521 
00522 inline IPosition::IPosition()
00523 : size_p (0),
00524   data_p (buffer_p)
00525 {}
00526 
00527 inline IPosition IPosition::makeAxisPath (uInt nrdim)
00528 {
00529     return makeAxisPath (nrdim, IPosition());
00530 }
00531 
00532 inline uInt IPosition::nelements() const
00533 {
00534     return size_p;
00535 }
00536 inline uInt IPosition::size() const
00537 {
00538     return size_p;
00539 }
00540 inline Bool IPosition::empty() const
00541 {
00542     return size_p == 0;
00543 }
00544 
00545 inline ssize_t& IPosition::operator[](uInt index)
00546 {
00547     return data_p[index];
00548 }
00549 
00550 inline ssize_t IPosition::operator[](uInt index) const
00551 {
00552     return data_p[index];
00553 }
00554 
00555 inline ssize_t& IPosition::operator()(uInt index)
00556 {
00557 #if defined(AIPS_ARRAY_INDEX_CHECK)
00558     if (index >= nelements()) {
00559         throwIndexError();
00560     }
00561 #endif
00562     return data_p[index];
00563 }
00564 
00565 inline ssize_t IPosition::operator()(uInt index) const
00566 {
00567 #if defined(AIPS_ARRAY_INDEX_CHECK)
00568     if (index >= nelements()) {
00569         throwIndexError();
00570     }
00571 #endif
00572     return data_p[index];
00573 }
00574 
00575 inline ssize_t& IPosition::last (uInt index)
00576 {
00577 #if defined(AIPS_ARRAY_INDEX_CHECK)
00578     if (size_p - index <= 0) {
00579         throwIndexError();
00580     }
00581 #endif
00582     return data_p[size_p-index-1];
00583 }
00584 
00585 inline ssize_t IPosition::last (uInt index) const
00586 {
00587 #if defined(AIPS_ARRAY_INDEX_CHECK)
00588     if (size_p - index <= 0) {
00589         throwIndexError();
00590     }
00591 #endif
00592     return data_p[size_p-index-1];
00593 }
00594 
00595 inline const ssize_t *IPosition::storage() const
00596 {
00597     return data_p;
00598 }
00599 
00600 inline Bool IPosition::conform(const IPosition& other) const
00601 {
00602     return  (size_p == other.size_p);
00603 }
00604 
00605 } //# NAMESPACE CASA - END
00606 
00607 #endif