//# IPosition.cc: A vector of integers, used to index into arrays. //# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2002 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #include "IPosition.h" #include "ArrayError.h" #include "Array.h" #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN IPosition::IPosition (size_t length) : size_p (length), data_p (buffer_p) { if (length > BufferLength) { allocateBuffer(); } } IPosition::IPosition(std::initializer_list list) : size_p (list.size()), data_p (buffer_p) { if (list.size() > BufferLength) { allocateBuffer(); } std::initializer_list::const_iterator list_iter = list.begin(); size_t i = 0; while(list_iter != list.end()) { data_p[i] = *list_iter; ++list_iter; ++i; } } IPosition::IPosition (const Array &other) : size_p (0), data_p (buffer_p) { if (other.size() > 0) { if (other.ndim() != 1) { throw(ArrayError("IPosition::IPosition(const Array &other) - " "other is not one-dimensional")); } fill (other.size(), other.begin()); } assert(ok()); } IPosition::IPosition (const Array &other) : size_p (0), data_p (buffer_p) { if (other.size() > 0) { if (other.ndim() != 1) { throw(ArrayError("IPosition::IPosition(const Array &other) - " "other is not one-dimensional")); } fill (other.size(), other.begin()); } assert(ok()); } IPosition::~IPosition() { if (data_p != &buffer_p[0]) { delete [] data_p; } } void IPosition::allocateBuffer() { if (size_p <= BufferLength) { data_p = buffer_p; } else { data_p = new ssize_t[size_p]; } assert(ok()); } IPosition::IPosition (size_t length, ssize_t val) : size_p (length), data_p (buffer_p) { if (size_p > BufferLength) { allocateBuffer(); } std::fill_n(data_p, size_p, val); } IPosition::IPosition (const IPosition& other) : size_p (other.size_p), data_p (buffer_p) { if (size_p > BufferLength) { allocateBuffer(); } std::copy_n(other.data_p, size_p, data_p); assert(ok()); } IPosition::IPosition (IPosition&& source) noexcept : size_p (source.size_p), data_p (size_p > BufferLength ? source.data_p : buffer_p) { std::copy_n(source.data_p, size_p, data_p); source.size_p = 0; source.data_p = source.buffer_p; } Vector IPosition::asVector() const { assert(ok()); Vector retval(nelements()); copy (retval.begin()); return retval; } Vector IPosition::asVector64() const { assert(ok()); Vector retval(nelements()); copy (retval.begin()); return retval; } IPosition::IPosition (const std::vector &other) : size_p (0), data_p (buffer_p) { fill (other.size(), other.begin()); assert(ok()); } IPosition::IPosition (const std::vector &other) : size_p (0), data_p (nullptr) { fill (other.size(), other.begin()); assert(ok()); } std::vector IPosition::asStdVector() const { assert(ok()); std::vector retval(nelements()); copy (retval.begin()); return retval; } std::vector IPosition::asStdVector64() const { assert(ok()); std::vector retval(nelements()); copy (retval.begin()); return retval; } IPosition IPosition::nonDegenerate (size_t startingAxis) const { if (startingAxis >= size_p) { return *this; } IPosition ignoreAxes(startingAxis); for (size_t i=0; i= ssize_t(size_p)) throw std::runtime_error("ignoreAxes(i) >= ssize_t(size_p)"); keepAxes(ignoreAxes(i)) = 1; } // Now count all axes to keep. size_t count=0; for (i=0; i // ArrayConformanceError // IPosition& IPosition::operator= (const IPosition& other) { assert(ok()); if (&other == this) { return *this; } if (size_p != other.size_p) { resize (other.nelements(), false); } std::copy_n(other.data_p, size_p, data_p); assert(ok()); return *this; } IPosition& IPosition::operator=(IPosition&& source) { size_p = source.size_p; if (data_p != &buffer_p[0]) delete [] data_p; data_p = size_p > BufferLength ? source.data_p : buffer_p; std::copy_n(source.data_p, size_p, data_p); source.size_p = 0; source.data_p = source.buffer_p; return *this; } IPosition& IPosition::operator= (ssize_t value) { assert(ok()); std::fill_n(data_p, size_p, value); return *this; } IPosition IPosition::operator() (const IPosition& axes) const { IPosition ipos(axes.nelements()); size_t i = 0; for (IPosition::const_iterator iter=axes.begin(); iter!=axes.end(); ++iter, ++i) { if (*iter >= int(size_p)) { throw std::runtime_error("IPosition::operator()(const IPosition&): " "Axis number must be less than size of current object"); } ipos[i] = data_p[*iter]; } return ipos; } void IPosition::append (const IPosition& other) { const size_t pos = size_p; resize (size_p + other.size_p); std::copy_n(other.data_p, other.size_p, data_p + pos); } void IPosition::prepend (const IPosition& other) { const size_t old_size = size_p; resize (size_p + other.size_p); std::move_backward(data_p, data_p + old_size, data_p + size_p); std::copy_n(other.data_p, other.size_p, data_p); } IPosition IPosition::concatenate (const IPosition& other) const { IPosition tmp(size_p + other.size_p); std::copy_n(data_p, size_p, tmp.data_p); std::copy_n(other.data_p, other.size_p, tmp.data_p + size_p); return tmp; } void IPosition::setFirst (const IPosition& other) { if (size_p < other.size_p) { throw (std::runtime_error ("IPosition::setFirst(other); other is too long")); } std::copy_n(other.data_p, other.size_p, data_p); } void IPosition::setLast (const IPosition& other) { if (size_p < other.size_p) { throw (std::runtime_error ("IPosition::setLast(other); other is too long")); } std::copy_n(other.data_p, other.size_p, data_p + size_p - other.size_p); } IPosition IPosition::getFirst (size_t n) const { if (size_p < n) { throw (std::runtime_error ("IPosition::getFirst(n); n is too high")); } IPosition tmp(n); std::copy_n(data_p, n, tmp.data_p); return tmp; } IPosition IPosition::getLast (size_t n) const { if (size_p < n) { throw (std::runtime_error ("IPosition::getLast(n); n is too high")); } IPosition tmp(n); std::copy_n(data_p + size_p - n, n, tmp.data_p); return tmp; } IPosition IPosition::removeAxes (const IPosition& axes) const { // Get the axes to keep. // It also checks if axes are specified correctly. IPosition resAxes = IPosition::otherAxes (size_p, axes); size_t ndimRes = resAxes.nelements(); // Create the result shape. IPosition resShape(ndimRes); if (ndimRes == 0) { resShape.resize(1); resShape[0] = 1; } else { for (size_t i=0; i // ArrayConformanceError // void IPosition::operator += (const IPosition& other) { assert(ok()); if (! conform(other)) { throw(ArrayConformanceError("IPosition::operator += " "(const IPosition&) - " "this and other differ in length")); } for (size_t i=0; i // ArrayConformanceError // void IPosition::operator -= (const IPosition& other) { assert(ok()); if (! conform(other)) { throw(ArrayConformanceError("IPosition::operator -= " "(const IPosition&) - " "this and other differ in length")); } for (size_t i=0; i // ArrayConformanceError // void IPosition::operator *= (const IPosition& other) { assert(ok()); if (! conform(other)) { throw(ArrayConformanceError("IPosition::operator *= " "(const IPosition&) - " "this and other differ in length")); } for (size_t i=0; i // ArrayConformanceError // void IPosition::operator /= (const IPosition& other) { assert(ok()); if (! conform(other)) { throw(ArrayConformanceError("IPosition::operator /= " "(const IPosition&) - " "this and other differ in length")); } for (size_t i=0; i= nrthat) { break; } if (data_p[i] != other(j)) { return false; } j++; } } for (; i nelements()) { nrCompare = nelements(); } for (size_t i=0; i // ArrayConformanceError // IPosition operator + (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator + " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } IPosition result(left); result += right; return result; } // // ArrayConformanceError // IPosition operator - (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator - " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } IPosition result(left); result -= right; return result; } // // ArrayConformanceError // IPosition operator * (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator * " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } IPosition result(left); result *= right; return result; } // // ArrayConformanceError // IPosition operator / (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator / " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } IPosition result(left); result /= right; return result; } IPosition operator + (const IPosition& left, ssize_t val) { IPosition result(left); result += val; return result; } IPosition operator - (const IPosition& left, ssize_t val) { IPosition result(left); result -= val; return result; } IPosition operator * (const IPosition& left, ssize_t val) { IPosition result(left); result *= val; return result; } IPosition operator / (const IPosition& left, ssize_t val) { IPosition result(left); result /= val; return result; } IPosition operator + (ssize_t val, const IPosition& right) { IPosition result(right.nelements()); result = val; result += right; return result; } IPosition operator - (ssize_t val, const IPosition& right) { IPosition result(right.nelements()); result = val; result -= right; return result; } IPosition operator * (ssize_t val, const IPosition& right) { IPosition result(right.nelements()); result = val; result *= right; return result; } IPosition operator / (ssize_t val, const IPosition& right) { IPosition result(right.nelements()); result = val; result /= right; return result; } IPosition max (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::max " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } IPosition result(left); const size_t ndim = result.nelements(); ssize_t max; for (size_t i = 0; i < ndim; i++) { if (result(i) < (max = right(i))) { result(i) = max; } } return result; } // // ArrayConformanceError // IPosition min (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::min " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } IPosition result(left); const size_t ndim = result.nelements(); ssize_t min; for (size_t i = 0; i < ndim; i++) { if (result(i) > (min = right(i))) { result(i) = min; } } return result; } long long IPosition::product() const { if (nelements() == 0) { return 0; } long long total = 1; for (size_t i=0; i // ArrayConformanceError // bool operator == (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator== " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } size_t n=left.nelements(); bool result = true; for (size_t i=0; i // ArrayConformanceError // bool operator != (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator!= " "(const IPosition&, const IPosition&) - " "left and right operand do not conform (left.shape()=" + to_string(left) + ", right.shape()=" + to_string(right) + ")")); } size_t n=left.nelements(); bool result = false; for (size_t i=0; i // ArrayConformanceError // bool operator < (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator< " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } size_t n=left.nelements(); bool result = true; for (size_t i=0; i // ArrayConformanceError // bool operator <= (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator<= " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } size_t n=left.nelements(); bool result = true; for (size_t i=0; i // ArrayConformanceError // bool operator > (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator> " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } size_t n=left.nelements(); bool result = true; for (size_t i=0; i right(i)) { // Nothing - written to make cut and paste easier } else { result = false; break; } } return result; } // // ArrayConformanceError // bool operator >= (const IPosition& left, const IPosition& right) { if (! left.conform(right)) { throw(ArrayConformanceError("::operator>= " "(const IPosition&, const IPosition&) - " "left and right operand do not conform ")); } size_t n=left.nelements(); bool result = true; for (size_t i=0; i= right(i)) { // Nothing - written to make cut and paste easier } else { result = false; break; } } return result; } bool operator == (const IPosition& left, ssize_t val) { bool result = true; size_t n = left.nelements(); for (size_t i=0; i (const IPosition& left, ssize_t val) { bool result = true; size_t n = left.nelements(); for (size_t i=0; i val) { // Nothing } else { result = false; break; } } return result; } bool operator >= (const IPosition& left, ssize_t val) { bool result = true; size_t n = left.nelements(); for (size_t i=0; i= val) { // Nothing } else { result = false; break; } } return result; } bool operator == (ssize_t val, const IPosition& right) { bool result = true; size_t n = right.nelements(); for (size_t i=0; i (ssize_t val, const IPosition& right) { bool result = true; size_t n = right.nelements(); for (size_t i=0; i right(i)) { // Nothing } else { result = false; break; } } return result; } bool operator >= (ssize_t val, const IPosition& right) { bool result = true; size_t n = right.nelements(); for (size_t i=0; i= right(i)) { // Nothing } else { result = false; break; } } return result; } std::string to_string(const IPosition& ip) { std::ostringstream oss; oss << ip; return oss.str(); } std::string IPosition::toString() const { return to_string(*this); } std::ostream& operator<< (std::ostream& os, const IPosition& ip) { os << "["; for (size_t i=0; i 0) { os << ", "; } os << ip(i); } os << "]"; return os; } bool IPosition::ok() const { assert(size_p > BufferLength || data_p == &buffer_p[0]); assert(data_p != nullptr); bool retval = true; if (size_p <= BufferLength && data_p != &buffer_p[0]) { retval = false; } if (data_p == nullptr) { retval = false; } return retval; } IPosition toIPositionInArray (long long offset, const IPosition& shape) { if (! isInsideArray (offset, shape) ) { throw (ArrayIndexError( "IPosition ::toIPositionInArray (long long offset," " const IPosition& shape)" " - Invalid offset.")); } IPosition iposition (shape.nelements()); long long divisor = 1; size_t ndim = shape.nelements(); for (size_t idim = 0; idim < ndim; idim++) { iposition(idim) = ((offset / divisor) % shape(idim)); divisor *= shape(idim); } return iposition; } long long toOffsetInArray (const IPosition& iposition, const IPosition& shape) { if (! (iposition.conform(shape)) ) { throw (ArrayConformanceError( "long long ::toOffsetInArray (const IPosition& iposition," " const IPosition& shape)" " - IPositions do not conform")); } if (! isInsideArray (iposition, shape) ) { throw (ArrayIndexError( "long long ::toOffsetInArray (const IPosition& iposition," " const IPosition& shape)" " - Invalid iposition.")); } long long offset = 0; long long multiplier = 1; size_t ndim = shape.nelements(); for (size_t idim = 0; idim < ndim; idim++) { offset += (iposition(idim) * multiplier); multiplier *= shape(idim); } return offset; } bool isInsideArray (long long offset, const IPosition& shape) { return (offset < shape.product()) ? true : false; } bool isInsideArray (const IPosition& iposition, const IPosition& shape) { if (! (iposition.conform(shape)) ) { throw (ArrayConformanceError( "bool ::isInsideArray (const IPosition& iposition," " const IPosition& shape)" " - IPositions do not conform")); } bool result = true; ssize_t ioff; size_t ndim = shape.nelements(); for (size_t idim = 0; idim < ndim; idim++) { ioff = iposition(idim); if ( (ioff < 0) || (ioff >= shape(idim)) ) { result = false; break; } } return result; } IPosition IPosition::makeAxisPath (size_t nrdim, const IPosition& partialPath) { // Check if the specified traversal axes are correct and unique. if (partialPath.nelements() > nrdim) std::runtime_error("partialPath.nelements() > nrdim"); IPosition path(nrdim); IPosition done(nrdim, 0); size_t i,j; for (i=0; i= int(nrdim) || done(path(i)) != 0) { throw (std::runtime_error ("IPosition::makeAxisPath: invalid defined axes")); } done(path(i)) = 1; } // Fill unspecified axes with the natural order. for (j=0; j - but that causes multiply // defined symbols with the current objectcenter. throw(std::runtime_error("IPosition::operator() - index error")); } bool IPositionComparator::operator ()(const IPosition& lhs, const IPosition& rhs) const { size_t lhsSize = lhs.size_p; size_t rhsSize = rhs.size_p; if (lhsSize == rhsSize) { ssize_t *lp = lhs.data_p; ssize_t *rp = rhs.data_p; for (size_t i=0; i