// Gestion de block de donnees avec partage de references // malheureusement tres mal concu... C.Magneville 04/99 // LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA #include "machdefs.h" #include #include #include #include #include "pexceptions.h" #include "ndatablock.h" #include "objfio.h" using namespace PlanckDPC; // define DEBUG_NDATABLOCK #ifdef DEBUG_NDATABLOCK static size_t NallocData = 0; static size_t NallocSRef = 0; #endif //////////////////////////////////////////////////////////////// //************ Createur, Destructeur template NDataBlock::NDataBlock(size_t n) // Createur d'une structure de "n" donnees : mSz(0), mSRef(NULL), mIsTemp(false) { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::NDataBlock("< NDataBlock::NDataBlock(size_t n, T* data, Bridge* br) // Createur d'une structure de "n" donnees, avec donnees preallouees. // Attention createur TRES DANGEREUX (Voir explications dans Alloc()). : mSz(0), mSRef(NULL), mIsTemp(false) { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::NDataBlock("< NDataBlock::NDataBlock() // Createur par default : mSz(0), mSRef(NULL), mIsTemp(false) { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::NDataBlock("< NDataBlock::NDataBlock(const NDataBlock& a) // Createur par copie: partage les donnees si "a" temporaire, clone sinon. : mSz(0), mSRef(NULL), mIsTemp(false) { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::NDataBlock("< NDataBlock::NDataBlock(const NDataBlock& a,bool share) // Createur avec choix de partager ou non selon "share" : mSz(0), mSRef(NULL), mIsTemp(false) { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::NDataBlock("< NDataBlock::~NDataBlock() // Destructeur { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::~NDataBlock("< void NDataBlock::Alloc(size_t n,T* data,Bridge* br) // Allocation d'un NOUVEL espace de stoquage de "n" donnees // Si data==NULL : allocation de l'espace memoire (remplit de zeros) // data!=NULL : partage des donnees avec l'adresse data // Si br==NULL : les donnees nous appartiennent // br!=NULL : les donnees ne nous appartiennent pas (ex: Blitz) // // Exemple: on veut connecter a un tableau de T* // > float *x = new float[5]; ... remplissage de x[] ...; // 1- On veut que NDataBlock NE DESALLOUE PAS le tableau "x[]" // a- Premiere solution // > NDataBlock A(5,x,new Bridge); // ...... // > delete [] x; // - Il faut deleter x[] explicitement. // - Le destructeur de "A" ne detruit pas x[]. // ATTENTION: Une fois x[] detruit, "A" ne peut // plus acceder les donnees! // - Bridge est detruit par le destructeur de "A" // b- Autre solution: // > NDataBlock A(5); A.FillFrom(5,x); // > delete [] x; // ...... // - Il faut deleter x[] explicitement. // - "A" possede une copie en local de x[]. // - Le destructeur de "A" ne detruit pas x[] mais la copie locale. // 2- On veut que NDataBlock desalloue le tableau // > NDataBlock A(5,x); // - Ne Pas Faire "delete [] x;" // - "A" partage les donnees avec x[]. // - Le destructeur de "A" detruit x[]. // // --- REMARQUE SUR LE DANGER DE CERTAINES SITUATIONS (CMV): // 1-/ x = new float[n1]; NDataBlock A(n2,x); // 1er danger: si n2>n1 depassement de tableaux (core dump) // 2sd danger: celui qui alloue x[] ne doit pas faire le "delete" // en desaccord avec toutes les regles de bonne conduite. // 2-/ float x[5]={1,2,3,4,5}; {NDataBlock A(n2,&x[0]);} cout<n1 depassement de tableaux (core dump) // 2sd danger: si la methode bridgee (blitz?) detruit x[] // "A" n'a plus de donnees connectees! // --- CONCLUSION // Cette classe est franchement merdique. // - On peut accepter la prise de risque liee a NDataBlock(n2,x,new Bridge); // car je ne vois pas comment on pourrait faire autrement pour connecter // un tableau de type blitz par exemple. // - Par contre le createur NDataBlock(n2,x); doit etre interdit // dans sa forme actelle car trop dangereux et il me semble inutile. // - Dans cette nouvelle optique: // NDataBlock(n2,x,new Bridge) et NDataBlock(n2,x) disparaissent // On remplace par NDataBlock(n2,x) {Alloc(n2,x,new Bridge);} // qui force le Bridge dans tout les cas puisque NDataBlock // ne possede pas les donnees. // Mais puis-je encore le faire vu que NDataBlock est a la base // de TVector,TMatrix et qu'il faut donc reprendre tout le code DPC // - Quoiqu'il arrive Alloc est une methode privee et peut donc rester // sous sa forme actuelle. // { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::Alloc("<nref = 1; if(data) mSRef->data = data; else {mSRef->data = new T[n]; memset(mSRef->data,0,n*sizeof(T));} mSRef->bridge = br; #ifdef DEBUG_NDATABLOCK // Meme dans le cas data!=0 et br==0 (connexion d'un tableau // avec destruction geree par ~NDataBlock (cas 2-) on compte // comme si on avait fait une allocation du tableau (ce qui a ete // fait au niveau du dessus!). if(!br) NallocData++; NallocSRef++; cout<<"...?_NDataBlock::Alloc mSz="<nref="<nref<<" mSRef->data="<< mSRef->data <<" mSRef->bridge="<bridge<<" IsTemp="< void NDataBlock::Clone(const NDataBlock& a) // Clone: copie de donnees a partir de "a" { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::Clone("< void NDataBlock::CloneOrShare(const NDataBlock& a) // CloneOrShare: Share si "a" temporaire, Clone sinon. { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::CloneOrShare("< void NDataBlock::Share(const NDataBlock& a) // Share: Partage les donnees avec "a" { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::Share("<nref++; #ifdef DEBUG_NDATABLOCK cout<<"...?_NDataBlock::Share mSz="<nref="<nref<<" mSRef->data="<< mSRef->data <<" mSRef->bridge="<bridge<<" IsTemp="< void NDataBlock::Delete(void) // Pour detruire les pointeurs en tenant compte des references { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::Delete("<nref="<nref<<" mSRef->data=" <data<<" mSRef->bridge="<bridge; cout<nref--; if(mSRef->nref != 0) { #ifdef DEBUG_NDATABLOCK cout<<"...?_NDataBlock::Delete() pas de desallocation il reste nref=" <nref<<" Total("<bridge) NallocData--; NallocSRef--; cout<<"...?_NDataBlock::Delete() desallocation complete il reste nref=" <nref<<" Total("<bridge) delete mSRef->bridge; else delete [] mSRef->data; mSRef->bridge=NULL; mSRef->data=NULL; delete mSRef; mSRef=NULL; mSz = 0; } template void NDataBlock::FillFrom(size_t n,T* data) // Remplissage par un tableau de donnees // - Si classe vide : creation de l'espace memoire // - Si classe connectee : on ecrit selon la longueur minimale // (cad this->mSz ou "n") { if(data==NULL) throw(NullPtrError("NDataBlock::FillFrom data==NULL\n")); if(n==0) throw(ParmError("NDataBlock::FillFrom n<=0\n")); if(mSRef==NULL) Alloc(n); if(mSz void NDataBlock::Realloc(size_t nnew,bool force) // Re-allocation de "nnew" place memoire pour les donnees // avec conservation des "nold" donnees precedentes si possible. // "force" gere la re-allocation de la place memoire pour les donnees. // Divers cas se presentent: // a-/ *** nnew>nold force=quelconque *** // place re-allouee, donnees [0,nold[ copiees, surplus [nold,new[ mis a zero // b-/ *** nnew<=nold force=true *** // place re-allouee, donnees [0,nnew[ copiees, pas de surplus // c-/ *** nnew<=nold force=false *** // place non re-allouee, seule la valeur de la taille est diminuee // - On tient compte du partage des donnees dans tous les cas. // - Si il n'y a pas de donnees connectees a la classe, on re-alloue // dans tous les cas { if(nnew==0) throw(ParmError("NDataBlock::Realloc n<=0\n")); // Cas sans re-allocation memoire if(mSRef && nnew<=mSz && ! force) { mSz=nnew; return;} // Cas avec re-allocation memoire size_t ncop; if(!mSRef || mSz==0) ncop=0; else if(mSz0) memcpy(dataloc,mSRef->data,ncop*sizeof(T)); if(nnew>ncop) memset(dataloc+ncop,0,(nnew-ncop)*sizeof(T)); Alloc(nnew,dataloc,NULL); //Alloc gere partage de reference et bridge } //////////////////////////////////////////////////////////////// //**** Impression template void NDataBlock::Print(ostream& os,size_t i1,size_t n) const // Impression de n elements a partir de i1 { size_t nr = 0; T* p = NULL; Bridge* br = NULL; if(mSRef) {nr = mSRef->nref; p = mSRef->data; br = mSRef->bridge;} os<<"NDataBlock::Print("<=mSz || n<=0 || !p) return; size_t i2 = i1+n; if(i2>mSz) i2=mSz; size_t im = 1; bool enl=false; while(i1 T NDataBlock::Sum(size_t i1,size_t n) const // Somme des elements de i1 a i1+n-1 { if(i1>=mSz) return 0; if(n>mSz) n = mSz; if(n==0) n = mSz-i1; T const *p=Begin()+i1, *pe=p+n; T val = 0; while (p T NDataBlock::Product(size_t i1,size_t n) const // Produit des elements de i1 a i1+n-1 { if(i1>=mSz) return 0; if(n>mSz) n = mSz; if(n==0) n = mSz-i1; T const *p=Begin()+i1, *pe=p+n; T val = 0; while (p b; template NDataBlock& NDataBlock::operator = (const NDataBlock& a) // Affectation: partage des donnees si "a" temporaire, clone sinon. { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::operator=("< NDataBlock& NDataBlock::operator = (T v) // Affectation de tous les elements a une constante "v" { #ifdef DEBUG_NDATABLOCK cout<<"?_NDataBlock::operator=("< b; template NDataBlock& NDataBlock::operator += (T b) { if(mSz==0) throw(SzMismatchError("NDataBlock::operator+=v null size\n")); T *p=Begin(), *pe=End(); while (p NDataBlock& NDataBlock::operator -= (T b) { if(mSz==0) throw(SzMismatchError("NDataBlock::operator-=v null size\n")); T *p=Begin(), *pe=End(); while (p NDataBlock& NDataBlock::operator *= (T b) { if(mSz==0) throw(SzMismatchError("NDataBlock::operator*=v null size\n")); T *p=Begin(), *pe=End(); while (p NDataBlock& NDataBlock::operator /= (T b) { if(b==(T) 0) throw(ParmError("NDataBlock::operator/=v divide by zero\n")); if(mSz==0) throw(SzMismatchError("NDataBlock::operator/=v null size\n")); T *p=Begin(), *pe=End(); while (p NDataBlock& NDataBlock::operator += (const NDataBlock& a) { if(mSz==0 || mSz!=a.mSz) throw(SzMismatchError("NDataBlock::operator+=A size mismatch/null")); T *p=Begin(), *pe=End(); T const * pa=a.Begin(); while (p NDataBlock& NDataBlock::operator -= (const NDataBlock& a) { if(mSz==0 || mSz!=a.mSz) throw(SzMismatchError("NDataBlock::operator-=A size mismatch/null")); T *p=Begin(), *pe=End(); T const *pa=a.Begin(); while (p NDataBlock& NDataBlock::operator *= (const NDataBlock& a) { if(mSz==0 || mSz!=a.mSz) throw(SzMismatchError("NDataBlock::operator*=A size mismatch/null")); T *p=Begin(), *pe=End(); T const *pa=a.Begin(); while (p NDataBlock& NDataBlock::operator /= (const NDataBlock& a) // Attention, aucune protection si un element de "a" est nul. { if(mSz==0 || mSz!=a.mSz) throw(SzMismatchError("NDataBlock::operator/=A size mismatch/null")); T *p=Begin(), *pe=End(); T const *pa=a.Begin(); while (pb; // NDataBlock = b+NDataBlock; template NDataBlock NDataBlock::Add(T b) const // Pour A+b { NDataBlock result(*this); result.SetTemp(true); result += b; return result; } template NDataBlock NDataBlock::Sub(T b) const // Pour A-b { NDataBlock result(*this); result.SetTemp(true); return result -= b; } template NDataBlock NDataBlock::SubInv(T b) const // Pour b-A { NDataBlock result(*this); result.SetTemp(true); T *p=result.Begin(), *pe=result.End(); T const *pa=this->Begin(); while(p NDataBlock NDataBlock::Mul(T b) const // Pour A*b { NDataBlock result(*this); result.SetTemp(true); return result *= b; } template NDataBlock NDataBlock::Div(T b) const // Pour A/b { NDataBlock result(*this); result.SetTemp(true); return result /= b; } template NDataBlock NDataBlock::DivInv(T b) const // Pour b/A { NDataBlock result(*this); result.SetTemp(true); T *p=result.Begin(), *pe=result.End(); T const *pa = this->Begin(); while(p NDataBlock NDataBlock::Add(const NDataBlock& b) const // Pour A+B { if(mSz!=b.mSz) throw(SzMismatchError("NDataBlock operator C=A+B size mismatch/null\n")); NDataBlock result; result.SetTemp(true); if(b.IsTemp()) {result.Share(b); result += *this;} else {result.CloneOrShare(*this); result += b;} return result; } template NDataBlock NDataBlock::Mul(const NDataBlock& b) const // Pour A*B { if(mSz!=b.mSz) throw(SzMismatchError("NDataBlock operator C=A*B size mismatch/null\n")); NDataBlock result; result.SetTemp(true); if(b.IsTemp()) {result.Share(b); result *= *this;} else {result.CloneOrShare(*this); result *= b;} return result; } template NDataBlock NDataBlock::Sub(const NDataBlock& b) const // Pour A-B { if(mSz!=b.mSz) throw(SzMismatchError("NDataBlock operator C=A-B size mismatch/null\n")); NDataBlock result; result.SetTemp(true); if(b.IsTemp()) { result.Share(b); T *p=result.Begin(), *pe=result.End(); T const *pa=Begin(); while(p NDataBlock NDataBlock::Div(const NDataBlock& b) const // Pour A/B { if(mSz!=b.mSz) throw(SzMismatchError("NDataBlock operator C=A/B size mismatch/null\n")); NDataBlock result; result.SetTemp(true); if(b.IsTemp()) { result.Share(b); T *p=result.Begin(), *pe=result.End(); T const *pa=Begin(); while(p void ObjFileIO< NDataBlock >::ReadSelf(PInPersist& is) template void ObjFileIO< NDataBlock >::WriteSelf(POutPersist& os) */ // Pour pouvoir ecrire des tableaux de complex, en attendant // PIn/POutPersist::Get/Put(complex<>) #include "piocmplx.h" template FIO_NDataBlock::FIO_NDataBlock() { dobj=new NDataBlock; ownobj=true; } template FIO_NDataBlock::FIO_NDataBlock(string const & filename) { dobj=new NDataBlock; ownobj=true; Read(filename); } template FIO_NDataBlock::FIO_NDataBlock(const NDataBlock & obj) { dobj = new NDataBlock(obj); ownobj=true; } template FIO_NDataBlock::FIO_NDataBlock(NDataBlock * obj) { dobj = obj; ownobj=false; } template FIO_NDataBlock::~FIO_NDataBlock() { if (ownobj && dobj) delete dobj; } template AnyDataObj* FIO_NDataBlock::DataObj() { return(dobj); } template void FIO_NDataBlock::ReadSelf(PInPersist& is) { // On lit les 3 premiers uint_8 uint_8 itab[3]; is.Get(itab, 3); if (dobj == NULL) dobj = new NDataBlock(itab[1]); else if (itab[1] != dobj->Size()) dobj->ReSize(itab[1]); // On lit le tableau de nombres PIOSReadArray(is, dobj->Data(), dobj->Size()); } template void FIO_NDataBlock::WriteSelf(POutPersist& os) const { if (dobj == NULL) return; // Attention - $CHECK$ Reza 26/04/99 // On ecrit 3 uint_8 // 0 : Numero de version, 1 : Taille, 2 reserve a l uint_8 itab[3]; itab[0] = 1; itab[1] = dobj->Size(); itab[2] = 0; os.Put(itab, 3); // On ecrit le tableau de nombres PIOSWriteArray(os, dobj->Data(), dobj->Size()); } /////////////////////////////////////////////////////////////// #ifdef __CXX_PRAGMA_TEMPLATES__ #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock #pragma define_template NDataBlock< complex > #pragma define_template NDataBlock< complex > // Instances des delegues FileIO (PPersist) #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock #pragma define_template FIO_NDataBlock< complex > #pragma define_template FIO_NDataBlock< complex > #endif #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES) template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock; template class NDataBlock< complex >; template class NDataBlock< complex >; // Instances des delegues FileIO (PPersist) template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock; template class FIO_NDataBlock< complex >; template class FIO_NDataBlock< complex >; #endif