casa
$Rev:20696$
|
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