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