X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FMEDCoupling%2FMEDCouplingMemArray.txx;h=48ac1c576fb9298c1a6f4e2a055fc949b0f9356f;hb=a6c4fa941f2f989606ab1ccf0d89c5992a0193a9;hp=4c5339a8b6671a5e34484af5c29501115aa647cd;hpb=10f37bf6f33a762626d7f1093b2f5450c1688667;p=tools%2Fmedcoupling.git diff --git a/src/MEDCoupling/MEDCouplingMemArray.txx b/src/MEDCoupling/MEDCouplingMemArray.txx index 4c5339a8b..48ac1c576 100644 --- a/src/MEDCoupling/MEDCouplingMemArray.txx +++ b/src/MEDCoupling/MEDCouplingMemArray.txx @@ -1,9 +1,9 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 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 @@ -16,6 +16,8 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // +// Author : Anthony Geay (EDF R&D) + #ifndef __PARAMEDMEM_MEDCOUPLINGMEMARRAY_TXX__ #define __PARAMEDMEM_MEDCOUPLINGMEMARRAY_TXX__ @@ -23,11 +25,16 @@ #include "NormalizedUnstructuredMesh.hxx" #include "InterpKernelException.hxx" #include "InterpolationUtils.hxx" +#include "MEDCouplingPartDefinition.hxx" +#include "InterpKernelAutoPtr.hxx" +#include "MCAuto.hxx" #include +#include +#include #include -namespace ParaMEDMEM +namespace MEDCoupling { template void MEDCouplingPointer::setInternal(T *pointer) @@ -44,37 +51,77 @@ namespace ParaMEDMEM } template - MemArray::MemArray(const MemArray& other):_nb_of_elem(-1),_ownership(false),_dealloc(CPP_DEALLOC) + MemArray::MemArray(const MemArray& other):_nb_of_elem(0),_nb_of_elem_alloc(0),_ownership(false),_dealloc(0),_param_for_deallocator(0) { if(!other._pointer.isNull()) { - T *pointer=new T[other._nb_of_elem]; + _nb_of_elem_alloc=other._nb_of_elem; + T *pointer=(T*)malloc(_nb_of_elem_alloc*sizeof(T)); std::copy(other._pointer.getConstPointer(),other._pointer.getConstPointer()+other._nb_of_elem,pointer); - useArray(pointer,true,CPP_DEALLOC,other._nb_of_elem); + useArray(pointer,true,C_DEALLOC,other._nb_of_elem); } } template - void MemArray::useArray(const T *array, bool ownership, DeallocType type, int nbOfElem) + void MemArray::useArray(const T *array, bool ownership, DeallocType type, std::size_t nbOfElem) { - _nb_of_elem=nbOfElem; destroy(); + _nb_of_elem=nbOfElem; + _nb_of_elem_alloc=nbOfElem; if(ownership) _pointer.setInternal(const_cast(array)); else _pointer.setExternal(array); _ownership=ownership; - _dealloc=type; + _dealloc=BuildFromType(type); + } + + template + void MemArray::useExternalArrayWithRWAccess(const T *array, std::size_t nbOfElem) + { + destroy(); + _nb_of_elem=nbOfElem; + _nb_of_elem_alloc=nbOfElem; + _pointer.setInternal(const_cast(array)); + _ownership=false; + _dealloc=CPPDeallocator; } template - void MemArray::writeOnPlace(int id, T element0, const T *others, int sizeOfOthers) + void MemArray::writeOnPlace(std::size_t id, T element0, const T *others, std::size_t sizeOfOthers) { - if(id+sizeOfOthers>=_nb_of_elem) - reAlloc(2*_nb_of_elem+sizeOfOthers+1); + if(id+sizeOfOthers>=_nb_of_elem_alloc) + reserve(2*_nb_of_elem+sizeOfOthers+1); T *pointer=_pointer.getPointer(); pointer[id]=element0; std::copy(others,others+sizeOfOthers,pointer+id+1); + _nb_of_elem=std::max(_nb_of_elem,id+sizeOfOthers+1); + } + + template + void MemArray::pushBack(T elem) + { + if(_nb_of_elem>=_nb_of_elem_alloc) + reserve(_nb_of_elem_alloc>0?2*_nb_of_elem_alloc:1); + T *pt=getPointer(); + pt[_nb_of_elem++]=elem; + } + + template + T MemArray::popBack() + { + if(_nb_of_elem>0) + { + const T *pt=getConstPointer(); + return pt[--_nb_of_elem]; + } + throw INTERP_KERNEL::Exception("MemArray::popBack : nothing to pop in array !"); + } + + template + void MemArray::pack() const + { + (const_cast * >(this))->reserve(_nb_of_elem); } template @@ -99,7 +146,7 @@ namespace ParaMEDMEM } if(pt1==pt2) return true; - for(int i=0;i<_nb_of_elem;i++) + for(std::size_t i=0;i<_nb_of_elem;i++) if(pt1[i]-pt2[i]<-prec || (pt1[i]-pt2[i])>prec) { oss << "The content of data differs at pos #" << i << " of coarse data ! this[i]=" << pt1[i] << " other[i]=" << pt2[i]; @@ -108,18 +155,19 @@ namespace ParaMEDMEM } return true; } - + /*! - * @param sl is typically the number of components [in parameter] + * \param [in] sl is typically the number of components + * \return True if a not null pointer is present, False if not. */ template - void MemArray::repr(int sl, std::ostream& stream) const + bool MemArray::reprHeader(int sl, std::ostream& stream) const { stream << "Number of tuples : "; if(!_pointer.isNull()) { if(sl!=0) - stream << _nb_of_elem/sl; + stream << _nb_of_elem/sl << std::endl << "Internal memory facts : " << _nb_of_elem << "/" << _nb_of_elem_alloc; else stream << "Empty Data"; } @@ -127,13 +175,25 @@ namespace ParaMEDMEM stream << "No data"; stream << "\n"; stream << "Data content :\n"; - const T *data=getConstPointer(); - if(!_pointer.isNull()) + bool ret=!_pointer.isNull(); + if(!ret) + stream << "No data !\n"; + return ret; + } + + /*! + * \param [in] sl is typically the number of components + */ + template + void MemArray::repr(int sl, std::ostream& stream) const + { + if(reprHeader(sl,stream)) { + const T *data=getConstPointer(); if(_nb_of_elem!=0 && sl!=0) { - int nbOfTuples=_nb_of_elem/sl; - for(int i=0;i(stream," ")); @@ -144,12 +204,10 @@ namespace ParaMEDMEM else stream << "Empty Data\n"; } - else - stream << "No data !\n"; } - + /*! - * @param sl is typically the number of components [in parameter] + * \param [in] sl is typically the number of components */ template void MemArray::reprZip(int sl, std::ostream& stream) const @@ -171,8 +229,8 @@ namespace ParaMEDMEM { if(_nb_of_elem!=0 && sl!=0) { - int nbOfTuples=_nb_of_elem/sl; - for(int i=0;i(stream," ")); @@ -187,36 +245,84 @@ namespace ParaMEDMEM else stream << "No data !\n"; } - + + /*! + * \param [in] sl is typically the number of components + */ + template + void MemArray::reprNotTooLong(int sl, std::ostream& stream) const + { + if(reprHeader(sl,stream)) + { + const T *data=getConstPointer(); + if(_nb_of_elem!=0 && sl!=0) + { + std::size_t nbOfTuples=_nb_of_elem/std::abs(sl); + if(nbOfTuples<=1000) + { + for(std::size_t i=0;i(stream," ")); + stream << "\n"; + data+=sl; + } + } + else + {// too much tuples -> print the 3 first tuples and 3 last. + stream << "Tuple #0 : "; + std::copy(data,data+sl,std::ostream_iterator(stream," ")); stream << "\n"; + stream << "Tuple #1 : "; + std::copy(data+sl,data+2*sl,std::ostream_iterator(stream," ")); stream << "\n"; + stream << "Tuple #2 : "; + std::copy(data+2*sl,data+3*sl,std::ostream_iterator(stream," ")); stream << "\n"; + stream << "...\n"; + stream << "Tuple #" << nbOfTuples-3 << " : "; + std::copy(data+(nbOfTuples-3)*sl,data+(nbOfTuples-2)*sl,std::ostream_iterator(stream," ")); stream << "\n"; + stream << "Tuple #" << nbOfTuples-2 << " : "; + std::copy(data+(nbOfTuples-2)*sl,data+(nbOfTuples-1)*sl,std::ostream_iterator(stream," ")); stream << "\n"; + stream << "Tuple #" << nbOfTuples-1 << " : "; + std::copy(data+(nbOfTuples-1)*sl,data+nbOfTuples*sl,std::ostream_iterator(stream," ")); stream << "\n"; + } + } + else + stream << "Empty Data\n"; + } + } + template void MemArray::fillWithValue(const T& val) { T *pt=_pointer.getPointer(); std::fill(pt,pt+_nb_of_elem,val); } - + template T *MemArray::fromNoInterlace(int nbOfComp) const { + if(nbOfComp<1) + throw INTERP_KERNEL::Exception("MemArray::fromNoInterlace : number of components must be > 0 !"); const T *pt=_pointer.getConstPointer(); - int nbOfTuples=_nb_of_elem/nbOfComp; - T *ret=new T[_nb_of_elem]; + std::size_t nbOfTuples=_nb_of_elem/nbOfComp; + T *ret=(T*)malloc(_nb_of_elem*sizeof(T)); T *w=ret; - for(int i=0;i T *MemArray::toNoInterlace(int nbOfComp) const { + if(nbOfComp<1) + throw INTERP_KERNEL::Exception("MemArray::toNoInterlace : number of components must be > 0 !"); const T *pt=_pointer.getConstPointer(); - int nbOfTuples=_nb_of_elem/nbOfComp; - T *ret=new T[_nb_of_elem]; + std::size_t nbOfTuples=_nb_of_elem/nbOfComp; + T *ret=(T*)malloc(_nb_of_elem*sizeof(T)); T *w=ret; for(int i=0;i - void MemArray::reverse() + void MemArray::reverse(int nbOfComp) { + if(nbOfComp<1) + throw INTERP_KERNEL::Exception("MemArray::reverse : only supported with 'this' array with ONE or more than ONE component !"); T *pt=_pointer.getPointer(); - std::reverse(pt,pt+_nb_of_elem); + if(nbOfComp==1) + { + std::reverse(pt,pt+_nb_of_elem); + return ; + } + else + { + T *pt2=pt+_nb_of_elem-nbOfComp; + std::size_t nbOfTuples=_nb_of_elem/nbOfComp; + for(std::size_t i=0;i - void MemArray::alloc(int nbOfElements) throw(INTERP_KERNEL::Exception) + void MemArray::alloc(std::size_t nbOfElements) { destroy(); - if(nbOfElements<0) - throw INTERP_KERNEL::Exception("MemArray::alloc : request for negative length of data !"); _nb_of_elem=nbOfElements; - _pointer.setInternal(new T[_nb_of_elem]); + _nb_of_elem_alloc=nbOfElements; + _pointer.setInternal((T*)malloc(_nb_of_elem_alloc*sizeof(T))); _ownership=true; - _dealloc=CPP_DEALLOC; + _dealloc=CDeallocator; } - + + /*! + * This method performs systematically an allocation of \a newNbOfElements elements in \a this. + * \a _nb_of_elem and \a _nb_of_elem_alloc will \b NOT be systematically equal (contrary to MemArray::reAlloc method. + * So after the call of this method \a _nb_of_elem will be equal tostd::min(_nb_of_elem,newNbOfElements) and \a _nb_of_elem_alloc equal to + * \a newNbOfElements. This method is typically used to perform a pushBack to avoid systematic allocations-copy-deallocation. + * So after the call of this method the accessible content is perfectly set. + * + * So this method should not be confused with MemArray::reserve that is close to MemArray::reAlloc but not same. + */ + template + void MemArray::reserve(std::size_t newNbOfElements) + { + if(_nb_of_elem_alloc==newNbOfElements) + return ; + T *pointer=(T*)malloc(newNbOfElements*sizeof(T)); + std::copy(_pointer.getConstPointer(),_pointer.getConstPointer()+std::min(_nb_of_elem,newNbOfElements),pointer); + if(_ownership) + DestroyPointer(const_cast(_pointer.getConstPointer()),_dealloc,_param_for_deallocator);//Do not use getPointer because in case of _external + _pointer.setInternal(pointer); + _nb_of_elem=std::min(_nb_of_elem,newNbOfElements); + _nb_of_elem_alloc=newNbOfElements; + _ownership=true; + _dealloc=CDeallocator; + _param_for_deallocator=0; + } + + /*! + * This method performs systematically an allocation of \a newNbOfElements elements in \a this. + * \a _nb_of_elem and \a _nb_of_elem_alloc will be equal even if only std::min(_nb_of_elem,newNbOfElements) come from the . + * The remaining part of the new allocated chunk are available but not set previously ! + * + * So this method should not be confused with MemArray::reserve that is close to MemArray::reAlloc but not same. + */ template - void MemArray::reAlloc(int newNbOfElements) throw(INTERP_KERNEL::Exception) + void MemArray::reAlloc(std::size_t newNbOfElements) { - if(newNbOfElements<0) - throw INTERP_KERNEL::Exception("MemArray::reAlloc : request for negative length of data !"); - T *pointer=new T[newNbOfElements]; - std::copy(_pointer.getConstPointer(),_pointer.getConstPointer()+std::min(_nb_of_elem,newNbOfElements),pointer); + if(_nb_of_elem==newNbOfElements) + return ; + T *pointer=(T*)malloc(newNbOfElements*sizeof(T)); + std::copy(_pointer.getConstPointer(),_pointer.getConstPointer()+std::min(_nb_of_elem,newNbOfElements),pointer); if(_ownership) - destroyPointer(const_cast(_pointer.getConstPointer()),_dealloc);//Do not use getPointer because in case of _external + DestroyPointer(const_cast(_pointer.getConstPointer()),_dealloc,_param_for_deallocator);//Do not use getPointer because in case of _external _pointer.setInternal(pointer); _nb_of_elem=newNbOfElements; + _nb_of_elem_alloc=newNbOfElements; _ownership=true; - _dealloc=CPP_DEALLOC; + _dealloc=CDeallocator; + _param_for_deallocator=0; + } + + template + void MemArray::CPPDeallocator(void *pt, void *param) + { + delete [] reinterpret_cast(pt); + } + + template + void MemArray::CDeallocator(void *pt, void *param) + { + free(pt); } template - void MemArray::destroyPointer(T *pt, DeallocType type) + typename MemArray::Deallocator MemArray::BuildFromType(DeallocType type) { switch(type) - { + { case CPP_DEALLOC: - { - delete [] pt; - return ; - } + return CPPDeallocator; case C_DEALLOC: - { - free(pt); - return ; - } + return CDeallocator; default: - std::ostringstream stream; - stream << "Invalid deallocation requested for pointer " << pt; - throw INTERP_KERNEL::Exception(stream.str().c_str()); - } + throw INTERP_KERNEL::Exception("Invalid deallocation requested ! Unrecognized enum DeallocType !"); + } + } + + template + void MemArray::DestroyPointer(T *pt, typename MemArray::Deallocator dealloc, void *param) + { + if(dealloc) + dealloc(pt,param); } template void MemArray::destroy() { if(_ownership) - destroyPointer(const_cast(_pointer.getConstPointer()),_dealloc);//Do not use getPointer because in case of _external + DestroyPointer(const_cast(_pointer.getConstPointer()),_dealloc,_param_for_deallocator);//Do not use getPointer because in case of _external _pointer.null(); _ownership=false; + _dealloc=NULL; + _param_for_deallocator=NULL; + _nb_of_elem=0; + _nb_of_elem_alloc=0; } - + template MemArray &MemArray::operator=(const MemArray& other) { @@ -307,6 +478,3286 @@ namespace ParaMEDMEM std::copy(other._pointer.getConstPointer(),other._pointer.getConstPointer()+_nb_of_elem,_pointer.getPointer()); return *this; } + + ////////////////////////////////// + + template + DataArrayIterator::DataArrayIterator(typename Traits::ArrayType *da):_da(da),_tuple_id(0),_nb_comp(0),_nb_tuple(0) + { + if(_da) + { + _da->incrRef(); + if(_da->isAllocated()) + { + _nb_comp=da->getNumberOfComponents(); + _nb_tuple=da->getNumberOfTuples(); + _pt=da->getPointer(); + } + } + } + + template + DataArrayIterator::~DataArrayIterator() + { + if(_da) + _da->decrRef(); + } + + template + typename Traits::ArrayTuple *DataArrayIterator::nextt() + { + if(_tuple_id<_nb_tuple) + { + _tuple_id++; + typename Traits::ArrayTuple *ret=new typename Traits::ArrayTuple(_pt,_nb_comp); + _pt+=_nb_comp; + return ret; + } + else + return 0; + } + + ////////////////////////////////// + + template + DataArrayTuple::DataArrayTuple(T *pt, int nbOfComp):_pt(pt),_nb_of_compo(nbOfComp) + { + } + + template + T DataArrayTuple::zeValue() const + { + if(_nb_of_compo==1) + return *_pt; + throw INTERP_KERNEL::Exception("DataArrayTuple::zeValue : DataArrayTuple instance has not exactly 1 component -> Not possible to convert it into a single value !"); + } + + template + typename Traits::ArrayType *DataArrayTuple::buildDA(int nbOfTuples, int nbOfCompo) const + { + if((_nb_of_compo==nbOfCompo && nbOfTuples==1) || (_nb_of_compo==nbOfTuples && nbOfCompo==1)) + { + typename Traits::ArrayType *ret=Traits::ArrayType::New(); + ret->useExternalArrayWithRWAccess(_pt,nbOfTuples,nbOfCompo); + return ret; + } + else + { + std::ostringstream oss; oss << "DataArrayTuple::buildDA : unable to build a requested DataArrayDouble instance with nbofTuple=" << nbOfTuples << " and nbOfCompo=" << nbOfCompo; + oss << ".\nBecause the number of elements in this is " << _nb_of_compo << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + + ////////////////////////////////// + + template + MCAuto< typename Traits::ArrayTypeCh > DataArrayTemplate::NewFromStdVector(const typename std::vector& v) + { + std::size_t sz(v.size()); + MCAuto< typename Traits::ArrayTypeCh > ret(Traits::ArrayTypeCh::New()); + ret->alloc(sz,1); + T *pt(ret->getPointer()); + std::copy(v.begin(),v.end(),pt); + return ret; + } + + template + std::vector< MCAuto< typename Traits::ArrayTypeCh > > DataArrayTemplate::explodeComponents() const + { + checkAllocated(); + std::size_t sz(getNumberOfComponents()); + int nbTuples(getNumberOfTuples()); + std::string name(getName()); + std::vector compNames(getInfoOnComponents()); + std::vector< MCAuto< typename Traits::ArrayTypeCh > > ret(sz); + const T *thisPt(begin()); + for(std::size_t i=0;i::ArrayTypeCh > part(Traits::ArrayTypeCh::New()); + part->alloc(nbTuples,1); + part->setName(name); + part->setInfoOnComponent(0,compNames[i]); + T *otherPt(part->getPointer()); + for(int j=0;j + std::size_t DataArrayTemplate::getHeapMemorySizeWithoutChildren() const + { + std::size_t sz(_mem.getNbOfElemAllocated()); + sz*=sizeof(T); + return DataArray::getHeapMemorySizeWithoutChildren()+sz; + } + + /*! + * Allocates the raw data in memory. If the memory was already allocated, then it is + * freed and re-allocated. See an example of this method use + * \ref MEDCouplingArraySteps1WC "here". + * \param [in] nbOfTuple - number of tuples of data to allocate. + * \param [in] nbOfCompo - number of components of data to allocate. + * \throw If \a nbOfTuple < 0 or \a nbOfCompo < 0. + */ + template + void DataArrayTemplate::alloc(std::size_t nbOfTuple, std::size_t nbOfCompo) + { + _info_on_compo.resize(nbOfCompo); + _mem.alloc(nbOfCompo*nbOfTuple); + declareAsNew(); + } + + /*! + * Sets a C array to be used as raw data of \a this. The previously set info + * of components is retained and re-sized. + * For more info see \ref MEDCouplingArraySteps1. + * \param [in] array - the C array to be used as raw data of \a this. + * \param [in] ownership - if \a true, \a array will be deallocated at destruction of \a this. + * \param [in] type - specifies how to deallocate \a array. If \a type == MEDCoupling::CPP_DEALLOC, + * \c delete [] \c array; will be called. If \a type == MEDCoupling::C_DEALLOC, + * \c free(\c array ) will be called. + * \param [in] nbOfTuple - new number of tuples in \a this. + * \param [in] nbOfCompo - new number of components in \a this. + */ + template + void DataArrayTemplate::useArray(const T *array, bool ownership, DeallocType type, int nbOfTuple, int nbOfCompo) + { + _info_on_compo.resize(nbOfCompo); + _mem.useArray(array,ownership,type,(std::size_t)nbOfTuple*nbOfCompo); + declareAsNew(); + } + + template + void DataArrayTemplate::useExternalArrayWithRWAccess(const T *array, int nbOfTuple, int nbOfCompo) + { + _info_on_compo.resize(nbOfCompo); + _mem.useExternalArrayWithRWAccess(array,(std::size_t)nbOfTuple*nbOfCompo); + declareAsNew(); + } + + /*! + * Returns a value located at specified tuple and component. + * This method is equivalent to DataArrayTemplate::getIJ() except that validity of + * parameters is checked. So this method is safe but expensive if used to go through + * all values of \a this. + * \param [in] tupleId - index of tuple of interest. + * \param [in] compoId - index of component of interest. + * \return double - value located by \a tupleId and \a compoId. + * \throw If \a this is not allocated. + * \throw If condition ( 0 <= tupleId < this->getNumberOfTuples() ) is violated. + * \throw If condition ( 0 <= compoId < this->getNumberOfComponents() ) is violated. + */ + template + T DataArrayTemplate::getIJSafe(int tupleId, int compoId) const + { + checkAllocated(); + if(tupleId<0 || tupleId>=getNumberOfTuples()) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::getIJSafe : request for tupleId " << tupleId << " should be in [0," << getNumberOfTuples() << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + if(compoId<0 || compoId>=(int)getNumberOfComponents()) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::getIJSafe : request for compoId " << compoId << " should be in [0," << getNumberOfComponents() << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + return _mem[tupleId*_info_on_compo.size()+compoId]; + } + + /*! + * This method \b do \b not modify content of \a this. It only modify its memory footprint if the allocated memory is to high regarding real data to store. + * + * \sa DataArray::getHeapMemorySizeWithoutChildren, DataArrayTemplate::reserve + */ + template + void DataArrayTemplate::pack() const + { + _mem.pack(); + } + + /*! + * Checks if raw data is allocated. Read more on the raw data + * in \ref MEDCouplingArrayBasicsTuplesAndCompo "DataArrays infos" for more information. + * \return bool - \a true if the raw data is allocated, \a false else. + */ + template + bool DataArrayTemplate::isAllocated() const + { + return getConstPointer()!=0; + } + + /*! + * Checks if raw data is allocated and throws an exception if it is not the case. + * \throw If the raw data is not allocated. + */ + template + void DataArrayTemplate::checkAllocated() const + { + if(!isAllocated()) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::checkAllocated : Array is defined but not allocated ! Call alloc or setValues method first !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + + /*! + * This method deallocated \a this without modification of information relative to the components. + * After call of this method, DataArrayDouble::isAllocated will return false. + * If \a this is already not allocated, \a this is let unchanged. + */ + template + void DataArrayTemplate::desallocate() + { + _mem.destroy(); + } + + /*! + * This method reserve nbOfElems elements in memory ( nbOfElems*8 bytes ) \b without impacting the number of tuples in \a this. + * If \a this has already been allocated, this method checks that \a this has only one component. If not an INTERP_KERNEL::Exception will be thrown. + * If \a this has not already been allocated, number of components is set to one. + * This method allows to reduce number of reallocations on invocation of DataArrayDouble::pushBackSilent and DataArrayDouble::pushBackValsSilent on \a this. + * + * \sa DataArrayDouble::pack, DataArrayDouble::pushBackSilent, DataArrayDouble::pushBackValsSilent + */ + template + void DataArrayTemplate::reserve(std::size_t nbOfElems) + { + int nbCompo(getNumberOfComponents()); + if(nbCompo==1) + { + _mem.reserve(nbOfElems); + } + else if(nbCompo==0) + { + _mem.reserve(nbOfElems); + _info_on_compo.resize(1); + } + else + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::reserve : not available for DataArrayDouble with number of components different than 1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + + /*! + * This method adds at the end of \a this the single value \a val. This method do \b not update its time label to avoid useless incrementation + * of counter. So the caller is expected to call TimeLabel::declareAsNew on \a this at the end of the push session. + * + * \param [in] val the value to be added in \a this + * \throw If \a this has already been allocated with number of components different from one. + * \sa DataArrayDouble::pushBackValsSilent + */ + template + void DataArrayTemplate::pushBackSilent(T val) + { + int nbCompo(getNumberOfComponents()); + if(nbCompo==1) + _mem.pushBack(val); + else if(nbCompo==0) + { + _info_on_compo.resize(1); + _mem.pushBack(val); + } + else + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::pushBackSilent : not available for DataArrayDouble with number of components different than 1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + + /*! + * This method adds at the end of \a this a series of values [\c valsBg,\c valsEnd). This method do \b not update its time label to avoid useless incrementation + * of counter. So the caller is expected to call TimeLabel::declareAsNew on \a this at the end of the push session. + * + * \param [in] valsBg - an array of values to push at the end of \c this. + * \param [in] valsEnd - specifies the end of the array \a valsBg, so that + * the last value of \a valsBg is \a valsEnd[ -1 ]. + * \throw If \a this has already been allocated with number of components different from one. + * \sa DataArrayDouble::pushBackSilent + */ + template + void DataArrayTemplate::pushBackValsSilent(const T *valsBg, const T *valsEnd) + { + int nbCompo(getNumberOfComponents()); + if(nbCompo==1) + _mem.insertAtTheEnd(valsBg,valsEnd); + else if(nbCompo==0) + { + _info_on_compo.resize(1); + _mem.insertAtTheEnd(valsBg,valsEnd); + } + else + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::pushBackValsSilent : not available for DataArrayDouble with number of components different than 1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + + /*! + * This method returns silently ( without updating time label in \a this ) the last value, if any and suppress it. + * \throw If \a this is already empty. + * \throw If \a this has number of components different from one. + */ + template + T DataArrayTemplate::popBackSilent() + { + if(getNumberOfComponents()==1) + return _mem.popBack(); + else + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::popBackSilent : not available for DataArrayDouble with number of components different than 1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + + /*! + * Allocates the raw data in memory. If exactly same memory as needed already + * allocated, it is not re-allocated. + * \param [in] nbOfTuple - number of tuples of data to allocate. + * \param [in] nbOfCompo - number of components of data to allocate. + * \throw If \a nbOfTuple < 0 or \a nbOfCompo < 0. + */ + template + void DataArrayTemplate::allocIfNecessary(int nbOfTuple, int nbOfCompo) + { + if(isAllocated()) + { + if(nbOfTuple!=getNumberOfTuples() || nbOfCompo!=(int)getNumberOfComponents()) + alloc(nbOfTuple,nbOfCompo); + } + else + alloc(nbOfTuple,nbOfCompo); + } + + /*! + * Checks the number of tuples. + * \return bool - \a true if getNumberOfTuples() == 0, \a false else. + * \throw If \a this is not allocated. + */ + template + bool DataArrayTemplate::empty() const + { + checkAllocated(); + return getNumberOfTuples()==0; + } + + /*! + * Copies all the data from another DataArrayDouble. For more info see + * \ref MEDCouplingArrayBasicsCopyDeepAssign. + * \param [in] other - another instance of DataArrayDouble to copy data from. + * \throw If the \a other is not allocated. + */ + template + void DataArrayTemplate::deepCopyFrom(const DataArrayTemplate& other) + { + other.checkAllocated(); + int nbOfTuples(other.getNumberOfTuples()),nbOfComp(other.getNumberOfComponents()); + allocIfNecessary(nbOfTuples,nbOfComp); + std::size_t nbOfElems((std::size_t)nbOfTuples*nbOfComp); + T *pt(getPointer()); + const T *ptI(other.begin()); + for(std::size_t i=0;igetNumberOfComponents() < 1. + * \throw If \a this is not allocated. + */ + template + void DataArrayTemplate::reverse() + { + checkAllocated(); + _mem.reverse(getNumberOfComponents()); + declareAsNew(); + } + + /*! + * Assign \a val to all values in \a this array. To know more on filling arrays see + * \ref MEDCouplingArrayFill. + * \param [in] val - the value to fill with. + * \throw If \a this is not allocated. + */ + template + void DataArrayTemplate::fillWithValue(T val) + { + checkAllocated(); + _mem.fillWithValue(val); + declareAsNew(); + } + + /*! + * Changes number of tuples in the array. If the new number of tuples is smaller + * than the current number the array is truncated, otherwise the array is extended. + * \param [in] nbOfTuples - new number of tuples. + * \throw If \a this is not allocated. + * \throw If \a nbOfTuples is negative. + */ + template + void DataArrayTemplate::reAlloc(std::size_t nbOfTuples) + { + checkAllocated(); + _mem.reAlloc(getNumberOfComponents()*nbOfTuples); + declareAsNew(); + } + + /*! + * Permutes values of \a this array as required by \a old2New array. The values are + * permuted so that \c new[ \a old2New[ i ]] = \c old[ i ]. Number of tuples remains + * the same as in \c this one. + * If a permutation reduction is needed, subArray() or selectByTupleId() should be used. + * For more info on renumbering see \ref numbering. + * \param [in] old2New - C array of length equal to \a this->getNumberOfTuples() + * giving a new position for i-th old value. + */ + template + void DataArrayTemplate::renumberInPlace(const int *old2New) + { + checkAllocated(); + int nbTuples(getNumberOfTuples()),nbOfCompo(getNumberOfComponents()); + T *tmp(new T[nbTuples*nbOfCompo]); + const T *iptr(begin()); + for(int i=0;i=0 && v::ArrayTypeName << "::renumberInPlace : At place #" << i << " value is " << v << " ! Should be in [0," << nbTuples << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + std::copy(tmp,tmp+nbTuples*nbOfCompo,getPointer()); + delete [] tmp; + declareAsNew(); + } + + + /*! + * Permutes values of \a this array as required by \a new2Old array. The values are + * permuted so that \c new[ i ] = \c old[ \a new2Old[ i ]]. Number of tuples remains + * the same as in \c this one. + * For more info on renumbering see \ref numbering. + * \param [in] new2Old - C array of length equal to \a this->getNumberOfTuples() + * giving a previous position of i-th new value. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + */ + template + void DataArrayTemplate::renumberInPlaceR(const int *new2Old) + { + checkAllocated(); + int nbTuples(getNumberOfTuples()),nbOfCompo(getNumberOfComponents()); + T *tmp(new T[nbTuples*nbOfCompo]); + const T *iptr(begin()); + for(int i=0;i=0 && v::ArrayTypeName << "::renumberInPlaceR : At place #" << i << " value is " << v << " ! Should be in [0," << nbTuples << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + std::copy(tmp,tmp+nbTuples*nbOfCompo,getPointer()); + delete [] tmp; + declareAsNew(); + } + + /*! + * Sorts values of the array. + * \param [in] asc - \a true means ascending order, \a false, descending. + * \throw If \a this is not allocated. + * \throw If \a this->getNumberOfComponents() != 1. + */ + template + void DataArrayTemplate::sort(bool asc) + { + checkAllocated(); + if(getNumberOfComponents()!=1) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::sort : only supported with 'this' array with ONE component !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + _mem.sort(asc); + declareAsNew(); + } + + /*! + * Returns a copy of \a this array with values permuted as required by \a old2New array. + * The values are permuted so that \c new[ \a old2New[ i ]] = \c old[ i ]. + * Number of tuples in the result array remains the same as in \c this one. + * If a permutation reduction is needed, renumberAndReduce() should be used. + * For more info on renumbering see \ref numbering. + * \param [in] old2New - C array of length equal to \a this->getNumberOfTuples() + * giving a new position for i-th old value. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplate::renumber(const int *old2New) const + { + checkAllocated(); + int nbTuples(getNumberOfTuples()),nbOfCompo(getNumberOfComponents()); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(nbTuples,nbOfCompo); + ret->copyStringInfoFrom(*this); + const T *iptr(begin()); + T *optr(ret->getPointer()); + for(int i=0;icopyStringInfoFrom(*this); + return ret.retn(); + } + + /*! + * Returns a copy of \a this array with values permuted as required by \a new2Old array. + * The values are permuted so that \c new[ i ] = \c old[ \a new2Old[ i ]]. Number of + * tuples in the result array remains the same as in \c this one. + * If a permutation reduction is needed, subArray() or selectByTupleId() should be used. + * For more info on renumbering see \ref numbering. + * \param [in] new2Old - C array of length equal to \a this->getNumberOfTuples() + * giving a previous position of i-th new value. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + */ + template + typename Traits::ArrayType *DataArrayTemplate::renumberR(const int *new2Old) const + { + checkAllocated(); + int nbTuples(getNumberOfTuples()),nbOfCompo(getNumberOfComponents()); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(nbTuples,nbOfCompo); + ret->copyStringInfoFrom(*this); + const T *iptr(getConstPointer()); + T *optr(ret->getPointer()); + for(int i=0;icopyStringInfoFrom(*this); + return ret.retn(); + } + + /*! + * Returns a shorten and permuted copy of \a this array. The new DataArrayDouble is + * of size \a newNbOfTuple and it's values are permuted as required by \a old2New array. + * The values are permuted so that \c new[ \a old2New[ i ]] = \c old[ i ] for all + * \a old2New[ i ] >= 0. In other words every i-th tuple in \a this array, for which + * \a old2New[ i ] is negative, is missing from the result array. + * For more info on renumbering see \ref numbering. + * \param [in] old2New - C array of length equal to \a this->getNumberOfTuples() + * giving a new position for i-th old tuple and giving negative position for + * for i-th old tuple that should be omitted. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + */ + template + typename Traits::ArrayType *DataArrayTemplate::renumberAndReduce(const int *old2New, int newNbOfTuple) const + { + checkAllocated(); + int nbTuples(getNumberOfTuples()),nbOfCompo(getNumberOfComponents()); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(newNbOfTuple,nbOfCompo); + const T *iptr=getConstPointer(); + T *optr=ret->getPointer(); + for(int i=0;i=0) + std::copy(iptr+i*nbOfCompo,iptr+(i+1)*nbOfCompo,optr+w*nbOfCompo); + } + ret->copyStringInfoFrom(*this); + return ret.retn(); + } + + /*! + * Returns a shorten and permuted copy of \a this array. The new DataArrayDouble is + * of size \a new2OldEnd - \a new2OldBg and it's values are permuted as required by + * \a new2OldBg array. + * The values are permuted so that \c new[ i ] = \c old[ \a new2OldBg[ i ]]. + * This method is equivalent to renumberAndReduce() except that convention in input is + * \c new2old and \b not \c old2new. + * For more info on renumbering see \ref numbering. + * \param [in] new2OldBg - pointer to the beginning of a permutation array that gives a + * tuple index in \a this array to fill the i-th tuple in the new array. + * \param [in] new2OldEnd - specifies the end of the permutation array that starts at + * \a new2OldBg, so that pointer to a tuple index (\a pi) varies as this: + * \a new2OldBg <= \a pi < \a new2OldEnd. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + */ + template + typename Traits::ArrayType *DataArrayTemplate::mySelectByTupleId(const int *new2OldBg, const int *new2OldEnd) const + { + checkAllocated(); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + int nbComp(getNumberOfComponents()); + ret->alloc((int)std::distance(new2OldBg,new2OldEnd),nbComp); + ret->copyStringInfoFrom(*this); + T *pt(ret->getPointer()); + const T *srcPt(getConstPointer()); + int i(0); + for(const int *w=new2OldBg;w!=new2OldEnd;w++,i++) + std::copy(srcPt+(*w)*nbComp,srcPt+((*w)+1)*nbComp,pt+i*nbComp); + ret->copyStringInfoFrom(*this); + return ret.retn(); + } + + template + typename Traits::ArrayType *DataArrayTemplate::mySelectByTupleId(const DataArrayInt& di) const + { + return DataArrayTemplate::mySelectByTupleId(di.begin(),di.end()); + } + + template + MCAuto::ArrayTypeCh> DataArrayTemplate::selectPartDef(const PartDefinition *pd) const + { + if(!pd) + throw INTERP_KERNEL::Exception("DataArrayTemplate::selectPartDef : null input pointer !"); + MCAuto::ArrayTypeCh> ret(Traits::ArrayTypeCh::New()); + const SlicePartDefinition *spd(dynamic_cast(pd)); + if(spd) + { + int a,b,c; + spd->getSlice(a,b,c); + if(a==0 && b==(int)getNumberOfTuples() && c==1) + { + DataArrayTemplate *directRet(const_cast *>(this)); + directRet->incrRef(); + MCAuto > ret2(directRet); + return DynamicCastSafe,typename Traits::ArrayTypeCh>(ret2); + } + else + { + MCAuto ret2(selectByTupleIdSafeSlice(a,b,c)); + return DynamicCastSafe::ArrayTypeCh>(ret2); + } + } + const DataArrayPartDefinition *dpd(dynamic_cast(pd)); + if(dpd) + { + MCAuto arr(dpd->toDAI()); + MCAuto ret2(selectByTupleIdSafe(arr->begin(),arr->end())); + return DynamicCastSafe::ArrayTypeCh>(ret2); + + } + throw INTERP_KERNEL::Exception("DataArrayTemplate::selectPartDef : unrecognized part def !"); + } + + /*! + * Returns a shorten and permuted copy of \a this array. The new DataArrayDouble is + * of size \a new2OldEnd - \a new2OldBg and it's values are permuted as required by + * \a new2OldBg array. + * The values are permuted so that \c new[ i ] = \c old[ \a new2OldBg[ i ]]. + * This method is equivalent to renumberAndReduce() except that convention in input is + * \c new2old and \b not \c old2new. + * This method is equivalent to selectByTupleId() except that it prevents coping data + * from behind the end of \a this array. + * For more info on renumbering see \ref numbering. + * \param [in] new2OldBg - pointer to the beginning of a permutation array that gives a + * tuple index in \a this array to fill the i-th tuple in the new array. + * \param [in] new2OldEnd - specifies the end of the permutation array that starts at + * \a new2OldBg, so that pointer to a tuple index (\a pi) varies as this: + * \a new2OldBg <= \a pi < \a new2OldEnd. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \throw If \a new2OldEnd - \a new2OldBg > \a this->getNumberOfTuples(). + */ + template + typename Traits::ArrayType *DataArrayTemplate::mySelectByTupleIdSafe(const int *new2OldBg, const int *new2OldEnd) const + { + checkAllocated(); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + int nbComp(getNumberOfComponents()),oldNbOfTuples(getNumberOfTuples()); + ret->alloc((int)std::distance(new2OldBg,new2OldEnd),nbComp); + ret->copyStringInfoFrom(*this); + T *pt(ret->getPointer()); + const T *srcPt(getConstPointer()); + int i(0); + for(const int *w=new2OldBg;w!=new2OldEnd;w++,i++) + if(*w>=0 && *w::ArrayTypeName << "::selectByTupleIdSafe : some ids has been detected to be out of [0,this->getNumberOfTuples) !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + ret->copyStringInfoFrom(*this); + return ret.retn(); + } + + /*! + * Changes the number of components within \a this array so that its raw data **does + * not** change, instead splitting this data into tuples changes. + * \warning This method erases all (name and unit) component info set before! + * \param [in] newNbOfComp - number of components for \a this array to have. + * \throw If \a this is not allocated + * \throw If getNbOfElems() % \a newNbOfCompo != 0. + * \throw If \a newNbOfCompo is lower than 1. + * \throw If the rearrange method would lead to a number of tuples higher than 2147483647 (maximal capacity of int32 !). + * \warning This method erases all (name and unit) component info set before! + */ + template + void DataArrayTemplate::rearrange(int newNbOfCompo) + { + checkAllocated(); + if(newNbOfCompo<1) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::rearrange : input newNbOfCompo must be > 0 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + std::size_t nbOfElems=getNbOfElems(); + if(nbOfElems%newNbOfCompo!=0) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::rearrange : nbOfElems%newNbOfCompo!=0 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + if(nbOfElems/newNbOfCompo>(std::size_t)std::numeric_limits::max()) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::rearrange : the rearrangement leads to too high number of tuples (> 2147483647) !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + _info_on_compo.clear(); + _info_on_compo.resize(newNbOfCompo); + declareAsNew(); + } + + /*! + * Changes the number of components within \a this array to be equal to its number + * of tuples, and inversely its number of tuples to become equal to its number of + * components. So that its raw data **does not** change, instead splitting this + * data into tuples changes. + * \warning This method erases all (name and unit) component info set before! + * \warning Do not confuse this method with fromNoInterlace() and toNoInterlace()! + * \throw If \a this is not allocated. + * \sa rearrange() + */ + template + void DataArrayTemplate::transpose() + { + checkAllocated(); + int nbOfTuples(getNumberOfTuples()); + rearrange(nbOfTuples); + } + + /*! + * Returns a shorten or extended copy of \a this array. If \a newNbOfComp is less + * than \a this->getNumberOfComponents() then the result array is shorten as each tuple + * is truncated to have \a newNbOfComp components, keeping first components. If \a + * newNbOfComp is more than \a this->getNumberOfComponents() then the result array is + * expanded as each tuple is populated with \a dftValue to have \a newNbOfComp + * components. + * \param [in] newNbOfComp - number of components for the new array to have. + * \param [in] dftValue - value assigned to new values added to the new array. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplate::changeNbOfComponents(int newNbOfComp, T dftValue) const + { + checkAllocated(); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(getNumberOfTuples(),newNbOfComp); + const T *oldc(getConstPointer()); + T *nc(ret->getPointer()); + int nbOfTuples(getNumberOfTuples()),oldNbOfComp(getNumberOfComponents()); + int dim(std::min(oldNbOfComp,newNbOfComp)); + for(int i=0;isetName(getName()); + for(int i=0;isetInfoOnComponent(i,getInfoOnComponent(i)); + ret->setName(getName()); + return ret.retn(); + } + + /*! + * Returns a copy of \a this array composed of selected components. + * The new DataArrayDouble has the same number of tuples but includes components + * specified by \a compoIds parameter. So that getNbOfElems() of the result array + * can be either less, same or more than \a this->getNbOfElems(). + * \param [in] compoIds - sequence of zero based indices of components to include + * into the new array. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \throw If \a this is not allocated. + * \throw If a component index (\a i) is not valid: + * \a i < 0 || \a i >= \a this->getNumberOfComponents(). + * + * \if ENABLE_EXAMPLES + * \ref py_mcdataarraydouble_KeepSelectedComponents "Here is a Python example". + * \endif + */ + template + typename Traits::ArrayType *DataArrayTemplate::myKeepSelectedComponents(const std::vector& compoIds) const + { + checkAllocated(); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + std::size_t newNbOfCompo(compoIds.size()); + int oldNbOfCompo(getNumberOfComponents()); + for(std::vector::const_iterator it=compoIds.begin();it!=compoIds.end();it++) + if((*it)<0 || (*it)>=oldNbOfCompo) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::keepSelectedComponents : invalid requested component : " << *it << " whereas it should be in [0," << oldNbOfCompo << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int nbOfTuples(getNumberOfTuples()); + ret->alloc(nbOfTuples,(int)newNbOfCompo); + ret->copyPartOfStringInfoFrom(*this,compoIds); + const T *oldc(getConstPointer()); + T *nc(ret->getPointer()); + for(int i=0;i \a this->getNumberOfTuples(). + * \throw If \a tupleIdEnd != -1 && \a tupleIdEnd < \a this->getNumberOfTuples(). + * \sa DataArrayDouble::selectByTupleIdSafeSlice + */ + template + typename Traits::ArrayType *DataArrayTemplate::subArray(int tupleIdBg, int tupleIdEnd) const + { + checkAllocated(); + int nbt(getNumberOfTuples()); + if(tupleIdBg<0) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::subArray : The tupleIdBg parameter must be greater than 0 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + if(tupleIdBg>nbt) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << ":subArray : The tupleIdBg parameter is greater than number of tuples !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + int trueEnd=tupleIdEnd; + if(tupleIdEnd!=-1) + { + if(tupleIdEnd>nbt) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << ":subArray : The tupleIdBg parameter is greater than number of tuples !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + trueEnd=nbt; + int nbComp(getNumberOfComponents()); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(trueEnd-tupleIdBg,nbComp); + ret->copyStringInfoFrom(*this); + std::copy(getConstPointer()+tupleIdBg*nbComp,getConstPointer()+trueEnd*nbComp,ret->getPointer()); + return ret.retn(); + } + + /*! + * Returns a shorten copy of \a this array. The new DataArrayDouble contains every + * (\a bg + \c i * \a step)-th tuple of \a this array located before the \a end2-th + * tuple. Indices of the selected tuples are the same as ones returned by the Python + * command \c range( \a bg, \a end2, \a step ). + * This method is equivalent to selectByTupleIdSafe() except that the input array is + * not constructed explicitly. + * For more info on renumbering see \ref numbering. + * \param [in] bg - index of the first tuple to copy from \a this array. + * \param [in] end2 - index of the tuple before which the tuples to copy are located. + * \param [in] step - index increment to get index of the next tuple to copy. + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \sa DataArrayDouble::subArray. + */ + template + typename Traits::ArrayType *DataArrayTemplate::mySelectByTupleIdSafeSlice(int bg, int end2, int step) const + { + checkAllocated(); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + int nbComp(getNumberOfComponents()); + std::ostringstream oss; oss << Traits::ArrayTypeName << "::selectByTupleIdSafeSlice : "; + int newNbOfTuples(GetNumberOfItemGivenBESRelative(bg,end2,step,oss.str())); + ret->alloc(newNbOfTuples,nbComp); + T *pt(ret->getPointer()); + const T *srcPt(getConstPointer()+bg*nbComp); + for(int i=0;icopyStringInfoFrom(*this); + return ret.retn(); + } + + /*! + * Copy all values from another DataArrayDouble into specified tuples and components + * of \a this array. Textual data is not copied. + * The tree parameters defining set of indices of tuples and components are similar to + * the tree parameters of the Python function \c range(\c start,\c stop,\c step). + * \param [in] a - the array to copy values from. + * \param [in] bgTuples - index of the first tuple of \a this array to assign values to. + * \param [in] endTuples - index of the tuple before which the tuples to assign to + * are located. + * \param [in] stepTuples - index increment to get index of the next tuple to assign to. + * \param [in] bgComp - index of the first component of \a this array to assign values to. + * \param [in] endComp - index of the component before which the components to assign + * to are located. + * \param [in] stepComp - index increment to get index of the next component to assign to. + * \param [in] strictCompoCompare - if \a true (by default), then \a a->getNumberOfComponents() + * must be equal to the number of columns to assign to, else an + * exception is thrown; if \a false, then it is only required that \a + * a->getNbOfElems() equals to number of values to assign to (this condition + * must be respected even if \a strictCompoCompare is \a true). The number of + * values to assign to is given by following Python expression: + * \a nbTargetValues = + * \c len(\c range(\a bgTuples,\a endTuples,\a stepTuples)) * + * \c len(\c range(\a bgComp,\a endComp,\a stepComp)). + * \throw If \a a is NULL. + * \throw If \a a is not allocated. + * \throw If \a this is not allocated. + * \throw If parameters specifying tuples and components to assign to do not give a + * non-empty range of increasing indices. + * \throw If \a a->getNbOfElems() != \a nbTargetValues. + * \throw If \a strictCompoCompare == \a true && \a a->getNumberOfComponents() != + * \c len(\c range(\a bgComp,\a endComp,\a stepComp)). + * + * \if ENABLE_EXAMPLES + * \ref py_mcdataarraydouble_setpartofvalues1 "Here is a Python example". + * \endif + */ + template + void DataArrayTemplate::setPartOfValues1(const typename Traits::ArrayType *a, int bgTuples, int endTuples, int stepTuples, int bgComp, int endComp, int stepComp, bool strictCompoCompare) + { + if(!a) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::setPartOfValues1 : input DataArrayDouble is NULL !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + const char msg[]="DataArrayTemplate::setPartOfValues1"; + checkAllocated(); + a->checkAllocated(); + int newNbOfTuples(DataArray::GetNumberOfItemGivenBES(bgTuples,endTuples,stepTuples,msg)); + int newNbOfComp(DataArray::GetNumberOfItemGivenBES(bgComp,endComp,stepComp,msg)); + int nbComp(getNumberOfComponents()),nbOfTuples(getNumberOfTuples()); + DataArray::CheckValueInRangeEx(nbOfTuples,bgTuples,endTuples,"invalid tuple value"); + DataArray::CheckValueInRangeEx(nbComp,bgComp,endComp,"invalid component value"); + bool assignTech(true); + if(a->getNbOfElems()==(std::size_t)newNbOfTuples*newNbOfComp) + { + if(strictCompoCompare) + a->checkNbOfTuplesAndComp(newNbOfTuples,newNbOfComp,msg); + } + else + { + a->checkNbOfTuplesAndComp(1,newNbOfComp,msg); + assignTech=false; + } + const T *srcPt(a->getConstPointer()); + T *pt(getPointer()+bgTuples*nbComp+bgComp); + if(assignTech) + { + for(int i=0;i + void DataArrayTemplate::setPartOfValuesSimple1(T a, int bgTuples, int endTuples, int stepTuples, int bgComp, int endComp, int stepComp) + { + const char msg[]="DataArrayTemplate::setPartOfValuesSimple1"; + checkAllocated(); + int newNbOfTuples(DataArray::GetNumberOfItemGivenBES(bgTuples,endTuples,stepTuples,msg)); + int newNbOfComp(DataArray::GetNumberOfItemGivenBES(bgComp,endComp,stepComp,msg)); + int nbComp(getNumberOfComponents()),nbOfTuples(getNumberOfTuples()); + DataArray::CheckValueInRangeEx(nbOfTuples,bgTuples,endTuples,"invalid tuple value"); + DataArray::CheckValueInRangeEx(nbComp,bgComp,endComp,"invalid component value"); + T *pt=getPointer()+bgTuples*nbComp+bgComp; + for(int i=0;igetNbOfElems() equals to number of values to assign to, then every value + * of \a a is assigned to its own location within \a this array. + * - If \a a includes one tuple, then all values of \a a are assigned to the specified + * components of every specified tuple of \a this array. In this mode it is required + * that \a a->getNumberOfComponents() equals to the number of specified components. + * + * \param [in] a - the array to copy values from. + * \param [in] bgTuples - pointer to an array of tuple indices of \a this array to + * assign values of \a a to. + * \param [in] endTuples - specifies the end of the array \a bgTuples, so that + * pointer to a tuple index (pi) varies as this: + * \a bgTuples <= \a pi < \a endTuples. + * \param [in] bgComp - pointer to an array of component indices of \a this array to + * assign values of \a a to. + * \param [in] endComp - specifies the end of the array \a bgTuples, so that + * pointer to a component index (pi) varies as this: + * \a bgComp <= \a pi < \a endComp. + * \param [in] strictCompoCompare - this parameter is checked only if the + * *mode of usage* is the first; if it is \a true (default), + * then \a a->getNumberOfComponents() must be equal + * to the number of specified columns, else this is not required. + * \throw If \a a is NULL. + * \throw If \a a is not allocated. + * \throw If \a this is not allocated. + * \throw If any index of tuple/component given by bgTuples / bgComp is + * out of a valid range for \a this array. + * \throw In the first *mode of usage*, if strictCompoCompare == true and + * if a->getNumberOfComponents() != (endComp - bgComp) . + * \throw In the second *mode of usage*, if \a a->getNumberOfTuples() != 1 or + * a->getNumberOfComponents() != (endComp - bgComp). + * + * \if ENABLE_EXAMPLES + * \ref py_mcdataarraydouble_setpartofvalues2 "Here is a Python example". + * \endif + */ + template + void DataArrayTemplate::setPartOfValues2(const typename Traits::ArrayType *a, const int *bgTuples, const int *endTuples, const int *bgComp, const int *endComp, bool strictCompoCompare) + { + if(!a) + throw INTERP_KERNEL::Exception("DataArrayDouble::setPartOfValues2 : input DataArrayDouble is NULL !"); + const char msg[]="DataArrayTemplate::setPartOfValues2"; + checkAllocated(); + a->checkAllocated(); + int nbComp(getNumberOfComponents()),nbOfTuples(getNumberOfTuples()); + for(const int *z=bgComp;z!=endComp;z++) + DataArray::CheckValueInRange(nbComp,*z,"invalid component id"); + int newNbOfTuples((int)std::distance(bgTuples,endTuples)); + int newNbOfComp((int)std::distance(bgComp,endComp)); + bool assignTech(true); + if(a->getNbOfElems()==(std::size_t)newNbOfTuples*newNbOfComp) + { + if(strictCompoCompare) + a->checkNbOfTuplesAndComp(newNbOfTuples,newNbOfComp,msg); + } + else + { + a->checkNbOfTuplesAndComp(1,newNbOfComp,msg); + assignTech=false; + } + T *pt(getPointer()); + const T *srcPt(a->getConstPointer()); + if(assignTech) + { + for(const int *w=bgTuples;w!=endTuples;w++) + { + DataArray::CheckValueInRange(nbOfTuples,*w,"invalid tuple id"); + for(const int *z=bgComp;z!=endComp;z++,srcPt++) + { + pt[(std::size_t)(*w)*nbComp+(*z)]=*srcPt; + } + } + } + else + { + for(const int *w=bgTuples;w!=endTuples;w++) + { + const T *srcPt2=srcPt; + DataArray::CheckValueInRange(nbOfTuples,*w,"invalid tuple id"); + for(const int *z=bgComp;z!=endComp;z++,srcPt2++) + { + pt[(std::size_t)(*w)*nbComp+(*z)]=*srcPt2; + } + } + } + } + + /*! + * Assign a given value to values at specified tuples and components of \a this array. + * The tuples and components to assign to are defined by C arrays of indices. + * \param [in] a - the value to assign. + * \param [in] bgTuples - pointer to an array of tuple indices of \a this array to + * assign \a a to. + * \param [in] endTuples - specifies the end of the array \a bgTuples, so that + * pointer to a tuple index (\a pi) varies as this: + * \a bgTuples <= \a pi < \a endTuples. + * \param [in] bgComp - pointer to an array of component indices of \a this array to + * assign \a a to. + * \param [in] endComp - specifies the end of the array \a bgTuples, so that + * pointer to a component index (\a pi) varies as this: + * \a bgComp <= \a pi < \a endComp. + * \throw If \a this is not allocated. + * \throw If any index of tuple/component given by bgTuples / bgComp is + * out of a valid range for \a this array. + * + * \if ENABLE_EXAMPLES + * \ref py_mcdataarraydouble_setpartofvaluessimple2 "Here is a Python example". + * \endif + */ + template + void DataArrayTemplate::setPartOfValuesSimple2(T a, const int *bgTuples, const int *endTuples, const int *bgComp, const int *endComp) + { + checkAllocated(); + int nbComp(getNumberOfComponents()),nbOfTuples(getNumberOfTuples()); + for(const int *z=bgComp;z!=endComp;z++) + DataArray::CheckValueInRange(nbComp,*z,"invalid component id"); + T *pt(getPointer()); + for(const int *w=bgTuples;w!=endTuples;w++) + for(const int *z=bgComp;z!=endComp;z++) + { + DataArray::CheckValueInRange(nbOfTuples,*w,"invalid tuple id"); + pt[(std::size_t)(*w)*nbComp+(*z)]=a; + } + } + + /*! + * Copy all values from another DataArrayDouble (\a a) into specified tuples and + * components of \a this array. Textual data is not copied. + * The tuples to assign to are defined by a C array of indices. + * The components to assign to are defined by three values similar to parameters of + * the Python function \c range(\c start,\c stop,\c step). + * There are two *modes of usage*: + * - If \a a->getNbOfElems() equals to number of values to assign to, then every value + * of \a a is assigned to its own location within \a this array. + * - If \a a includes one tuple, then all values of \a a are assigned to the specified + * components of every specified tuple of \a this array. In this mode it is required + * that \a a->getNumberOfComponents() equals to the number of specified components. + * + * \param [in] a - the array to copy values from. + * \param [in] bgTuples - pointer to an array of tuple indices of \a this array to + * assign values of \a a to. + * \param [in] endTuples - specifies the end of the array \a bgTuples, so that + * pointer to a tuple index (pi) varies as this: + * \a bgTuples <= \a pi < \a endTuples. + * \param [in] bgComp - index of the first component of \a this array to assign to. + * \param [in] endComp - index of the component before which the components to assign + * to are located. + * \param [in] stepComp - index increment to get index of the next component to assign to. + * \param [in] strictCompoCompare - this parameter is checked only in the first + * *mode of usage*; if \a strictCompoCompare is \a true (default), + * then \a a->getNumberOfComponents() must be equal + * to the number of specified columns, else this is not required. + * \throw If \a a is NULL. + * \throw If \a a is not allocated. + * \throw If \a this is not allocated. + * \throw If any index of tuple given by \a bgTuples is out of a valid range for + * \a this array. + * \throw In the first *mode of usage*, if strictCompoCompare == true and + * if a->getNumberOfComponents() is unequal to the number of components + * defined by (bgComp,endComp,stepComp). + * \throw In the second *mode of usage*, if \a a->getNumberOfTuples() != 1 or + * a->getNumberOfComponents() is unequal to the number of components + * defined by (bgComp,endComp,stepComp). + * \throw If parameters specifying components to assign to, do not give a + * non-empty range of increasing indices or indices are out of a valid range + * for \c this array. + * + * \if ENABLE_EXAMPLES + * \ref py_mcdataarraydouble_setpartofvalues3 "Here is a Python example". + * \endif + */ + template + void DataArrayTemplate::setPartOfValues3(const typename Traits::ArrayType *a, const int *bgTuples, const int *endTuples, int bgComp, int endComp, int stepComp, bool strictCompoCompare) + { + if(!a) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setPartOfValues3 : input DataArrayDouble is NULL !"); + const char msg[]="DataArrayTemplate::setPartOfValues3"; + checkAllocated(); + a->checkAllocated(); + int newNbOfComp=DataArray::GetNumberOfItemGivenBES(bgComp,endComp,stepComp,msg); + int nbComp=getNumberOfComponents(); + int nbOfTuples=getNumberOfTuples(); + DataArray::CheckValueInRangeEx(nbComp,bgComp,endComp,"invalid component value"); + int newNbOfTuples=(int)std::distance(bgTuples,endTuples); + bool assignTech=true; + if(a->getNbOfElems()==(std::size_t)newNbOfTuples*newNbOfComp) + { + if(strictCompoCompare) + a->checkNbOfTuplesAndComp(newNbOfTuples,newNbOfComp,msg); + } + else + { + a->checkNbOfTuplesAndComp(1,newNbOfComp,msg); + assignTech=false; + } + T *pt(getPointer()+bgComp); + const T *srcPt(a->getConstPointer()); + if(assignTech) + { + for(const int *w=bgTuples;w!=endTuples;w++) + for(int j=0;j(pi) varies as this: + * \a bgTuples <= \a pi < \a endTuples. + * \param [in] bgComp - index of the first component of \a this array to assign to. + * \param [in] endComp - index of the component before which the components to assign + * to are located. + * \param [in] stepComp - index increment to get index of the next component to assign to. + * \throw If \a this is not allocated. + * \throw If any index of tuple given by \a bgTuples is out of a valid range for + * \a this array. + * \throw If parameters specifying components to assign to, do not give a + * non-empty range of increasing indices or indices are out of a valid range + * for \c this array. + * + * \if ENABLE_EXAMPLES + * \ref py_mcdataarraydouble_setpartofvaluessimple3 "Here is a Python example". + * \endif + */ + template + void DataArrayTemplate::setPartOfValuesSimple3(T a, const int *bgTuples, const int *endTuples, int bgComp, int endComp, int stepComp) + { + const char msg[]="DataArrayTemplate::setPartOfValuesSimple3"; + checkAllocated(); + int newNbOfComp(DataArray::GetNumberOfItemGivenBES(bgComp,endComp,stepComp,msg)); + int nbComp(getNumberOfComponents()),nbOfTuples(getNumberOfTuples()); + DataArray::CheckValueInRangeEx(nbComp,bgComp,endComp,"invalid component value"); + T *pt(getPointer()+bgComp); + for(const int *w=bgTuples;w!=endTuples;w++) + for(int j=0;jgetNumberOfComponents() + * must be equal to the number of columns to assign to, else an + * exception is thrown; if \a false, then it is only required that \a + * a->getNbOfElems() equals to number of values to assign to (this condition + * must be respected even if \a strictCompoCompare is \a true). The number of + * values to assign to is given by following Python expression: + * \a nbTargetValues = + * \c len(\c range(\a bgTuples,\a endTuples,\a stepTuples)) * + * \c len(\c range(\a bgComp,\a endComp,\a stepComp)). + * \throw If \a a is NULL. + * \throw If \a a is not allocated. + * \throw If \a this is not allocated. + * \throw If parameters specifying tuples and components to assign to do not give a + * non-empty range of increasing indices. + * \throw If \a a->getNbOfElems() != \a nbTargetValues. + * \throw If \a strictCompoCompare == \a true && \a a->getNumberOfComponents() != + * \c len(\c range(\a bgComp,\a endComp,\a stepComp)). + * + */ + template + void DataArrayTemplate::setPartOfValues4(const typename Traits::ArrayType *a, int bgTuples, int endTuples, int stepTuples, const int *bgComp, const int *endComp, bool strictCompoCompare) + {if(!a) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setPartOfValues4 : input DataArrayTemplate is NULL !"); + const char msg[]="DataArrayTemplate::setPartOfValues4"; + checkAllocated(); + a->checkAllocated(); + int newNbOfTuples(DataArray::GetNumberOfItemGivenBES(bgTuples,endTuples,stepTuples,msg)); + int newNbOfComp((int)std::distance(bgComp,endComp)); + int nbComp(getNumberOfComponents()); + for(const int *z=bgComp;z!=endComp;z++) + DataArray::CheckValueInRange(nbComp,*z,"invalid component id"); + int nbOfTuples(getNumberOfTuples()); + DataArray::CheckValueInRangeEx(nbOfTuples,bgTuples,endTuples,"invalid tuple value"); + bool assignTech(true); + if(a->getNbOfElems()==(std::size_t)newNbOfTuples*newNbOfComp) + { + if(strictCompoCompare) + a->checkNbOfTuplesAndComp(newNbOfTuples,newNbOfComp,msg); + } + else + { + a->checkNbOfTuplesAndComp(1,newNbOfComp,msg); + assignTech=false; + } + const T *srcPt(a->getConstPointer()); + T *pt(getPointer()+bgTuples*nbComp); + if(assignTech) + { + for(int i=0;i + void DataArrayTemplate::setPartOfValuesSimple4(T a, int bgTuples, int endTuples, int stepTuples, const int *bgComp, const int *endComp) + { + const char msg[]="DataArrayTemplate::setPartOfValuesSimple4"; + checkAllocated(); + int newNbOfTuples(DataArray::GetNumberOfItemGivenBES(bgTuples,endTuples,stepTuples,msg)); + int nbComp(getNumberOfComponents()); + for(const int *z=bgComp;z!=endComp;z++) + DataArray::CheckValueInRange(nbComp,*z,"invalid component id"); + int nbOfTuples(getNumberOfTuples()); + DataArray::CheckValueInRangeEx(nbOfTuples,bgTuples,endTuples,"invalid tuple value"); + T *pt=getPointer()+bgTuples*nbComp; + for(int i=0;ithis->getNumberOfComponents() != a->getNumberOfComponents(). + * \throw If \a tuplesSelec->getNumberOfComponents() != 2. + * \throw If any tuple index given by \a tuplesSelec is out of a valid range for + * the corresponding (\a this or \a a) array. + */ + template + void DataArrayTemplate::setPartOfValuesAdv(const typename Traits::ArrayType *a, const DataArrayInt *tuplesSelec) + { + if(!a || !tuplesSelec) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setPartOfValuesAdv : input DataArrayTemplate is NULL !"); + checkAllocated(); + a->checkAllocated(); + tuplesSelec->checkAllocated(); + std::size_t nbOfComp(getNumberOfComponents()); + if(nbOfComp!=a->getNumberOfComponents()) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setPartOfValuesAdv : This and a do not have the same number of components !"); + if(tuplesSelec->getNumberOfComponents()!=2) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setPartOfValuesAdv : Expecting to have a tuple selector DataArrayInt instance with exactly 2 components !"); + int thisNt(getNumberOfTuples()); + int aNt(a->getNumberOfTuples()); + T *valsToSet(getPointer()); + const T *valsSrc(a->getConstPointer()); + for(const int *tuple=tuplesSelec->begin();tuple!=tuplesSelec->end();tuple+=2) + { + if(tuple[1]>=0 && tuple[1]=0 && tuple[0]begin(),tuple)/2; + oss << " of 'tuplesSelec' request of tuple id #" << tuple[0] << " in 'this' ! It should be in [0," << thisNt << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + { + std::ostringstream oss; oss << "DataArrayTemplate::setPartOfValuesAdv : Tuple #" << std::distance(tuplesSelec->begin(),tuple)/2; + oss << " of 'tuplesSelec' request of tuple id #" << tuple[1] << " in 'a' ! It should be in [0," << aNt << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } + + /*! + * Copy some tuples from another DataArrayDouble (\a aBase) into contiguous tuples + * of \a this array. Textual data is not copied. Both arrays must have equal number of + * components. + * The tuples to assign to are defined by index of the first tuple, and + * their number is defined by \a tuplesSelec->getNumberOfTuples(). + * The tuples to copy are defined by values of a DataArrayInt. + * All components of selected tuples are copied. + * \param [in] tupleIdStart - index of the first tuple of \a this array to assign + * values to. + * \param [in] aBase - the array to copy values from. + * \param [in] tuplesSelec - the array specifying tuples of \a a to copy. + * \throw If \a this is not allocated. + * \throw If \a aBase is NULL. + * \throw If \a aBase is not allocated. + * \throw If \a tuplesSelec is NULL. + * \throw If \a tuplesSelec is not allocated. + * \throw If this->getNumberOfComponents() != aBase->getNumberOfComponents(). + * \throw If \a tuplesSelec->getNumberOfComponents() != 1. + * \throw If tupleIdStart + tuplesSelec->getNumberOfTuples() > this->getNumberOfTuples(). + * \throw If any tuple index given by \a tuplesSelec is out of a valid range for + * \a aBase array. + */ + template + void DataArrayTemplate::setContigPartOfSelectedValues(int tupleIdStart, const DataArray *aBase, const DataArrayInt *tuplesSelec) + { + if(!aBase || !tuplesSelec) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValues : input DataArray is NULL !"); + const typename Traits::ArrayType *a(dynamic_cast::ArrayType *>(aBase)); + if(!a) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValues : input DataArray aBase is not a DataArrayDouble !"); + checkAllocated(); + a->checkAllocated(); + tuplesSelec->checkAllocated(); + std::size_t nbOfComp(getNumberOfComponents()); + if(nbOfComp!=a->getNumberOfComponents()) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValues : This and a do not have the same number of components !"); + if(tuplesSelec->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValues : Expecting to have a tuple selector DataArrayInt instance with exactly 1 component !"); + int thisNt(getNumberOfTuples()); + int aNt(a->getNumberOfTuples()); + int nbOfTupleToWrite(tuplesSelec->getNumberOfTuples()); + T *valsToSet(getPointer()+tupleIdStart*nbOfComp); + if(tupleIdStart+nbOfTupleToWrite>thisNt) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValues : invalid number range of values to write !"); + const T *valsSrc=a->getConstPointer(); + for(const int *tuple=tuplesSelec->begin();tuple!=tuplesSelec->end();tuple++,valsToSet+=nbOfComp) + { + if(*tuple>=0 && *tuple::ArrayTypeName << "::setContigPartOfSelectedValues : Tuple #" << std::distance(tuplesSelec->begin(),tuple); + oss << " of 'tuplesSelec' request of tuple id #" << *tuple << " in 'a' ! It should be in [0," << aNt << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + } + + /*! + * Copy some tuples from another DataArrayDouble (\a aBase) into contiguous tuples + * of \a this array. Textual data is not copied. Both arrays must have equal number of + * components. + * The tuples to copy are defined by three values similar to parameters of + * the Python function \c range(\c start,\c stop,\c step). + * The tuples to assign to are defined by index of the first tuple, and + * their number is defined by number of tuples to copy. + * All components of selected tuples are copied. + * \param [in] tupleIdStart - index of the first tuple of \a this array to assign + * values to. + * \param [in] aBase - the array to copy values from. + * \param [in] bg - index of the first tuple to copy of the array \a aBase. + * \param [in] end2 - index of the tuple of \a aBase before which the tuples to copy + * are located. + * \param [in] step - index increment to get index of the next tuple to copy. + * \throw If \a this is not allocated. + * \throw If \a aBase is NULL. + * \throw If \a aBase is not allocated. + * \throw If this->getNumberOfComponents() != aBase->getNumberOfComponents(). + * \throw If tupleIdStart + len(range(bg,end2,step)) > this->getNumberOfTuples(). + * \throw If parameters specifying tuples to copy, do not give a + * non-empty range of increasing indices or indices are out of a valid range + * for the array \a aBase. + */ + template + void DataArrayTemplate::setContigPartOfSelectedValuesSlice(int tupleIdStart, const DataArray *aBase, int bg, int end2, int step) + { + if(!aBase) + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::setContigPartOfSelectedValuesSlice : input DataArray is NULL !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + const typename Traits::ArrayType *a(dynamic_cast::ArrayType *>(aBase)); + if(!a) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValuesSlice : input DataArray aBase is not a DataArrayDouble !"); + checkAllocated(); + a->checkAllocated(); + std::size_t nbOfComp(getNumberOfComponents()); + const char msg[]="DataArrayDouble::setContigPartOfSelectedValuesSlice"; + int nbOfTupleToWrite(DataArray::GetNumberOfItemGivenBES(bg,end2,step,msg)); + if(nbOfComp!=a->getNumberOfComponents()) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValuesSlice : This and a do not have the same number of components !"); + int thisNt(getNumberOfTuples()),aNt(a->getNumberOfTuples()); + T *valsToSet(getPointer()+tupleIdStart*nbOfComp); + if(tupleIdStart+nbOfTupleToWrite>thisNt) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValuesSlice : invalid number range of values to write !"); + if(end2>aNt) + throw INTERP_KERNEL::Exception("DataArrayTemplate::setContigPartOfSelectedValuesSlice : invalid range of values to read !"); + const T *valsSrc(a->getConstPointer()+bg*nbOfComp); + for(int i=0;i \a this->getNumberOfTuples(). + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplate::mySelectByTupleRanges(const std::vector >& ranges) const + { + checkAllocated(); + int nbOfComp(getNumberOfComponents()),nbOfTuplesThis(getNumberOfTuples()); + if(ranges.empty()) + { + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(0,nbOfComp); + ret->copyStringInfoFrom(*this); + return ret.retn(); + } + int ref(ranges.front().first),nbOfTuples(0); + bool isIncreasing(true); + for(std::vector >::const_iterator it=ranges.begin();it!=ranges.end();it++) + { + if((*it).first<=(*it).second) + { + if((*it).first>=0 && (*it).second<=nbOfTuplesThis) + { + nbOfTuples+=(*it).second-(*it).first; + if(isIncreasing) + isIncreasing=ref<=(*it).first; + ref=(*it).second; + } + else + { + std::ostringstream oss; oss << "DataArrayTemplate::selectByTupleRanges : on range #" << std::distance(ranges.begin(),it); + oss << " (" << (*it).first << "," << (*it).second << ") is greater than number of tuples of this :" << nbOfTuples << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + { + std::ostringstream oss; oss << "DataArrayTemplate::selectByTupleRanges : on range #" << std::distance(ranges.begin(),it); + oss << " (" << (*it).first << "," << (*it).second << ") end is before begin !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + if(isIncreasing && nbOfTuplesThis==nbOfTuples) + return static_cast::ArrayType *>(deepCopy()); + MCAuto ret0(buildNewEmptyInstance()); + MCAuto< typename Traits::ArrayType > ret(DynamicCastSafe::ArrayType>(ret0)); + ret->alloc(nbOfTuples,nbOfComp); + ret->copyStringInfoFrom(*this); + const T *src(getConstPointer()); + T *work(ret->getPointer()); + for(std::vector >::const_iterator it=ranges.begin();it!=ranges.end();it++) + work=std::copy(src+(*it).first*nbOfComp,src+(*it).second*nbOfComp,work); + return ret.retn(); + } + + /*! + * Returns the first value of \a this. + * \return double - the last value of \a this array. + * \throw If \a this is not allocated. + * \throw If \a this->getNumberOfComponents() != 1. + * \throw If \a this->getNumberOfTuples() < 1. + */ + template + T DataArrayTemplate::front() const + { + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayTemplate::front : number of components not equal to one !"); + int nbOfTuples(getNumberOfTuples()); + if(nbOfTuples<1) + throw INTERP_KERNEL::Exception("DataArrayTemplate::front : number of tuples must be >= 1 !"); + return *(getConstPointer()); + } + + /*! + * Returns the last value of \a this. + * \return double - the last value of \a this array. + * \throw If \a this is not allocated. + * \throw If \a this->getNumberOfComponents() != 1. + * \throw If \a this->getNumberOfTuples() < 1. + */ + template + T DataArrayTemplate::back() const + { + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayTemplate::back : number of components not equal to one !"); + int nbOfTuples(getNumberOfTuples()); + if(nbOfTuples<1) + throw INTERP_KERNEL::Exception("DataArrayTemplate::back : number of tuples must be >= 1 !"); + return *(getConstPointer()+nbOfTuples-1); + } + + /*! + * Returns the maximal value and its location within \a this one-dimensional array. + * \param [out] tupleId - index of the tuple holding the maximal value. + * \return double - the maximal value among all values of \a this array. + * \throw If \a this->getNumberOfComponents() != 1 + * \throw If \a this->getNumberOfTuples() < 1 + * \sa getMaxAbsValue, getMinValue + */ + template + T DataArrayTemplate::getMaxValue(int& tupleId) const + { + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayDouble::getMaxValue : must be applied on DataArrayDouble with only one component, you can call 'rearrange' method before or call 'getMaxValueInArray' method !"); + int nbOfTuples(getNumberOfTuples()); + if(nbOfTuples<=0) + throw INTERP_KERNEL::Exception("DataArrayDouble::getMaxValue : array exists but number of tuples must be > 0 !"); + const T *vals(getConstPointer()); + const T *loc(std::max_element(vals,vals+nbOfTuples)); + tupleId=(int)std::distance(vals,loc); + return *loc; + } + + /*! + * Returns the maximal value within \a this array that is allowed to have more than + * one component. + * \return double - the maximal value among all values of \a this array. + * \throw If \a this is not allocated. + * \sa getMaxAbsValueInArray, getMinValueInArray + */ + template + T DataArrayTemplate::getMaxValueInArray() const + { + checkAllocated(); + const T *loc(std::max_element(begin(),end())); + return *loc; + } + + /*! + * Returns the maximal absolute value in \a this and the first occurrence location associated to it. + * \return the element in this (positive or negative) having the max abs value in \a this. + * \throw If \a this is not allocated. + * \throw If \a this is non one component array. + * \throw If \a this is empty. + */ + template + T DataArrayTemplate::getMaxAbsValue(std::size_t& tupleId) const + { + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayDouble::getMaxAbsValue : must be applied on DataArrayDouble with only one component, you can call 'rearrange' method before or call 'getMaxValueInArray' method !"); + std::size_t nbTuples(this->getNumberOfTuples()); + if(nbTuples==0) + throw INTERP_KERNEL::Exception("DataArrayTemplate::getMaxAbsValue : empty array !"); + T ret((T)-1); + tupleId=0; + const T *pt(begin()); + for(std::size_t i=0;iret) + { + ret=cand; + tupleId=i; + } + } + return this->getIJ(tupleId,0); + } + + /*! + * Returns the maximal absolute value in \a this. + * \throw If \a this is not allocated. + * \throw If \a this is non one component array. + * \throw If \a this is empty. + */ + template + T DataArrayTemplate::getMaxAbsValueInArray() const + { + std::size_t dummy; + return getMaxAbsValue(dummy); + } + + /*! + * Returns the minimal value and its location within \a this one-dimensional array. + * \param [out] tupleId - index of the tuple holding the minimal value. + * \return double - the minimal value among all values of \a this array. + * \throw If \a this->getNumberOfComponents() != 1 + * \throw If \a this->getNumberOfTuples() < 1 + */ + template + T DataArrayTemplate::getMinValue(int& tupleId) const + { + checkAllocated(); + if(getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayDouble::getMinValue : must be applied on DataArrayDouble with only one component, you can call 'rearrange' method before call 'getMinValueInArray' method !"); + int nbOfTuples(getNumberOfTuples()); + if(nbOfTuples<=0) + throw INTERP_KERNEL::Exception("DataArrayDouble::getMinValue : array exists but number of tuples must be > 0 !"); + const T *vals(getConstPointer()); + const T *loc(std::min_element(vals,vals+nbOfTuples)); + tupleId=(int)std::distance(vals,loc); + return *loc; + } + + /*! + * Returns the minimal value within \a this array that is allowed to have more than + * one component. + * \return double - the minimal value among all values of \a this array. + * \throw If \a this is not allocated. + */ + template + T DataArrayTemplate::getMinValueInArray() const + { + checkAllocated(); + const T *loc=std::min_element(begin(),end()); + return *loc; + } + + template + void DataArrayTemplate::circularPermutation(int nbOfShift) + { + checkAllocated(); + int nbOfCompo(getNumberOfComponents()),nbTuples(getNumberOfTuples()); + int effNbSh(EffectiveCircPerm(nbOfShift,nbTuples)); + if(effNbSh==0) + return ; + T *work(getPointer()); + if(effNbSh buf(new T[effNbSh*nbOfCompo]); + std::copy(work,work+effNbSh*nbOfCompo,(T *)buf); + std::copy(work+effNbSh*nbOfCompo,work+nbTuples*nbOfCompo,work);// ze big shift + std::copy((T *)buf,(T *)buf+effNbSh*nbOfCompo,work+(nbTuples-effNbSh)*nbOfCompo); + } + else + { + typename INTERP_KERNEL::AutoPtr buf(new T[(nbTuples-effNbSh)*nbOfCompo]); + std::copy(work+effNbSh*nbOfCompo,work+nbTuples*nbOfCompo,(T *)buf); + std::copy(work,work+effNbSh*nbOfCompo,work+(nbTuples-effNbSh)*nbOfCompo);// ze big shift + std::copy((T*)buf,(T *)buf+(nbTuples-effNbSh)*nbOfCompo,work); + } + } + + template + void DataArrayTemplate::circularPermutationPerTuple(int nbOfShift) + { + checkAllocated(); + int nbOfCompo(getNumberOfComponents()),nbTuples(getNumberOfTuples()); + int effNbSh(EffectiveCircPerm(nbOfShift,nbOfCompo)); + if(effNbSh==0) + return ; + T *work(getPointer()); + if(effNbSh buf(new T[effNbSh]); + for(int i=0;i buf(new T[nbOfCompo-effNbSh]); + for(int i=0;i sts(nbOfCompo); + for(int i=0;i + void DataArrayTemplate::reversePerTuple() + { + checkAllocated(); + int nbOfCompo(getNumberOfComponents()),nbTuples(getNumberOfTuples()); + if(nbOfCompo<=1) + return ; + T *work(getPointer()); + for(int i=0;i + void DataArrayTemplate::SetArrayIn(typename Traits::ArrayType *newArray, typename Traits::ArrayType* &arrayToSet) + { + if(newArray!=arrayToSet) + { + if(arrayToSet) + arrayToSet->decrRef(); + arrayToSet=newArray; + if(arrayToSet) + arrayToSet->incrRef(); + } + } + + /*! + * Assign zero to all values in \a this array. To know more on filling arrays see + * \ref MEDCouplingArrayFill. + * \throw If \a this is not allocated. + */ + template + void DataArrayTemplate::fillWithZero() + { + fillWithValue((T)0); + } + + ////////////////////////////// + + template + template + MCAuto< typename Traits::ArrayType > DataArrayTemplateClassic::convertToOtherTypeOfArr() const + { + this->checkAllocated(); + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->alloc(this->getNumberOfTuples(),this->getNumberOfComponents()); + std::size_t nbOfVals(this->getNbOfElems()); + const T *src(this->begin()); + U *dest(ret->getPointer()); + // to make Visual C++ happy : instead of std::size_t nbOfVals=getNbOfElems(); std::copy(src,src+nbOfVals,dest); + //for(const T *src=this->begin();src!=this->end();src++,dest++) + // *dest=(int)*src; + std::copy(src,src+nbOfVals,dest); + ret->copyStringInfoFrom(*this); + return ret; + } + + /*! + * Creates a new DataArrayDouble and assigns all (textual and numerical) data of \a this + * array to the new one. + * \return DataArrayDouble * - the new instance of DataArrayInt. + */ + template + MCAuto DataArrayTemplateClassic::convertToDblArr() const + { + return convertToOtherTypeOfArr(); + } + + /*! + * Creates a new DataArrayInt and assigns all (textual and numerical) data of \a this + * array to the new one. + * \return DataArrayInt * - the new instance of DataArrayInt. + */ + template + MCAuto DataArrayTemplateClassic::convertToIntArr() const + { + return convertToOtherTypeOfArr(); + } + + /*! + * Creates a new DataArrayFloat and assigns all (textual and numerical) data of \a this + * array to the new one. + * \return DataArrayFloat * - the new instance of DataArrayInt. + */ + template + MCAuto DataArrayTemplateClassic::convertToFloatArr() const + { + return convertToOtherTypeOfArr(); + } + + /*! + * Apply a linear function to a given component of \a this array, so that + * an array element (x) becomes \f$ a * x + b \f$. + * \param [in] a - the first coefficient of the function. + * \param [in] b - the second coefficient of the function. + * \param [in] compoId - the index of component to modify. + * \throw If \a this is not allocated, or \a compoId is not in [0,\c this->getNumberOfComponents() ). + */ + template + void DataArrayTemplateClassic::applyLin(T a, T b, int compoId) + { + this->checkAllocated(); + T *ptr(this->getPointer()+compoId); + int nbOfComp(this->getNumberOfComponents()),nbOfTuple(this->getNumberOfTuples()); + if(compoId<0 || compoId>=nbOfComp) + { + std::ostringstream oss; oss << "DataArrayDouble::applyLin : The compoId requested (" << compoId << ") is not valid ! Must be in [0," << nbOfComp << ") !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + for(int i=0;ideclareAsNew(); + } + + /*! + * Apply a linear function to all elements of \a this array, so that + * an element _x_ becomes \f$ a * x + b \f$. + * \param [in] a - the first coefficient of the function. + * \param [in] b - the second coefficient of the function. + * \throw If \a this is not allocated. + */ + template + void DataArrayTemplateClassic::applyLin(T a, T b) + { + this->checkAllocated(); + T *ptr(this->getPointer()); + std::size_t nbOfElems(this->getNbOfElems()); + for(std::size_t i=0;ideclareAsNew(); + } + + /*! + * Returns a full copy of \a this array except that sign of all elements is reversed. + * \return DataArrayDouble * - the new instance of DataArrayDouble containing the + * same number of tuples and component as \a this array. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::negate() const + { + this->checkAllocated(); + MCAuto::ArrayType> newArr(Traits::ArrayType::New()); + int nbOfTuples(this->getNumberOfTuples()),nbOfComp(this->getNumberOfComponents()); + newArr->alloc(nbOfTuples,nbOfComp); + const T *cptr(this->begin()); + std::transform(cptr,cptr+nbOfTuples*nbOfComp,newArr->getPointer(),std::negate()); + newArr->copyStringInfoFrom(*this); + return newArr.retn(); + } + + template + template + void DataArrayTemplateClassic::somethingEqual(const typename Traits::ArrayType *other) + { + if(!other) + throw INTERP_KERNEL::Exception("DataArray::SomethingEqual : input DataArray instance is NULL !"); + const char *msg="Nb of tuples mismatch for DataArrayDouble::multiplyEqual !"; + this->checkAllocated(); + other->checkAllocated(); + int nbOfTuple(this->getNumberOfTuples()),nbOfTuple2(other->getNumberOfTuples()); + int nbOfComp(this->getNumberOfComponents()),nbOfComp2(other->getNumberOfComponents()); + if(nbOfTuple==nbOfTuple2) + { + if(nbOfComp==nbOfComp2) + { + std::transform(this->begin(),this->end(),other->begin(),this->getPointer(),FCT()); + } + else if(nbOfComp2==1) + { + T *ptr(this->getPointer()); + const T *ptrc(other->begin()); + for(int i=0;igetPointer()); + const T *ptrc(other->begin()); + for(int i=0;ideclareAsNew(); + } + + /*! + * Adds values of another DataArrayDouble to values of \a this one. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * \a other array is added to the corresponding value of \a this array, i.e.: + * _a_ [ i, j ] += _other_ [ i, j ]. + * 2. The arrays have same number of tuples and \a other array has one component. Then + * _a_ [ i, j ] += _other_ [ i, 0 ]. + * 3. The arrays have same number of components and \a other array has one tuple. Then + * _a_ [ i, j ] += _a2_ [ 0, j ]. + * + * \param [in] other - an array to add to \a this one. + * \throw If \a other is NULL. + * \throw If \a this->getNumberOfTuples() != \a other->getNumberOfTuples() and + * \a this->getNumberOfComponents() != \a other->getNumberOfComponents() and + * \a other has number of both tuples and components not equal to 1. + */ + template + void DataArrayTemplateClassic::addEqual(const typename Traits::ArrayType *other) + { + this->somethingEqual< std::plus >(other); + } + + /*! + * Subtract values of another DataArrayDouble from values of \a this one. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * \a other array is subtracted from the corresponding value of \a this array, i.e.: + * _a_ [ i, j ] -= _other_ [ i, j ]. + * 2. The arrays have same number of tuples and \a other array has one component. Then + * _a_ [ i, j ] -= _other_ [ i, 0 ]. + * 3. The arrays have same number of components and \a other array has one tuple. Then + * _a_ [ i, j ] -= _a2_ [ 0, j ]. + * + * \param [in] other - an array to subtract from \a this one. + * \throw If \a other is NULL. + * \throw If \a this->getNumberOfTuples() != \a other->getNumberOfTuples() and + * \a this->getNumberOfComponents() != \a other->getNumberOfComponents() and + * \a other has number of both tuples and components not equal to 1. + */ + template + void DataArrayTemplateClassic::substractEqual(const typename Traits::ArrayType *other) + { + this->somethingEqual< std::minus >(other); + } + + /*! + * Multiply values of another DataArrayDouble to values of \a this one. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * \a other array is multiplied to the corresponding value of \a this array, i.e. + * _this_ [ i, j ] *= _other_ [ i, j ]. + * 2. The arrays have same number of tuples and \a other array has one component. Then + * _this_ [ i, j ] *= _other_ [ i, 0 ]. + * 3. The arrays have same number of components and \a other array has one tuple. Then + * _this_ [ i, j ] *= _a2_ [ 0, j ]. + * + * \param [in] other - an array to multiply to \a this one. + * \throw If \a other is NULL. + * \throw If \a this->getNumberOfTuples() != \a other->getNumberOfTuples() and + * \a this->getNumberOfComponents() != \a other->getNumberOfComponents() and + * \a other has number of both tuples and components not equal to 1. + */ + template + void DataArrayTemplateClassic::multiplyEqual(const typename Traits::ArrayType *other) + { + this->somethingEqual< std::multiplies >(other); + } + + /*! + * Divide values of \a this array by values of another DataArrayDouble. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * \a this array is divided by the corresponding value of \a other one, i.e.: + * _a_ [ i, j ] /= _other_ [ i, j ]. + * 2. The arrays have same number of tuples and \a other array has one component. Then + * _a_ [ i, j ] /= _other_ [ i, 0 ]. + * 3. The arrays have same number of components and \a other array has one tuple. Then + * _a_ [ i, j ] /= _a2_ [ 0, j ]. + * + * \warning No check of division by zero is performed! + * \param [in] other - an array to divide \a this one by. + * \throw If \a other is NULL. + * \throw If \a this->getNumberOfTuples() != \a other->getNumberOfTuples() and + * \a this->getNumberOfComponents() != \a other->getNumberOfComponents() and + * \a other has number of both tuples and components not equal to 1. + */ + template + void DataArrayTemplateClassic::divideEqual(const typename Traits::ArrayType *other) + { + this->somethingEqual< std::divides >(other); + } + + template + typename Traits::ArrayType *DivSub(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + if(!a1 || !a2) + throw INTERP_KERNEL::Exception("DivSub : input DataArrayDouble instance is NULL !"); + int nbOfTuple1(a1->getNumberOfTuples()),nbOfTuple2(a2->getNumberOfTuples()); + int nbOfComp1(a1->getNumberOfComponents()),nbOfComp2(a2->getNumberOfComponents()); + if(nbOfTuple2==nbOfTuple1) + { + if(nbOfComp1==nbOfComp2) + { + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->alloc(nbOfTuple2,nbOfComp1); + std::transform(a1->begin(),a1->end(),a2->begin(),ret->getPointer(),FCT()); + ret->copyStringInfoFrom(*a1); + return ret.retn(); + } + else if(nbOfComp2==1) + { + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->alloc(nbOfTuple1,nbOfComp1); + const T *a2Ptr(a2->begin()),*a1Ptr(a1->begin()); + T *res(ret->getPointer()); + for(int i=0;icopyStringInfoFrom(*a1); + return ret.retn(); + } + else + { + a1->checkNbOfComps(nbOfComp2,"Nb of components mismatch for array Divide !"); + return 0; + } + } + else if(nbOfTuple2==1) + { + a1->checkNbOfComps(nbOfComp2,"Nb of components mismatch for array Divide !"); + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->alloc(nbOfTuple1,nbOfComp1); + const T *a1ptr=a1->begin(),*a2ptr(a2->begin()); + T *pt(ret->getPointer()); + for(int i=0;icopyStringInfoFrom(*a1); + return ret.retn(); + } + else + { + a1->checkNbOfTuples(nbOfTuple2,"Nb of tuples mismatch for array Divide !");//will always throw an exception + return 0; + } + } + + /*! + * Returns a new DataArrayDouble that is a subtraction of two given arrays. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * the result array (_a_) is a subtraction of the corresponding values of \a a1 and + * \a a2, i.e.: _a_ [ i, j ] = _a1_ [ i, j ] - _a2_ [ i, j ]. + * 2. The arrays have same number of tuples and one array, say _a2_, has one + * component. Then + * _a_ [ i, j ] = _a1_ [ i, j ] - _a2_ [ i, 0 ]. + * 3. The arrays have same number of components and one array, say _a2_, has one + * tuple. Then + * _a_ [ i, j ] = _a1_ [ i, j ] - _a2_ [ 0, j ]. + * + * Info on components is copied either from the first array (in the first case) or from + * the array with maximal number of elements (getNbOfElems()). + * \param [in] a1 - an array to subtract from. + * \param [in] a2 - an array to subtract. + * \return DataArrayDouble * - the new instance of DataArrayDouble. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If either \a a1 or \a a2 is NULL. + * \throw If \a a1->getNumberOfTuples() != \a a2->getNumberOfTuples() and + * \a a1->getNumberOfComponents() != \a a2->getNumberOfComponents() and + * none of them has number of tuples or components equal to 1. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::Substract(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + return DivSub< T,std::minus >(a1,a2); + } + + /*! + * Returns a new DataArrayDouble that is a division of two given arrays. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * the result array (_a_) is a division of the corresponding values of \a a1 and + * \a a2, i.e.: _a_ [ i, j ] = _a1_ [ i, j ] / _a2_ [ i, j ]. + * 2. The arrays have same number of tuples and one array, say _a2_, has one + * component. Then + * _a_ [ i, j ] = _a1_ [ i, j ] / _a2_ [ i, 0 ]. + * 3. The arrays have same number of components and one array, say _a2_, has one + * tuple. Then + * _a_ [ i, j ] = _a1_ [ i, j ] / _a2_ [ 0, j ]. + * + * Info on components is copied either from the first array (in the first case) or from + * the array with maximal number of elements (getNbOfElems()). + * \warning No check of division by zero is performed! + * \param [in] a1 - a numerator array. + * \param [in] a2 - a denominator array. + * \return DataArrayDouble * - the new instance of DataArrayDouble. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If either \a a1 or \a a2 is NULL. + * \throw If \a a1->getNumberOfTuples() != \a a2->getNumberOfTuples() and + * \a a1->getNumberOfComponents() != \a a2->getNumberOfComponents() and + * none of them has number of tuples or components equal to 1. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::Divide(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + return DivSub< T,std::divides >(a1,a2); + } + + template + typename Traits::ArrayType *MulAdd(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + if(!a1 || !a2) + throw INTERP_KERNEL::Exception("DataArrayDouble::MulAdd : input DataArrayDouble instance is NULL !"); + int nbOfTuple(a1->getNumberOfTuples()),nbOfTuple2(a2->getNumberOfTuples()); + int nbOfComp(a1->getNumberOfComponents()),nbOfComp2(a2->getNumberOfComponents()); + MCAuto::ArrayType> ret=0; + if(nbOfTuple==nbOfTuple2) + { + if(nbOfComp==nbOfComp2) + { + ret=Traits::ArrayType::New(); + ret->alloc(nbOfTuple,nbOfComp); + std::transform(a1->begin(),a1->end(),a2->begin(),ret->getPointer(),FCT()); + ret->copyStringInfoFrom(*a1); + } + else + { + int nbOfCompMin,nbOfCompMax; + const typename Traits::ArrayType *aMin, *aMax; + if(nbOfComp>nbOfComp2) + { + nbOfCompMin=nbOfComp2; nbOfCompMax=nbOfComp; + aMin=a2; aMax=a1; + } + else + { + nbOfCompMin=nbOfComp; nbOfCompMax=nbOfComp2; + aMin=a1; aMax=a2; + } + if(nbOfCompMin==1) + { + ret=Traits::ArrayType::New(); + ret->alloc(nbOfTuple,nbOfCompMax); + const T *aMinPtr(aMin->begin()); + const T *aMaxPtr(aMax->begin()); + T *res=ret->getPointer(); + for(int i=0;icopyStringInfoFrom(*aMax); + } + else + throw INTERP_KERNEL::Exception("Nb of components mismatch for array MulAdd !"); + } + } + else if((nbOfTuple==1 && nbOfTuple2>1) || (nbOfTuple>1 && nbOfTuple2==1)) + { + if(nbOfComp==nbOfComp2) + { + int nbOfTupleMax=std::max(nbOfTuple,nbOfTuple2); + const typename Traits::ArrayType *aMin(nbOfTuple>nbOfTuple2?a2:a1); + const typename Traits::ArrayType *aMax(nbOfTuple>nbOfTuple2?a1:a2); + const T *aMinPtr(aMin->begin()),*aMaxPtr(aMax->begin()); + ret=Traits::ArrayType::New(); + ret->alloc(nbOfTupleMax,nbOfComp); + T *res(ret->getPointer()); + for(int i=0;icopyStringInfoFrom(*aMax); + } + else + throw INTERP_KERNEL::Exception("Nb of components mismatch for array MulAdd !"); + } + else + throw INTERP_KERNEL::Exception("Nb of tuples mismatch for array MulAdd !"); + return ret.retn(); + } + + /*! + * Returns a new DataArrayDouble that is a product of two given arrays. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * the result array (_a_) is a product of the corresponding values of \a a1 and + * \a a2, i.e. _a_ [ i, j ] = _a1_ [ i, j ] * _a2_ [ i, j ]. + * 2. The arrays have same number of tuples and one array, say _a2_, has one + * component. Then + * _a_ [ i, j ] = _a1_ [ i, j ] * _a2_ [ i, 0 ]. + * 3. The arrays have same number of components and one array, say _a2_, has one + * tuple. Then + * _a_ [ i, j ] = _a1_ [ i, j ] * _a2_ [ 0, j ]. + * + * Info on components is copied either from the first array (in the first case) or from + * the array with maximal number of elements (getNbOfElems()). + * \param [in] a1 - a factor array. + * \param [in] a2 - another factor array. + * \return DataArrayDouble * - the new instance of DataArrayDouble. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If either \a a1 or \a a2 is NULL. + * \throw If \a a1->getNumberOfTuples() != \a a2->getNumberOfTuples() and + * \a a1->getNumberOfComponents() != \a a2->getNumberOfComponents() and + * none of them has number of tuples or components equal to 1. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::Multiply(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + return MulAdd< T , std::multiplies >(a1,a2); + } + + /*! + * Returns a new DataArrayDouble that is a sum of two given arrays. There are 3 + * valid cases. + * 1. The arrays have same number of tuples and components. Then each value of + * the result array (_a_) is a sum of the corresponding values of \a a1 and \a a2, + * i.e.: _a_ [ i, j ] = _a1_ [ i, j ] + _a2_ [ i, j ]. + * 2. The arrays have same number of tuples and one array, say _a2_, has one + * component. Then + * _a_ [ i, j ] = _a1_ [ i, j ] + _a2_ [ i, 0 ]. + * 3. The arrays have same number of components and one array, say _a2_, has one + * tuple. Then + * _a_ [ i, j ] = _a1_ [ i, j ] + _a2_ [ 0, j ]. + * + * Info on components is copied either from the first array (in the first case) or from + * the array with maximal number of elements (getNbOfElems()). + * \param [in] a1 - an array to sum up. + * \param [in] a2 - another array to sum up. + * \return DataArrayDouble * - the new instance of DataArrayDouble. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If either \a a1 or \a a2 is NULL. + * \throw If \a a1->getNumberOfTuples() != \a a2->getNumberOfTuples() and + * \a a1->getNumberOfComponents() != \a a2->getNumberOfComponents() and + * none of them has number of tuples or components equal to 1. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::Add(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + return MulAdd< T , std::plus >(a1,a2); + } + + /*! + * Returns either a \a deep or \a shallow copy of this array. For more info see + * \ref MEDCouplingArrayBasicsCopyDeep and \ref MEDCouplingArrayBasicsCopyShallow. + * \param [in] dCpy - if \a true, a deep copy is returned, else, a shallow one. + * \return DataArrayDouble * - either a new instance of DataArrayDouble (if \a dCpy + * == \a true) or \a this instance (if \a dCpy == \a false). + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::PerformCopyOrIncrRef(bool dCpy, const typename Traits::ArrayType& self) + { + if(dCpy) + return self.deepCopy(); + else + { + self.incrRef(); + return const_cast::ArrayType *>(&self); + } + } + + template + struct GreatEqual + { + GreatEqual(T v):_v(v) { } + bool operator()(T v) const { return v>=_v; } + T _v; + }; + + template + struct GreaterThan + { + GreaterThan(T v):_v(v) { } + bool operator()(T v) const { return v>_v; } + T _v; + }; + + template + struct LowerEqual + { + LowerEqual(T v):_v(v) { } + bool operator()(T v) const { return v<=_v; } + T _v; + }; + + template + struct LowerThan + { + LowerThan(T v):_v(v) { } + bool operator()(T v) const { return v<_v; } + T _v; + }; + + template + struct InRange + { + InRange(T a, T b):_a(a),_b(b) { } + bool operator()(T v) const { return v>=_a && v<_b; } + T _a,_b; + }; + +template +struct NotInRange +{ + NotInRange(T a, T b):_a(a),_b(b) { } + bool operator()(T v) const { return v<_a || v>=_b; } + T _a,_b; +}; + + /*! + * This method works only on data array with one component. This method returns a newly allocated array storing stored ascendantly of tuple ids in \a this so that this[id]<0. + * + * \return a newly allocated data array that the caller should deal with. + * \sa DataArrayInt::findIdsInRange + */ + template + DataArrayInt *DataArrayTemplateClassic::findIdsStrictlyNegative() const + { + LowerThan lt((T)0); + MCAuto ret(findIdsAdv(lt)); + return ret.retn(); + } + + template + MCAuto DataArrayTemplateClassic::findIdsGreaterOrEqualTo(T val) const + { + GreatEqual ge(val); + return findIdsAdv(ge); + } + + template + MCAuto DataArrayTemplateClassic::findIdsGreaterThan(T val) const + { + GreaterThan gt(val); + return findIdsAdv(gt); + } + + template + MCAuto DataArrayTemplateClassic::findIdsLowerOrEqualTo(T val) const + { + LowerEqual le(val); + return findIdsAdv(le); + } + + template + MCAuto DataArrayTemplateClassic::findIdsLowerThan(T val) const + { + LowerThan lt(val); + return findIdsAdv(lt); + } + + /*! + * Returns a new DataArrayDouble by aggregating two given arrays, so that (1) the number + * of components in the result array is a sum of the number of components of given arrays + * and (2) the number of tuples in the result array is same as that of each of given + * arrays. In other words the i-th tuple of result array includes all components of + * i-th tuples of all given arrays. + * Number of tuples in the given arrays must be the same. + * \param [in] a1 - an array to include in the result array. + * \param [in] a2 - another array to include in the result array. + * \return DataArrayDouble * - the new instance of DataArrayDouble. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If both \a a1 and \a a2 are NULL. + * \throw If any given array is not allocated. + * \throw If \a a1->getNumberOfTuples() != \a a2->getNumberOfTuples() + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::Meld(const typename Traits::ArrayType *a1, const typename Traits::ArrayType *a2) + { + std::vector::ArrayType *> arr(2); + arr[0]=a1; arr[1]=a2; + return Meld(arr); + } + + /*! + * Returns a new DataArrayDouble by aggregating all given arrays, so that (1) the number + * of components in the result array is a sum of the number of components of given arrays + * and (2) the number of tuples in the result array is same as that of each of given + * arrays. In other words the i-th tuple of result array includes all components of + * i-th tuples of all given arrays. + * Number of tuples in the given arrays must be the same. + * \param [in] arr - a sequence of arrays to include in the result array. + * \return DataArrayDouble * - the new instance of DataArrayDouble. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If all arrays within \a arr are NULL. + * \throw If any given array is not allocated. + * \throw If getNumberOfTuples() of arrays within \a arr is different. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::Meld(const std::vector::ArrayType *>& arr) + { + std::vector::ArrayType *> a; + for(typename std::vector::ArrayType *>::const_iterator it4=arr.begin();it4!=arr.end();it4++) + if(*it4) + a.push_back(*it4); + if(a.empty()) + throw INTERP_KERNEL::Exception("DataArrayDouble::Meld : input list must contain at least one NON EMPTY DataArrayDouble !"); + typename std::vector::ArrayType *>::const_iterator it; + for(it=a.begin();it!=a.end();it++) + (*it)->checkAllocated(); + it=a.begin(); + std::size_t nbOfTuples((*it)->getNumberOfTuples()); + std::vector nbc(a.size()); + std::vector pts(a.size()); + nbc[0]=(*it)->getNumberOfComponents(); + pts[0]=(*it++)->getConstPointer(); + for(int i=1;it!=a.end();it++,i++) + { + if(nbOfTuples!=(*it)->getNumberOfTuples()) + throw INTERP_KERNEL::Exception("DataArrayDouble::Meld : mismatch of number of tuples !"); + nbc[i]=(*it)->getNumberOfComponents(); + pts[i]=(*it)->getConstPointer(); + } + int totalNbOfComp=std::accumulate(nbc.begin(),nbc.end(),0); + typename Traits::ArrayType *ret(Traits::ArrayType::New()); + ret->alloc(nbOfTuples,totalNbOfComp); + T *retPtr(ret->getPointer()); + for(std::size_t i=0;isetInfoOnComponent(k,a[i]->getInfoOnComponent(j)); + return ret; + } + + /*! + * Returns a new DataArrayDouble holding the same values as \a this array but differently + * arranged in memory. If \a this array holds 2 components of 3 values: + * \f$ x_0,x_1,x_2,y_0,y_1,y_2 \f$, then the result array holds these values arranged + * as follows: \f$ x_0,y_0,x_1,y_1,x_2,y_2 \f$. + * \warning Do not confuse this method with transpose()! + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::fromNoInterlace() const + { + if(this->_mem.isNull()) + throw INTERP_KERNEL::Exception("DataArrayDouble::fromNoInterlace : Not defined array !"); + T *tab(this->_mem.fromNoInterlace(this->getNumberOfComponents())); + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->useArray(tab,true,C_DEALLOC,this->getNumberOfTuples(),this->getNumberOfComponents()); + return ret.retn(); + } + + /*! + * Returns a new DataArrayDouble holding the same values as \a this array but differently + * arranged in memory. If \a this array holds 2 components of 3 values: + * \f$ x_0,y_0,x_1,y_1,x_2,y_2 \f$, then the result array holds these values arranged + * as follows: \f$ x_0,x_1,x_2,y_0,y_1,y_2 \f$. + * \warning Do not confuse this method with transpose()! + * \return DataArrayDouble * - the new instance of DataArrayDouble that the caller + * is to delete using decrRef() as it is no more needed. + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::toNoInterlace() const + { + if(this->_mem.isNull()) + throw INTERP_KERNEL::Exception("DataArrayDouble::toNoInterlace : Not defined array !"); + T *tab(this->_mem.toNoInterlace(this->getNumberOfComponents())); + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->useArray(tab,true,C_DEALLOC,this->getNumberOfTuples(),this->getNumberOfComponents()); + return ret.retn(); + } + + /*! + * Appends components of another array to components of \a this one, tuple by tuple. + * So that the number of tuples of \a this array remains the same and the number of + * components increases. + * \param [in] other - the DataArrayDouble to append to \a this one. + * \throw If \a this is not allocated. + * \throw If \a this and \a other arrays have different number of tuples. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcdataarraydouble_meldwith "Here is a C++ example". + * + * \ref py_mcdataarraydouble_meldwith "Here is a Python example". + * \endif + */ + template + void DataArrayTemplateClassic::meldWith(const typename Traits::ArrayType *other) + { + this->checkAllocated(); + other->checkAllocated(); + std::size_t nbOfTuples(this->getNumberOfTuples()); + if(nbOfTuples!=other->getNumberOfTuples()) + throw INTERP_KERNEL::Exception("DataArrayDouble::meldWith : mismatch of number of tuples !"); + int nbOfComp1(this->getNumberOfComponents()),nbOfComp2(other->getNumberOfComponents()); + T *newArr=(T *)malloc((nbOfTuples*(nbOfComp1+nbOfComp2))*sizeof(T)); + T *w=newArr; + const T *inp1(this->begin()),*inp2(other->begin()); + for(std::size_t i=0;iuseArray(newArr,true,C_DEALLOC,nbOfTuples,nbOfComp1+nbOfComp2); + std::vector compIds(nbOfComp2); + for(int i=0;icopyPartOfStringInfoFrom2(compIds,*other); + } + + /*! + * + * \param [in] nbTimes specifies the nb of times each tuples in \a this will be duplicated contiguouly in returned DataArrayDouble instance. + * \a nbTimes should be at least equal to 1. + * \return a newly allocated DataArrayDouble having one component and number of tuples equal to \a nbTimes * \c this->getNumberOfTuples. + * \throw if \a this is not allocated or if \a this has not number of components set to one or if \a nbTimes is lower than 1. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::duplicateEachTupleNTimes(int nbTimes) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayDouble::duplicateEachTupleNTimes : this should have only one component !"); + if(nbTimes<1) + throw INTERP_KERNEL::Exception("DataArrayDouble::duplicateEachTupleNTimes : nb times should be >= 1 !"); + int nbTuples(this->getNumberOfTuples()); + const T *inPtr(this->begin()); + MCAuto::ArrayType> ret(Traits::ArrayType::New()); ret->alloc(nbTimes*nbTuples,1); + T *retPtr(ret->getPointer()); + for(int i=0;icopyStringInfoFrom(*this); + return ret.retn(); + } + + template + void DataArrayTemplateClassic::aggregate(const typename Traits::ArrayType *other) + { + if(!other) + throw INTERP_KERNEL::Exception("DataArrayDouble::aggregate : null pointer !"); + if(this->getNumberOfComponents()!=other->getNumberOfComponents()) + throw INTERP_KERNEL::Exception("DataArrayDouble::aggregate : mismatch number of components !"); + this->_mem.insertAtTheEnd(other->begin(),other->end()); + } + + /*! + * Converts every value of \a this array to its absolute value. + * \b WARNING this method is non const. If a new DataArrayDouble instance should be built containing the result of abs DataArrayDouble::computeAbs + * should be called instead. + * + * \throw If \a this is not allocated. + * \sa DataArrayDouble::computeAbs + */ + template + void DataArrayTemplateClassic::abs() + { + this->checkAllocated(); + T *ptr(this->getPointer()); + std::size_t nbOfElems(this->getNbOfElems()); + std::transform(ptr,ptr+nbOfElems,ptr,std::ptr_fun(std::abs)); + this->declareAsNew(); + } + + /*! + * This method builds a new instance of \a this object containing the result of std::abs applied of all elements in \a this. + * This method is a const method (that do not change any values in \a this) contrary to DataArrayDouble::abs method. + * + * \return DataArrayDouble * - the new instance of DataArrayDouble containing the + * same number of tuples and component as \a this array. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If \a this is not allocated. + * \sa DataArrayDouble::abs + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::computeAbs() const + { + this->checkAllocated(); + MCAuto::ArrayType> newArr(Traits::ArrayType::New()); + int nbOfTuples(this->getNumberOfTuples()); + int nbOfComp(this->getNumberOfComponents()); + newArr->alloc(nbOfTuples,nbOfComp); + std::transform(this->begin(),this->end(),newArr->getPointer(),std::ptr_fun(std::abs)); + newArr->copyStringInfoFrom(*this); + return newArr.retn(); + } + + /*! + * Returns either a \a deep or \a shallow copy of this array. For more info see + * \ref MEDCouplingArrayBasicsCopyDeep and \ref MEDCouplingArrayBasicsCopyShallow. + * \param [in] dCpy - if \a true, a deep copy is returned, else, a shallow one. + * \return DataArrayDouble * - either a new instance of DataArrayDouble (if \a dCpy + * == \a true) or \a this instance (if \a dCpy == \a false). + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::performCopyOrIncrRef(bool dCpy) const + { + const typename Traits::ArrayType *thisC(static_cast::ArrayType *>(this)); + return DataArrayTemplateClassic::PerformCopyOrIncrRef(dCpy,*thisC); + } + + /*! + * Computes for each tuple the sum of number of components values in the tuple and return it. + * + * \return DataArrayDouble * - the new instance of DataArrayDouble containing the + * same number of tuples as \a this array and one component. + * The caller is to delete this result array using decrRef() as it is no more + * needed. + * \throw If \a this is not allocated. + */ + template + typename Traits::ArrayType *DataArrayTemplateClassic::sumPerTuple() const + { + this->checkAllocated(); + std::size_t nbOfComp(this->getNumberOfComponents()),nbOfTuple(this->getNumberOfTuples()); + MCAuto::ArrayType> ret(Traits::ArrayType::New()); + ret->alloc(nbOfTuple,1); + const T *src(this->begin()); + T *dest(ret->getPointer()); + for(std::size_t i=0;igetNumberOfComponents() != 1 + * \throw If \a this is not allocated. + */ + template + void DataArrayTemplateClassic::iota(T init) + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayDouble::iota : works only for arrays with only one component, you can call 'rearrange' method before !"); + T *ptr(this->getPointer()); + std::size_t ntuples(this->getNumberOfTuples()); + for(std::size_t i=0;ideclareAsNew(); + } + + template + struct ImplReprTraits { static void SetPrecision(std::ostream& oss) { } }; + + template<> + struct ImplReprTraits { static void SetPrecision(std::ostream& oss) { oss.precision(17); } }; + + template<> + struct ImplReprTraits { static void SetPrecision(std::ostream& oss) { oss.precision(7); } }; + + template + void DataArrayTemplateClassic::reprStream(std::ostream& stream) const + { + stream << "Name of " << Traits::ReprStr << " array : \"" << this->_name << "\"\n"; + reprWithoutNameStream(stream); + } + + template + void DataArrayTemplateClassic::reprZipStream(std::ostream& stream) const + { + stream << "Name of " << Traits::ReprStr << " array : \"" << this->_name << "\"\n"; + reprZipWithoutNameStream(stream); + } + + template + void DataArrayTemplateClassic::reprNotTooLongStream(std::ostream& stream) const + { + stream << "Name of "<< Traits::ReprStr << " array : \"" << this->_name << "\"\n"; + reprNotTooLongWithoutNameStream(stream); + } + + template + void DataArrayTemplateClassic::reprWithoutNameStream(std::ostream& stream) const + { + DataArray::reprWithoutNameStream(stream); + ImplReprTraits::SetPrecision(stream); + this->_mem.repr(this->getNumberOfComponents(),stream); + } + + template + void DataArrayTemplateClassic::reprZipWithoutNameStream(std::ostream& stream) const + { + DataArray::reprWithoutNameStream(stream); + ImplReprTraits::SetPrecision(stream); + this->_mem.reprZip(this->getNumberOfComponents(),stream); + } + + template + void DataArrayTemplateClassic::reprNotTooLongWithoutNameStream(std::ostream& stream) const + { + DataArray::reprWithoutNameStream(stream); + ImplReprTraits::SetPrecision(stream); + this->_mem.reprNotTooLong(this->getNumberOfComponents(),stream); + } + + /*! + * This method is close to repr method except that when \a this has more than 1000 tuples, all tuples are not + * printed out to avoid to consume too much space in interpretor. + * \sa repr + */ + template + std::string DataArrayTemplateClassic::reprNotTooLong() const + { + std::ostringstream ret; + reprNotTooLongStream(ret); + return ret.str(); + } + + ///////////////////////////////// + + /*! + * Checks if all values in \a this array are equal to \a val at precision \a eps. + * \param [in] val - value to check equality of array values to. + * \param [in] eps - precision to check the equality. + * \return bool - \a true if all values are in range (_val_ - _eps_; _val_ + _eps_), + * \a false else. + * \throw If \a this->getNumberOfComponents() != 1 + * \throw If \a this is not allocated. + */ + template + bool DataArrayTemplateFP::isUniform(T val, T eps) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayDouble::isUniform : must be applied on DataArrayDouble with only one component, you can call 'rearrange' method before !"); + const T *w(this->begin()),*end2(this->end()); + const T vmin(val-eps),vmax(val+eps); + for(;w!=end2;w++) + if(*wvmax) + return false; + return true; + } + + /*! + * Equivalent to DataArrayInt::isEqual except that if false the reason of + * mismatch is given. + * + * \param [in] other the instance to be compared with \a this + * \param [out] reason In case of inequality returns the reason. + * \sa DataArrayInt::isEqual + */ + template + bool DataArrayDiscrete::isEqualIfNotWhy(const DataArrayDiscrete& other, std::string& reason) const + { + if(!this->areInfoEqualsIfNotWhy(other,reason)) + return false; + return this->_mem.isEqual(other._mem,0,reason); + } + + /*! + * Checks if \a this and another DataArrayInt are fully equal. For more info see + * \ref MEDCouplingArrayBasicsCompare. + * \param [in] other - an instance of DataArrayInt to compare with \a this one. + * \return bool - \a true if the two arrays are equal, \a false else. + */ + template + bool DataArrayDiscrete::isEqual(const DataArrayDiscrete& other) const + { + std::string tmp; + return isEqualIfNotWhy(other,tmp); + } + + /*! + * Checks if values of \a this and another DataArrayInt are equal. For more info see + * \ref MEDCouplingArrayBasicsCompare. + * \param [in] other - an instance of DataArrayInt to compare with \a this one. + * \return bool - \a true if the values of two arrays are equal, \a false else. + */ + template + bool DataArrayDiscrete::isEqualWithoutConsideringStr(const DataArrayDiscrete& other) const + { + std::string tmp; + return this->_mem.isEqual(other._mem,0,tmp); + } + + /*! + * Checks if values of \a this and another DataArrayInt are equal. Comparison is + * performed on sorted value sequences. + * For more info see\ref MEDCouplingArrayBasicsCompare. + * \param [in] other - an instance of DataArrayInt to compare with \a this one. + * \return bool - \a true if the sorted values of two arrays are equal, \a false else. + */ + template + bool DataArrayDiscrete::isEqualWithoutConsideringStrAndOrder(const typename Traits::ArrayType& other) const + { + MCAuto a(static_cast::ArrayType *>(this)->deepCopy()),b(other.deepCopy()); + a->sort(); + b->sort(); + return a->isEqualWithoutConsideringStr(*b); + } + + template + template + void DataArrayDiscrete::switchOnTupleAlg(T val, std::vector& vec, ALG algo) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::switchOnTupleEqualTo : number of components of this should be equal to one !"); + int nbOfTuples(this->getNumberOfTuples()); + if(nbOfTuples!=(int)vec.size()) + throw INTERP_KERNEL::Exception("DataArrayInt::switchOnTupleEqualTo : number of tuples of this should be equal to size of input vector of bool !"); + const T *pt(this->begin()); + for(int i=0;i + void DataArrayDiscrete::switchOnTupleEqualTo(T val, std::vector& vec) const + { + switchOnTupleAlg(val,vec,std::equal_to()); + } + + /*! + * This method assumes that \a this has one component and is allocated. This method scans all tuples in \a this and for all tuple different from \a val + * put True to the corresponding entry in \a vec. + * \a vec is expected to be with the same size than the number of tuples of \a this. + * + * \sa DataArrayInt::switchOnTupleEqualTo. + */ + template + void DataArrayDiscrete::switchOnTupleNotEqualTo(T val, std::vector& vec) const + { + switchOnTupleAlg(val,vec,std::not_equal_to()); + } + + /*! + * Creates a new one-dimensional DataArrayInt of the same size as \a this and a given + * one-dimensional arrays that must be of the same length. The result array describes + * correspondence between \a this and \a other arrays, so that + * other.getIJ(i,0) == this->getIJ(ret->getIJ(i),0). If such a permutation is + * not possible because some element in \a other is not in \a this, an exception is thrown. + * \param [in] other - an array to compute permutation to. + * \return DataArrayInt * - a new instance of DataArrayInt, which is a permutation array + * from \a this to \a other. The caller is to delete this array using decrRef() as it is + * no more needed. + * \throw If \a this->getNumberOfComponents() != 1. + * \throw If \a other->getNumberOfComponents() != 1. + * \throw If \a this->getNumberOfTuples() != \a other->getNumberOfTuples(). + * \throw If \a other includes a value which is not in \a this array. + * + * \if ENABLE_EXAMPLES + * \ref cpp_mcdataarrayint_buildpermutationarr "Here is a C++ example". + * + * \ref py_mcdataarrayint_buildpermutationarr "Here is a Python example". + * \endif + */ + template + DataArrayIdType *DataArrayDiscrete::buildPermutationArr(const DataArrayDiscrete& other) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1 || other.getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::buildPermutationArr : 'this' and 'other' have to have exactly ONE component !"); + std::size_t nbTuple(this->getNumberOfTuples()); + other.checkAllocated(); + if(nbTuple!=other.getNumberOfTuples()) + throw INTERP_KERNEL::Exception("DataArrayInt::buildPermutationArr : 'this' and 'other' must have the same number of tuple !"); + MCAuto ret(DataArrayIdType::New()); + ret->alloc(nbTuple,1); + ret->fillWithValue(-1); + const T *pt(this->begin()); + std::map mm; + for(std::size_t i=0;igetPointer()); + for(std::size_t i=0;i::const_iterator it=mm.find(pt[i]); + if(it==mm.end()) + { + std::ostringstream oss; oss << "DataArrayInt::buildPermutationArr : Arrays mismatch : element (" << pt[i] << ") in 'other' not findable in 'this' !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + retToFill[i]=(*it).second; + } + return ret.retn(); + } + + /*! + * Elements of \a partOfThis are expected to be included in \a this. + * The returned array \a ret is so that this[ret]==partOfThis + * + * For example, if \a this array contents are [9,10,0,6,4,11,3,8] and if \a partOfThis contains [6,0,11,8] + * the return array will contain [3,2,5,7]. + * + * \a this is expected to be a 1 compo allocated array. + * \param [in] partOfThis - A 1 compo allocated array + * \return - A newly allocated array to be dealed by caller having the same number of tuples than \a partOfThis. + * \throw if two same element is present twice in \a this + * \throw if an element in \a partOfThis is \b NOT in \a this. + */ + template + DataArrayIdType *DataArrayDiscrete::indicesOfSubPart(const DataArrayDiscrete& partOfThis) const + { + if(this->getNumberOfComponents()!=1 || partOfThis.getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::indicesOfSubPart : this and input array must be one component array !"); + this->checkAllocated(); partOfThis.checkAllocated(); + std::size_t thisNbTuples(this->getNumberOfTuples()),nbTuples(partOfThis.getNumberOfTuples()); + const T *thisPt(this->begin()),*pt(partOfThis.begin()); + MCAuto ret(DataArrayIdType::New()); + ret->alloc(nbTuples,1); + T *retPt(ret->getPointer()); + std::map m; + for(std::size_t i=0;i::const_iterator it(m.find(*pt)); + if(it!=m.end()) + *retPt=(*it).second; + else + { + std::ostringstream oss; oss << "DataArrayInt::indicesOfSubPart : At pos #" << i << " of input array value is " << *pt << " not in this !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + } + return ret.retn(); + } + + /*! + * Checks that \a this array is consistently **increasing** or **decreasing** in value. + * If not an exception is thrown. + * \param [in] increasing - if \a true, the array values should be increasing. + * \throw If sequence of values is not strictly monotonic in agreement with \a + * increasing arg. + * \throw If \a this->getNumberOfComponents() != 1. + * \throw If \a this is not allocated. + */ + template + void DataArrayDiscrete::checkMonotonic(bool increasing) const + { + if(!isMonotonic(increasing)) + { + if (increasing) + throw INTERP_KERNEL::Exception("DataArrayInt::checkMonotonic : 'this' is not INCREASING monotonic !"); + else + throw INTERP_KERNEL::Exception("DataArrayInt::checkMonotonic : 'this' is not DECREASING monotonic !"); + } + } + + /*! + * Checks that \a this array is consistently **increasing** or **decreasing** in value. + * \param [in] increasing - if \a true, array values should be increasing. + * \return bool - \a true if values change in accordance with \a increasing arg. + * \throw If \a this->getNumberOfComponents() != 1. + * \throw If \a this is not allocated. + */ + template + bool DataArrayDiscrete::isMonotonic(bool increasing) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::isMonotonic : only supported with 'this' array with ONE component !"); + std::size_t nbOfElements(this->getNumberOfTuples()); + const T *ptr(this->begin()); + if(nbOfElements==0) + return true; + T ref(ptr[0]); + if(increasing) + { + for(std::size_t i=1;i=ref) + ref=ptr[i]; + else + return false; + } + } + else + { + for(std::size_t i=1;i + bool DataArrayDiscrete::isStrictlyMonotonic(bool increasing) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::isStrictlyMonotonic : only supported with 'this' array with ONE component !"); + std::size_t nbOfElements(this->getNumberOfTuples()); + const T *ptr(this->begin()); + if(nbOfElements==0) + return true; + T ref(ptr[0]); + if(increasing) + { + for(std::size_t i=1;iref) + ref=ptr[i]; + else + return false; + } + } + else + { + for(std::size_t i=1;i + void DataArrayDiscrete::checkStrictlyMonotonic(bool increasing) const + { + if(!isStrictlyMonotonic(increasing)) + { + if (increasing) + throw INTERP_KERNEL::Exception("DataArrayInt::checkStrictlyMonotonic : 'this' is not strictly INCREASING monotonic !"); + else + throw INTERP_KERNEL::Exception("DataArrayInt::checkStrictlyMonotonic : 'this' is not strictly DECREASING monotonic !"); + } + } + + //////////////////////////////////// + + /*! + * This method compares content of input vector \a v and \a this. + * If for each id in \a this v[id]==True and for all other ids id2 not in \a this v[id2]==False, true is returned. + * For performance reasons \a this is expected to be sorted ascendingly. If not an exception will be thrown. + * + * \param [in] v - the vector of 'flags' to be compared with \a this. + * + * \throw If \a this is not sorted ascendingly. + * \throw If \a this has not exactly one component. + * \throw If \a this is not allocated. + */ + template + bool DataArrayDiscreteSigned::isFittingWith(const std::vector& v) const + { + this->checkAllocated(); + if(this->getNumberOfComponents()!=1) + throw INTERP_KERNEL::Exception("DataArrayInt::isFittingWith : number of components of this should be equal to one !"); + const T *w(this->begin()),*end2(this->end()); + T refVal=-std::numeric_limits::max(); + int i=0; + std::vector::const_iterator it(v.begin()); + for(;it!=v.end();it++,i++) + { + if(*it) + { + if(w!=end2) + { + if(*w++==i) + { + if(i>refVal) + refVal=i; + else + { + std::ostringstream oss; oss << "DataArrayInt::isFittingWith : At pos #" << std::distance(this->begin(),w-1) << " this is not sorted ascendingly !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } + else + return false; + } + else + return false; + } + } + return w==end2; + } } #endif