Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TEmulatedCollectionProxy.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Markus Frank 28/10/04
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 /**
13  \class TEmulatedCollectionProxy
14  \ingroup IO
15 
16 Streamer around an arbitrary STL like container, which implements basic
17 container functionality.
18 
19 ### Note:
20 Although this class contains all the setup necessary to deal
21 with maps, the map-like functionality is NOT supported.
22 For optimization reasons this functionality is put into
23 the class TEmulatedMapProxy.
24 */
25 
27 #include "TStreamerElement.h"
28 #include "TStreamerInfo.h"
29 #include "TClassEdit.h"
30 #include "TError.h"
31 #include "TROOT.h"
32 #include "Riostream.h"
33 
34 #include "TVirtualMutex.h" // For R__LOCKGUARD
35 #include "TInterpreter.h" // For gInterpreterMutex
36 
37 //
38 // Utility function to allow the creation of a TClass for a std::pair without
39 // a dictionary (See end of file for implementation
40 //
41 
42 static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const char *dmFull, Int_t offset);
43 static TStreamerInfo *R__GenerateTClassForPair(const std::string &f, const std::string &s);
44 
45 TEmulatedCollectionProxy::TEmulatedCollectionProxy(const TEmulatedCollectionProxy& copy)
46  : TGenCollectionProxy(copy)
47 {
48  // Build a Streamer for an emulated vector whose type is 'name'.
49  fProperties |= kIsEmulated;
50 }
51 
52 TEmulatedCollectionProxy::TEmulatedCollectionProxy(const char* cl_name, Bool_t silent)
53  : TGenCollectionProxy(typeid(std::vector<char>), sizeof(std::vector<char>::iterator))
54 {
55  // Build a Streamer for a collection whose type is described by 'collectionClass'.
56 
57  fName = cl_name;
58  if ( this->TEmulatedCollectionProxy::InitializeEx(silent) ) {
59  fCreateEnv = TGenCollectionProxy::Env_t::Create;
60  }
61  fProperties |= kIsEmulated;
62 }
63 
64 TEmulatedCollectionProxy::~TEmulatedCollectionProxy()
65 {
66  // Standard destructor
67  if ( fEnv && fEnv->fObject ) {
68  Clear();
69  }
70 }
71 
72 TVirtualCollectionProxy* TEmulatedCollectionProxy::Generate() const
73 {
74  // Virtual copy constructor
75 
76  if ( !fClass ) Initialize(kFALSE);
77  return new TEmulatedCollectionProxy(*this);
78 }
79 
80 void TEmulatedCollectionProxy::Destructor(void* p, Bool_t dtorOnly) const
81 {
82  // Virtual destructor
83 
84  if (!p) return;
85  if (!fEnv || fEnv->fObject != p) { // Envoid the cost of TPushPop if we don't need it
86  // FIXME: This is not thread safe.
87  TVirtualCollectionProxy::TPushPop env(const_cast<TEmulatedCollectionProxy*>(this), p);
88  const_cast<TEmulatedCollectionProxy*>(this)->Clear("force");
89  } else {
90  const_cast<TEmulatedCollectionProxy*>(this)->Clear("force");
91  }
92  if (dtorOnly) {
93  ((Cont_t*)p)->~Cont_t();
94  } else {
95  delete (Cont_t*) p;
96  }
97 }
98 
99 void TEmulatedCollectionProxy::DeleteArray(void* p, Bool_t dtorOnly) const
100 {
101  // Virtual array destructor
102 
103  // Cannot implement this properly, we do not know
104  // how many elements are in the array.
105  Warning("DeleteArray", "Cannot properly delete emulated array of %s at %p, I don't know how many elements it has!", fClass->GetName(), p);
106  if (!dtorOnly) {
107  delete[] (Cont_t*) p;
108  }
109 }
110 
111 TGenCollectionProxy *TEmulatedCollectionProxy::InitializeEx(Bool_t silent)
112 {
113  // Proxy initializer
114  R__LOCKGUARD(gInterpreterMutex);
115  if (fClass) return this;
116 
117 
118  TClass *cl = TClass::GetClass(fName.c_str());
119  fEnv = 0;
120  fKey = 0;
121  if ( cl ) {
122  int nested = 0;
123  std::vector<std::string> inside;
124  fPointers = false;
125  int num = TClassEdit::GetSplit(fName.c_str(),inside,nested);
126  if ( num > 1 ) {
127  std::string nam;
128  if ( inside[0].find("stdext::hash_") != std::string::npos ) {
129  inside[0].replace(3,10,"::");
130  }
131  if ( inside[0].find("__gnu_cxx::hash_") != std::string::npos ) {
132  inside[0].replace(0,16,"std::");
133  }
134  fSTL_type = TClassEdit::STLKind(inside[0]);
135  // Note: an emulated collection proxy is never really associative
136  // since under-neath is actually an array.
137 
138  // std::cout << "Initialized " << typeid(*this).name() << ":" << fName << std::endl;
139  auto alignedSize = [](size_t in) {
140  constexpr size_t kSizeOfPtr = sizeof(void*);
141  return in + (kSizeOfPtr - in%kSizeOfPtr)%kSizeOfPtr;
142  };
143  switch ( fSTL_type ) {
144  case ROOT::kSTLmap:
145  case ROOT::kSTLmultimap:
146  nam = "pair<"+inside[1]+","+inside[2];
147  nam += (nam[nam.length()-1]=='>') ? " >" : ">";
148  if (0==TClass::GetClass(nam.c_str())) {
149  // We need to emulate the pair
150  R__GenerateTClassForPair(inside[1],inside[2]);
151  }
152  fValue = new Value(nam,silent);
153  fKey = new Value(inside[1],silent);
154  fVal = new Value(inside[2],silent);
155  if ( !(*fValue).IsValid() || !fKey->IsValid() || !fVal->IsValid() ) {
156  return 0;
157  }
158  fPointers |= 0 != (fKey->fCase&kIsPointer);
159  if (fPointers || (0 != (fKey->fProperties&kNeedDelete))) {
160  fProperties |= kNeedDelete;
161  }
162  if ( 0 == fValOffset ) {
163  fValOffset = alignedSize(fKey->fSize);
164  }
165  if ( 0 == fValDiff ) {
166  fValDiff = alignedSize(fValOffset + fVal->fSize);
167  }
168  if (num > 3 && !inside[3].empty()) {
169  if (! TClassEdit::IsDefAlloc(inside[3].c_str(),inside[0].c_str())) {
170  fProperties |= kCustomAlloc;
171  }
172  }
173  break;
174  case ROOT::kSTLbitset:
175  inside[1] = "bool";
176  // Intentional fall through
177  default:
178  fValue = new Value(inside[1],silent);
179  fVal = new Value(*fValue);
180  if ( !(*fValue).IsValid() || !fVal->IsValid() ) {
181  return 0;
182  }
183  if ( 0 == fValDiff ) {
184  fValDiff = fVal->fSize;
185  // No need to align, the size even for a class should already
186  // be correctly padded for use in a vector.
187  }
188  if (num > 2 && !inside[2].empty()) {
189  if (! TClassEdit::IsDefAlloc(inside[2].c_str(),inside[0].c_str())) {
190  fProperties |= kCustomAlloc;
191  }
192  }
193  break;
194  }
195  fPointers |= 0 != (fVal->fCase&kIsPointer);
196  if (fPointers || (0 != (fVal->fProperties&kNeedDelete))) {
197  fProperties |= kNeedDelete;
198  }
199  fClass = cl;
200  return this;
201  }
202  Fatal("TEmulatedCollectionProxy","Components of %s not analysed!",cl->GetName());
203  }
204  Fatal("TEmulatedCollectionProxy","Collection class %s not found!",fTypeinfo.name());
205  return 0;
206 }
207 
208 Bool_t TEmulatedCollectionProxy::IsValid() const
209 {
210  // Return true if the collection proxy was well initialized.
211  return (0 != fCreateEnv.call);
212 }
213 
214 UInt_t TEmulatedCollectionProxy::Size() const
215 {
216  // Return the current size of the container
217 
218  if ( fEnv && fEnv->fObject ) {
219  return fEnv->fSize = PCont_t(fEnv->fObject)->size()/fValDiff;
220  }
221  Fatal("TEmulatedCollectionProxy","Size> Logic error - no proxy object set.");
222  return 0;
223 }
224 
225 void TEmulatedCollectionProxy::Clear(const char* opt)
226 {
227  // Clear the emulated collection.
228  Resize(0, opt && *opt=='f');
229 }
230 
231 void TEmulatedCollectionProxy::Shrink(UInt_t nCurr, UInt_t left, Bool_t force )
232 {
233  // Shrink the container
234 
235  typedef std::string String_t;
236  PCont_t c = PCont_t(fEnv->fObject);
237  char* addr = ((char*)fEnv->fStart) + fValDiff*left;
238  size_t i;
239 
240  switch ( fSTL_type ) {
241  case ROOT::kSTLmap:
242  case ROOT::kSTLmultimap:
243  addr = ((char*)fEnv->fStart) + fValDiff*left;
244  switch(fKey->fCase) {
245  case kIsFundamental: // Only handle primitives this way
246  case kIsEnum:
247  break;
248  case kIsClass:
249  for( i= fKey->fType ? left : nCurr; i<nCurr; ++i, addr += fValDiff ) {
250  // Call emulation in case non-compiled content
251  fKey->fType->Destructor(addr, kTRUE);
252  }
253  break;
254  case kBIT_ISSTRING:
255  for( i=left; i<nCurr; ++i, addr += fValDiff ) {
256  ((std::string*)addr)->~String_t();
257  }
258  break;
259  case kIsPointer|kIsClass:
260  for( i=left; i<nCurr; ++i, addr += fValDiff ) {
261  StreamHelper* h = (StreamHelper*)addr;
262  //Eventually we'll need to delete this
263  //(but only when needed).
264  void* ptr = h->ptr();
265  if (force) fKey->fType->Destructor(ptr);
266  h->set(0);
267  }
268  break;
269  case kIsPointer|kBIT_ISSTRING:
270  for( i=nCurr; i<left; ++i, addr += fValDiff ) {
271  StreamHelper* h = (StreamHelper*)addr;
272  //Eventually we'll need to delete this
273  //(but only when needed).
274  if (force) delete (std::string*)h->ptr();
275  h->set(0);
276  }
277  break;
278  case kIsPointer|kBIT_ISTSTRING|kIsClass:
279  for( i=nCurr; i<left; ++i, addr += fValDiff ) {
280  StreamHelper* h = (StreamHelper*)addr;
281  if (force) delete (TString*)h->ptr();
282  h->set(0);
283  }
284  break;
285  }
286  addr = ((char*)fEnv->fStart)+fValOffset+fValDiff*left;
287  // DO NOT break; just continue
288 
289  // General case for all values
290  default:
291  switch( fVal->fCase ) {
292  case kIsFundamental: // Only handle primitives this way
293  case kIsEnum:
294  break;
295  case kIsClass:
296  for( i=left; i<nCurr; ++i, addr += fValDiff ) {
297  // Call emulation in case non-compiled content
298  fVal->fType->Destructor(addr,kTRUE);
299  }
300  break;
301  case kBIT_ISSTRING:
302  for( i=left; i<nCurr; ++i, addr += fValDiff )
303  ((std::string*)addr)->~String_t();
304  break;
305  case kIsPointer|kIsClass:
306  for( i=left; i<nCurr; ++i, addr += fValDiff ) {
307  StreamHelper* h = (StreamHelper*)addr;
308  void* p = h->ptr();
309  if ( p && force ) {
310  fVal->fType->Destructor(p);
311  }
312  h->set(0);
313  }
314  break;
315  case kIsPointer|kBIT_ISSTRING:
316  for( i=nCurr; i<left; ++i, addr += fValDiff ) {
317  StreamHelper* h = (StreamHelper*)addr;
318  if (force) delete (std::string*)h->ptr();
319  h->set(0);
320  }
321  break;
322  case kIsPointer|kBIT_ISTSTRING|kIsClass:
323  for( i=nCurr; i<left; ++i, addr += fValDiff ) {
324  StreamHelper* h = (StreamHelper*)addr;
325  if (force) delete (TString*)h->ptr();
326  h->set(0);
327  }
328  break;
329  }
330  }
331  c->resize(left*fValDiff,0);
332  fEnv->fStart = left>0 ? &(*c->begin()) : 0;
333  return;
334 }
335 
336 void TEmulatedCollectionProxy::Expand(UInt_t nCurr, UInt_t left)
337 {
338  // Expand the container
339  size_t i;
340  PCont_t c = PCont_t(fEnv->fObject);
341  c->resize(left*fValDiff,0);
342  void *oldstart = fEnv->fStart;
343  fEnv->fStart = left>0 ? &(*c->begin()) : 0;
344 
345  char* addr = ((char*)fEnv->fStart) + fValDiff*nCurr;
346  switch ( fSTL_type ) {
347  case ROOT::kSTLmap:
348  case ROOT::kSTLmultimap:
349  switch(fKey->fCase) {
350  case kIsFundamental: // Only handle primitives this way
351  case kIsEnum:
352  break;
353  case kIsClass:
354  if (oldstart && oldstart != fEnv->fStart) {
355  Long_t offset = 0;
356  for( i=0; i<=nCurr; ++i, offset += fValDiff ) {
357  // For now 'Move' only register the change of location
358  // so per se this is wrong since the object are copied via memcpy
359  // rather than a copy (or move) constructor.
360  fKey->fType->Move(((char*)oldstart)+offset,((char*)fEnv->fStart)+offset);
361  }
362  }
363  for( i=nCurr; i<left; ++i, addr += fValDiff )
364  fKey->fType->New(addr);
365  break;
366  case kBIT_ISSTRING:
367  for( i=nCurr; i<left; ++i, addr += fValDiff )
368  ::new(addr) std::string();
369  break;
370  case kIsPointer|kIsClass:
371  case kIsPointer|kBIT_ISSTRING:
372  case kIsPointer|kBIT_ISTSTRING|kIsClass:
373  for( i=nCurr; i<left; ++i, addr += fValDiff )
374  *(void**)addr = 0;
375  break;
376  }
377  addr = ((char*)fEnv->fStart)+fValOffset+fValDiff*nCurr;
378  // DO NOT break; just continue
379 
380  // General case for all values
381  default:
382  switch(fVal->fCase) {
383  case kIsFundamental: // Only handle primitives this way
384  case kIsEnum:
385  break;
386  case kIsClass:
387  if (oldstart && oldstart != fEnv->fStart) {
388  Long_t offset = 0;
389  for( i=0; i<=nCurr; ++i, offset += fValDiff ) {
390  // For now 'Move' only register the change of location
391  // so per se this is wrong since the object are copied via memcpy
392  // rather than a copy (or move) constructor.
393  fVal->fType->Move(((char*)oldstart)+offset,((char*)fEnv->fStart)+offset);
394  }
395  }
396  for( i=nCurr; i<left; ++i, addr += fValDiff ) {
397  fVal->fType->New(addr);
398  }
399  break;
400  case kBIT_ISSTRING:
401  for( i=nCurr; i<left; ++i, addr += fValDiff )
402  ::new(addr) std::string();
403  break;
404  case kIsPointer|kIsClass:
405  case kIsPointer|kBIT_ISSTRING:
406  case kIsPointer|kBIT_ISTSTRING|kIsClass:
407  for( i=nCurr; i<left; ++i, addr += fValDiff )
408  *(void**)addr = 0;
409  break;
410  }
411  break;
412  }
413 }
414 
415 void TEmulatedCollectionProxy::Resize(UInt_t left, Bool_t force)
416 {
417  // Resize the container
418 
419  if ( fEnv && fEnv->fObject ) {
420  size_t nCurr = Size();
421  PCont_t c = PCont_t(fEnv->fObject);
422  fEnv->fStart = nCurr>0 ? &(*c->begin()) : 0;
423  if ( left == nCurr ) {
424  return;
425  }
426  else if ( left < nCurr ) {
427  Shrink(nCurr, left, force);
428  return;
429  }
430  Expand(nCurr, left);
431  return;
432  }
433  Fatal("TEmulatedCollectionProxy","Resize> Logic error - no proxy object set.");
434 }
435 
436 void* TEmulatedCollectionProxy::At(UInt_t idx)
437 {
438  // Return the address of the value at index 'idx'
439  if ( fEnv && fEnv->fObject ) {
440  PCont_t c = PCont_t(fEnv->fObject);
441  size_t s = c->size();
442  if ( idx >= (s/fValDiff) ) {
443  return 0;
444  }
445  return idx<(s/fValDiff) ? ((char*)&(*c->begin()))+idx*fValDiff : 0;
446  }
447  Fatal("TEmulatedCollectionProxy","At> Logic error - no proxy object set.");
448  return 0;
449 }
450 
451 void* TEmulatedCollectionProxy::Allocate(UInt_t n, Bool_t forceDelete)
452 {
453  // Allocate the necessary space.
454 
455  Resize(n, forceDelete);
456  return fEnv->fObject;
457 }
458 
459 ////////////////////////////////////////////////////////////////////////////////
460 /// Insert data into the container where data is a C-style array of the actual type contained in the collection
461 /// of the given size. For associative container (map, etc.), the data type is the pair<key,value>.
462 
463 void TEmulatedCollectionProxy::Insert(const void * /* data */, void * /*container*/, size_t /*size*/)
464 {
465  Fatal("Insert","Not yet implemented, require copy of objects.");
466 }
467 
468 void TEmulatedCollectionProxy::Commit(void* /* env */ )
469 {
470 }
471 
472 void TEmulatedCollectionProxy::ReadItems(int nElements, TBuffer &b)
473 {
474  // Object input streamer
475  Bool_t vsn3 = b.GetInfo() && b.GetInfo()->GetOldVersion()<=3;
476  StreamHelper* itm = (StreamHelper*)At(0);
477  switch (fVal->fCase) {
478  case kIsFundamental: // Only handle primitives this way
479  case kIsEnum:
480  switch( int(fVal->fKind) ) {
481  case kBool_t: b.ReadFastArray(&itm->boolean , nElements); break;
482  case kChar_t: b.ReadFastArray(&itm->s_char , nElements); break;
483  case kShort_t: b.ReadFastArray(&itm->s_short , nElements); break;
484  case kInt_t: b.ReadFastArray(&itm->s_int , nElements); break;
485  case kLong_t: b.ReadFastArray(&itm->s_long , nElements); break;
486  case kLong64_t: b.ReadFastArray(&itm->s_longlong, nElements); break;
487  case kFloat_t: b.ReadFastArray(&itm->flt , nElements); break;
488  case kFloat16_t: b.ReadFastArrayFloat16(&itm->flt, nElements); break;
489  case kDouble_t: b.ReadFastArray(&itm->dbl , nElements); break;
490  case kUChar_t: b.ReadFastArray(&itm->u_char , nElements); break;
491  case kUShort_t: b.ReadFastArray(&itm->u_short , nElements); break;
492  case kUInt_t: b.ReadFastArray(&itm->u_int , nElements); break;
493  case kULong_t: b.ReadFastArray(&itm->u_long , nElements); break;
494  case kULong64_t: b.ReadFastArray(&itm->u_longlong, nElements); break;
495  case kDouble32_t:b.ReadFastArrayDouble32(&itm->dbl,nElements); break;
496  case kchar:
497  case kNoType_t:
498  case kOther_t:
499  Error("TEmulatedCollectionProxy","fType %d is not supported yet!\n",fVal->fKind);
500  }
501  break;
502 
503 #define DOLOOP(x) {int idx=0; while(idx<nElements) {StreamHelper* i=(StreamHelper*)(((char*)itm) + fValDiff*idx); { x ;} ++idx;} break;}
504 
505  case kIsClass:
506  DOLOOP( b.StreamObject(i,fVal->fType) );
507  case kBIT_ISSTRING:
508  DOLOOP( i->read_std_string(b) );
509  case kIsPointer|kIsClass:
510  DOLOOP( i->read_any_object(fVal,b) );
511  case kIsPointer|kBIT_ISSTRING:
512  DOLOOP( i->read_std_string_pointer(b) );
513  case kIsPointer|kBIT_ISTSTRING|kIsClass:
514  DOLOOP( i->read_tstring_pointer(vsn3,b) );
515  }
516 
517 #undef DOLOOP
518 
519 }
520 
521 void TEmulatedCollectionProxy::WriteItems(int nElements, TBuffer &b)
522 {
523  // Object output streamer
524  StreamHelper* itm = (StreamHelper*)At(0);
525  switch (fVal->fCase) {
526  case kIsFundamental: // Only handle primitives this way
527  case kIsEnum:
528  itm = (StreamHelper*)At(0);
529  switch( int(fVal->fKind) ) {
530  case kBool_t: b.WriteFastArray(&itm->boolean , nElements); break;
531  case kChar_t: b.WriteFastArray(&itm->s_char , nElements); break;
532  case kShort_t: b.WriteFastArray(&itm->s_short , nElements); break;
533  case kInt_t: b.WriteFastArray(&itm->s_int , nElements); break;
534  case kLong_t: b.WriteFastArray(&itm->s_long , nElements); break;
535  case kLong64_t: b.WriteFastArray(&itm->s_longlong, nElements); break;
536  case kFloat_t: b.WriteFastArray(&itm->flt , nElements); break;
537  case kFloat16_t: b.WriteFastArrayFloat16(&itm->flt, nElements); break;
538  case kDouble_t: b.WriteFastArray(&itm->dbl , nElements); break;
539  case kUChar_t: b.WriteFastArray(&itm->u_char , nElements); break;
540  case kUShort_t: b.WriteFastArray(&itm->u_short , nElements); break;
541  case kUInt_t: b.WriteFastArray(&itm->u_int , nElements); break;
542  case kULong_t: b.WriteFastArray(&itm->u_long , nElements); break;
543  case kULong64_t: b.WriteFastArray(&itm->u_longlong, nElements); break;
544  case kDouble32_t:b.WriteFastArrayDouble32(&itm->dbl,nElements); break;
545  case kchar:
546  case kNoType_t:
547  case kOther_t:
548  Error("TEmulatedCollectionProxy","fType %d is not supported yet!\n",fVal->fKind);
549  }
550  break;
551 #define DOLOOP(x) {int idx=0; while(idx<nElements) {StreamHelper* i=(StreamHelper*)(((char*)itm) + fValDiff*idx); { x ;} ++idx;} break;}
552  case kIsClass:
553  DOLOOP( b.StreamObject(i,fVal->fType) );
554  case kBIT_ISSTRING:
555  DOLOOP( TString(i->c_str()).Streamer(b) );
556  case kIsPointer|kIsClass:
557  DOLOOP( b.WriteObjectAny(i->ptr(),fVal->fType) );
558  case kBIT_ISSTRING|kIsPointer:
559  DOLOOP( i->write_std_string_pointer(b) );
560  case kBIT_ISTSTRING|kIsClass|kIsPointer:
561  DOLOOP( i->write_tstring_pointer(b) );
562  }
563 #undef DOLOOP
564 }
565 
566 void TEmulatedCollectionProxy::ReadBuffer(TBuffer &b, void *obj, const TClass *onfileClass)
567 {
568  // Read portion of the streamer.
569 
570  SetOnFileClass((TClass*)onfileClass);
571  ReadBuffer(b,obj);
572 }
573 
574 void TEmulatedCollectionProxy::ReadBuffer(TBuffer &b, void *obj)
575 {
576  // Read portion of the streamer.
577 
578  TPushPop env(this,obj);
579  int nElements = 0;
580  b >> nElements;
581  if ( fEnv->fObject ) {
582  Resize(nElements,true);
583  }
584  if ( nElements > 0 ) {
585  ReadItems(nElements, b);
586  }
587 }
588 
589 void TEmulatedCollectionProxy::Streamer(TBuffer &b)
590 {
591  // TClassStreamer IO overload
592  if ( b.IsReading() ) { //Read mode
593  int nElements = 0;
594  b >> nElements;
595  if ( fEnv->fObject ) {
596  Resize(nElements,true);
597  }
598  if ( nElements > 0 ) {
599  ReadItems(nElements, b);
600  }
601  }
602  else { // Write case
603  int nElements = fEnv->fObject ? Size() : 0;
604  b << nElements;
605  if ( nElements > 0 ) {
606  WriteItems(nElements, b);
607  }
608  }
609 }
610 
611 //
612 // Utility functions
613 //
614 static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const char *dmFull, Int_t offset)
615 {
616  // Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.
617 
618  TString s1( TClassEdit::ShortType(dmFull,0) );
619  TString dmType( TClassEdit::ShortType(dmFull,1) );
620  Bool_t dmIsPtr = (s1 != dmType);
621  const char *dmTitle = "Emulation";
622 
623  TDataType *dt = gROOT->GetType(dmType);
624  if (dt && dt->GetType() > 0 ) { // found a basic type
625  Int_t dsize,dtype;
626  dtype = dt->GetType();
627  dsize = dt->Size();
628  if (dmIsPtr && dtype != kCharStar) {
629  Error("Pair Emulation Building","%s is not yet supported in pair emulation",
630  dmFull);
631  return 0;
632  } else {
633  TStreamerElement *el = new TStreamerBasicType(dmName,dmTitle,offset,dtype,dmFull);
634  el->SetSize(dsize);
635  return el;
636  }
637  } else {
638 
639  static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
640  if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
641  return new TStreamerSTLstring(dmName,dmTitle,offset,dmFull,dmIsPtr);
642  }
643  if (TClassEdit::IsSTLCont(dmType)) {
644  return new TStreamerSTL(dmName,dmTitle,offset,dmFull,dmFull,dmIsPtr);
645  }
646  TClass *clm = TClass::GetClass(dmType);
647  if (!clm) {
648  // either we have an Emulated enum or a really unknown class!
649  // let's just claim its an enum :(
650  Int_t dtype = kInt_t;
651  return new TStreamerBasicType(dmName,dmTitle,offset,dtype,dmFull);
652  }
653  // a pointer to a class
654  if ( dmIsPtr ) {
655  if (clm->IsTObject()) {
656  return new TStreamerObjectPointer(dmName,dmTitle,offset,dmFull);
657  } else {
658  return new TStreamerObjectAnyPointer(dmName,dmTitle,offset,dmFull);
659  }
660  }
661  // a class
662  if (clm->IsTObject()) {
663  return new TStreamerObject(dmName,dmTitle,offset,dmFull);
664  } else if(clm == TString::Class() && !dmIsPtr) {
665  return new TStreamerString(dmName,dmTitle,offset);
666  } else {
667  return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull);
668  }
669  }
670 }
671 
672 
673 static TStreamerInfo *R__GenerateTClassForPair(const std::string &fname, const std::string &sname)
674 {
675  // Generate a TStreamerInfo for a std::pair<fname,sname>
676  // This TStreamerInfo is then used as if it was read from a file to generate
677  // and emulated TClass.
678 
679  TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
680  std::string pname = "pair<"+fname+","+sname;
681  pname += (pname[pname.length()-1]=='>') ? " >" : ">";
682  i->SetName(pname.c_str());
683  i->SetClass(0);
684  i->GetElements()->Delete();
685  TStreamerElement *fel = R__CreateEmulatedElement("first", fname.c_str(), 0);
686  Int_t size = 0;
687  if (fel) {
688  i->GetElements()->Add( fel );
689 
690  size = fel->GetSize();
691  Int_t sp = sizeof(void *);
692  //align the non-basic data types (required on alpha and IRIX!!)
693  if (size%sp != 0) size = size - size%sp + sp;
694  } else {
695  delete i;
696  return 0;
697  }
698  TStreamerElement *second = R__CreateEmulatedElement("second", sname.c_str(), size);
699  if (second) {
700  i->GetElements()->Add( second );
701  } else {
702  delete i;
703  return 0;
704  }
705  Int_t oldlevel = gErrorIgnoreLevel;
706  // Hide the warning about the missing pair dictionary.
707  gErrorIgnoreLevel = kError;
708  i->BuildCheck();
709  gErrorIgnoreLevel = oldlevel;
710  i->BuildOld();
711  return i;
712 }