source: Sophya/trunk/SophyaLib/BaseTools/ndatablock.cc@ 3460

Last change on this file since 3460 was 3212, checked in by ansari, 18 years ago

Remplacement include thsafeop.h par declaration de la classe ThSafeOp ds ndatablock.h, Reza 11/04/2007

File size: 27.5 KB
Line 
1// Gestion de block de donnees avec partage de references
2// malheureusement tres mal concu... C.Magneville 04/99
3// LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA
4#include "sopnamsp.h"
5#include "machdefs.h"
6#include <stdio.h>
7#include <stdlib.h>
8#include <iostream>
9#include <complex>
10#include "pexceptions.h"
11#include "ndatablock.h"
12#include "thsafeop.h" // for ThreadSafe operations (Ref.Count/Share)
13
14/* ---- Pour renvoyer un identificateur unique ---- */
15static uint_8 _ndrefid_ = 0; // Identificateur de NDREF cree
16uint_8 AnyDataObj::getUniqueId()
17{
18 _ndrefid_++;
19 return ( _ndrefid_ );
20}
21
22/*!
23 \class SOPHYA::NDataBlock
24 \ingroup BaseTools
25 Management of data blocks
26*/
27
28//////////////////////////////////
29// Fonctionnement en mode debug //
30//////////////////////////////////
31
32template <class T> int NDataBlock<T>::Debug_NDataBlock = 0;
33template <class T> size_t NDataBlock<T>::NallocData = 0;
34template <class T> size_t NDataBlock<T>::NallocSRef = 0;
35template <class T> ThSafeOp* NDataBlock<T>::gThsop = NULL;
36
37//! Set debug (and level print) for allocation and references debug.
38/*!
39 \param prtlevel : activate/des-activate debug mode
40 and select print level
41
42 \arg prtlevel <= 0 : no debug
43 \arg prtlevel == 1 : debug activated, no print
44 \arg prtlevel >=2 : debug activated,
45 print infos in all routines that have something to do with
46 allocations or des-allocation of datas or references.
47 */
48template <class T>
49void NDataBlock<T>::SetPrintDebug(int prtdbglevel)
50{
51 Debug_NDataBlock = prtdbglevel;
52}
53
54//! Reset debug counter values.
55/*!
56 \param nallocdata : reset number of allocated data structures to \b nallocdata
57 \param nallocsref : reset number of allocated references to \b nallocsref
58 \warning In principle this routine should not be use (only experts)
59 */
60template <class T>
61void NDataBlock<T>::ResetDebug(size_t nallocdata, size_t nallocsref)
62{
63NallocData = nallocdata;
64NallocSRef = nallocsref;
65}
66
67//! Print debug current status.
68/*!
69 Print debug current status for number of allocated
70 data structures and number of allocated references.
71 */
72template <class T>
73void NDataBlock<T>::PrintDebug()
74{
75cout<<"... ... ... NallocData = "<<NallocData
76 <<" , NallocSRef = "<<NallocSRef
77 <<" ... ... ..."<<endl;
78}
79
80///////////////////////////
81// Createur, Destructeur //
82///////////////////////////
83
84//! Constructor for \b n datas. if \b zero=true, filled with zeros
85template <class T>
86NDataBlock<T>::NDataBlock(size_t n, bool fzero)
87// Createur d'une structure de "n" donnees
88: mSz(0), mSRef(NULL), mIsTemp(false)
89{
90if(Debug_NDataBlock>1)
91 cout<<"?_NDataBlock::NDataBlock("<<this<<",n="<<n<<")"<<endl;
92if (gThsop == NULL) gThsop = new ThSafeOp;
93
94Alloc(n, NULL, NULL, fzero); // allocation et mise a zero
95}
96
97//! Constructor for \b n datas shared with external
98/*!
99 Datas are previously allocated by an other external source.
100 \warning This require particular care (see Alloc)
101 \sa Alloc
102 */
103template <class T>
104NDataBlock<T>::NDataBlock(size_t n, T* data, Bridge* br)
105// Createur d'une structure de "n" donnees, avec donnees preallouees.
106// Attention createur TRES DANGEREUX (Voir explications dans Alloc()).
107: mSz(0), mSRef(NULL), mIsTemp(false)
108{
109if(Debug_NDataBlock>1)
110 cout<<"?_NDataBlock::NDataBlock("<<this
111 <<",data="<<data<<",br="<<br<<")"<<endl;
112if (gThsop == NULL) gThsop = new ThSafeOp;
113
114Alloc(n,data,br);
115}
116
117//! Default constructor
118template <class T>
119NDataBlock<T>::NDataBlock()
120// Createur par default
121: mSz(0), mSRef(NULL), mIsTemp(false)
122{
123if(Debug_NDataBlock>1)
124 cout<<"?_NDataBlock::NDataBlock("<<this<<") default"<<endl;
125if (gThsop == NULL) gThsop = new ThSafeOp;
126}
127
128//! Copy constructor
129/*!
130 \warning datas are \b SHARED with \b a.
131 */
132template <class T>
133NDataBlock<T>::NDataBlock(const NDataBlock<T>& a)
134// Createur par copie: partage les donnees dans tous les cas
135: mSz(0), mSRef(NULL), mIsTemp(false)
136{
137if(Debug_NDataBlock>1)
138 cout<<"?_NDataBlock::NDataBlock("<<this<<",&a="<<&a<<" a.mSz="<<a.mSz<<")"<<endl;
139
140if(a.mSRef && a.mSz>0) Share(a);
141}
142
143//! Copy constructor with \b share option
144/*!
145 \warning datas are shared if \b share is \b true, cloned if not.
146 */
147template <class T>
148NDataBlock<T>::NDataBlock(const NDataBlock<T>& a,bool share)
149// Createur avec choix de partager ou non selon "share"
150: mSz(0), mSRef(NULL), mIsTemp(false)
151{
152if(Debug_NDataBlock>1)
153 cout<<"?_NDataBlock::NDataBlock("<<this<<",&a="<<&a
154 <<",sh=<<"<<share<<")"<<endl;
155
156if(a.mSRef && a.mSz>0) {if(share) Share(a); else Clone(a);}
157}
158
159//! Destructor
160template <class T>
161NDataBlock<T>::~NDataBlock()
162// Destructeur
163{
164if(Debug_NDataBlock>1)
165 cout<<"?_NDataBlock::~NDataBlock("<<this<<")"<<endl;
166
167Dealloc(); // ThreadSafe version of Delete()
168}
169
170////////////////////////
171// Gestion de donnees //
172////////////////////////
173
174//! Clone datas from \b a
175template <class T>
176void NDataBlock<T>::Clone(const NDataBlock<T>& a)
177// Clone: copie de donnees a partir de "a"
178{
179if(Debug_NDataBlock>1)
180 cout<<"?_NDataBlock::Clone("<<this<<","<<&a<<") a.(mSz="
181 <<a.mSz<<" mSRef="<<a.mSRef<<" IsTemp="<<a.IsTemp()
182 <<"), mSz="<<mSz<<" mSRef="<<mSRef<<" IsTemp="<<mIsTemp<<endl;
183
184if(&a==NULL) throw(NullPtrError("NDataBlock::Clone &a==NULL\n"));
185if(!a.mSRef || a.mSz==0) throw(NullPtrError("NDataBlock::Clone a.mSz=0\n"));
186Alloc(a.mSz, NULL, NULL, false); // pas de mise a zero
187memcpy(Data(),a.Data(),mSz*sizeof(T));
188}
189
190//! Share datas with \b a
191template <class T>
192void NDataBlock<T>::Share(const NDataBlock<T>& a)
193// Share: Partage les donnees avec "a"
194{
195if(Debug_NDataBlock>1) {
196 cout<<"?_NDataBlock::Share("<<this<<","<<&a<<")";
197 if(&a!=NULL) cout<<" a.(mSz="<<a.mSz<<" mSRef="<<a.mSRef
198 <<" IsTemp="<<a.IsTemp()<<")";
199 cout<<", mSz="<<mSz<<" mSRef="<<mSRef<<" IsTemp="<<mIsTemp<<endl;
200}
201
202if(&a==NULL) throw(NullPtrError("NDataBlock::Share &a==NULL\n"));
203if(!a.mSRef || a.mSz==0) throw(NullPtrError("NDataBlock::Share a.mSz=0\n"));
204//--- Start of atomic (in one block) operation for thread safety
205gThsop->lock(); // (ThreadSafe)
206if(mSRef) Delete();
207mSz = a.mSz; mSRef = a.mSRef; mSRef->nref++;
208gThsop->unlock(); // (ThreadSafe)
209//--- End of atomic operation
210
211if(Debug_NDataBlock>1)
212 cout<<"...?_NDataBlock::Share mSz="<<mSz<<" mSRef="<<mSRef
213 <<" mSRef->nref="<<mSRef->nref<<" mSRef->data="<< mSRef->data
214 <<" mSRef->bridge="<<mSRef->bridge
215 <<" IsTemp="<<mIsTemp<<endl;
216}
217
218//! \b Share with \b a if \b temporary, \b clone from \b a if not.
219/*! \warning For most purposes, users don't have to worry with
220 the "temporary" nature of a NDataBlock. That is used
221 internaly to avoid memory allocation in operation
222 like A = B + C + D for instance. The method is not
223 protected to allow users to write complicated functions
224 on NDataBlock.
225 \verbatim
226 ----------------------------------------------------------
227 Pourquoi une complication avec la notion de "temporaire" :
228 ----------------------------------------------------------
229 - Le constructeur par copie partageant les donnees,
230 dans une methode un { NDataBlock<T> result; ...; return result;}
231 ne va pas allouer de la memoire pour retourner "result".
232 - La gestion de temporaire sert quand on enchaine plusieurs
233 operations sur la meme ligne, par exemple : A = B+C+D;
234 Dans ce cas l'objet CD=C+D est d'abord alloue et rempli
235 avec C+D, puis CD est mis a "temporaire".
236 Quand on ajoute B a CD, la methode d'addition va se rendre compte
237 que CD est "temporaire" et additionner B "in-place" dans CD
238 sans allouer une fois de plus de la place (pas d'allocation
239 de place BCD pour mettre B+CD mais une operation CD += B).
240 Si la notion d'objet "temporaire" n'avait pas ete consideree
241 l'addition A = B+C+D aurait alloue de la place pour "CD=C+D"
242 puis pour BCD=B+CD : 2 allocations auraient ete necessaires
243 contre 1 seule dans notre cas de geston de "temporaire".
244 \endverbatim
245*/
246template <class T>
247void NDataBlock<T>::CloneOrShare(const NDataBlock<T>& a)
248// CloneOrShare: Share si "a" temporaire, Clone sinon.
249{
250if(Debug_NDataBlock>1)
251 cout<<"?_NDataBlock::CloneOrShare("<<this<<","<<&a<<")"<<endl;
252
253if(&a==NULL) throw(NullPtrError("NDataBlock::CloneOrShare &a==NULL\n"));
254if(a.IsTemp()) Share(a); else Clone(a);
255}
256
257////////////////////////////////////////////////////////////
258// Allocation , destruction , remplissage et reallocation //
259////////////////////////////////////////////////////////////
260
261//! Allocation management
262/*!
263 Allocation d'un NOUVEL espace de stoquage de "n" donnees
264 \verbatim
265 Si data==NULL : allocation de l'espace memoire
266 si zero == true , l'espace est remplis de zeros
267 data!=NULL : partage des donnees avec l'adresse data
268 Si br==NULL : les donnees nous appartiennent
269 br!=NULL : les donnees ne nous appartiennent pas (ex: Blitz)
270
271 Exemple: on veut connecter a un tableau de T*
272 > float *x = new float[5]; ... remplissage de x[] ...;
273 1- On veut que NDataBlock NE DESALLOUE PAS le tableau "x[]"
274 a- Premiere solution
275 > NDataBlock A(5,x,new Bridge);
276 ......
277 > delete [] x;
278 - Il faut deleter x[] explicitement.
279 - Le destructeur de "A" ne detruit pas x[].
280 ATTENTION: Une fois x[] detruit, "A" ne peut
281 plus acceder les donnees!
282 - Bridge est detruit par le destructeur de "A"
283 b- Autre solution:
284 > NDataBlock A(5); A.FillFrom(5,x);
285 > delete [] x;
286 ......
287 - Il faut deleter x[] explicitement.
288 - "A" possede une copie en local de x[].
289 - Le destructeur de "A" ne detruit pas x[] mais la copie locale.
290 2- On veut que NDataBlock desalloue le tableau
291 > NDataBlock A(5,x);
292 - Ne Pas Faire "delete [] x;"
293 - "A" partage les donnees avec x[].
294 - Le destructeur de "A" detruit x[].
295
296 --- REMARQUE SUR LE DANGER DE CERTAINES SITUATIONS (CMV):
297 1-/ x = new float[n1]; NDataBlock A(n2,x);
298 1er danger: si n2>n1 depassement de tableaux (core dump)
299 2sd danger: celui qui alloue x[] ne doit pas faire le "delete"
300 en desaccord avec toutes les regles de bonne conduite.
301 2-/ float x[5]={1,2,3,4,5}; {NDataBlock A(n2,&x[0]);} cout<<x[2];
302 Ici, a la sortie du bloc {}, le destructeur de "A" va detruire
303 l'adresse de &x[0]: je n'ose imaginer que ca se fasse sans probleme
304 et de toute facon, cout<<x[2]; va surement faire des etincelles.
305 3-/ x = new float[n1]; NDataBlock A(n2,x,new Bridge);
306 1er danger: si n2>n1 depassement de tableaux (core dump)
307 2sd danger: si la methode bridgee (blitz?) detruit x[]
308 "A" n'a plus de donnees connectees!
309 --- CONCLUSION
310 Cette classe est franchement merdique.
311 - On peut accepter la prise de risque liee a NDataBlock(n2,x,new Bridge);
312 car je ne vois pas comment on pourrait faire autrement pour connecter
313 un tableau de type blitz par exemple.
314 - Par contre le createur NDataBlock(n2,x); doit etre interdit
315 dans sa forme actelle car trop dangereux et il me semble inutile.
316 - Dans cette nouvelle optique:
317 NDataBlock(n2,x,new Bridge) et NDataBlock(n2,x) disparaissent
318 On remplace par NDataBlock(n2,x) {Alloc(n2,x,new Bridge);}
319 qui force le Bridge dans tout les cas puisque NDataBlock
320 ne possede pas les donnees.
321 Mais puis-je encore le faire vu que NDataBlock est a la base
322 de TVector,TMatrix et qu'il faut donc reprendre tout le code DPC
323 - Quoiqu'il arrive Alloc est une methode privee et peut donc rester
324 sous sa forme actuelle.
325
326 \endverbatim
327 */
328
329
330template <class T>
331void NDataBlock<T>::Alloc(size_t n,T* data,Bridge* br,bool zero)
332{
333if(Debug_NDataBlock>1)
334 cout<<"?_NDataBlock::Alloc("<<this<<","
335 <<n<<","<<data<<","<<br<<") mSz="<<mSz
336 <<" mSRef="<<mSRef<<" IsTemp="<<mIsTemp<<endl;
337
338if(br && !data)
339 throw(NullPtrError("NDataBlock::Alloc br!=NULL && data==NULL\n"));
340if(n==0) throw(SzMismatchError("NDataBlock::Alloc n==0\n"));
341//--- Start of atomic (in one block) operation for thread safety (ThreadSafe)
342gThsop->lock(); // (ThreadSafe)
343if(mSRef) Delete();
344mSz = n;
345mSRef = new NDREF;
346mSRef->nref = 1;
347mSRef->dsid = AnyDataObj::getUniqueId();
348if(data) mSRef->data = data;
349else {mSRef->data = new T[n]; if (zero) memset(mSRef->data,0,n*sizeof(T));}
350mSRef->bridge = br;
351gThsop->unlock(); // (ThreadSafe)
352//--- End of atomic operation (ThreadSafe)
353
354if(Debug_NDataBlock>0) {
355 // Meme dans le cas data!=0 et br==0 (connexion d'un tableau
356 // avec destruction geree par ~NDataBlock (cas 2-) on compte
357 // comme si on avait fait une allocation du tableau (ce qui a ete
358 // fait au niveau du dessus!).
359 if(!br) NallocData++; NallocSRef++;
360 if(Debug_NDataBlock>1)
361 cout<<"...?_NDataBlock::Alloc mSz="<<mSz<<" mSRef="<<mSRef
362 <<" mSRef->nref="<<mSRef->nref<<" mSRef->data="<<mSRef->data
363 <<" mSRef->bridge="<<mSRef->bridge
364 <<" IsTemp="<<mIsTemp
365 <<" Total("<<NallocData<<","<<NallocSRef<<")"<<endl;
366}
367}
368
369//! Management of de-allocation (NOT thread-safe)
370template <class T>
371void NDataBlock<T>::Delete(void)
372// Pour detruire les pointeurs en tenant compte des references
373{
374if(Debug_NDataBlock>1) {
375 cout<<"?_NDataBlock::Delete("<<this<<") mSz="<<mSz
376 <<" mSRef="<<mSRef<<" IsTemp="<<mIsTemp;
377 if(mSRef)
378 cout<<" mSRef->nref="<<mSRef->nref<<" mSRef->data="
379 <<mSRef->data<<" mSRef->bridge="<<mSRef->bridge;
380 cout<<endl;
381}
382
383if(mSRef==NULL) return;
384
385mSRef->nref--;
386if(mSRef->nref != 0) {
387
388if(Debug_NDataBlock>1)
389 cout<<"...?_NDataBlock::Delete() pas de desallocation il reste nref="
390 <<mSRef->nref<<" Total("<<NallocData<<","<<NallocSRef<<")"<<endl;
391
392 mSz = 0; mSRef=NULL;
393 return;
394}
395
396if(Debug_NDataBlock>0) {
397 if(!mSRef->bridge) NallocData--; NallocSRef--;
398 if(Debug_NDataBlock>1)
399 cout<<"...?_NDataBlock::Delete() desallocation complete il reste nref="
400 <<mSRef->nref<<" Total("<<NallocData<<","<<NallocSRef<<")"<<endl;
401}
402
403// Si il y a un Bridge les donnees ne n'appartiennent pas, on detruit le Bridge
404// sinon, les donnees ont ete allouees par nos soins, on libere l'espace
405if(mSRef->bridge) {
406 if(Debug_NDataBlock>1)
407 cout<<"...?_NDataBlock::Delete() Bridge "<<mSRef->bridge<<" deleted"<<endl;
408 delete mSRef->bridge;
409} else {
410 if(Debug_NDataBlock>1)
411 cout<<"...?_NDataBlock::Delete() data "<<mSRef->data<<" deleted"<<endl;
412 delete [] mSRef->data;
413}
414mSRef->bridge=NULL; mSRef->data=NULL;
415delete mSRef; mSRef=NULL; mSz = 0;
416}
417
418//! Fill dats of this NDataBlock with the \b n datas pointed by \b data
419/*!
420 \warning If class empty : allocate space in memory
421 \warning If class already connected : overwrite with minimum size
422 (\b n or \b mSz)
423 */
424template <class T>
425void NDataBlock<T>::FillFrom(size_t n,T* data)
426// Remplissage par un tableau de donnees
427// - Si classe vide : creation de l'espace memoire
428// - Si classe connectee : on ecrit selon la longueur minimale
429// (cad this->mSz ou "n")
430{
431if(data==NULL) throw(NullPtrError("NDataBlock::FillFrom data==NULL\n"));
432if(n==0) throw(ParmError("NDataBlock::FillFrom n<=0\n"));
433if(mSRef==NULL) Alloc(n, NULL, NULL, false); // Pas de mise a zero
434if(mSz<n) n = mSz;
435memcpy(Data(),data,n*sizeof(T));
436}
437
438//! Re-allocate space for \b nnew datas
439/*!
440 \param nnnew : new size
441 \param force : to manage the way re-allocation will be done (see after).
442 \verbatim
443 Re-allocation de "nnew" place memoire pour les donnees
444 avec conservation des "nold" donnees precedentes si possible.
445 "force" gere la re-allocation de la place memoire pour les donnees.
446 Divers cas se presentent:
447 a-/ *** nnew>nold force=quelconque ***
448 place re-allouee, donnees [0,nold[ copiees, surplus [nold,new[ mis a zero
449 b-/ *** nnew<=nold force=true ***
450 place re-allouee, donnees [0,nnew[ copiees, pas de surplus
451 c-/ *** nnew<=nold force=false ***
452 place non re-allouee, seule la valeur de la taille est diminuee
453 - On tient compte du partage des donnees dans tous les cas.
454 - Si il n'y a pas de donnees connectees a la classe, on re-alloue
455 dans tous les cas
456 \endverbatim
457 */
458template <class T>
459void NDataBlock<T>::Realloc(size_t nnew,bool force)
460{
461if(nnew==0) throw(ParmError("NDataBlock::Realloc n<=0\n"));
462
463// Cas sans re-allocation memoire
464if(mSRef && nnew<=mSz && ! force) { mSz=nnew; return;}
465
466// Cas avec re-allocation memoire
467size_t ncop;
468if(!mSRef || mSz==0) ncop=0; else if(mSz<nnew) ncop=mSz; else ncop=nnew;
469T* dataloc = new T[nnew];
470if(ncop>0) memcpy(dataloc,mSRef->data,ncop*sizeof(T));
471if(nnew>ncop) memset(dataloc+ncop,0,(nnew-ncop)*sizeof(T));
472Alloc(nnew,dataloc,NULL); //Alloc gere partage de reference et bridge
473}
474
475/*!
476 \brief Calls the protected Delete() method to set the size to zero
477 This is the public - thread safe version - of the Delete() method
478 The memory is freed if last referenced structure.
479*/
480template <class T>
481void NDataBlock<T>::Dealloc()
482{
483 gThsop->lock();
484 Delete();
485 gThsop->unlock();
486}
487
488////////////////
489// Impression //
490////////////////
491
492//! Give infos and print \b n datas beginning at \b i1 on stream \b os.
493template <class T>
494void NDataBlock<T>::Print(ostream& os,size_t i1,size_t n) const
495// Impression de n elements a partir de i1
496{
497size_t nr = 0;
498T* p = NULL; Bridge* br = NULL;
499if(mSRef) {nr = mSRef->nref; p = mSRef->data; br = mSRef->bridge;}
500os<<"NDataBlock::Print("<<this<<",Sz="<<mSz<<",IsTemp="<<mIsTemp<<")\n"
501 <<" mSRef="<<mSRef<<"(nref="<<nr<<",data="<<p
502 <<",bridge="<<br<<")"<<endl;
503if(i1>=mSz || n<=0 || !p) return;
504size_t i2 = i1+n; if(i2>mSz) i2=mSz;
505size_t im = 1; bool enl=false;
506while(i1<i2) {
507 enl = false;
508 os<<" "<<(*this)(i1); i1++;
509 if(im==8) {os<<"\n"; im=1; enl=true;} else im++;
510}
511if(!enl) os<<endl;
512}
513
514//////////////////////////////////////////////
515// Calcul de la somme / produit des donnees //
516//////////////////////////////////////////////
517
518//! Return sum of \b n datas beginning at data \b i1.
519template <class T>
520T NDataBlock<T>::Sum(size_t i1,size_t n) const
521// Somme des elements de i1 a i1+n-1
522{
523if(i1>=mSz) return 0;
524if(n>mSz) n = mSz; if(n==0) n = mSz-i1;
525T const *p=Begin()+i1, *pe=p+n;
526T val = 0;
527while (p<pe) val += *p++;
528return val;
529}
530
531//! Return product of \b n datas beginning at data \b i1.
532template <class T>
533T NDataBlock<T>::Product(size_t i1,size_t n) const
534// Produit des elements de i1 a i1+n-1
535{
536if(i1>=mSz) return 0;
537if(n>mSz) n = mSz; if(n==0) n = mSz-i1;
538T const *p=Begin()+i1, *pe=p+n;
539T val = 0;
540while (p<pe) val *= *p++;
541return val;
542}
543
544///////////////////////////////////////////////////////////////
545// Surcharge de = : NDataBlock=NDataBlock; NDataBlock=<T> b; //
546///////////////////////////////////////////////////////////////
547
548//! Operator = : ND = NDa
549/*! \warning Datas are copied (cloned) from \b a. */
550template <class T>
551NDataBlock<T>& NDataBlock<T>::operator = (const NDataBlock<T>& a)
552// Affectation: partage des donnees si "a" temporaire, clone sinon.
553{
554if(Debug_NDataBlock>1)
555 cout<<"?_NDataBlock::operator=("<<this<<","<<&a<<") a.(mSz="
556 <<a.mSz<<" mSRef="<<a.mSRef<<" IsTemp="<<a.IsTemp()
557 <<"), mSz="<<mSz<<" mSRef="<<mSRef<<" IsTemp="<<mIsTemp<<endl;
558
559if(this == &a) return *this;
560if(a.mSz==0)
561 throw(SzMismatchError("NDataBlock::operator=A null size \n"));
562if (mSz==0) { CloneOrShare(a); return *this; }
563if (a.mSz != mSz)
564 throw(SzMismatchError("NDataBlock::operator=A Unequal sizes \n"));
565memcpy(Data(),a.Data(),mSz*sizeof(T));
566return *this;
567}
568
569//! Operator = : ND = \b v (at dats set to \b v).
570template <class T>
571NDataBlock<T>& NDataBlock<T>::operator = (T v)
572// Affectation de tous les elements a une constante "v"
573{
574if(Debug_NDataBlock>1)
575 cout<<"?_NDataBlock::operator=("<<this<<","<<v<<")"
576 <<" mSz="<<mSz<<" mSRef="<<mSRef<<" IsTemp="<<mIsTemp<<endl;
577
578if(mSz==0) throw(SzMismatchError("NDataBlock::operator=v null size\n"));
579T *p=Begin(), *pe=End(); while (p<pe) *p++ = v;
580return *this;
581}
582
583//////////////////////////////////////////////////////////////
584// Surcharge de +=,-=,*=,/= (INPLACE): NDataBlock += <T> b; //
585//////////////////////////////////////////////////////////////
586
587//! Add a constant : ND += b
588template <class T>
589NDataBlock<T>& NDataBlock<T>::operator += (T b)
590{
591if(mSz==0) throw(SzMismatchError("NDataBlock::operator+=v null size\n"));
592T *p=Begin(), *pe=End(); while (p<pe) *p++ += b;
593return *this;
594}
595
596//! Substract a constant : ND -= b
597template <class T>
598NDataBlock<T>& NDataBlock<T>::operator -= (T b)
599{
600if(mSz==0) throw(SzMismatchError("NDataBlock::operator-=v null size\n"));
601T *p=Begin(), *pe=End(); while (p<pe) *p++ -= b;
602return *this;
603}
604
605//! Multiply by a constant : ND *= b
606template <class T>
607NDataBlock<T>& NDataBlock<T>::operator *= (T b)
608{
609if(mSz==0) throw(SzMismatchError("NDataBlock::operator*=v null size\n"));
610T *p=Begin(), *pe=End(); while (p<pe) *p++ *= b;
611return *this;
612}
613
614//! Divide by a constant : ND /= b
615template <class T>
616NDataBlock<T>& NDataBlock<T>::operator /= (T b)
617{
618if(b==(T) 0) throw(ParmError("NDataBlock::operator/=v divide by zero\n"));
619if(mSz==0) throw(SzMismatchError("NDataBlock::operator/=v null size\n"));
620T *p=Begin(), *pe=End(); while (p<pe) *p++ /= b;
621return *this;
622}
623
624////////////////////////////////////////////////////////////////////
625// Surcharge de +=,-=,*=,/= (INPLACE): NDataBlock += NDataBlock1; //
626////////////////////////////////////////////////////////////////////
627
628//! Add a NDataBlock : ND += NDa
629template <class T>
630NDataBlock<T>& NDataBlock<T>::operator += (const NDataBlock<T>& a)
631{
632if(mSz==0 || mSz!=a.mSz)
633 throw(SzMismatchError("NDataBlock::operator+=A size mismatch/null"));
634T *p=Begin(), *pe=End();
635T const * pa=a.Begin();
636while (p<pe) *p++ += *pa++;
637return *this;
638}
639
640//! Substract a NDataBlock : ND -= NDa
641template <class T>
642NDataBlock<T>& NDataBlock<T>::operator -= (const NDataBlock<T>& a)
643{
644if(mSz==0 || mSz!=a.mSz)
645 throw(SzMismatchError("NDataBlock::operator-=A size mismatch/null"));
646T *p=Begin(), *pe=End();
647T const *pa=a.Begin();
648while (p<pe) *p++ -= *pa++;
649return *this;
650}
651
652//! Multiply by a NDataBlock : ND *= NDa
653template <class T>
654NDataBlock<T>& NDataBlock<T>::operator *= (const NDataBlock<T>& a)
655{
656if(mSz==0 || mSz!=a.mSz)
657 throw(SzMismatchError("NDataBlock::operator*=A size mismatch/null"));
658T *p=Begin(), *pe=End();
659T const *pa=a.Begin();
660while (p<pe) *p++ *= *pa++;
661return *this;
662}
663
664//! Divide by a NDataBlock : ND /= NDa
665template <class T>
666NDataBlock<T>& NDataBlock<T>::operator /= (const NDataBlock<T>& a)
667// Attention, aucune protection si un element de "a" est nul.
668{
669if(mSz==0 || mSz!=a.mSz)
670 throw(SzMismatchError("NDataBlock::operator/=A size mismatch/null"));
671T *p=Begin(), *pe=End();
672T const *pa=a.Begin();
673while (p<pe) *p++ /= *pa++; // Division par zero non protegee
674return *this;
675}
676
677//////////////////////////////////////////////////////////////////
678// Pour surcharge de +,-,*,/ : NDataBlock = NDataBlock1+<T>b; //
679// NDataBlock = <T>b+NDataBlock1; //
680// Pour la notion de "temporaire" voir blabla dans CloneOrShare //
681//////////////////////////////////////////////////////////////////
682
683//! Add a constant and return NDataBlock : NDret = ND + b
684template <class T>
685NDataBlock<T> NDataBlock<T>::Add(T b) const
686// Pour A+b
687{
688NDataBlock<T> result;
689result.CloneOrShare(*this); result.SetTemp(true);
690result += b;
691return result;
692}
693
694//! Substract a constant and return NDataBlock : NDret = ND - b or NDret = b - ND
695/*! Substract a constant or from a constant
696 \param fginv==false : performs NDret = ND - b (default)
697 \param fginv==true : performs NDret = b - ND
698*/
699template <class T>
700NDataBlock<T> NDataBlock<T>::Sub(T b,bool fginv) const
701// Pour A-b sauf si fginv==true b-A (- n'est pas commutatif!)
702{
703NDataBlock<T> result;
704result.CloneOrShare(*this); result.SetTemp(true);
705if(fginv) {
706 T *p=result.Begin(), *pe=result.End();
707 T const *pa=this->Begin();
708 while(p<pe) {*p++ = b - *pa++;}
709} else result -= b;
710return result;
711}
712
713//! Multiply by a constant and return NDataBlock : NDret = ND * b
714template <class T>
715NDataBlock<T> NDataBlock<T>::Mul(T b) const
716// Pour A*b
717{
718NDataBlock<T> result;
719result.CloneOrShare(*this); result.SetTemp(true);
720result *= b;
721return result;
722}
723
724//! Divide by a constant and return NDataBlock : NDret = ND / b or NDret = b / ND
725/*! Divide by a constant or from a constant
726 \param fginv==false : performs NDret = ND / b (default)
727 \param fginv==true : performs NDret = b / ND
728*/
729template <class T>
730NDataBlock<T> NDataBlock<T>::Div(T b,bool fginv) const
731// Pour A/b sauf si fginv==true b/A (/ n'est pas commutatif!)
732{
733NDataBlock<T> result;
734result.CloneOrShare(*this); result.SetTemp(true);
735 if(fginv) {
736 T *p=result.Begin(), *pe=result.End();
737 T const *pa = this->Begin();
738 while(p<pe) {*p++ = b / *pa++;} // Division par zero non protegee
739} else {
740 if( b == (T) 0 ) throw MathExc("NDataBlock<T>::Div(T) - Divide by zero ! ");
741 result /= b;
742}
743return result;
744}
745
746///////////////////////////////////////////////////////////////////////
747// Pour surcharge de +,-,*,/ : NDataBlock = NDataBlock1+NDataBlock2; //
748///////////////////////////////////////////////////////////////////////
749
750//! Add a NDataBlock and return a NDataBlock: ND = NDthis + NDb
751template <class T>
752NDataBlock<T> NDataBlock<T>::Add(const NDataBlock<T>& b) const
753// Pour A+B
754{
755if(mSz!=b.mSz)
756 throw(SzMismatchError("NDataBlock operator C=A+B size mismatch/null\n"));
757NDataBlock<T> result; result.SetTemp(true);
758if(b.IsTemp()) {result.Share(b); result += *this;}
759 else {result.CloneOrShare(*this); result += b;}
760return result;
761}
762
763//! Multiply by a NDataBlock and return a NDataBlock: ND = NDthis * NDb
764template <class T>
765NDataBlock<T> NDataBlock<T>::Mul(const NDataBlock<T>& b) const
766// Pour A*B
767{
768if(mSz!=b.mSz)
769 throw(SzMismatchError("NDataBlock operator C=A*B size mismatch/null\n"));
770NDataBlock<T> result; result.SetTemp(true);
771if(b.IsTemp()) {result.Share(b); result *= *this;}
772 else {result.CloneOrShare(*this); result *= b;}
773return result;
774}
775
776//! Substract a NDataBlock and return a NDataBlock: ND = NDthis - NDb
777template <class T>
778NDataBlock<T> NDataBlock<T>::Sub(const NDataBlock<T>& b) const
779// Pour A-B
780{
781if(mSz!=b.mSz)
782 throw(SzMismatchError("NDataBlock operator C=A-B size mismatch/null\n"));
783NDataBlock<T> result; result.SetTemp(true);
784if(b.IsTemp()) {
785 result.Share(b);
786 T *p=result.Begin(), *pe=result.End(); T const *pa=Begin();
787 while(p<pe) {*p = *pa++ - *p; p++;}
788} else {result.CloneOrShare(*this); result -= b;}
789return result;
790}
791
792//! Divide by a NDataBlock and return a NDataBlock: ND = NDthis / NDb
793template <class T>
794NDataBlock<T> NDataBlock<T>::Div(const NDataBlock<T>& b) const
795// Pour A/B
796{
797if(mSz!=b.mSz)
798 throw(SzMismatchError("NDataBlock operator C=A/B size mismatch/null\n"));
799NDataBlock<T> result; result.SetTemp(true);
800if(b.IsTemp()) {
801 result.Share(b);
802 T *p=result.Begin(), *pe=result.End(); T const *pa=Begin();
803 while(p<pe) {*p = *pa++ / *p; p++;} // Division par zero non protegee
804} else {result.CloneOrShare(*this); result /= b;}
805return result;
806}
807
808
809///////////////////////////////////////////////////////////////
810#ifdef __CXX_PRAGMA_TEMPLATES__
811#pragma define_template NDataBlock<uint_1>
812#pragma define_template NDataBlock<uint_2>
813#pragma define_template NDataBlock<int_2>
814#pragma define_template NDataBlock<int_4>
815#pragma define_template NDataBlock<int_8>
816#pragma define_template NDataBlock<uint_4>
817#pragma define_template NDataBlock<uint_8>
818#pragma define_template NDataBlock<r_4>
819#pragma define_template NDataBlock<r_8>
820#pragma define_template NDataBlock< complex<r_4> >
821#pragma define_template NDataBlock< complex<r_8> >
822#endif
823
824#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
825namespace SOPHYA {
826template class NDataBlock<uint_1>;
827template class NDataBlock<uint_2>;
828template class NDataBlock<int_2>;
829template class NDataBlock<int_4>;
830template class NDataBlock<int_8>;
831template class NDataBlock<uint_4>;
832template class NDataBlock<uint_8>;
833template class NDataBlock<r_4>;
834template class NDataBlock<r_8>;
835template class NDataBlock< complex<r_4> >;
836template class NDataBlock< complex<r_8> >;
837}
838#endif
Note: See TracBrowser for help on using the repository browser.