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

Last change on this file since 3277 was 3214, checked in by ansari, 18 years ago

Debug protections thread-safe pour SegDataBlock<T> et SwSegDataBlock<T>, Reza 12/04/2007

File size: 10.0 KB
Line 
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
16#include "thsafeop.h" // for ThreadSafe operations (Ref.Count/Share)
17
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
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(); }
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;
58};
59
60
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 {
76 a.mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
77 mSRef = a.mSRef;
78 mSRef->nref++;
79 a.mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
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) {
85 a.mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
86 mSRef = a.mSRef;
87 mSRef->nref++;
88 a.mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
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);
99 if (sdb != NULL) {
100 sdb->mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
101 mSRef = sdb->mSRef;
102 mSRef->nref++;
103 sdb->mSRefg->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
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;
111 Delete();
112 }
113
114
115 //! Adds one segment to the data structure - returns the number of allocated segments.
116 virtual size_t Extend()
117 {
118 T * p = new T[mSRef->segsize];
119 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
120 mSRef->dseg.push_back(p);
121 size_t rs = mSRef->dseg.size();
122 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
123 return( rs );
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;
132 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
133 mSRef->nref = 1;
134 mSRef->segsize = segsz;
135 mSRef->dsid = AnyDataObj::getUniqueId();
136 for(size_t k=0; k<nbseg; k++) Extend_P();
137 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
138 }
139//! Shares the data between two SegDataBlock objects
140 void Share(const SegDataBlock<T>& a)
141 {
142 Delete();
143 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
144 mSRef = a.mSRef;
145 mSRef->nref++;
146 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
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;
154 mSRef->gThsop.lock(); // (ThreadSafe) - Start of atomic operation
155 mSRef->nref = 1;
156 mSRef->segsize = a.SegmentSize();
157 mSRef->gThsop.unlock(); // (ThreadSafe) - End of atomic operation
158 for(size_t k=0; k<a.NbSegments(); k++) {
159 Extend();
160 if (cpval) {
161 T * dst = GetSegment(k);
162 const T * src = a.GetCstSegment(k);
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
176 //! Return the pointer to data segment \b k
177 virtual T* GetSegment(size_t k) { return mSRef->dseg[k]; }
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]; }
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 }
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 }
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
246 inline uint_8 DRefId() const { return mSRef->dsid; }
247
248protected:
249 //! NON-thread safe: Decrement the number of reference counts, and free the memory if NRef=0
250 void Delete()
251 {
252 if (mSRef == NULL) return;
253 mSRef->gThsop.lock();
254 mSRef->nref--;
255 if (mSRef->nref > 0) {
256 mSRef->gThsop.unlock();
257 mSRef = NULL;
258 return;
259 }
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 }
265 mSRef->gThsop.unlock();
266 delete mSRef;
267 mSRef = NULL;
268 }
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
277 /*! \cond
278 SDREF structure for reference management - for internal use by SegDataBlock
279 */
280 typedef struct {
281 size_t nref; // Number of references to the data structure
282 uint_8 dsid; // Data structure Id - Used by FIO_SegDataBlock
283 std::vector<T *> dseg;
284 size_t segsize;
285 ThSafeOp gThsop; // Mutex for thread safe operation
286 } SDREF;
287 /*! \endcond */
288 SDREF * mSRef; //!< SDREF structure for reference sharing
289
290};
291
292
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.