Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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 
26 ClassImp(TBuffer);
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 
52 TBuffer::TBuffer(EMode mode)
53 {
54  fBufSize = kInitialSize;
55  fMode = mode;
56  fVersion = 0;
57  fParent = 0;
58 
59  SetBit(kIsOwner);
60 
61  fBuffer = new char[fBufSize+kExtraSpace];
62 
63  fBufCur = fBuffer;
64  fBufMax = fBuffer + fBufSize;
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 
73 TBuffer::TBuffer(EMode mode, Int_t bufsiz)
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 
83  SetBit(kIsOwner);
84 
85  fBuffer = new char[fBufSize+kExtraSpace];
86 
87  fBufCur = fBuffer;
88  fBufMax = fBuffer + fBufSize;
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 ) {
118  fBufSize -= kExtraSpace;
119  }
120  if (!adopt) ResetBit(kIsOwner);
121  } else {
122  if (fBufSize < kMinimalSize) {
123  fBufSize = kMinimalSize;
124  }
125  fBuffer = new char[(Long64_t)fBufSize+kExtraSpace];
126  }
127  fBufCur = fBuffer;
128  fBufMax = fBuffer + fBufSize;
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 
140 TBuffer::~TBuffer()
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
195  ResetBit(kIsOwner);
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  }
206  fBufMax = fBuffer + fBufSize;
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 ) {
239  fBuffer = fReAllocFunc(fBuffer, newsize+kExtraSpace,
240  copy ? fBufSize+kExtraSpace : 0);
241  } else {
242  fBuffer = fReAllocFunc(fBuffer, newsize,
243  copy ? fBufSize : 0);
244  }
245  if (fBuffer == 0) {
246  if (fReAllocFunc == TStorage::ReAllocChar) {
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;
256  fBufMax = fBuffer + fBufSize;
257 }
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 /// Return pointer to parent of this buffer.
261 
262 TObject *TBuffer::GetParent() const
263 {
264  return fParent;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Set parent owning this buffer.
269 
270 void TBuffer::SetParent(TObject *parent)
271 {
272  fParent = parent;
273 }
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Return the reallocation method currently used.
276 
277 ReAllocCharFun_t TBuffer::GetReAllocFunc() const
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 
286 void TBuffer::SetReAllocFunc(ReAllocCharFun_t reallocfunc )
287 {
288  if (reallocfunc) {
289  fReAllocFunc = reallocfunc;
290  } else {
291  if (TestBit(kIsOwner)) {
292  fReAllocFunc = TStorage::ReAllocChar;
293  } else {
294  fReAllocFunc = R__NoReAllocChar;
295  }
296  }
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// Set buffer in read mode.
301 
302 void TBuffer::SetReadMode()
303 {
304  if ( (fMode&kWrite)!=0 ) {
305  // We had reserved space for the free block count,
306  // release it,
307  fBufSize += kExtraSpace;
308  }
309  fMode = kRead;
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// Set buffer in write mode.
314 
315 void TBuffer::SetWriteMode()
316 {
317  if ( (fMode&kWrite)==0 ) {
318  // We had not yet reserved space for the free block count,
319  // reserve it now.
320  fBufSize -= kExtraSpace;
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 
344 TProcessID *TBuffer::ReadProcessID(UShort_t pidf)
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 
353 UShort_t TBuffer::WriteProcessID(TProcessID *)
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 
362 void TBuffer::PushDataCache(TVirtualArray *obj)
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 
371 TVirtualArray *TBuffer::PeekDataCache() const
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 
381 TVirtualArray *TBuffer::PopDataCache()
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 
392 Bool_t TBuffer::ByteSwapBuffer(Long64_t n, EDataType type)
393 {
394  char *input_buf = GetCurrent();
395  if ((type == EDataType::kShort_t) || (type == EDataType::kUShort_t)) {
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
413  } else if ((type == EDataType::kDouble_t) || (type == EDataType::kLong64_t) || (type == EDataType::kULong64_t)) {
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 }