Logo ROOT  
Reference Guide
TBuffer.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id: 6da0b5b613bbcfaa3a5cd4074e7b2be2448dfb31 $
2 // Author: Fons Rademakers 04/05/96
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TBuffer
13 \ingroup Base
14 
15 Buffer base class used for serializing objects.
16 */
17 
18 #include "TBuffer.h"
19 #include "TClass.h"
20 #include "TProcessID.h"
21 
22 constexpr Int_t kExtraSpace = 8; // extra space at end of buffer (used for free block count)
23 constexpr Int_t kMaxBufferSize = 0x7FFFFFFE; // largest possible size.
24 
25 
27 
28 /// Default streamer implementation used by ClassDefInline to avoid
29 /// requirement to include TBuffer.h
30 void ROOT::Internal::DefaultStreamer(TBuffer &R__b, const TClass *cl, void *objpointer)
31 {
32  if (R__b.IsReading())
33  R__b.ReadClassBuffer(cl, objpointer);
34  else
35  R__b.WriteClassBuffer(cl, objpointer);
36 }
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 /// The user has provided memory than we don't own, thus we can not extent it
40 /// either.
41 
42 static char *R__NoReAllocChar(char *, size_t, size_t)
43 {
44  return 0;
45 }
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// Create an I/O buffer object. Mode should be either TBuffer::kRead or
49 /// TBuffer::kWrite. By default the I/O buffer has a size of
50 /// TBuffer::kInitialSize (1024) bytes.
51 
53 {
55  fMode = mode;
56  fVersion = 0;
57  fParent = 0;
58 
60 
61  fBuffer = new char[fBufSize+kExtraSpace];
62 
63  fBufCur = fBuffer;
65 
66  SetReAllocFunc( 0 );
67 }
68 
69 ////////////////////////////////////////////////////////////////////////////////
70 /// Create an I/O buffer object. Mode should be either TBuffer::kRead or
71 /// TBuffer::kWrite.
72 
74 {
75  if (bufsiz < 0)
76  Fatal("TBuffer","Request to create a buffer with a negative size, likely due to an integer overflow: 0x%x for a max of 0x%x.", bufsiz, kMaxBufferSize);
77  if (bufsiz < kMinimalSize) bufsiz = kMinimalSize;
78  fBufSize = bufsiz;
79  fMode = mode;
80  fVersion = 0;
81  fParent = 0;
82 
84 
85  fBuffer = new char[fBufSize+kExtraSpace];
86 
87  fBufCur = fBuffer;
89 
90  SetReAllocFunc( 0 );
91 }
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Create an I/O buffer object. Mode should be either TBuffer::kRead or
95 /// TBuffer::kWrite. By default the I/O buffer has a size of
96 /// TBuffer::kInitialSize (1024) bytes. An external buffer can be passed
97 /// to TBuffer via the buf argument. By default this buffer will be adopted
98 /// unless adopt is false.
99 ///
100 /// If the new buffer is _not_ adopted and no memory allocation routine
101 /// is provided, a Fatal error will be issued if the Buffer attempts to
102 /// expand.
103 
104 TBuffer::TBuffer(EMode mode, Int_t bufsiz, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc)
105 {
106  if (bufsiz < 0)
107  Fatal("TBuffer","Request to create a buffer with a negative size, likely due to an integer overflow: 0x%x for a max of 0x%x.", bufsiz, kMaxBufferSize);
108  fBufSize = bufsiz;
109  fMode = mode;
110  fVersion = 0;
111  fParent = 0;
112 
113  SetBit(kIsOwner);
114 
115  if (buf) {
116  fBuffer = (char *)buf;
117  if ( (fMode&kWrite)!=0 ) {
119  }
120  if (!adopt) ResetBit(kIsOwner);
121  } else {
122  if (fBufSize < kMinimalSize) {
124  }
125  fBuffer = new char[(Long64_t)fBufSize+kExtraSpace];
126  }
127  fBufCur = fBuffer;
129 
130  SetReAllocFunc( reallocfunc );
131 
132  if (buf && ( (fMode&kWrite)!=0 ) && fBufSize < 0) {
133  Expand( kMinimalSize );
134  }
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Delete an I/O buffer object.
139 
141 {
142  if (TestBit(kIsOwner)) {
143  //printf("Deleting fBuffer=%lx\n", fBuffer);
144  delete [] fBuffer;
145  }
146  fBuffer = 0;
147  fParent = 0;
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Automatically calculate a new size and expand the buffer to fit at least size_needed.
152 /// The goals is to minimize the number of memory allocation and the memory allocation
153 /// which avoiding too much memory wastage.
154 ///
155 /// If the size_needed is larger than the current size, the policy
156 /// is to expand to double the current size or the size_needed which ever is largest.
157 
158 void TBuffer::AutoExpand(Int_t size_needed)
159 {
160  if (size_needed < 0) {
161  Fatal("AutoExpand","Request to expand to a negative size, likely due to an integer overflow: 0x%x for a max of 0x%x.", size_needed, kMaxBufferSize);
162  }
163  if (size_needed > fBufSize) {
164  Long64_t doubling = 2LLU * fBufSize;
165  if (doubling > kMaxBufferSize)
166  doubling = kMaxBufferSize;
167  if (size_needed > doubling) {
168  Expand(size_needed);
169  } else {
170  Expand(doubling);
171  }
172  }
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 /// Sets a new buffer in an existing TBuffer object. If newsiz=0 then the
177 /// new buffer is expected to have the same size as the previous buffer.
178 /// The current buffer position is reset to the start of the buffer.
179 /// If the TBuffer owned the previous buffer, it will be deleted prior
180 /// to accepting the new buffer. By default the new buffer will be
181 /// adopted unless adopt is false.
182 ///
183 /// If the new buffer is _not_ adopted and no memory allocation routine
184 /// is provided, a Fatal error will be issued if the Buffer attempts to
185 /// expand.
186 
187 void TBuffer::SetBuffer(void *buf, UInt_t newsiz, Bool_t adopt, ReAllocCharFun_t reallocfunc)
188 {
189  if (fBuffer && TestBit(kIsOwner))
190  delete [] fBuffer;
191 
192  if (adopt)
193  SetBit(kIsOwner);
194  else
196 
197  fBuffer = (char *)buf;
198  fBufCur = fBuffer;
199  if (newsiz > 0) {
200  if ( (fMode&kWrite)!=0 ) {
201  fBufSize = newsiz - kExtraSpace;
202  } else {
203  fBufSize = newsiz;
204  }
205  }
207 
208  SetReAllocFunc( reallocfunc );
209 
210  if (buf && ( (fMode&kWrite)!=0 ) && fBufSize < 0) {
211  Expand( kMinimalSize );
212  }
213 }
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Expand (or shrink) the I/O buffer to newsize bytes.
217 /// If copy is true (the default), the existing content of the
218 /// buffer is preserved, otherwise the buffer is returned zero-ed out.
219 ///
220 /// In order to avoid losing data, if the current length is greater than
221 /// the requested size, we only shrink down to the current length.
222 
223 void TBuffer::Expand(Int_t newsize, Bool_t copy)
224 {
225  Int_t l = Length();
226  if ( (l > newsize) && copy ) {
227  newsize = l;
228  }
229  const Int_t extraspace = (fMode&kWrite)!=0 ? kExtraSpace : 0;
230 
231  if ( ((Long64_t)newsize+extraspace) > kMaxBufferSize) {
232  if (l < kMaxBufferSize) {
233  newsize = kMaxBufferSize - extraspace;
234  } else {
235  Fatal("Expand","Requested size (%d) is too large (max is %d).", newsize, kMaxBufferSize);
236  }
237  }
238  if ( (fMode&kWrite)!=0 ) {
240  copy ? fBufSize+kExtraSpace : 0);
241  } else {
242  fBuffer = fReAllocFunc(fBuffer, newsize,
243  copy ? fBufSize : 0);
244  }
245  if (fBuffer == 0) {
247  Fatal("Expand","Failed to expand the data buffer using TStorage::ReAllocChar.");
248  } else if (fReAllocFunc == R__NoReAllocChar) {
249  Fatal("Expand","Failed to expand the data buffer because TBuffer does not own it and no custom memory reallocator was provided.");
250  } else {
251  Fatal("Expand","Failed to expand the data buffer using custom memory reallocator 0x%lx.", (Long_t)fReAllocFunc);
252  }
253  }
254  fBufSize = newsize;
255  fBufCur = fBuffer + l;
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Return pointer to parent of this buffer.
261 
263 {
264  return fParent;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Set parent owning this buffer.
269 
271 {
272  fParent = parent;
273 }
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Return the reallocation method currently used.
276 
278 {
279  return fReAllocFunc;
280 }
281 
282 ////////////////////////////////////////////////////////////////////////////////
283 /// Set which memory reallocation method to use. If reallocafunc is null,
284 /// reset it to the default value (TStorage::ReAlloc)
285 
287 {
288  if (reallocfunc) {
289  fReAllocFunc = reallocfunc;
290  } else {
291  if (TestBit(kIsOwner)) {
293  } else {
295  }
296  }
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// Set buffer in read mode.
301 
303 {
304  if ( (fMode&kWrite)!=0 ) {
305  // We had reserved space for the free block count,
306  // release it,
308  }
309  fMode = kRead;
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// Set buffer in write mode.
314 
316 {
317  if ( (fMode&kWrite)==0 ) {
318  // We had not yet reserved space for the free block count,
319  // reserve it now.
321  }
322  fMode = kWrite;
323 }
324 
325 ////////////////////////////////////////////////////////////////////////////////
326 /// Forward to TROOT::GetClass().
327 
328 TClass *TBuffer::GetClass(const std::type_info &typeinfo)
329 {
330  return TClass::GetClass(typeinfo);
331 }
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Forward to TROOT::GetClass().
335 
336 TClass *TBuffer::GetClass(const char *className)
337 {
338  return TClass::GetClass(className);
339 }
340 
341 ////////////////////////////////////////////////////////////////////////////////
342 /// Return the current Process-ID.
343 
345 {
346  if (!pidf) return TProcessID::GetPID(); //may happen when cloning an object
347  return 0;
348 }
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// Always return 0 (current processID).
352 
354 {
355  return 0;
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Push a new data cache area onto the list of area to be used for
360 /// temporarily store 'missing' data members.
361 
363 {
364  fCacheStack.push_back(obj);
365 }
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 /// Return the 'current' data cache area from the list of area to be used for
369 /// temporarily store 'missing' data members.
370 
372 {
373  if (fCacheStack.empty()) return 0;
374  return fCacheStack.back();
375 }
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 /// Pop and Return the 'current' data cache area from the list of area to be used for
379 /// temporarily store 'missing' data members.
380 
382 {
383  TVirtualArray *val = PeekDataCache();
384  fCacheStack.pop_back();
385  return val;
386 }
387 
388 ////////////////////////////////////////////////////////////////////////////////
389 /// Byte-swap N primitive-elements in the buffer.
390 /// Bulk API relies on this function.
391 
393 {
394  char *input_buf = GetCurrent();
396 #ifdef R__BYTESWAP
397  Short_t *buf __attribute__((aligned(8))) = reinterpret_cast<Short_t*>(input_buf);
398  for (int idx=0; idx<n; idx++) {
399  Short_t tmp = *reinterpret_cast<Short_t*>(buf + idx); // Makes a copy of the values; frombuf can't handle aliasing.
400  char *tmp_ptr = reinterpret_cast<char *>(&tmp);
401  frombuf(tmp_ptr, buf + idx);
402  }
403 #endif
404  } else if ((type == EDataType::kFloat_t) || (type == EDataType::kInt_t) || (type == EDataType::kUInt_t)) {
405 #ifdef R__BYTESWAP
406  Float_t *buf __attribute__((aligned(8))) = reinterpret_cast<Float_t*>(input_buf);
407  for (int idx=0; idx<n; idx++) {
408  Float_t tmp = *reinterpret_cast<Float_t*>(buf + idx); // Makes a copy of the values; frombuf can't handle aliasing.
409  char *tmp_ptr = reinterpret_cast<char *>(&tmp);
410  frombuf(tmp_ptr, buf + idx);
411  }
412 #endif
414 #ifdef R__BYTESWAP
415  Double_t *buf __attribute__((aligned(8))) = reinterpret_cast<Double_t*>(input_buf);
416  for (int idx=0; idx<n; idx++) {
417  Double_t tmp = *reinterpret_cast<Double_t*>(buf + idx); // Makes a copy of the values; frombuf can't handle aliasing.
418  char *tmp_ptr = reinterpret_cast<char*>(&tmp);
419  frombuf(tmp_ptr, buf + idx);
420  }
421 #endif
422  } else {
423  return false;
424  }
425 
426  return true;
427 }
kULong64_t
@ kULong64_t
Definition: TDataType.h:38
l
auto * l
Definition: textangle.C:4
TBuffer::fParent
TObject * fParent
Definition: TBuffer.h:54
kMaxBufferSize
constexpr Int_t kMaxBufferSize
Definition: TBuffer.cxx:23
kDouble_t
@ kDouble_t
Definition: TDataType.h:37
n
const Int_t n
Definition: legend1.C:16
TBuffer::PopDataCache
virtual TVirtualArray * PopDataCache()
Pop and Return the 'current' data cache area from the list of area to be used for temporarily store '...
Definition: TBuffer.cxx:381
kInt_t
@ kInt_t
Definition: TDataType.h:36
TObject::TestBit
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
TBuffer::PushDataCache
virtual void PushDataCache(TVirtualArray *)
Push a new data cache area onto the list of area to be used for temporarily store 'missing' data memb...
Definition: TBuffer.cxx:362
TBuffer::kRead
@ kRead
Definition: TBuffer.h:73
TBuffer::SetBuffer
void SetBuffer(void *buf, UInt_t bufsiz=0, Bool_t adopt=kTRUE, ReAllocCharFun_t reallocfunc=0)
Sets a new buffer in an existing TBuffer object.
Definition: TBuffer.cxx:187
TBuffer::fBufCur
char * fBufCur
Definition: TBuffer.h:52
UShort_t
unsigned short UShort_t
Definition: RtypesCore.h:40
TBuffer::TBuffer
TBuffer()
Definition: TBuffer.h:59
TBuffer::Expand
void Expand(Int_t newsize, Bool_t copy=kTRUE)
Expand (or shrink) the I/O buffer to newsize bytes.
Definition: TBuffer.cxx:223
ClassImp
#define ClassImp(name)
Definition: Rtypes.h:364
TBuffer::ReadClassBuffer
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=0)=0
R__NoReAllocChar
static char * R__NoReAllocChar(char *, size_t, size_t)
The user has provided memory than we don't own, thus we can not extent it either.
Definition: TBuffer.cxx:42
Long64_t
long long Long64_t
Definition: RtypesCore.h:73
TBuffer::fBuffer
char * fBuffer
Definition: TBuffer.h:51
TBuffer::fVersion
Int_t fVersion
Definition: TBuffer.h:49
Float_t
float Float_t
Definition: RtypesCore.h:57
TProcessID
Definition: TProcessID.h:74
TObject::Fatal
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:918
Int_t
int Int_t
Definition: RtypesCore.h:45
kUInt_t
@ kUInt_t
Definition: TDataType.h:36
TClass.h
TBuffer::fBufMax
char * fBufMax
Definition: TBuffer.h:53
ReAllocCharFun_t
char *(* ReAllocCharFun_t)(char *, size_t, size_t)
Definition: TStorage.h:30
ROOT::Internal::DefaultStreamer
void DefaultStreamer(TBuffer &R__b, const TClass *cl, void *objpointer)
Default streamer implementation used by ClassDefInline to avoid requirement to include TBuffer....
Definition: TBuffer.cxx:30
TVirtualArray
Definition: TVirtualArray.h:26
TBuffer
Definition: TBuffer.h:43
bool
TBuffer::GetCurrent
char * GetCurrent() const
Definition: TBuffer.h:97
TProcessID.h
TBuffer::Length
Int_t Length() const
Definition: TBuffer.h:100
TBuffer::SetReadMode
void SetReadMode()
Set buffer in read mode.
Definition: TBuffer.cxx:302
TBuffer.h
TBuffer::fReAllocFunc
ReAllocCharFun_t fReAllocFunc
Definition: TBuffer.h:55
TObject::ResetBit
void ResetBit(UInt_t f)
Definition: TObject.h:171
TBuffer::EMode
EMode
Definition: TBuffer.h:73
TObject::SetBit
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
TBuffer::WriteClassBuffer
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
kUShort_t
@ kUShort_t
Definition: TDataType.h:35
Long_t
long Long_t
Definition: RtypesCore.h:54
TBuffer::kMinimalSize
@ kMinimalSize
Definition: TBuffer.h:78
TStorage::ReAllocChar
static char * ReAllocChar(char *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:265
TBuffer::SetReAllocFunc
void SetReAllocFunc(ReAllocCharFun_t reallocfunc=0)
Set which memory reallocation method to use.
Definition: TBuffer.cxx:286
TBuffer::kIsOwner
@ kIsOwner
Definition: TBuffer.h:75
TClass::GetClass
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2925
TBuffer::ByteSwapBuffer
Bool_t ByteSwapBuffer(Long64_t n, EDataType type)
Byte-swap N primitive-elements in the buffer.
Definition: TBuffer.cxx:392
Short_t
short Short_t
Definition: RtypesCore.h:39
TBuffer::GetParent
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:262
kLong64_t
@ kLong64_t
Definition: TDataType.h:38
kFloat_t
@ kFloat_t
Definition: TDataType.h:37
unsigned int
TBuffer::IsReading
Bool_t IsReading() const
Definition: TBuffer.h:86
TBuffer::PeekDataCache
virtual TVirtualArray * PeekDataCache() const
Return the 'current' data cache area from the list of area to be used for temporarily store 'missing'...
Definition: TBuffer.cxx:371
Double_t
double Double_t
Definition: RtypesCore.h:59
TBuffer::fBufSize
Int_t fBufSize
Definition: TBuffer.h:50
TBuffer::WriteProcessID
virtual UShort_t WriteProcessID(TProcessID *pid)=0
Always return 0 (current processID).
Definition: TBuffer.cxx:353
kExtraSpace
constexpr Int_t kExtraSpace
Definition: TBuffer.cxx:22
TClass
Definition: TClass.h:80
frombuf
void frombuf(char *&buf, Bool_t *x)
Definition: Bytes.h:278
EDataType
EDataType
Definition: TDataType.h:28
TObject
Definition: TObject.h:37
TBuffer::fMode
Bool_t fMode
Definition: TBuffer.h:48
TBuffer::GetReAllocFunc
ReAllocCharFun_t GetReAllocFunc() const
Return the reallocation method currently used.
Definition: TBuffer.cxx:277
TBuffer::ReadProcessID
virtual TProcessID * ReadProcessID(UShort_t pidf)=0
Return the current Process-ID.
Definition: TBuffer.cxx:344
TProcessID::GetPID
static TProcessID * GetPID()
static: returns pointer to current TProcessID
Definition: TProcessID.cxx:343
TBuffer::AutoExpand
void AutoExpand(Int_t size_needed)
Automatically calculate a new size and expand the buffer to fit at least size_needed.
Definition: TBuffer.cxx:158
TBuffer::SetWriteMode
void SetWriteMode()
Set buffer in write mode.
Definition: TBuffer.cxx:315
type
int type
Definition: TGX11.cxx:121
TBuffer::SetParent
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:270
TBuffer::GetClass
static TClass * GetClass(const std::type_info &typeinfo)
Forward to TROOT::GetClass().
Definition: TBuffer.cxx:328
kShort_t
@ kShort_t
Definition: TDataType.h:35
TBuffer::kInitialSize
@ kInitialSize
Definition: TBuffer.h:78
TBuffer::kWrite
@ kWrite
Definition: TBuffer.h:73
TBuffer::~TBuffer
virtual ~TBuffer()
Delete an I/O buffer object.
Definition: TBuffer.cxx:140
TBuffer::fCacheStack
CacheList_t fCacheStack
Realloc function to be used when extending the buffer.
Definition: TBuffer.h:56
int