//# MaskedArray.cc: A templated N-D masked array class with variable origin. //# Copyright (C) 1993,1994,1995,1996,1997,1999,2001,2005 //# 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$ #ifndef CASA_MASKEDARRAY_2_TCC #define CASA_MASKEDARRAY_2_TCC #include "MaskedArray.h" #include "Array.h" #include "ArrayLogical.h" #include "Slicer.h" #include "ArrayError.h" #include namespace casacore { //# NAMESPACE CASACORE - BEGIN template MaskedArray::MaskedArray () : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (false) {} template MaskedArray::MaskedArray (const array_type &inarray, const LogicalArray &inmask, bool isreadonly) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (isreadonly) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray(const array_type &," " const LogicalArray &, bool)" " - arrays do not conform")); } pArray.reset( new array_type (inarray) ); pMask.reset( new LogicalArray (inmask.shape()) ); pMask->assign_conforming(inmask); assert(ok()); } template MaskedArray::MaskedArray (const array_type &inarray, const LogicalArray &inmask) : pArray(), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (false) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray(const array_type &," " const LogicalArray &)" " - arrays do not conform")); } pArray.reset( new array_type (inarray) ); pMask.reset( new LogicalArray (inmask.shape()) ); pMask->assign_conforming(inmask); assert(ok()); } template MaskedArray::MaskedArray (const MaskedArray &inarray, const LogicalArray &inmask, bool isreadonly) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO ( (inarray.isRO || isreadonly)) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray (const MaskedArray &," " const LogicalArray &, bool)" " - arrays do not conform")); } pArray.reset( new array_type (inarray.getArray()) ); pMask.reset( new LogicalArray (inmask.shape()) ); *pMask = (inmask && inarray.getMask()); assert(ok()); } template MaskedArray::MaskedArray (const MaskedArray &inarray, const LogicalArray &inmask) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (inarray.isRO) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray (const MaskedArray &," " const LogicalArray &)" " - arrays do not conform")); } pArray.reset( new array_type (inarray.getArray()) ); pMask.reset( new LogicalArray (inmask.shape()) ); *pMask = (inmask && inarray.getMask()); assert(ok()); } template MaskedArray::MaskedArray (const array_type &inarray, const MaskedLogicalArray &inmask, bool isreadonly) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (isreadonly) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray(const array_type &inarray," " const MaskedLogicalArray &inmask, bool isreadonly)" " - arrays do not conform")); } pArray.reset( new array_type (inarray) ); pMask.reset( new LogicalArray (inarray.shape()) ); pMask->assign_conforming(inmask.getArray() && inmask.getMask()); assert(ok()); } template MaskedArray::MaskedArray (const array_type &inarray, const MaskedLogicalArray &inmask) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (false) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray(const array_type &inarray," " const MaskedLogicalArray &inmask)" " - arrays do not conform")); } pArray.reset( new array_type (inarray) ); pMask.reset( new LogicalArray (inarray.shape()) ); pMask->assign_conforming(inmask.getArray() && inmask.getMask()); assert(ok()); } template MaskedArray::MaskedArray (const MaskedArray &inarray, const MaskedLogicalArray &inmask) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO (inarray.isRO) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray (const MaskedArray &inarray," " const MaskedLogicalArray &inmask)" " - arrays do not conform")); } pArray.reset( new array_type (inarray.getArray()) ); pMask.reset( new LogicalArray (inarray.shape()) ); *pMask = (inmask.getArray() && inmask.getMask() && inarray.getMask()); assert(ok()); } template MaskedArray::MaskedArray (const MaskedArray &inarray, const MaskedLogicalArray &inmask, bool isreadonly) : pArray (), pMask (), nelemValid (0), nelemValidIsOK (false), isRO ( (inarray.isRO || isreadonly)) { // if (! conform2 (inarray, inmask)) { if (inarray.shape() != inmask.shape()) { throw (ArrayConformanceError( "MaskedArray::MaskedArray (const MaskedArray &inarray," " const MaskedLogicalArray &inmask, bool isreadonly)" " - arrays do not conform")); } pArray.reset( new array_type (inarray.getArray()) ); pMask.reset( new LogicalArray (inarray.shape()) ); *pMask = (inmask.getArray() && inmask.getMask() && inarray.getMask()); assert(ok()); } template MaskedArray::MaskedArray(const MaskedArray &other, bool isreadonly) : pArray (), pMask (), nelemValid (other.nelemValid), nelemValidIsOK (other.nelemValidIsOK), isRO ( (other.isRO || isreadonly)) { pArray.reset( new array_type (*(other.pArray)) ); pMask.reset( new LogicalArray (*(other.pMask)) ); assert(ok()); } template MaskedArray::MaskedArray(const MaskedArray &other) : pArray (), pMask (), nelemValid (other.nelemValid), nelemValidIsOK (other.nelemValidIsOK), isRO (other.isRO) { pArray.reset( new array_type (*(other.pArray)) ); pMask.reset( new LogicalArray (*(other.pMask)) ); assert(ok()); } template MaskedArray::MaskedArray(MaskedArray&& source) : pArray (std::move(source.pArray)), pMask (std::move(source.pMask)), nelemValid (source.nelemValid), nelemValidIsOK (source.nelemValidIsOK), isRO (source.isRO) { source.nelemValid = 0; source.nelemValidIsOK = false; source.isRO = false; assert(ok()); assert(source.ok()); } template void MaskedArray::setData (const array_type &data, const mask_type &mask, bool isReadOnly) { if (data.shape() != mask.shape()) { throw (ArrayConformanceError( "MaskedArray::setData(const array_type &," " const LogicalArray &, bool)" " - arrays do not conform")); } pArray.reset( new array_type(data) ); pMask.reset( new mask_type (mask.copy()) ); nelemValid = 0; nelemValidIsOK = false; isRO = isReadOnly; assert(ok()); } template void MaskedArray::setData (const MaskedArray & array, bool isReadOnly){ pArray.reset( new array_type(array.getArray()) ); pMask.reset( new LogicalArray(array.getMask().copy()) ); nelemValid = 0; nelemValidIsOK = false; isRO = isReadOnly; assert(ok()); } template MaskedArray MaskedArray::copy(bool isreadonly) const { assert(ok()); MaskedArray retval (pArray->copy(), *pMask, isreadonly); retval.nelemValid = nelemValid; retval.nelemValidIsOK = nelemValidIsOK; return retval; } template MaskedArray MaskedArray::copy() const { assert(ok()); MaskedArray retval (pArray->copy(), *pMask); retval.nelemValid = nelemValid; retval.nelemValidIsOK = nelemValidIsOK; return retval; } template MaskedArray MaskedArray::operator() (const LogicalArray &mask) const { assert(ok()); MaskedArray ret (*this, mask); return ret; } template MaskedArray MaskedArray::operator() (const MaskedLogicalArray &mask) const { assert(ok()); MaskedArray ret (*this, mask); return ret; } template MaskedArray MaskedArray::operator() (const IPosition &start, const IPosition &end) { assert(ok()); return MaskedArray ((*pArray)(start,end), (*pMask)(start,end), isRO); } template MaskedArray MaskedArray::operator() (const IPosition &start, const IPosition &end, const IPosition &inc) { assert(ok()); return MaskedArray ((*pArray)(start,end,inc), (*pMask)(start,end,inc), isRO); } template MaskedArray MaskedArray::operator() (const Slicer &slicer) { assert(ok()); return MaskedArray ((*pArray)(slicer), (*pMask)(slicer), isRO); } template const Array &MaskedArray::getArray() const { assert(ok()); return *pArray; } template const Array & MaskedArray::getMask() const { assert(ok()); return *pMask; } template size_t MaskedArray::ndim() const { assert(ok()); return pArray->ndim(); } template size_t MaskedArray::nelementsValid() const { assert(ok()); if (!nelemValidIsOK) { // Calculate nelemValid; bool maskDelete; const LogicalArrayElem *maskStorage = getMaskStorage(maskDelete); const LogicalArrayElem *maskS = maskStorage; size_t nelemValidTmp = 0; size_t ntotal = nelements(); while (ntotal--) { if (*maskS) { nelemValidTmp++; } maskS++; } freeMaskStorage(maskStorage, maskDelete); MaskedArray *nonconstThis = (MaskedArray *) this; nonconstThis->nelemValid = nelemValidTmp; nonconstThis->nelemValidIsOK = true; } return nelemValid; } template size_t MaskedArray::nelements() const { assert(ok()); return pArray->nelements(); } template bool MaskedArray::ok() const { if (!pArray && !pMask) return true; // default constructed is ok if (!pArray || !pMask) return false; // not both set is not ok return (pArray->ok() && pMask->ok()) ? true : false; } template bool MaskedArray::conform(const array_type &other) const { assert(ok()); return pArray->conform(other); } template bool MaskedArray::conform(const MaskedArray &other) const { assert(ok()); return pArray->conform(*(other.pArray)); } template void MaskedArray::setReadOnly() const { assert(ok()); MaskedArray *nonconstThis = (MaskedArray *) this; nonconstThis->isRO = true; } template Array MaskedArray::getCompressedArray () const { array_type result (IPosition (1,nelementsValid())); bool deleteResult; T *resultStorage = result.getStorage (deleteResult); T *resultS = resultStorage; bool deleteArr; const T *arrStorage = getArrayStorage (deleteArr); const T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage (deleteMask); const LogicalArrayElem *maskS = maskStorage; size_t ntotal = nelementsValid(); while (ntotal) { if (*maskS) { *resultS = *arrS; resultS++; ntotal--; } maskS++; arrS++; } result.putStorage (resultStorage, deleteResult); freeArrayStorage (arrStorage, deleteArr); freeMaskStorage (maskStorage, deleteMask); return result; } template Array MaskedArray::getCompressedArray (const IPosition & shape) const { if (int(nelementsValid()) != shape.product()) { throw (ArrayError ("void MaskedArray::getCompressedArray (const IPosition & shape)" " - input shape will create Array with incorrect number of elements")); } array_type result (shape); bool deleteResult; T *resultStorage = result.getStorage (deleteResult); T *resultS = resultStorage; bool deleteArr; const T *arrStorage = getArrayStorage (deleteArr); const T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage (deleteMask); const LogicalArrayElem *maskS = maskStorage; size_t ntotal = nelementsValid(); while (ntotal) { if (*maskS) { *resultS = *arrS; resultS++; ntotal--; } maskS++; arrS++; } result.putStorage (resultStorage, deleteResult); freeArrayStorage (arrStorage, deleteArr); freeMaskStorage (maskStorage, deleteMask); return result; } template void MaskedArray::getCompressedArray (array_type & inarr) const { if (nelementsValid() != inarr.nelements()) { throw (ArrayError ("void MaskedArray::getCompressedArray (array_type & inarr)" " - input Array number of elements is incorrect")); } bool deleteInarr; T *inarrStorage = inarr.getStorage (deleteInarr); T *inarrS = inarrStorage; bool deleteArr; const T *arrStorage = getArrayStorage (deleteArr); const T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage (deleteMask); const LogicalArrayElem *maskS = maskStorage; size_t ntotal = nelementsValid(); while (ntotal) { if (*maskS) { *inarrS = *arrS; inarrS++; ntotal--; } maskS++; arrS++; } inarr.putStorage (inarrStorage, deleteInarr); freeArrayStorage (arrStorage, deleteArr); freeMaskStorage (maskStorage, deleteMask); } template void MaskedArray::setCompressedArray (const array_type & inarr) { if (nelementsValid() != inarr.nelements()) { throw (ArrayError ("void MaskedArray::setCompressedArray (const array_type & inarr)" " - input array number of elements is incorrect")); } bool deleteInarr; const T *inarrStorage = inarr.getStorage (deleteInarr); const T *inarrS = inarrStorage; bool deleteArr; T *arrStorage = getRWArrayStorage (deleteArr); T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage (deleteMask); const LogicalArrayElem *maskS = maskStorage; size_t ntotal = nelementsValid(); while (ntotal) { if (*maskS) { *arrS = *inarrS; inarrS++; ntotal--; } maskS++; arrS++; } inarr.freeStorage (inarrStorage, deleteInarr); putArrayStorage (arrStorage, deleteArr); freeMaskStorage (maskStorage, deleteMask); } template const T * MaskedArray::getArrayStorage (bool &deleteIt) const { assert(ok()); return pArray->getStorage (deleteIt); } template void MaskedArray::freeArrayStorage(const T *&storage, bool deleteIt) const { assert(ok()); pArray->freeStorage (storage, deleteIt); } template const LogicalArrayElem * MaskedArray::getMaskStorage (bool &deleteIt) const { assert(ok()); return pMask->getStorage (deleteIt); } template void MaskedArray::freeMaskStorage (const LogicalArrayElem *&storage, bool deleteIt) const { assert(ok()); pMask->freeStorage (storage, deleteIt); } template MaskedArray& MaskedArray::operator= (const array_type &inarray) { assert(ok()); if (!pArray) { pArray.reset( new array_type(inarray) ); pMask.reset( new mask_type(inarray.shape(), true) ); nelemValid = 0; nelemValidIsOK = false; isRO = false; return *this; } if (!conform(inarray)) { throw(ArrayConformanceError( "MaskedArray & MaskedArray::operator= " "(const array_type &inarray)" "- Conformance error.")); } if (isRO) { throw(ArrayError( "MaskedArray & MaskedArray::operator= " "(const array_type &inarray)" "- this is read only.")); } bool deleteArr; T *arrStorage = getRWArrayStorage(deleteArr); T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage(deleteMask); const LogicalArrayElem *maskS = maskStorage; bool deleteInarr; const T *inarrStorage = inarray.getStorage(deleteInarr); const T *inarrS = inarrStorage; size_t ntotal = pArray->nelements(); while (ntotal--) { if (*maskS) { *arrS = *inarrS; } arrS++; maskS++; inarrS++; } putArrayStorage(arrStorage, deleteArr); freeMaskStorage(maskStorage, deleteMask); inarray.freeStorage(inarrStorage, deleteInarr); return *this; } template MaskedArray& MaskedArray::operator= (array_type&& inarray) { assert(ok()); if (!pArray) { pMask.reset( new mask_type(inarray.shape(), true) ); pArray.reset( new array_type(inarray) ); nelemValid = 0; nelemValidIsOK = false; isRO = false; return *this; } else { return operator=(inarray); // do ordinary copy assignment } } template MaskedArray& MaskedArray::operator= (const MaskedArray &other) { assert(ok()); if (this == &other) return *this; if (!pArray) { setData(other.copy()); return *this; } if (!conform(other)) { throw(ArrayConformanceError( "MaskedArray & MaskedArray::operator= " "(const MaskedArray &other)" "- Conformance error.")); } if (isRO) { throw(ArrayError( "MaskedArray & MaskedArray::operator= " "(const MaskedArray &other)" "- this is read only.")); } bool deleteArr; T *arrStorage = getRWArrayStorage(deleteArr); T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage(deleteMask); const LogicalArrayElem *maskS = maskStorage; bool deleteOarr; const T *oarrStorage = other.getArrayStorage(deleteOarr); const T *oarrS = oarrStorage; bool deleteOmask; const LogicalArrayElem *omaskStorage = other.getMaskStorage(deleteOmask); const LogicalArrayElem *omaskS = omaskStorage; size_t ntotal = pArray->nelements(); while (ntotal--) { if (*maskS && *omaskS) { *arrS = *oarrS; } arrS++; maskS++; oarrS++; omaskS++; } putArrayStorage(arrStorage, deleteArr); freeMaskStorage(maskStorage, deleteMask); other.freeArrayStorage(oarrStorage, deleteOarr); other.freeMaskStorage(omaskStorage, deleteOmask); return *this; } template MaskedArray& MaskedArray::operator= (MaskedArray&& other) { assert(ok()); if (other.isReadOnly()) return operator=(other); if (this == &other) return *this; if (!pArray) { pArray = std::move(other.pArray); pMask = std::move(other.pMask); nelemValid = 0; nelemValidIsOK = false; isRO = false; other.nelemValid = 0; other.nelemValidIsOK = false; // other.isRO = false; // we already know this is false return *this; } else { return operator=(other); } } template MaskedArray &MaskedArray::operator=(const T &val) { assert(ok()); if (!pArray) return *this; if (isRO) { throw(ArrayError( "MaskedArray & MaskedArray::operator= (const T &val)" "- this is read only.")); } bool deleteArr; T *arrStorage = getRWArrayStorage(deleteArr); T *arrS = arrStorage; bool deleteMask; const LogicalArrayElem *maskStorage = getMaskStorage(deleteMask); const LogicalArrayElem *maskS = maskStorage; size_t ntotal = pArray->nelements(); while (ntotal--) { if (*maskS) { *arrS = val; } arrS++; maskS++; } putArrayStorage(arrStorage, deleteArr); freeMaskStorage(maskStorage, deleteMask); return *this; } template T * MaskedArray::getRWArrayStorage (bool &deleteIt) const { assert(ok()); if (isRO) { throw(ArrayError( "MaskedArray::getRWArrayStorage (bool &deleteIt) const" "- this is read only.")); } return pArray->getStorage (deleteIt); } template void MaskedArray::putArrayStorage(T *&storage, bool deleteAndCopy) const { assert(ok()); if (isRO) { throw(ArrayError( "MaskedArray::putArrayStorage (bool deleteAndCopy) const" "- this is read only.")); } pArray->putStorage (storage, deleteAndCopy); } template Array& MaskedArray::getRWArray() const { assert(ok()); if (isRO) { throw(ArrayError( "array_type & MaskedArray::getRWArray () const" "- this is read only.")); } return *pArray; } //# Global functions. template bool conform2 (const MaskedArray &left, const Array &right) { IPosition leftShape (left.shape()); IPosition rightShape (right.shape()); return ( (leftShape.conform (rightShape)) && (leftShape == rightShape) ) ? true : false; } template bool conform2 (const Array &left, const MaskedArray &right) { IPosition leftShape (left.shape()); IPosition rightShape (right.shape()); return ( (leftShape.conform (rightShape)) && (leftShape == rightShape) ) ? true : false; } template bool conform2 (const MaskedArray &left, const MaskedArray &right) { IPosition leftShape (left.shape()); IPosition rightShape (right.shape()); return ( (leftShape.conform (rightShape)) && (leftShape == rightShape) ) ? true : false; } } //# NAMESPACE CASACORE - END #endif