Logo ROOT   6.14/05
Reference Guide
TBufferText.cxx
Go to the documentation of this file.
1 // $Id$
2 // Author: Sergey Linev 21.12.2017
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2017, 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 /**
13 \class TBufferText
14 \ingroup IO
15 
16 Base class for text-based streamers like TBufferJSON or TBufferXML
17 Special actions list will use methods, introduced in this class.
18 
19 Idea to have equivalent methods names in TBufferFile and TBufferText, that
20 actions list for both are the same.
21 */
22 
23 #include "TBufferText.h"
24 
25 #include "TStreamerInfo.h"
26 #include "TStreamerElement.h"
27 #include "TStreamerInfoActions.h"
28 #include "TFile.h"
29 #include "TVirtualMutex.h"
30 #include "TInterpreter.h"
31 #include "TROOT.h"
32 #include "TExMap.h"
33 #include "TError.h"
34 
36 
37 const char *TBufferText::fgFloatFmt = "%e";
38 const char *TBufferText::fgDoubleFmt = "%.14e";
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 /// Default constructor
42 
44 {
45 }
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 /// Normal constructor
49 
51 {
52  fBufSize = 1000000000;
53 
54  SetParent(parent);
56 }
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 /// destructor
60 
62 {
63 }
64 
65 ////////////////////////////////////////////////////////////////////////////////
66 /// Read one collection of objects from the buffer using the StreamerInfoLoopAction.
67 /// The collection needs to be a split TClonesArray or a split vector of pointers.
68 
70 {
71  TVirtualStreamerInfo *info = sequence.fStreamerInfo;
72  IncrementLevel(info);
73 
74  if (gDebug) {
75  // loop on all active members
76  TStreamerInfoActions::ActionContainer_t::const_iterator end = sequence.fActions.end();
77  for (TStreamerInfoActions::ActionContainer_t::const_iterator iter = sequence.fActions.begin(); iter != end;
78  ++iter) {
79  // Idea: Try to remove this function call as it is really needed only for JSON streaming.
80  SetStreamerElementNumber((*iter).fConfiguration->fCompInfo->fElem, (*iter).fConfiguration->fCompInfo->fType);
81  (*iter).PrintDebug(*this, obj);
82  (*iter)(*this, obj);
83  }
84  } else {
85  // loop on all active members
86  TStreamerInfoActions::ActionContainer_t::const_iterator end = sequence.fActions.end();
87  for (TStreamerInfoActions::ActionContainer_t::const_iterator iter = sequence.fActions.begin(); iter != end;
88  ++iter) {
89  // Idea: Try to remove this function call as it is really needed only for JSON streaming.
90  SetStreamerElementNumber((*iter).fConfiguration->fCompInfo->fElem, (*iter).fConfiguration->fCompInfo->fType);
91  (*iter)(*this, obj);
92  }
93  }
94  DecrementLevel(info);
95  return 0;
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Read one collection of objects from the buffer using the StreamerInfoLoopAction.
100 /// The collection needs to be a split TClonesArray or a split vector of pointers.
101 
103  void *end_collection)
104 {
105  TVirtualStreamerInfo *info = sequence.fStreamerInfo;
106  IncrementLevel(info);
107 
108  if (gDebug) {
109  // loop on all active members
110  TStreamerInfoActions::ActionContainer_t::const_iterator end = sequence.fActions.end();
111  for (TStreamerInfoActions::ActionContainer_t::const_iterator iter = sequence.fActions.begin(); iter != end;
112  ++iter) {
113  // Idea: Try to remove this function call as it is really needed only for JSON streaming.
114  SetStreamerElementNumber((*iter).fConfiguration->fCompInfo->fElem, (*iter).fConfiguration->fCompInfo->fType);
115  (*iter).PrintDebug(
116  *this, *(char **)start_collection); // Warning: This limits us to TClonesArray and vector of pointers.
117  (*iter)(*this, start_collection, end_collection);
118  }
119  } else {
120  // loop on all active members
121  TStreamerInfoActions::ActionContainer_t::const_iterator end = sequence.fActions.end();
122  for (TStreamerInfoActions::ActionContainer_t::const_iterator iter = sequence.fActions.begin(); iter != end;
123  ++iter) {
124  // Idea: Try to remove this function call as it is really needed only for JSON streaming.
125  SetStreamerElementNumber((*iter).fConfiguration->fCompInfo->fElem, (*iter).fConfiguration->fCompInfo->fType);
126  (*iter)(*this, start_collection, end_collection);
127  }
128  }
129  DecrementLevel(info);
130  return 0;
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 /// Read one collection of objects from the buffer using the StreamerInfoLoopAction.
135 
137  void *end_collection)
138 {
139  TVirtualStreamerInfo *info = sequence.fStreamerInfo;
140  IncrementLevel(info);
141 
143  if (gDebug) {
144 
145  // Get the address of the first item for the PrintDebug.
146  // (Performance is not essential here since we are going to print to
147  // the screen anyway).
148  void *arr0 = loopconfig->GetFirstAddress(start_collection, end_collection);
149  // loop on all active members
150  TStreamerInfoActions::ActionContainer_t::const_iterator end = sequence.fActions.end();
151  for (TStreamerInfoActions::ActionContainer_t::const_iterator iter = sequence.fActions.begin(); iter != end;
152  ++iter) {
153  // Idea: Try to remove this function call as it is really needed only for JSON streaming.
154  SetStreamerElementNumber((*iter).fConfiguration->fCompInfo->fElem, (*iter).fConfiguration->fCompInfo->fType);
155  (*iter).PrintDebug(*this, arr0);
156  (*iter)(*this, start_collection, end_collection, loopconfig);
157  }
158  } else {
159  // loop on all active members
160  TStreamerInfoActions::ActionContainer_t::const_iterator end = sequence.fActions.end();
161  for (TStreamerInfoActions::ActionContainer_t::const_iterator iter = sequence.fActions.begin(); iter != end;
162  ++iter) {
163  // Idea: Try to remove this function call as it is really needed only for JSON streaming.
164  SetStreamerElementNumber((*iter).fConfiguration->fCompInfo->fElem, (*iter).fConfiguration->fCompInfo->fType);
165  (*iter)(*this, start_collection, end_collection, loopconfig);
166  }
167  }
168  DecrementLevel(info);
169  return 0;
170 }
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 /// Function called by the Streamer functions to serialize object at p
174 /// to buffer b. The optional argument info may be specified to give an
175 /// alternative StreamerInfo instead of using the default StreamerInfo
176 /// automatically built from the class definition.
177 /// For more information, see class TStreamerInfo.
178 
179 Int_t TBufferText::WriteClassBuffer(const TClass *cl, void *pointer)
180 {
181  // build the StreamerInfo if first time for the class
182  TStreamerInfo *sinfo = (TStreamerInfo *)const_cast<TClass *>(cl)->GetCurrentStreamerInfo();
183  if (!sinfo) {
184  // Have to be sure between the check and the taking of the lock if the current streamer has changed
186  sinfo = (TStreamerInfo *)const_cast<TClass *>(cl)->GetCurrentStreamerInfo();
187  if (!sinfo) {
188  const_cast<TClass *>(cl)->BuildRealData(pointer);
189  sinfo = new TStreamerInfo(const_cast<TClass *>(cl));
190  const_cast<TClass *>(cl)->SetCurrentStreamerInfo(sinfo);
191  const_cast<TClass *>(cl)->RegisterStreamerInfo(sinfo);
192  if (gDebug > 0)
193  Info("WriteClassBuffer", "Creating StreamerInfo for class: %s, version: %d", cl->GetName(),
194  cl->GetClassVersion());
195  sinfo->Build();
196  }
197  } else if (!sinfo->IsCompiled()) {
199  // Redo the test in case we have been victim of a data race on fIsCompiled.
200  if (!sinfo->IsCompiled()) {
201  const_cast<TClass *>(cl)->BuildRealData(pointer);
202  sinfo->BuildOld();
203  }
204  }
205 
206  // write the class version number and reserve space for the byte count
207  UInt_t R__c = WriteVersion(cl, kTRUE);
208 
209  // NOTE: In the future Philippe wants this to happen via a custom action
210  TagStreamerInfo(sinfo);
211  ApplySequence(*(sinfo->GetWriteTextActions()), (char *)pointer);
212 
213  // write the byte count at the start of the buffer
214  SetByteCount(R__c, kTRUE);
215 
216  if (gDebug > 2)
217  Info("WriteClassBuffer", "class: %s version %d has written %d bytes", cl->GetName(), cl->GetClassVersion(),
218  UInt_t(fBufCur - fBuffer) - R__c - (UInt_t)sizeof(UInt_t));
219  return 0;
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Deserialize information from a buffer into an object.
224 ///
225 /// Note: This function is called by the xxx::Streamer() functions in
226 /// rootcint-generated dictionaries.
227 /// This function assumes that the class version and the byte count
228 /// information have been read.
229 ///
230 /// \param[in] version The version number of the class
231 /// \param[in] start The starting position in the buffer b
232 /// \param[in] count The number of bytes for this object in the buffer
233 ///
234 
235 Int_t TBufferText::ReadClassBuffer(const TClass *cl, void *pointer, Int_t version, UInt_t start, UInt_t count,
236  const TClass *onFileClass)
237 {
238 
239  //---------------------------------------------------------------------------
240  // The ondisk class has been specified so get foreign streamer info
241  /////////////////////////////////////////////////////////////////////////////
242 
243  TStreamerInfo *sinfo = nullptr;
244  if (onFileClass) {
245  sinfo = (TStreamerInfo *)cl->GetConversionStreamerInfo(onFileClass, version);
246  if (!sinfo) {
247  Error("ReadClassBuffer",
248  "Could not find the right streamer info to convert %s version %d into a %s, object skipped at offset %d",
249  onFileClass->GetName(), version, cl->GetName(), Length());
250  CheckByteCount(start, count, onFileClass);
251  return 0;
252  }
253  }
254  //---------------------------------------------------------------------------
255  // Get local streamer info
256  /////////////////////////////////////////////////////////////////////////////
257  /// The StreamerInfo should exist at this point.
258 
259  else {
261  auto infos = cl->GetStreamerInfos();
262  auto ninfos = infos->GetSize();
263  if (version < -1 || version >= ninfos) {
264  Error("ReadBuffer1", "class: %s, attempting to access a wrong version: %d, object skipped at offset %d",
265  cl->GetName(), version, Length());
266  CheckByteCount(start, count, cl);
267  return 0;
268  }
269  sinfo = (TStreamerInfo *)infos->At(version);
270  if (!sinfo) {
271  // Unless the data is coming via a socket connection from with schema evolution
272  // (tracking) was not enabled. So let's create the StreamerInfo if it is the
273  // one for the current version, otherwise let's complain ...
274  // We could also get here if there old class version was '1' and the new class version is higher than 1
275  // AND the checksum is the same.
276  if (version == cl->GetClassVersion() || version == 1) {
277  const_cast<TClass *>(cl)->BuildRealData(pointer);
278  // This creation is alright since we just checked within the
279  // current 'locked' section.
280  sinfo = new TStreamerInfo(const_cast<TClass *>(cl));
281  const_cast<TClass *>(cl)->RegisterStreamerInfo(sinfo);
282  if (gDebug > 0)
283  Info("ReadClassBuffer", "Creating StreamerInfo for class: %s, version: %d", cl->GetName(), version);
284  sinfo->Build();
285  } else if (version == 0) {
286  // When the object was written the class was version zero, so
287  // there is no StreamerInfo to be found.
288  // Check that the buffer position corresponds to the byte count.
289  CheckByteCount(start, count, cl);
290  return 0;
291  } else {
292  Error("ReadClassBuffer",
293  "Could not find the StreamerInfo for version %d of the class %s, object skipped at offset %d",
294  version, cl->GetName(), Length());
295  CheckByteCount(start, count, cl);
296  return 0;
297  }
298  } else if (!sinfo->IsCompiled()) { // Note this read is protected by the above lock.
299  // Streamer info has not been compiled, but exists.
300  // Therefore it was read in from a file and we have to do schema evolution.
301  const_cast<TClass *>(cl)->BuildRealData(pointer);
302  sinfo->BuildOld();
303  }
304  }
305 
306  // Deserialize the object.
307  ApplySequence(*(sinfo->GetReadTextActions()), (char *)pointer);
308  if (sinfo->IsRecovered())
309  count = 0;
310 
311  // Check that the buffer position corresponds to the byte count.
312  CheckByteCount(start, count, cl);
313  return 0;
314 }
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 /// Deserialize information from a buffer into an object.
318 ///
319 /// Note: This function is called by the xxx::Streamer()
320 /// functions in rootcint-generated dictionaries.
321 ///
322 
323 Int_t TBufferText::ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onFileClass)
324 {
325  // Read the class version from the buffer.
326  UInt_t R__s = 0; // Start of object.
327  UInt_t R__c = 0; // Count of bytes.
328  Version_t version;
329 
330  if (onFileClass)
331  version = ReadVersion(&R__s, &R__c, onFileClass);
332  else
333  version = ReadVersion(&R__s, &R__c, cl);
334 
335  Bool_t v2file = kFALSE;
336  TFile *file = (TFile *)GetParent();
337  if (file && file->GetVersion() < 30000) {
338  version = -1; // This is old file
339  v2file = kTRUE;
340  }
341 
342  //---------------------------------------------------------------------------
343  // The ondisk class has been specified so get foreign streamer info
344  /////////////////////////////////////////////////////////////////////////////
345 
346  TStreamerInfo *sinfo = nullptr;
347  if (onFileClass) {
348  sinfo = (TStreamerInfo *)cl->GetConversionStreamerInfo(onFileClass, version);
349  if (!sinfo) {
350  Error("ReadClassBuffer",
351  "Could not find the right streamer info to convert %s version %d into a %s, object skipped at offset %d",
352  onFileClass->GetName(), version, cl->GetName(), Length());
353  CheckByteCount(R__s, R__c, onFileClass);
354  return 0;
355  }
356  }
357  //---------------------------------------------------------------------------
358  // Get local streamer info
359  /////////////////////////////////////////////////////////////////////////////
360  /// The StreamerInfo should exist at this point.
361 
362  else {
363  TStreamerInfo *guess = (TStreamerInfo *)cl->GetLastReadInfo();
364  if (guess && guess->GetClassVersion() == version) {
365  sinfo = guess;
366  } else {
367  // The last one is not the one we are looking for.
368  {
370 
371  const TObjArray *infos = cl->GetStreamerInfos();
372  Int_t infocapacity = infos->Capacity();
373  if (infocapacity) {
374  if (version < -1 || version >= infocapacity) {
375  Error("ReadClassBuffer",
376  "class: %s, attempting to access a wrong version: %d, object skipped at offset %d",
377  cl->GetName(), version, Length());
378  CheckByteCount(R__s, R__c, cl);
379  return 0;
380  }
381  sinfo = (TStreamerInfo *)infos->UncheckedAt(version);
382  if (sinfo) {
383  if (!sinfo->IsCompiled()) {
384  // Streamer info has not been compiled, but exists.
385  // Therefore it was read in from a file and we have to do schema evolution?
387  const_cast<TClass *>(cl)->BuildRealData(pointer);
388  sinfo->BuildOld();
389  }
390  // If the compilation succeeded, remember this StreamerInfo.
391  // const_cast okay because of the lock on gInterpreterMutex.
392  if (sinfo->IsCompiled())
393  const_cast<TClass *>(cl)->SetLastReadInfo(sinfo);
394  }
395  }
396  }
397 
398  if (!sinfo) {
399  // Unless the data is coming via a socket connection from with schema evolution
400  // (tracking) was not enabled. So let's create the StreamerInfo if it is the
401  // one for the current version, otherwise let's complain ...
402  // We could also get here when reading a file prior to the introduction of StreamerInfo.
403  // We could also get here if there old class version was '1' and the new class version is higher than 1
404  // AND the checksum is the same.
405  if (v2file || version == cl->GetClassVersion() || version == 1) {
407 
408  // We need to check if another thread did not get here first
409  // and did the StreamerInfo creation already.
410  auto infos = cl->GetStreamerInfos();
411  auto ninfos = infos->GetSize();
412  if (!(version < -1 || version >= ninfos)) {
413  sinfo = (TStreamerInfo *)infos->At(version);
414  }
415  if (!sinfo) {
416  const_cast<TClass *>(cl)->BuildRealData(pointer);
417  sinfo = new TStreamerInfo(const_cast<TClass *>(cl));
418  sinfo->SetClassVersion(version);
419  const_cast<TClass *>(cl)->RegisterStreamerInfo(sinfo);
420  if (gDebug > 0)
421  Info("ReadClassBuffer", "Creating StreamerInfo for class: %s, version: %d", cl->GetName(),
422  version);
423  if (v2file) {
424  sinfo->Build(); // Get the elements.
425  sinfo->Clear("build"); // Undo compilation.
426  sinfo->BuildEmulated(file); // Fix the types and redo compilation.
427  } else {
428  sinfo->Build();
429  }
430  }
431  } else if (version == 0) {
432  // When the object was written the class was version zero, so
433  // there is no StreamerInfo to be found.
434  // Check that the buffer position corresponds to the byte count.
435  CheckByteCount(R__s, R__c, cl);
436  return 0;
437  } else {
438  Error("ReadClassBuffer",
439  "Could not find the StreamerInfo for version %d of the class %s, object skipped at offset %d",
440  version, cl->GetName(), Length());
441  CheckByteCount(R__s, R__c, cl);
442  return 0;
443  }
444  }
445  }
446  }
447 
448  // deserialize the object
449  ApplySequence(*(sinfo->GetReadTextActions()), (char *)pointer);
450  if (sinfo->TStreamerInfo::IsRecovered())
451  R__c = 0; // 'TStreamerInfo::' avoids going via a virtual function.
452 
453  // Check that the buffer position corresponds to the byte count.
454  CheckByteCount(R__s, R__c, cl);
455 
456  if (gDebug > 2)
457  Info("ReadClassBuffer", "for class: %s has read %d bytes", cl->GetName(), R__c);
458 
459  return 0;
460 }
461 
462 ////////////////////////////////////////////////////////////////////////////////
463 /// stream object to/from buffer
464 
465 void TBufferText::StreamObject(void *obj, const std::type_info &typeinfo, const TClass * /* onFileClass */)
466 {
467  StreamObject(obj, TClass::GetClass(typeinfo));
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 /// stream object to/from buffer
472 
473 void TBufferText::StreamObject(void *obj, const char *className, const TClass * /* onFileClass */)
474 {
475  StreamObject(obj, TClass::GetClass(className));
476 }
477 
479 {
480  // stream object to/from buffer
481 
482  StreamObject(obj, obj ? obj->IsA() : TObject::Class());
483 }
484 
485 ////////////////////////////////////////////////////////////////////////////////
486 /// read a Float16_t from the buffer
487 
489 {
490  ReadFloat(*f);
491 }
492 
493 ////////////////////////////////////////////////////////////////////////////////
494 /// read a Double32_t from the buffer
495 
497 {
498  ReadDouble(*d);
499 }
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 /// Read a Double32_t from the buffer when the factor and minimun value have
503 /// been specified
504 /// see comments about Double32_t encoding at TBufferFile::WriteDouble32().
505 /// Currently TBufferText does not optimize space in this case.
506 
507 void TBufferText::ReadWithFactor(Float_t *f, Double_t /* factor */, Double_t /* minvalue */)
508 {
509  ReadFloat(*f);
510 }
511 
512 ////////////////////////////////////////////////////////////////////////////////
513 /// Read a Float16_t from the buffer when the number of bits is specified
514 /// (explicitly or not)
515 /// see comments about Float16_t encoding at TBufferFile::WriteFloat16().
516 /// Currently TBufferText does not optimize space in this case.
517 
519 {
520  ReadFloat(*f);
521 }
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 /// Read a Double32_t from the buffer when the factor and minimun value have
525 /// been specified
526 /// see comments about Double32_t encoding at TBufferFile::WriteDouble32().
527 /// Currently TBufferText does not optimize space in this case.
528 
529 void TBufferText::ReadWithFactor(Double_t *d, Double_t /* factor */, Double_t /* minvalue */)
530 {
531  ReadDouble(*d);
532 }
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 /// Read a Double32_t from the buffer when the number of bits is specified
536 /// (explicitly or not)
537 /// see comments about Double32_t encoding at TBufferFile::WriteDouble32().
538 /// Currently TBufferText does not optimize space in this case.
539 
541 {
542  ReadDouble(*d);
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// write a Float16_t to the buffer
547 
549 {
550  WriteFloat(*f);
551 }
552 
553 ////////////////////////////////////////////////////////////////////////////////
554 /// write a Double32_t to the buffer
555 
557 {
558  WriteDouble(*d);
559 }
560 
561 ////////////////////////////////////////////////////////////////////////////////
562 /// Read array of Float16_t from buffer
563 
565 {
566  return ReadArray(f);
567 }
568 
569 ////////////////////////////////////////////////////////////////////////////////
570 /// Read array of Double32_t from buffer
571 
573 {
574  return ReadArray(d);
575 }
576 
577 ////////////////////////////////////////////////////////////////////////////////
578 /// Read array of Float16_t from buffer
579 
581 {
582  return ReadStaticArray(f);
583 }
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 /// Read array of Double32_t from buffer
587 
589 {
590  return ReadStaticArray(d);
591 }
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 /// read array of Float16_t from buffer
595 
597 {
598  ReadFastArray(f, n);
599 }
600 
601 ////////////////////////////////////////////////////////////////////////////////
602 /// read array of Float16_t from buffer
603 
605 {
606  ReadFastArray(f, n);
607 }
608 
609 ////////////////////////////////////////////////////////////////////////////////
610 /// read array of Float16_t from buffer
611 
613 {
614  ReadFastArray(f, n);
615 }
616 
617 ////////////////////////////////////////////////////////////////////////////////
618 /// read array of Double32_t from buffer
619 
621 {
622  ReadFastArray(d, n);
623 }
624 
625 ////////////////////////////////////////////////////////////////////////////////
626 /// read array of Double32_t from buffer
627 
629 {
630  ReadFastArray(d, n);
631 }
632 
633 ////////////////////////////////////////////////////////////////////////////////
634 /// read array of Double32_t from buffer
635 
637 {
638  ReadFastArray(d, n);
639 }
640 ////////////////////////////////////////////////////////////////////////////////
641 /// Write array of Float16_t to buffer
642 
644 {
645  WriteArray(f, n);
646 }
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 /// Write array of Double32_t to buffer
650 
652 {
653  WriteArray(d, n);
654 }
655 
656 ////////////////////////////////////////////////////////////////////////////////
657 /// Write array of Float16_t to buffer
658 
660 {
661  WriteFastArray(f, n);
662 }
663 
664 ////////////////////////////////////////////////////////////////////////////////
665 /// Write array of Double32_t to buffer
666 
668 {
669  WriteFastArray(d, n);
670 }
671 
672 ////////////////////////////////////////////////////////////////////////////////
673 /// Skip class version from I/O buffer.
674 
676 {
677  ReadVersion(nullptr, nullptr, cl);
678 }
679 
680 ////////////////////////////////////////////////////////////////////////////////
681 /// Write data of base class.
682 
684 {
685  elem->WriteBuffer(*this, (char *)start);
686 }
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 /// Read data of base class.
690 
692 {
693  elem->ReadBuffer(*this, (char *)start);
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 /// method compress float string, excluding exp and/or move float point
698 /// - 1.000000e-01 -> 0.1
699 /// - 3.750000e+00 -> 3.75
700 /// - 3.750000e-03 -> 0.00375
701 /// - 3.750000e-04 -> 3.75e-4
702 /// - 1.100000e-10 -> 1.1e-10
703 
704 void TBufferText::CompactFloatString(char *sbuf, unsigned len)
705 {
706  char *pnt = nullptr, *exp = nullptr, *lastdecimal = nullptr, *s = sbuf;
707  bool negative_exp = false;
708  int power = 0;
709  while (*s && --len) {
710  switch (*s) {
711  case '.': pnt = s; break;
712  case 'E':
713  case 'e': exp = s; break;
714  case '-':
715  if (exp)
716  negative_exp = true;
717  break;
718  case '+': break;
719  default: // should be digits from '0' to '9'
720  if ((*s < '0') || (*s > '9'))
721  return;
722  if (exp)
723  power = power * 10 + (*s - '0');
724  else if (pnt && *s != '0')
725  lastdecimal = s;
726  break;
727  }
728  ++s;
729  }
730  if (*s)
731  return; // if end-of-string was not found
732 
733  if (!exp) {
734  // value without exponent like 123.4569000
735  if (pnt) {
736  if (lastdecimal)
737  *(lastdecimal + 1) = 0;
738  else
739  *pnt = 0;
740  }
741  } else if (power == 0) {
742  if (lastdecimal)
743  *(lastdecimal + 1) = 0;
744  else if (pnt)
745  *pnt = 0;
746  } else if (!negative_exp && pnt && exp && (exp - pnt > power)) {
747  // this is case of value 1.23000e+02
748  // we can move point and exclude exponent easily
749  for (int cnt = 0; cnt < power; ++cnt) {
750  char tmp = *pnt;
751  *pnt = *(pnt + 1);
752  *(++pnt) = tmp;
753  }
754  if (lastdecimal && (pnt < lastdecimal))
755  *(lastdecimal + 1) = 0;
756  else
757  *pnt = 0;
758  } else if (negative_exp && pnt && exp && (power < (s - exp))) {
759  // this is small negative exponent like 1.2300e-02
760  if (!lastdecimal)
761  lastdecimal = pnt;
762  *(lastdecimal + 1) = 0;
763  // copy most significant digit on the point place
764  *pnt = *(pnt - 1);
765 
766  for (char *pos = lastdecimal + 1; pos >= pnt; --pos)
767  *(pos + power) = *pos;
768  *(pnt - 1) = '0';
769  *pnt = '.';
770  for (int cnt = 1; cnt < power; ++cnt)
771  *(pnt + cnt) = '0';
772  } else if (pnt && exp) {
773  // keep exponent, but non-significant zeros
774  if (lastdecimal)
775  pnt = lastdecimal + 1;
776  // copy exponent sign
777  *pnt++ = *exp++;
778  if (*exp == '+')
779  ++exp;
780  else if (*exp == '-')
781  *pnt++ = *exp++;
782  // exclude zeros in the begin of exponent
783  while (*exp == '0')
784  ++exp;
785  while (*exp)
786  *pnt++ = *exp++;
787  *pnt = 0;
788  }
789 }
790 
791 ////////////////////////////////////////////////////////////////////////////////
792 /// set printf format for float/double members, default "%e"
793 /// to change format only for doubles, use SetDoubleFormat
794 
795 void TBufferText::SetFloatFormat(const char *fmt)
796 {
797  if (!fmt)
798  fmt = "%e";
799  fgFloatFmt = fmt;
800  fgDoubleFmt = fmt;
801 }
802 
803 ////////////////////////////////////////////////////////////////////////////////
804 /// return current printf format for float members, default "%e"
805 
807 {
808  return fgFloatFmt;
809 }
810 
811 ////////////////////////////////////////////////////////////////////////////////
812 /// set printf format for double members, default "%.14e"
813 /// use it after SetFloatFormat, which also overwrites format for doubles
814 
815 void TBufferText::SetDoubleFormat(const char *fmt)
816 {
817  if (!fmt)
818  fmt = "%.14e";
819  fgDoubleFmt = fmt;
820 }
821 
822 ////////////////////////////////////////////////////////////////////////////////
823 /// return current printf format for double members, default "%.14e"
824 
826 {
827  return fgDoubleFmt;
828 }
829 
830 ////////////////////////////////////////////////////////////////////////////////
831 /// convert float to string with configured format
832 
833 const char *TBufferText::ConvertFloat(Float_t value, char *buf, unsigned len, Bool_t not_optimize)
834 {
835  if (not_optimize) {
836  snprintf(buf, len, fgFloatFmt, value);
837  } else if ((value == std::nearbyint(value)) && (std::abs(value) < 1e15)) {
838  snprintf(buf, len, "%1.0f", value);
839  } else {
840  snprintf(buf, len, fgFloatFmt, value);
841  CompactFloatString(buf, len);
842  }
843  return buf;
844 }
845 
846 ////////////////////////////////////////////////////////////////////////////////
847 /// convert float to string with configured format
848 
849 const char *TBufferText::ConvertDouble(Double_t value, char *buf, unsigned len, Bool_t not_optimize)
850 {
851  if (not_optimize) {
852  snprintf(buf, len, fgFloatFmt, value);
853  } else if ((value == std::nearbyint(value)) && (std::abs(value) < 1e25)) {
854  snprintf(buf, len, "%1.0f", value);
855  } else {
856  snprintf(buf, len, fgDoubleFmt, value);
857  CompactFloatString(buf, len);
858  }
859  return buf;
860 }
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:43
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
static const char * ConvertFloat(Float_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
char * fBuffer
Definition: TBuffer.h:48
void BuildEmulated(TFile *file)
Create an Emulation TStreamerInfo object.
short Version_t
Definition: RtypesCore.h:61
virtual void WriteArrayFloat16(const Float_t *f, Int_t n, TStreamerElement *ele=nullptr)
Write array of Float16_t to buffer.
TLoopConfiguration * fLoopConfig
If this is a bundle of memberwise streaming action, this configures the looping.
float Float_t
Definition: RtypesCore.h:53
virtual void ReadFastArrayWithFactor(Float_t *ptr, Int_t n, Double_t factor, Double_t minvalue)
read array of Float16_t from buffer
TVirtualStreamerInfo * GetConversionStreamerInfo(const char *onfile_classname, Int_t version) const
Return a Conversion StreamerInfo from the class &#39;classname&#39; for version number &#39;version&#39; to this clas...
Definition: TClass.cxx:6757
virtual void WriteFastArrayDouble32(const Double_t *d, Int_t n, TStreamerElement *ele=nullptr)
Write array of Double32_t to buffer.
TObject * GetParent() const
Return pointer to parent of this buffer.
Definition: TBuffer.cxx:241
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:40
virtual void WriteDouble32(Double_t *d, TStreamerElement *ele=nullptr)
write a Double32_t to the buffer
TStreamerInfoActions::TActionSequence * GetReadTextActions()
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:47
static void SetDoubleFormat(const char *fmt="%.14e")
set printf format for double members, default "%.14e" use it after SetFloatFormat, which also overwrites format for doubles
virtual void WriteDouble(Double_t d)=0
#define f(i)
Definition: RSha256.hxx:104
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
virtual Int_t ReadArrayDouble32(Double_t *&d, TStreamerElement *ele=nullptr)
Read array of Double32_t from buffer.
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition: TBuffer.cxx:249
virtual Int_t ReadStaticArrayDouble32(Double_t *d, TStreamerElement *ele=nullptr)
Read array of Double32_t from buffer.
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)=0
virtual ~TBufferText()
destructor
Definition: TBufferText.cxx:61
virtual Int_t CheckByteCount(UInt_t, UInt_t, const TClass *)
Definition: TBufferText.h:79
virtual Int_t ReadStaticArray(Bool_t *b)=0
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
Int_t Length() const
Definition: TBuffer.h:96
virtual void StreamObject(void *obj, const std::type_info &typeinfo, const TClass *onFileClass=nullptr)
stream object to/from buffer
virtual void WriteFloat16(Float_t *f, TStreamerElement *ele=nullptr)
write a Float16_t to the buffer
virtual Int_t ApplySequence(const TStreamerInfoActions::TActionSequence &sequence, void *object)
Read one collection of objects from the buffer using the StreamerInfoLoopAction.
Definition: TBufferText.cxx:69
virtual void WriteArray(const Bool_t *b, Int_t n)=0
virtual void * GetFirstAddress(void *start, const void *end) const =0
Int_t GetVersion() const
Definition: TFile.h:228
void Class()
Definition: Class.C:29
virtual void SetStreamerElementNumber(TStreamerElement *elem, Int_t comp_type)=0
virtual void ReadDouble(Double_t &d)=0
virtual void ReadFastArrayFloat16(Float_t *f, Int_t n, TStreamerElement *ele=nullptr)
read array of Float16_t from buffer
virtual void WriteArrayDouble32(const Double_t *d, Int_t n, TStreamerElement *ele=nullptr)
Write array of Double32_t to buffer.
virtual void WriteFloat(Float_t f)=0
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:457
Base class of the Configurations for the member wise looping routines.
virtual void ReadFastArrayWithNbits(Float_t *ptr, Int_t n, Int_t nbits)
read array of Float16_t from buffer
static const char * fgFloatFmt
! printf argument for floats, either "%f" or "%e" or "%10f" and so on
Definition: TBufferText.h:137
void BuildOld()
rebuild the TStreamerInfo structure
void Clear(Option_t *)
If opt contains &#39;built&#39;, reset this StreamerInfo as if Build or BuildOld was never called on it (usef...
TVirtualStreamerInfo * GetLastReadInfo() const
Definition: TClass.h:410
virtual void ReadWithFactor(Float_t *ptr, Double_t factor, Double_t minvalue)
Read a Double32_t from the buffer when the factor and minimun value have been specified see comments ...
TBufferText()
Default constructor.
Definition: TBufferText.cxx:43
Int_t WriteBuffer(TBuffer &b, char *pointer)
Write the base class into the buffer.
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void SetByteCount(UInt_t, Bool_t=kFALSE)
Definition: TBufferText.h:81
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)
Function called by the Streamer functions to serialize object at p to buffer b.
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
virtual Int_t ApplySequenceVecPtr(const TStreamerInfoActions::TActionSequence &sequence, void *start_collection, void *end_collection)
Read one collection of objects from the buffer using the StreamerInfoLoopAction.
char * fBufCur
Definition: TBuffer.h:49
void SetClassVersion(Int_t vers)
virtual void ReadFastArray(Bool_t *b, Int_t n)=0
virtual void WriteFastArray(const Bool_t *b, Int_t n)=0
static const char * ConvertDouble(Double_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
const Bool_t kFALSE
Definition: RtypesCore.h:88
virtual void DecrementLevel(TVirtualStreamerInfo *)=0
#define d(i)
Definition: RSha256.hxx:102
Version_t GetClassVersion() const
Definition: TClass.h:391
Base class for text-based streamers like TBufferJSON or TBufferXML Special actions list will use meth...
Definition: TBufferText.h:21
void Build()
Build the I/O data structure for the current class version.
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
#define ClassImp(name)
Definition: Rtypes.h:359
double Double_t
Definition: RtypesCore.h:55
virtual void ReadWithNbits(Float_t *ptr, Int_t nbits)
Read a Float16_t from the buffer when the number of bits is specified (explicitly or not) see comment...
static void SetFloatFormat(const char *fmt="%e")
set printf format for float/double members, default "%e" to change format only for doubles...
virtual void ReadDouble32(Double_t *d, TStreamerElement *ele=nullptr)
read a Double32_t from the buffer
static constexpr double s
#define R__LOCKGUARD(mutex)
virtual Int_t ReadStaticArrayFloat16(Float_t *f, TStreamerElement *ele=nullptr)
Read array of Float16_t from buffer.
TStreamerInfoActions::TActionSequence * GetWriteTextActions()
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:2887
static const char * GetDoubleFormat()
return current printf format for double members, default "%.14e"
Mother of all ROOT objects.
Definition: TObject.h:37
Int_t GetClassVersion() const
virtual void WriteBaseClass(void *start, TStreamerBase *elem)
Write data of base class.
static const char * fgDoubleFmt
! printf argument for doubles, either "%f" or "%e" or "%10f" and so on
Definition: TBufferText.h:138
Direct subclass of TBuffer, implements common methods for TBufferFile and TBufferText classes...
Definition: TBufferIO.h:30
Definition: file.py:1
Int_t Capacity() const
Definition: TCollection.h:165
virtual Int_t ReadArrayFloat16(Float_t *&f, TStreamerElement *ele=nullptr)
Read array of Float16_t from buffer.
static const char * GetFloatFormat()
return current printf format for float members, default "%e"
virtual void TagStreamerInfo(TVirtualStreamerInfo *info)
Mark the classindex of the current file as using this TStreamerInfo.
Definition: TBufferIO.cxx:350
#define snprintf
Definition: civetweb.c:1351
Int_t fBufSize
Definition: TBuffer.h:47
Int_t ReadBuffer(TBuffer &b, char *pointer)
Read the content of the buffer.
static void CompactFloatString(char *buf, unsigned len)
method compress float string, excluding exp and/or move float point
R__EXTERN Int_t gDebug
Definition: Rtypes.h:86
virtual void ReadBaseClass(void *start, TStreamerBase *elem)
Read data of base class.
virtual void SkipVersion(const TClass *cl=nullptr)
Skip class version from I/O buffer.
virtual void IncrementLevel(TVirtualStreamerInfo *info)=0
virtual void ReadFloat(Float_t &f)=0
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
double exp(double)
Abstract Interface class describing Streamer information for one class.
virtual void ReadFastArrayDouble32(Double_t *d, Int_t n, TStreamerElement *ele=nullptr)
read array of Double32_t from buffer
const Bool_t kTRUE
Definition: RtypesCore.h:87
virtual void WriteFastArrayFloat16(const Float_t *d, Int_t n, TStreamerElement *ele=nullptr)
Write array of Float16_t to buffer.
const Int_t n
Definition: legend1.C:16
virtual Int_t ReadClassBuffer(const TClass *, void *, const TClass *=nullptr)
Deserialize information from a buffer into an object.
const char * cnt
Definition: TXMLSetup.cxx:74
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
virtual void ReadFloat16(Float_t *f, TStreamerElement *ele=nullptr)
read a Float16_t from the buffer
virtual Int_t ReadArray(Bool_t *&b)=0
TVirtualStreamerInfo * fStreamerInfo
StreamerInfo used to derive these actions.