DABC (Data Acquisition Backbone Core)  2.9.9
Buffer.cxx
Go to the documentation of this file.
1 // $Id: Buffer.cxx 4726 2021-03-13 18:09:15Z linev $
2 
3 /************************************************************
4  * The Data Acquisition Backbone Core (DABC) *
5  ************************************************************
6  * Copyright (C) 2009 - *
7  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
8  * Planckstr. 1, 64291 Darmstadt, Germany *
9  * Contact: http://dabc.gsi.de *
10  ************************************************************
11  * This software can be used under the GPL license *
12  * agreements as stated in LICENSE.txt file *
13  * which is part of the distribution. *
14  ************************************************************/
15 
16 #include "dabc/Buffer.h"
17 
18 #include "dabc/Pointer.h"
19 #include "dabc/MemoryPool.h"
20 
22 
23 namespace dabc {
24 
25 
28  class MemoryContainer : public Object {
29  public:
30 
31  void* fPtr;
32 
33  MemoryContainer(void *ptr = 0) :
34  Object(0, "", flAutoDestroy),
35  fPtr(ptr)
36  {
37  #ifdef DABC_EXTRA_CHECKS
38  DebugObject("Memory", this, 1);
39  #endif
40  }
41 
42  virtual ~MemoryContainer()
43  {
44  if (fPtr) { free(fPtr); fPtr = 0; }
45  #ifdef DABC_EXTRA_CHECKS
46  DebugObject("Memory", this, -1);
47  #endif
48  }
49  };
50 }
51 
52 
54 {
55  dabc::MemoryPool* pool = dynamic_cast<dabc::MemoryPool*> (fPool());
56 
57 // DOUT0("~dabc::BufferContainer %p THRD %s\n", this, dabc::mgr.CurrentThread().GetName());
58 
59  if (pool) {
61 // DOUT0("Release %u segments first id %u", fNumSegments, fSegm[0].id);
62  } else {
63 
64  }
65 
66  fPool.Release();
67 
68 #ifdef DABC_EXTRA_CHECKS
69  DebugObject("Buffer", this, -1);
70 #endif
71 
72 }
73 
74 
75 // ========================================================
76 
77 
79 {
80  return PoolPtr();
81 }
82 
84 {
85  if (null()) return 0;
86 
87  return dynamic_cast<MemoryPool*> (GetObject()->fPool());
88 }
89 
90 
92 {
93  BufferSize_t sz = 0;
94  for (unsigned n=0;n<NumSegments();n++)
95  sz += SegmentSize(n);
96  return sz;
97 }
98 
100 {
101  if (len==0) {
102  Release();
103  return;
104  }
105 
106  if (null()) return;
107 
108  BufferSize_t totalsize = GetTotalSize();
109  if (len > totalsize)
110  throw dabc::Exception(dabc::ex_Buffer, "Cannot extend size of the buffer by SetTotalSize method, use Append() method instead", "Buffer");
111 
112  if (len == totalsize) return;
113 
114  unsigned nseg(0), npos(0);
115  Locate(len, nseg, npos);
116 
117  if (nseg >= NumSegments())
118  throw dabc::Exception(dabc::ex_Buffer, "FATAL nseg>=NumSegments", dabc::format("Buffer numseg %u", NumSegments()));
119 
120  if (npos>0) {
121  GetObject()->fSegm[nseg].datasize = npos;
122  nseg++;
123  }
124 
125  // we should release peaces which are no longer required
126 
127  if (nseg<NumSegments()) {
128 
129  dabc::MemoryPool* pool = (dabc::MemoryPool*) GetObject()->fPool();
130 
131  if (pool)
132  pool->DecreaseSegmRefs(Segments()+nseg, NumSegments() - nseg);
133 
134  GetObject()->fNumSegments = nseg;
135  }
136 }
137 
138 
140 {
141  if (len==0) return;
142 
143  if (len>=GetTotalSize()) {
144  Release();
145  return;
146  }
147 
148  unsigned nseg(0), npos(0);
149  Locate(len, nseg, npos);
150 
151  if (nseg >= NumSegments())
152  throw dabc::Exception(dabc::ex_Buffer, "FATAL nseg >= NumSegments()", dabc::format("Buffer numseg %u", NumSegments()));
153 
154  // we should release segments which are no longer required
155  if (nseg>0) {
156 
157  if (PoolPtr()) PoolPtr()->DecreaseSegmRefs(Segments(), nseg);
158 
159  for (unsigned n=0;n<NumSegments()-nseg;n++)
160  GetObject()->fSegm[n].copy_from(GetObject()->fSegm + n + nseg);
161 
162  GetObject()->fNumSegments -= nseg;
163  }
164 
165  if (npos>0) {
166  GetObject()->fSegm[0].datasize -= npos;
167  GetObject()->fSegm[0].buffer = (char*) (GetObject()->fSegm[0].buffer) + npos;
168  }
169 }
170 
171 
172 void dabc::Buffer::Locate(BufferSize_t p, unsigned& seg_indx, unsigned& seg_shift) const
173 {
174  seg_indx = 0;
175  seg_shift = 0;
176 
177  BufferSize_t curr(0);
178 
179  while ((curr < p) && (seg_indx<NumSegments())) {
180  if (curr + SegmentSize(seg_indx) <= p) {
181  curr += SegmentSize(seg_indx);
182  seg_indx++;
183  continue;
184  }
185 
186  seg_shift = p - curr;
187  return;
188  }
189 }
190 
191 
193 {
194  dabc::Buffer res;
195 
196  if (null()) return res;
197 
198  if (PoolPtr()) PoolPtr()->IncreaseSegmRefs(Segments(), NumSegments());
199 
200  res.AllocateContainer(GetObject()->fCapacity);
201 
202  res.GetObject()->fPool = GetObject()->fPool;
203 
204  res.SetTypeId(GetTypeId());
205 
206  res.GetObject()->fNumSegments = NumSegments();
207 
208  for (unsigned n=0;n<NumSegments();n++)
209  res.GetObject()->fSegm[n].copy_from(GetObject()->fSegm + n);
210 
211  return res;
212 }
213 
214 
215 bool dabc::Buffer::Append(Buffer& src, bool moverefs) throw()
216 {
217  return Insert(GetTotalSize(), src, moverefs);
218 }
219 
220 bool dabc::Buffer::Prepend(Buffer& src, bool moverefs) throw()
221 {
222  return Insert(0, src, moverefs);
223 }
224 
225 bool dabc::Buffer::Insert(BufferSize_t pos, Buffer& src, bool moverefs)
226 {
227  if (src.null() || (src.GetTotalSize()==0)) return true;
228 
229  if (null()) {
230  if (moverefs)
231  *this << src;
232  else
233  *this = src.Duplicate();
234  return true;
235  }
236 
237  Buffer ownbuf;
238 
239  // if we have buffer assigned to the pool and its differ from
240  // source object we need deep copy to be able extend refs array
241  if ((PoolPtr()!=0) && (src.PoolPtr()!=PoolPtr())) {
242 
243  // first new memory allocated in our pool
244  ownbuf = PoolPtr()->TakeBuffer(src.GetTotalSize());
245 
246  // and second memory is copied
247  ownbuf.CopyFrom(src, src.GetTotalSize());
248  } else
249  if (!moverefs) {
250  // we just duplicate list with refs
251  ownbuf = src.Duplicate();
252  } else
253  ownbuf = src;
254 
255 
256  unsigned tgtseg(0), tgtpos(0);
257 
258  Locate(pos, tgtseg, tgtpos);
259 
260  unsigned numrequired = NumSegments() + ownbuf.NumSegments();
261  if (tgtpos>0) numrequired++;
262 
263  if (numrequired > GetObject()->fCapacity)
264  throw dabc::Exception(dabc::ex_Buffer, "Required number of segments less than available in the buffer", dabc::format("Buffer numseg %u", NumSegments()));
265 
266  MemSegment *segm = Segments();
267 
268  // first move complete segments to the end
269  for (unsigned n=NumSegments(); n>tgtseg + (tgtpos>0 ? 1 : 0); ) {
270  n--;
271 
272  // DOUT0("Move segm %u->%u", n, n + numrequired - NumSegments());
273 
274  segm[n + numrequired - NumSegments()] = segm[n];
275  segm[n].datasize = 0;
276  segm[n].id = 0;
277  segm[n].buffer = 0;
278  }
279 
280  MemSegment *srcsegm = ownbuf.Segments();
281  // copy all segments from external buffer
282  for (unsigned n=0;n<ownbuf.NumSegments();n++) {
283  // DOUT0("copy segm src[%u]->tgt[%u]", n, tgtseg + n + (tgtpos>0 ? 1 : 0));
284  segm[tgtseg + n + (tgtpos>0 ? 1 : 0)].copy_from(&(srcsegm[n]));
285  }
286 
287  // in case when segment is divided on two parts
288  if (tgtpos>0) {
289  if(PoolPtr()) PoolPtr()->IncreaseSegmRefs(segm + tgtseg, 1);
290 
291  unsigned seg2 = tgtseg + ownbuf.NumSegments() + 1;
292 
293  segm[seg2].id = segm[tgtseg].id;
294  segm[seg2].datasize = segm[tgtseg].datasize - tgtpos;
295  segm[seg2].buffer = (char*) segm[tgtseg].buffer + tgtpos;
296 
297  segm[tgtseg].datasize = tgtpos;
298 
299  DOUT0("split segment %u on two parts, second is in %u", tgtseg, seg2);
300  }
301 
302  // at the end
303  GetObject()->fNumSegments = numrequired;
304 
305  if (PoolPtr() && (ownbuf.PoolPtr() == PoolPtr())) {
306  // forget about all segments - they are moved to target
307  ownbuf.GetObject()->fNumSegments = 0;
308  ownbuf.Release();
309  }
310 
311  if (moverefs) src.Release();
312 
313  return true;
314 }
315 
316 
318 {
319  std::string sbuf;
320 
321  if (null()) return sbuf;
322 
323  DOUT0("Num segments = %u", NumSegments());
324 
325  for (unsigned nseg=0; nseg<NumSegments(); nseg++) {
326  DOUT0("Segm %u = %p %u", nseg, SegmentPtr(nseg), SegmentSize(nseg));
327  sbuf.append((const char*)SegmentPtr(nseg), SegmentSize(nseg));
328  }
329 
330  return sbuf;
331 }
332 
334 {
335  return Pointer(*this).copyfrom(Pointer(srcbuf), len);
336 }
337 
338 
339 dabc::BufferSize_t dabc::Buffer::CopyFromStr(const char* src, unsigned len) throw()
340 {
341  return Pointer(*this).copyfromstr(src, len);
342 }
343 
345 {
346  return Pointer(*this).copyto(ptr, len);
347 }
348 
349 dabc::Buffer dabc::Buffer::GetNextPart(Pointer& ptr, BufferSize_t len, bool allowsegmented) throw()
350 {
351  dabc::Buffer res;
352 
353  if (ptr.fullsize()<len) return res;
354 
355  while (!allowsegmented && (len > ptr.rawsize())) {
356  ptr.shift(ptr.rawsize());
357  if (ptr.fullsize() < len) break;
358  }
359 
360  if (ptr.fullsize() < len) return res;
361 
362  unsigned firstseg(0), lastseg(0);
363  void* firstptr(0);
364  BufferSize_t firstlen(0), lastlen(0);
365 
366  while ((len>0) && (ptr.fSegm<NumSegments())) {
367  unsigned partlen(len);
368  if (partlen>ptr.rawsize()) partlen = ptr.rawsize();
369  if (partlen==0) break;
370 
371  if (firstptr==0) {
372  firstptr = ptr.ptr();
373  firstlen = partlen;
374  firstseg = ptr.fSegm;
375  }
376 
377  lastseg = ptr.fSegm;
378  lastlen = partlen;
379 
380  len -= partlen;
381  ptr.shift(partlen);
382  }
383 
384  if (len>0) {
385  EOUT("Internal problem - not full length covered");
386  return res;
387  }
388 
389  res.AllocateContainer(GetObject()->fCapacity);
390 
391  MemoryPool* pool = PoolPtr();
392 
393  if (pool) {
394  pool->IncreaseSegmRefs(Segments() + firstseg, lastseg-firstseg+1);
395 
396  res.GetObject()->fPool.SetObject(pool);
397  }
398 
399  for (unsigned n=firstseg;n<=lastseg;n++) {
400 
401  res.Segments()[n-firstseg].copy_from(Segments() + n);
402  if (n==firstseg) {
403  res.Segments()->buffer = firstptr;
404  res.Segments()->datasize = firstlen;
405  }
406  if (n==lastseg)
407  res.Segments()[n-firstseg].datasize = lastlen;
408  }
409 
410  res.GetObject()->fNumSegments = lastseg - firstseg + 1;
411 
412 // DOUT0("GetNextPart returns %u", res.GetTotalSize());
413 
414  return res;
415 }
416 
417 
418 
420 {
421  return CreateBuffer(malloc(sz), sz, true);
422 }
423 
424 dabc::Buffer dabc::Buffer::CreateBuffer(const void* ptr, unsigned size, bool owner, bool makecopy) throw()
425 {
426  dabc::Buffer res;
427 
428  res.AllocateContainer(8);
429 
430  if (owner) {
431  res.GetObject()->fPool = new MemoryContainer((void*)ptr);
432  } else if (makecopy) {
433  void *newptr = malloc(size);
434  if (!newptr) {
435  EOUT("Failed to allocate buffer of size %u", size);
436  return res;
437  }
438  memcpy(newptr, ptr, size);
439  res.GetObject()->fPool = new MemoryContainer((void*)newptr);
440  ptr = newptr;
441  }
442 
443  res.GetObject()->fNumSegments = 1;
444  res.GetObject()->fSegm[0].buffer = (void*) ptr;
445  res.GetObject()->fSegm[0].datasize = size;
446 
447  return res;
448 }
449 
450 
452 {
453  MemoryPool* pool = PoolPtr();
454  if (!null() && (pool!=0))
455  return pool->IsSingleSegmRefs(GetObject()->fSegm, GetObject()->fNumSegments);
456  return true;
457 
458 }
459 
460 
461 
462 void dabc::Buffer::AllocateContainer(unsigned capacity)
463 {
464  Release();
465 
466  unsigned obj_size = sizeof(BufferContainer) + sizeof(MemSegment) * capacity;
467 
468  void* area = malloc(obj_size);
469 
470  BufferContainer* cont = new (area) BufferContainer;
471 
472  cont->fCapacity = capacity;
473  cont->fSegm = (MemSegment*) ((char*) area + sizeof(BufferContainer));
474 
475  memset(cont->fSegm, 0, sizeof(MemSegment) * capacity);
476 
477  *this = cont;
478 }
Container for data, referenced by Buffer class.
Definition: Buffer.h:69
MemSegment * fSegm
array of segments
Definition: Buffer.h:81
unsigned fNumSegments
number of entries in segments list
Definition: Buffer.h:76
virtual ~BufferContainer()
Definition: Buffer.cxx:53
Reference fPool
reference on the memory pool (or other object, containing memory)
Definition: Buffer.h:79
unsigned fCapacity
capacity of segments list
Definition: Buffer.h:77
Reference on memory from memory pool.
Definition: Buffer.h:135
Buffer Duplicate() const
Duplicates instance of Buffer with new segments list independent from source.
Definition: Buffer.cxx:192
unsigned NumSegments() const
Returns number of segment in buffer.
Definition: Buffer.h:163
bool Insert(BufferSize_t pos, Buffer &src, bool moverefs=true)
Insert content of buffer at specified position.
Definition: Buffer.cxx:225
bool Append(Buffer &src, bool moverefs=true)
Append content of provided buffer.
Definition: Buffer.cxx:215
void AllocateContainer(unsigned capacity)
Definition: Buffer.cxx:462
BufferSize_t CopyTo(void *ptr, BufferSize_t len) const
Copy content into provided raw buffer.
Definition: Buffer.cxx:344
void CutFromBegin(BufferSize_t len)
Remove part of buffer from the beginning.
Definition: Buffer.cxx:139
void SetTotalSize(BufferSize_t len)
Set total length of the buffer to specified value Size cannot be bigger than original size of the buf...
Definition: Buffer.cxx:99
BufferSize_t CopyFrom(const Buffer &srcbuf, BufferSize_t len=0)
Copy content from source buffer.
Definition: Buffer.cxx:333
BufferSize_t GetTotalSize() const
Return total size of all buffer segments.
Definition: Buffer.cxx:91
MemoryPool * PoolPtr() const
Definition: Buffer.cxx:83
MemSegment * Segments() const
Definition: Buffer.h:165
Buffer GetNextPart(Pointer &ptr, BufferSize_t len, bool allowsegmented=true)
Returns reference on the part of the memory, referenced by the object.
Definition: Buffer.cxx:349
std::string AsStdString()
Convert content of the buffer into std::string.
Definition: Buffer.cxx:317
BufferSize_t CopyFromStr(const char *src, unsigned len=0)
Copy data from string.
Definition: Buffer.cxx:339
bool Prepend(Buffer &src, bool moverefs=true)
Prepend content of provided buffer.
Definition: Buffer.cxx:220
bool CanSafelyChange() const
Returns true when user can modify buffer content without any doubts.
Definition: Buffer.cxx:451
Reference GetPool() const
Returns reference on the pool, in user code MemoryPoolRef can be used like dabc::Buffer buf = Recv();...
Definition: Buffer.cxx:78
static Buffer CreateBuffer(BufferSize_t sz)
This static method create independent buffer for any other memory pools Therefore it can be used in s...
Definition: Buffer.cxx:419
void SetTypeId(unsigned tid)
Definition: Buffer.h:151
void Locate(BufferSize_t p, unsigned &seg_indx, unsigned &seg_shift) const
Definition: Buffer.cxx:172
DABC exception.
Definition: Exception.h:57
Helper class to release memory, allocated independently from memory pool Object will be deleted (with...
Definition: Buffer.cxx:28
MemoryContainer(void *ptr=0)
Definition: Buffer.cxx:33
virtual ~MemoryContainer()
Definition: Buffer.cxx:42
void IncreaseSegmRefs(MemSegment *segm, unsigned num)
Method increases ref.counuters of all segments.
Definition: MemoryPool.cxx:423
bool IsSingleSegmRefs(MemSegment *segm, unsigned num)
Return true when all segments has refcnt==1.
Definition: MemoryPool.cxx:442
void DecreaseSegmRefs(MemSegment *segm, unsigned num)
Decrease references of specified segments.
Definition: MemoryPool.cxx:462
Base class for most of the DABC classes.
Definition: Object.h:116
@ flAutoDestroy
object will be automatically destroyed when no references exists, normally set in constructor,...
Definition: Object.h:167
Manipulator with dabc::Buffer class.
Definition: Pointer.h:34
BufferSize_t copyfrom(const Pointer &src, BufferSize_t sz=0)
Returns actual size copied.
Definition: Pointer.cxx:54
BufferSize_t copyto(void *tgt, BufferSize_t sz) const
Definition: Pointer.cxx:98
BufferSize_t copyfromstr(const char *str, unsigned len=0)
Definition: Pointer.cxx:129
Reference on the arbitrary object
Definition: Reference.h:73
void Release()
Releases reference on the object.
Definition: Reference.cxx:138
Object * GetObject() const
Return pointer on the object.
Definition: Reference.h:129
bool null() const
Returns true if reference contains nullptr.
Definition: Reference.h:151
#define DOUT0(args ...)
Definition: logging.h:156
#define EOUT(args ...)
Definition: logging.h:150
Event manipulation API.
Definition: api.h:23
const BufferSize_t BufferSizeError
Definition: Buffer.cxx:21
uint32_t BufferSize_t
Definition: Buffer.h:32
std::string format(const char *fmt,...)
Definition: string.cxx:49
@ ex_Buffer
Definition: Exception.h:36
Structure with descriptor of single memory segment.
Definition: Buffer.h:53
unsigned id
id of the buffer
Definition: Buffer.h:54
void * buffer
pointer on the beginning of buffer (must be in the area of id)
Definition: Buffer.h:56
unsigned datasize
length of data
Definition: Buffer.h:55
void copy_from(MemSegment *src)
Definition: Buffer.h:57