source: Sophya/trunk/SophyaLib/BaseTools/segdatablock.h@ 3603

Last change on this file since 3603 was 3566, checked in by ansari, 17 years ago

Correction bug ds SegDataBlock.Share() provoquant core dump (a l'origine du pb de KeepObj(DataTable) - plus exactement ds DataTable::Share() - Reza 06/02/2009

File size: 10.0 KB
RevLine 
[2660]1// This may look like C code, but it is really -*- C++ -*-
2// Gestion de block de donnees avec partage de references
3// R. Ansari Mars 2005
4// LAL (Orsay) / IN2P3-CNRS DAPNIA/SPP (Saclay) / CEA
5#ifndef SEGDATABLOCK_H
6#define SEGDATABLOCK_H
7
8#include "machdefs.h"
9#include "anydataobj.h"
10#include <string.h>
11#include <vector>
12#include <iostream>
13#include <iomanip>
14#include <typeinfo>
15
[3213]16#include "thsafeop.h" // for ThreadSafe operations (Ref.Count/Share)
17
[2805]18/*!
19 \class SOPHYA::SegDBInterface
20 \ingroup BaseTools
21 Interface definition for segmented data container (template class).
22*/
23/*!
24 \class SOPHYA::SegDataBlock
25 \ingroup BaseTools
26 Template class impementing segmented data container in memory with
27 management of reference sharing.
28*/
29
[2660]30namespace SOPHYA {
31
32////////////////////////////////////////////////////////////////
33//// ---------------- Class SegDBInterface ------------------ //
34//// ----------------- Class SegDataBlock ------------------- //
35////////////////////////////////////////////////////////////////
36
37template <class T>
38class SegDBInterface : public AnyDataObj {
39public:
40 virtual ~SegDBInterface() {}
41 //! Changes the data segment size and reallocates the memory segments
42 // segsz : Segment size ; nbseg : Number of data segments
43 virtual void SetSize(size_t segsz, size_t nbseg=0) = 0;
44 //! Alias for SetSize()
45 inline void ReSize(size_t segsz, size_t nbseg=0) { SetSize(segsz, nbseg); }
46 //! Adds one segment to the data structure - returns the new number of segments.
47 virtual size_t Extend() = 0;
48 //! Return the segment size data structure
49 virtual size_t SegmentSize() const = 0;
50 //! Return the number of data segments
51 virtual size_t NbSegments() const = 0;
52 //! Return the current size of the segmented data structure
53 inline size_t Size() const { return SegmentSize()*NbSegments(); }
[2698]54 //! Return the pointer to data segment \b k
55 virtual T* GetSegment(size_t k) = 0;
56 //! Return the const (read-only) pointer to data segment \b k
57 virtual T const * GetCstSegment(size_t k) const = 0;
[2660]58};
59
[2805]60
[2660]61// classe de container avec partage de reference
62template <class T>
63class SegDataBlock : public SegDBInterface<T> {
64
65public:
66
67 //! Default constructor - optional specification of segment size and number of segments
68 explicit SegDataBlock(size_t segsz=32, size_t nbseg=0)
69 {
70 mSRef = NULL;
71 SetSize(segsz, nbseg);
72 }
73 //! copy constructor - shares the data
74 SegDataBlock(const SegDataBlock<T>& a)
75 {
[3214]76 a.mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2660]77 mSRef = a.mSRef;
78 mSRef->nref++;
[3214]79 a.mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
[2660]80 }
81 //! copy constructor with specification of flags for data sharing and element value copy
82 SegDataBlock(const SegDataBlock<T>& a, bool share, bool cpval=true)
83 {
84 if (share) {
[3214]85 a.mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2660]86 mSRef = a.mSRef;
87 mSRef->nref++;
[3214]88 a.mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
[2660]89 }
90 else {
91 mSRef = NULL;
92 Clone(a, cpval);
93 }
94 }
95 //! copy constructor - shares the data if \b is a SegDataBlock, clones otherwise
96 SegDataBlock(const SegDBInterface<T>& a)
97 {
98 SegDataBlock<T> * sdb = dynamic_cast< SegDataBlock<T> *>(&a);
[2884]99 if (sdb != NULL) {
[3214]100 sdb->mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2884]101 mSRef = sdb->mSRef;
[2660]102 mSRef->nref++;
[3214]103 sdb->mSRefg->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
[2660]104 }
105 else Clone(a, true);
106 }
107 //! Destructor. The memory is freed when the last object referencing the data segment is destroyed
108 virtual ~SegDataBlock()
109 {
110 //DEL cout << " DEBUG-~SegDataBlock() " << hex << mSRef << dec << " NRef()= " << NRef() << endl;
[3213]111 Delete();
[2660]112 }
113
114
[3213]115 //! Adds one segment to the data structure - returns the number of allocated segments.
[2660]116 virtual size_t Extend()
117 {
118 T * p = new T[mSRef->segsize];
[3214]119 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2660]120 mSRef->dseg.push_back(p);
[3214]121 size_t rs = mSRef->dseg.size();
122 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
123 return( rs );
[2660]124 }
125
126 //! Changes the data segment size and reallocates the memory segments
127 // segsz : Segment size ; nbseg : Number of data segments
128 virtual void SetSize(size_t segsz, size_t nbseg=0)
129 {
130 Delete();
131 mSRef = new SDREF;
[3214]132 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2660]133 mSRef->nref = 1;
134 mSRef->segsize = segsz;
135 mSRef->dsid = AnyDataObj::getUniqueId();
[3213]136 for(size_t k=0; k<nbseg; k++) Extend_P();
[3214]137 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
[2660]138 }
139//! Shares the data between two SegDataBlock objects
140 void Share(const SegDataBlock<T>& a)
141 {
142 Delete();
[3566]143 a.mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2660]144 mSRef = a.mSRef;
145 mSRef->nref++;
[3566]146 a.mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
[2660]147 }
148
149//! Makes a clone of the data structure and optionaly copie the data
150 void Clone(const SegDBInterface<T> & a, bool cpval=true)
151 {
152 Delete();
153 mSRef = new SDREF;
[3214]154 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
[2660]155 mSRef->nref = 1;
156 mSRef->segsize = a.SegmentSize();
[3214]157 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
[2660]158 for(size_t k=0; k<a.NbSegments(); k++) {
159 Extend();
160 if (cpval) {
161 T * dst = GetSegment(k);
[2698]162 const T * src = a.GetCstSegment(k);
[2660]163 memcpy(dst, src, mSRef->segsize*sizeof(T));
164 }
165 }
166 }
167
168
169 //! Return the segment size of the data structure
170 virtual size_t SegmentSize() const { return mSRef->segsize; }
171 //! Return the number of data segments
172 virtual size_t NbSegments() const { return mSRef->dseg.size(); }
173 //! Return the current size of the segmented data structure
174 inline size_t Size() const { return mSRef->segsize*mSRef->dseg.size(); }
175
[2698]176 //! Return the pointer to data segment \b k
[2660]177 virtual T* GetSegment(size_t k) { return mSRef->dseg[k]; }
[2698]178 //! Return the const (read-only) pointer to data segment \b k
179 virtual T const * GetCstSegment(size_t k) const { return mSRef->dseg[k]; }
[2660]180
181 //! Return the segment index for element \b i
182 inline size_t SegIndex(size_t i) { return i/mSRef->segsize; }
183 //! Return the offset (in data segment) for element \b i
184 inline size_t EltOffset(size_t i) { return i%mSRef->segsize; }
185
186 //! Return the \b i th element of the segmented data structure
187 inline T& operator()(size_t i) { return *(mSRef->dseg[SegIndex(i)]+EltOffset(i));}
188 //! Return the \b i th element of the data structure
189 inline T& operator()(size_t i) const { return *(mSRef->dseg[SegIndex(i)]+EltOffset(i));}
190 //! Return the \b i th element of the segmented data structure
191 inline T& operator[](size_t i) { return *(mSRef->dseg[SegIndex(i)]+EltOffset(i));}
192 //! Return the \b i th element of the data structure
193 inline T& operator[](size_t i) const { return *(mSRef->dseg[SegIndex(i)]+EltOffset(i));}
194
195
196 //! Return the number of references to the data structure
197 inline size_t NRef() const { return mSRef->nref; }
198
199 //! Equal operator. Set all element values to \b v
200 SegDataBlock<T>& operator = (T const & v)
201 {
202 for(size_t k=0; k<NbSegments(); k++) {
203 T * p = mSRef->dseg[k];
204 for(size_t j=0; j<SegmentSize(); j++) p[j] = v;
205 }
206 return (*this);
207 }
208 //! Equal operator. Clones and copie values from \b a
209 inline SegDataBlock<T>& operator = (const SegDBInterface<T> & a)
210 {
211 Clone(a, true);
212 return (*this);
213 }
[2692]214 //! Equal operator. Clones and copie values from \b a
215 inline SegDataBlock<T>& operator = (const SegDataBlock<T> & a)
216 {
217 Clone(a, true);
218 return (*this);
219 }
[2660]220
221 //! ASCII formatted output (print)
222 void Print(ostream& os, int lev=0, const char * sep=NULL) const
223 {
224 os << "SegDataBlock< " << typeid(T).name() << "> mSRef= " << hex << mSRef
225 << " NRef=" << dec << NRef() << " DSId= " << DRefId() << endl;
226 os << " ... SegSize= " << SegmentSize() << " NbSeg= " << NbSegments()
227 << " Size= " << Size() << endl;
228 if (sep == NULL) sep = " ";
229 if (lev > 0) {
230 for(size_t k=0; k<NbSegments(); k++) {
231 T * p = mSRef->dseg[k];
232 os << " ..... DataSeg[ " << k << " ] : " << hex << p << dec << endl;
233 if (lev > 1)
234 for(size_t j=0; j<SegmentSize(); j++) os << p[j] << sep;
235 os << endl;
236 }
237 }
238 }
239 //! ASCII formatted output (print) on cout
240 inline void Print(int lev=0, const char * sep=NULL) const
241 {
242 Print(cout, lev, sep);
243 }
244
245 //! Returns the unique object identifier
[3385]246 inline uint_8 DRefId() const { return ((mSRef)?mSRef->dsid:0); }
[2660]247
248protected:
[3213]249 //! NON-thread safe: Decrement the number of reference counts, and free the memory if NRef=0
[2660]250 void Delete()
251 {
252 if (mSRef == NULL) return;
[3214]253 mSRef->gThsop.lock();
[2660]254 mSRef->nref--;
[3214]255 if (mSRef->nref > 0) {
256 mSRef->gThsop.unlock();
257 mSRef = NULL;
258 return;
259 }
[2660]260 //DEL cout << " DEBUG-SegDataBlock::Delete() NbSegments() = " << NbSegments() << endl;
261 for(size_t k=0; k<NbSegments(); k++) {
262 delete[] mSRef->dseg[k];
263 mSRef->dseg[k] = NULL;
264 }
[3214]265 mSRef->gThsop.unlock();
[2660]266 delete mSRef;
267 mSRef = NULL;
268 }
[3213]269 //! NON-thread safe, version of Extend() : Adds one segment to the data structure
270 size_t Extend_P()
271 {
272 T * p = new T[mSRef->segsize];
273 mSRef->dseg.push_back(p);
274 return( mSRef->dseg.size());
275 }
276
[2805]277 /*! \cond
278 SDREF structure for reference management - for internal use by SegDataBlock
279 */
[2660]280 typedef struct {
[2805]281 size_t nref; // Number of references to the data structure
282 uint_8 dsid; // Data structure Id - Used by FIO_SegDataBlock
[2660]283 std::vector<T *> dseg;
284 size_t segsize;
[3214]285 ThSafeOp gThsop; // Mutex for thread safe operation
[2660]286 } SDREF;
[2805]287 /*! \endcond */
[2660]288 SDREF * mSRef; //!< SDREF structure for reference sharing
[3213]289
[2660]290};
291
[3213]292
[2660]293//! Definition of operator \<\< for ascii formatted output of SegDataBlock
294template<class T>
295inline ostream& operator << (ostream& os, const SegDataBlock<T>& a)
296 { a.Print(os); return(os); }
297
298} // Fin du namespace
299
300#endif
Note: See TracBrowser for help on using the repository browser.