Logo ROOT   6.10/09
Reference Guide
TClass.cxx
Go to the documentation of this file.
1 // @(#)root/meta:$Id: 7109cb45f1219c2aae6be19906ae5a63e31972ef $
2 // Author: Rene Brun 07/01/95
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 TClass
13 The ROOT global object gROOT contains a list of all defined
14 classes. This list is build when a reference to a class dictionary
15 is made. When this happens, the static "class"::Dictionary()
16 function is called to create a TClass object describing the
17 class. The Dictionary() function is defined in the ClassDef
18 macro and stored (at program startup or library load time) together
19 with the class name in the TClassTable singleton object.
20 For a description of all dictionary classes see TDictionary.
21 
22 The name of the class as registered in the TClass object and in the
23 list of class is the "normalized name" and is defined as:
24 
25 The name of the type as accessible from the global scope to which
26 a 'using namespace std;' has been applied to and with:
27  - all typedefs disagreed except for Double32_t, Float16_t,
28  Long64_t, ULong64_t and std::string.
29  - default template parameters removed for STL collections and
30  added for any other class templates instances.
31  - Fully qualified both for the class name itself and all of its
32  component, except that, at least for moment, all 'std::' are
33  stripped.
34 */
35 
36 //*-*x7.5 macros/layout_class
37 
38 #include "TClass.h"
39 
40 #include "Riostream.h"
41 #include "TBaseClass.h"
42 #include "TBrowser.h"
43 #include "TBuffer.h"
44 #include "TClassGenerator.h"
45 #include "TClassEdit.h"
46 #include "TClassMenuItem.h"
47 #include "TClassRef.h"
48 #include "TClassTable.h"
49 #include "TDataMember.h"
50 #include "TDataType.h"
51 #include "TEnum.h"
52 #include "TError.h"
53 #include "TExMap.h"
54 #include "TFunctionTemplate.h"
55 #include "THashList.h"
56 #include "TInterpreter.h"
57 #include "TMemberInspector.h"
58 #include "TMethod.h"
59 #include "TMethodArg.h"
60 #include "TMethodCall.h"
61 #include "TObjArray.h"
62 #include "TProtoClass.h"
63 #include "TROOT.h"
64 #include "TRealData.h"
65 #include "TStreamer.h"
66 #include "TStreamerElement.h"
67 #include "TVirtualStreamerInfo.h"
69 #include "TVirtualIsAProxy.h"
70 #include "TVirtualRefProxy.h"
71 #include "TVirtualMutex.h"
72 #include "TVirtualPad.h"
73 #include "THashTable.h"
74 #include "TSchemaRuleSet.h"
75 #include "TGenericClassInfo.h"
76 #include "TIsAProxy.h"
77 #include "TSchemaRule.h"
78 #include "TSystem.h"
79 #include "TThreadSlots.h"
80 
81 #include <cstdio>
82 #include <cctype>
83 #include <set>
84 #include <sstream>
85 #include <string>
86 #include <map>
87 #include <typeinfo>
88 #include <cmath>
89 #include <assert.h>
90 #include <vector>
91 #include <memory>
92 
93 #ifdef WIN32
94 #include <io.h>
95 #include "Windows4Root.h"
96 #include <Psapi.h>
97 #define RTLD_DEFAULT ((void *)::GetModuleHandle(NULL))
98 #define dlsym(library, function_name) ::GetProcAddress((HMODULE)library, function_name)
99 #else
100 #include <dlfcn.h>
101 #endif
102 
103 #include "TListOfDataMembers.h"
104 #include "TListOfFunctions.h"
106 #include "TListOfEnums.h"
107 #include "TListOfEnumsWithLock.h"
108 #include "TViewPubDataMembers.h"
109 #include "TViewPubFunctions.h"
110 #include "TArray.h"
111 #include "TClonesArray.h"
112 #include "TRef.h"
113 #include "TRefArray.h"
114 
115 using namespace std;
116 
117 // Mutex to protect CINT and META operations
118 // (exported to be used for similar cases in related classes)
119 
121 
122 namespace {
123  class TMmallocDescTemp {
124  private:
125  void *fSave;
126  public:
127  TMmallocDescTemp(void *value = 0) :
129  ~TMmallocDescTemp() { ROOT::Internal::gMmallocDesc = fSave; }
130  };
131 }
132 
133 std::atomic<Int_t> TClass::fgClassCount;
134 
135 // Implementation of the TDeclNameRegistry
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// TDeclNameRegistry class constructor.
139 
140 TClass::TDeclNameRegistry::TDeclNameRegistry(Int_t verbLevel): fVerbLevel(verbLevel)
141 {
142  // MSVC doesn't support fSpinLock=ATOMIC_FLAG_INIT; in the class definition
143  std::atomic_flag_clear( &fSpinLock );
144 }
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// Extract this part of the name
148 /// 1. Templates ns::ns2::,,,::THISPART<...
149 /// 2. Namespaces,classes ns::ns2::,,,::THISPART
150 
152 {
153  // Sanity check
154  auto strLen = strlen(name);
155  if (strLen == 0) return;
156  // find <. If none, put end of string
157  const char* endCharPtr = strchr(name, '<');
158  endCharPtr = !endCharPtr ? &name[strLen] : endCharPtr;
159  // find last : before the <. If not found, put begin of string
160  const char* beginCharPtr = endCharPtr;
161  while (beginCharPtr!=name){
162  if (*beginCharPtr==':'){
163  beginCharPtr++;
164  break;
165  }
166  beginCharPtr--;
167  }
168  beginCharPtr = beginCharPtr!=endCharPtr ? beginCharPtr : name;
169  std::string s(beginCharPtr, endCharPtr);
170  if (fVerbLevel>1)
171  printf("TDeclNameRegistry::AddQualifiedName Adding key %s for class/namespace %s\n", s.c_str(), name);
173  fClassNamesSet.insert(s);
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 
179 {
180  Bool_t found = false;
181  {
183  found = fClassNamesSet.find(name) != fClassNamesSet.end();
184  }
185  return found;
186 }
187 
188 ////////////////////////////////////////////////////////////////////////////////
189 
191 {
192  if (fVerbLevel > 1) {
193  printf("TDeclNameRegistry Destructor. List of %lu names:\n",
194  (long unsigned int)fClassNamesSet.size());
195  for (auto const & key: fClassNamesSet) {
196  printf(" - %s\n", key.c_str());
197  }
198  }
199 }
200 
201 // Implementation of the spinlock guard in the registry
202 
203 ////////////////////////////////////////////////////////////////////////////////
204 
205 TClass::TSpinLockGuard::TSpinLockGuard(std::atomic_flag& aflag):fAFlag(aflag)
206 {
207  while (fAFlag.test_and_set(std::memory_order_acquire));
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 
213 {
214  fAFlag.clear(std::memory_order_release);
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 
220  const char *name,
221  TDeclNameRegistry &emuRegistry): fState(state),fName(name), fNoInfoOrEmuOrFwdDeclNameRegistry(emuRegistry) {}
222 
223 ////////////////////////////////////////////////////////////////////////////////
224 
226  if (fState == TClass::kNoInfo ||
230  }
231  }
232 
233 // Initialise the global member of TClass
235 
236 //Intent of why/how TClass::New() is called
237 //[Not a static data member because MacOS does not support static thread local data member ... who knows why]
239  TTHREAD_TLS(TClass::ENewType) fgCallingNew = TClass::kRealNew;
240  return fgCallingNew;
241 }
242 
243 struct ObjRepoValue {
244  ObjRepoValue(const TClass *what, Version_t version) : fClass(what),fVersion(version) {}
245  const TClass *fClass;
246  Version_t fVersion;
247 };
248 
250 typedef std::multimap<void*, ObjRepoValue> RepoCont_t;
252 
253 static void RegisterAddressInRepository(const char * /*where*/, void *location, const TClass *what)
254 {
255  // Register the object for special handling in the destructor.
256 
257  Version_t version = what->GetClassVersion();
258 // if (!gObjectVersionRepository.count(location)) {
259 // Info(where, "Registering address %p of class '%s' version %d", location, what->GetName(), version);
260 // } else {
261 // Warning(where, "Registering address %p again of class '%s' version %d", location, what->GetName(), version);
262 // }
263  {
264  R__LOCKGUARD2(gOVRMutex);
265  gObjectVersionRepository.insert(RepoCont_t::value_type(location, RepoCont_t::mapped_type(what,version)));
266  }
267 #if 0
268  // This code could be used to prevent an address to be registered twice.
269  std::pair<RepoCont_t::iterator, Bool_t> tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version)));
270  if (!tmp.second) {
271  Warning(where, "Reregistering an object of class '%s' version %d at address %p", what->GetName(), version, p);
272  gObjectVersionRepository.erase(tmp.first);
273  tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version)));
274  if (!tmp.second) {
275  Warning(where, "Failed to reregister an object of class '%s' version %d at address %p", what->GetName(), version, location);
276  }
277  }
278 #endif
279 }
280 
281 static void UnregisterAddressInRepository(const char * /*where*/, void *location, const TClass *what)
282 {
283  // Remove an address from the repository of address/object.
284 
285  R__LOCKGUARD2(gOVRMutex);
286  RepoCont_t::iterator cur = gObjectVersionRepository.find(location);
287  for (; cur != gObjectVersionRepository.end();) {
288  RepoCont_t::iterator tmp = cur++;
289  if ((tmp->first == location) && (tmp->second.fVersion == what->GetClassVersion())) {
290  // -- We still have an address, version match.
291  // Info(where, "Unregistering address %p of class '%s' version %d", location, what->GetName(), what->GetClassVersion());
292  gObjectVersionRepository.erase(tmp);
293  } else {
294  // -- No address, version match, we've reached the end.
295  break;
296  }
297  }
298 }
299 
300 static void MoveAddressInRepository(const char * /*where*/, void *oldadd, void *newadd, const TClass *what)
301 {
302  // Register in the repository that an object has moved.
303 
304  // Move not only the object itself but also any base classes or sub-objects.
305  size_t objsize = what->Size();
306  long delta = (char*)newadd - (char*)oldadd;
307  R__LOCKGUARD2(gOVRMutex);
308  RepoCont_t::iterator cur = gObjectVersionRepository.find(oldadd);
309  for (; cur != gObjectVersionRepository.end();) {
310  RepoCont_t::iterator tmp = cur++;
311  if (oldadd <= tmp->first && tmp->first < ( ((char*)oldadd) + objsize) ) {
312  // The location is within the object, let's move it.
313 
314  gObjectVersionRepository.insert(RepoCont_t::value_type(((char*)tmp->first)+delta, RepoCont_t::mapped_type(tmp->second.fClass,tmp->second.fVersion)));
315  gObjectVersionRepository.erase(tmp);
316 
317  } else {
318  // -- No address, version match, we've reached the end.
319  break;
320  }
321  }
322 }
323 
324 //______________________________________________________________________________
325 //______________________________________________________________________________
326 namespace ROOT {
327 #define R__USE_STD_MAP
328  class TMapTypeToTClass {
329 #if defined R__USE_STD_MAP
330  // This wrapper class allow to avoid putting #include <map> in the
331  // TROOT.h header file.
332  public:
333 #ifdef R__GLOBALSTL
334  typedef map<string,TClass*> IdMap_t;
335 #else
336  typedef std::map<std::string,TClass*> IdMap_t;
337 #endif
338  typedef IdMap_t::key_type key_type;
339  typedef IdMap_t::const_iterator const_iterator;
340  typedef IdMap_t::size_type size_type;
341 #ifdef R__WIN32
342  // Window's std::map does NOT defined mapped_type
343  typedef TClass* mapped_type;
344 #else
345  typedef IdMap_t::mapped_type mapped_type;
346 #endif
347 
348  private:
349  IdMap_t fMap;
350 
351  public:
352  void Add(const key_type &key, mapped_type &obj)
353  {
354  // Add the <key,obj> pair to the map.
355  fMap[key] = obj;
356  }
357  mapped_type Find(const key_type &key) const
358  {
359  // Find the type corresponding to the key.
360  IdMap_t::const_iterator iter = fMap.find(key);
361  mapped_type cl = 0;
362  if (iter != fMap.end()) cl = iter->second;
363  return cl;
364  }
365  void Remove(const key_type &key) {
366  // Remove the type corresponding to the key.
367  fMap.erase(key);
368  }
369 #else
370  private:
371  TMap fMap;
372 
373  public:
374 #ifdef R__COMPLETE_MEM_TERMINATION
375  TMapTypeToTClass() {
376  TIter next(&fMap);
377  TObjString *key;
378  while((key = (TObjString*)next())) {
379  delete key;
380  }
381  }
382 #endif
383  void Add(const char *key, TClass *&obj) {
384  TObjString *realkey = new TObjString(key);
385  fMap.Add(realkey, obj);
386  }
387  TClass* Find(const char *key) const {
388  const TPair *a = (const TPair *)fMap.FindObject(key);
389  if (a) return (TClass*) a->Value();
390  return 0;
391  }
392  void Remove(const char *key) {
393  TObjString realkey(key);
394  TObject *actual = fMap.Remove(&realkey);
395  delete actual;
396  }
397 #endif
398  };
399 
400  class TMapDeclIdToTClass {
401  // Wrapper class for the multimap of DeclId_t and TClass.
402  public:
403  typedef multimap<TDictionary::DeclId_t, TClass*> DeclIdMap_t;
404  typedef DeclIdMap_t::key_type key_type;
405  typedef DeclIdMap_t::mapped_type mapped_type;
406  typedef DeclIdMap_t::const_iterator const_iterator;
407  typedef std::pair <const_iterator, const_iterator> equal_range;
408  typedef DeclIdMap_t::size_type size_type;
409 
410  private:
411  DeclIdMap_t fMap;
412 
413  public:
414  void Add(const key_type &key, mapped_type obj)
415  {
416  // Add the <key,obj> pair to the map.
417  std::pair<const key_type, mapped_type> pair = make_pair(key, obj);
418  fMap.insert(pair);
419  }
420  size_type CountElementsWithKey(const key_type &key)
421  {
422  return fMap.count(key);
423  }
424  equal_range Find(const key_type &key) const
425  {
426  // Find the type corresponding to the key.
427  return fMap.equal_range(key);
428  }
429  void Remove(const key_type &key) {
430  // Remove the type corresponding to the key.
431  fMap.erase(key);
432  }
433  };
434 }
435 
437 
438 #ifdef R__COMPLETE_MEM_TERMINATION
439  static IdMap_t gIdMapObject;
440  return &gIdMap;
441 #else
442  static IdMap_t *gIdMap = new IdMap_t;
443  return gIdMap;
444 #endif
445 }
446 
448 
449 #ifdef R__COMPLETE_MEM_TERMINATION
450  static DeclIdMap_t gDeclIdMapObject;
451  return &gIdMap;
452 #else
453  static DeclIdMap_t *gDeclIdMap = new DeclIdMap_t;
454  return gDeclIdMap;
455 #endif
456 }
457 
458 ////////////////////////////////////////////////////////////////////////////////
459 /// static: Add a class to the list and map of classes.
460 
462 {
463  if (!cl) return;
464 
465  R__LOCKGUARD2(gInterpreterMutex);
466  gROOT->GetListOfClasses()->Add(cl);
467  if (cl->GetTypeInfo()) {
468  GetIdMap()->Add(cl->GetTypeInfo()->name(),cl);
469  }
470  if (cl->fClassInfo) {
471  GetDeclIdMap()->Add((void*)(cl->fClassInfo), cl);
472  }
473 }
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// static: Add a TClass* to the map of classes.
477 
479 {
480  if (!cl || !id) return;
481  GetDeclIdMap()->Add(id, cl);
482 }
483 
484 ////////////////////////////////////////////////////////////////////////////////
485 /// static: Remove a class from the list and map of classes
486 
488 {
489  if (!oldcl) return;
490 
491  R__LOCKGUARD2(gInterpreterMutex);
492  gROOT->GetListOfClasses()->Remove(oldcl);
493  if (oldcl->GetTypeInfo()) {
494  GetIdMap()->Remove(oldcl->GetTypeInfo()->name());
495  }
496  if (oldcl->fClassInfo) {
497  //GetDeclIdMap()->Remove((void*)(oldcl->fClassInfo));
498  }
499 }
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 
504 {
505  if (!id) return;
506  GetDeclIdMap()->Remove(id);
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// Indirect call to the implementation of ShowMember allowing [forward]
511 /// declaration with out a full definition of the TClass class.
512 
513 void ROOT::Class_ShowMembers(TClass *cl, const void *obj, TMemberInspector&insp)
514 {
515  gInterpreter->InspectMembers(insp, obj, cl, kFALSE);
516 }
517 
518 //______________________________________________________________________________
519 //______________________________________________________________________________
520 
521 class TDumpMembers : public TMemberInspector {
522  bool fNoAddr;
523 public:
524  TDumpMembers(bool noAddr): fNoAddr(noAddr) { }
525 
527  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
528 };
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 /// Print value of member mname.
532 ///
533 /// This method is called by the ShowMembers() method for each
534 /// data member when object.Dump() is invoked.
535 ///
536 /// - cl is the pointer to the current class
537 /// - pname is the parent name (in case of composed objects)
538 /// - mname is the data member name
539 /// - add is the data member address
540 
541 void TDumpMembers::Inspect(TClass *cl, const char *pname, const char *mname, const void *add, Bool_t /* isTransient */)
542 {
543  const Int_t kvalue = 30;
544 #ifdef R__B64
545  const Int_t ktitle = 50;
546 #else
547  const Int_t ktitle = 42;
548 #endif
549  const Int_t kline = 1024;
550  Int_t cdate = 0;
551  Int_t ctime = 0;
552  UInt_t *cdatime = 0;
553  char line[kline];
554 
555  TDataType *membertype;
556  EDataType memberDataType = kNoType_t;
557  const char *memberName;
558  const char *memberFullTypeName;
559  const char *memberTitle;
560  Bool_t isapointer;
561  Bool_t isbasic;
562 
563  if (TDataMember *member = cl->GetDataMember(mname)) {
564  if (member->GetDataType()) {
565  memberDataType = (EDataType)member->GetDataType()->GetType();
566  }
567  memberName = member->GetName();
568  memberFullTypeName = member->GetFullTypeName();
569  memberTitle = member->GetTitle();
570  isapointer = member->IsaPointer();
571  isbasic = member->IsBasic();
572  membertype = member->GetDataType();
573  } else if (!cl->IsLoaded()) {
574  // The class is not loaded, hence it is 'emulated' and the main source of
575  // information is the StreamerInfo.
577  if (!info) return;
578  const char *cursor = mname;
579  while ( (*cursor)=='*' ) ++cursor;
580  TString elname( cursor );
581  Ssiz_t pos = elname.Index("[");
582  if ( pos != kNPOS ) {
583  elname.Remove( pos );
584  }
585  TStreamerElement *element = (TStreamerElement*)info->GetElements()->FindObject(elname.Data());
586  if (!element) return;
587  memberFullTypeName = element->GetTypeName();
588 
589  memberDataType = (EDataType)element->GetType();
590 
591  memberName = element->GetName();
592  memberTitle = element->GetTitle();
593  isapointer = element->IsaPointer() || element->GetType() == TVirtualStreamerInfo::kCharStar;
594  membertype = gROOT->GetType(memberFullTypeName);
595 
596  isbasic = membertype !=0;
597  } else {
598  return;
599  }
600 
601 
602  Bool_t isdate = kFALSE;
603  if (strcmp(memberName,"fDatime") == 0 && memberDataType == kUInt_t) {
604  isdate = kTRUE;
605  }
606  Bool_t isbits = kFALSE;
607  if (strcmp(memberName,"fBits") == 0 && memberDataType == kUInt_t) {
608  isbits = kTRUE;
609  }
610  TClass * dataClass = TClass::GetClass(memberFullTypeName);
611  Bool_t isTString = (dataClass == TString::Class());
612  static TClassRef stdClass("std::string");
613  Bool_t isStdString = (dataClass == stdClass);
614 
615  Int_t i;
616  for (i = 0;i < kline; i++) line[i] = ' ';
617  line[kline-1] = 0;
618  snprintf(line,kline,"%s%s ",pname,mname);
619  i = strlen(line); line[i] = ' ';
620 
621  // Encode data value or pointer value
622  char *pointer = (char*)add;
623  char **ppointer = (char**)(pointer);
624 
625  if (isapointer) {
626  char **p3pointer = (char**)(*ppointer);
627  if (!p3pointer)
628  snprintf(&line[kvalue],kline-kvalue,"->0");
629  else if (!isbasic) {
630  if (!fNoAddr) {
631  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)p3pointer);
632  }
633  } else if (membertype) {
634  if (!strcmp(membertype->GetTypeName(), "char")) {
635  i = strlen(*ppointer);
636  if (kvalue+i > kline) i=kline-1-kvalue;
637  Bool_t isPrintable = kTRUE;
638  for (Int_t j = 0; j < i; j++) {
639  if (!std::isprint((*ppointer)[j])) {
640  isPrintable = kFALSE;
641  break;
642  }
643  }
644  if (isPrintable) {
645  strncpy(line + kvalue, *ppointer, i);
646  line[kvalue+i] = 0;
647  } else {
648  line[kvalue] = 0;
649  }
650  } else {
651  strncpy(&line[kvalue], membertype->AsString(p3pointer), TMath::Min(kline-1-kvalue,(int)strlen(membertype->AsString(p3pointer))));
652  }
653  } else if (!strcmp(memberFullTypeName, "char*") ||
654  !strcmp(memberFullTypeName, "const char*")) {
655  i = strlen(*ppointer);
656  if (kvalue+i >= kline) i=kline-1-kvalue;
657  Bool_t isPrintable = kTRUE;
658  for (Int_t j = 0; j < i; j++) {
659  if (!std::isprint((*ppointer)[j])) {
660  isPrintable = kFALSE;
661  break;
662  }
663  }
664  if (isPrintable) {
665  strncpy(line + kvalue, *ppointer, i);
666  line[kvalue+i] = 0;
667  } else {
668  line[kvalue] = 0;
669  }
670  } else {
671  if (!fNoAddr) {
672  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)p3pointer);
673  }
674  }
675  } else if (membertype) {
676  if (isdate) {
677  cdatime = (UInt_t*)pointer;
678  TDatime::GetDateTime(cdatime[0],cdate,ctime);
679  snprintf(&line[kvalue],kline-kvalue,"%d/%d",cdate,ctime);
680  } else if (isbits) {
681  snprintf(&line[kvalue],kline-kvalue,"0x%08x", *(UInt_t*)pointer);
682  } else {
683  strncpy(&line[kvalue], membertype->AsString(pointer), TMath::Min(kline-1-kvalue,(int)strlen(membertype->AsString(pointer))));
684  }
685  } else {
686  if (isStdString) {
687  std::string *str = (std::string*)pointer;
688  snprintf(&line[kvalue],kline-kvalue,"%s",str->c_str());
689  } else if (isTString) {
690  TString *str = (TString*)pointer;
691  snprintf(&line[kvalue],kline-kvalue,"%s",str->Data());
692  } else {
693  if (!fNoAddr) {
694  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)pointer);
695  }
696  }
697  }
698  // Encode data member title
699  if (isdate == kFALSE && strcmp(memberFullTypeName, "char*") && strcmp(memberFullTypeName, "const char*")) {
700  i = strlen(&line[0]); line[i] = ' ';
701  Int_t lentit = strlen(memberTitle);
702  if (lentit > 250-ktitle) lentit = 250-ktitle;
703  strncpy(&line[ktitle],memberTitle,lentit);
704  line[ktitle+lentit] = 0;
705  }
706  Printf("%s", line);
707 }
708 
710 
711 //______________________________________________________________________________
712 //______________________________________________________________________________
713 ////////////////////////////////////////////////////////////////////////////////
714 
715 TClass::TNameMapNode::TNameMapNode (const char* typedf, const char* orig)
716  : TObjString (typedf),
717  fOrigName (orig)
718 {
719 }
720 
721 //______________________________________________________________________________
722 
723 class TBuildRealData : public TMemberInspector {
724 
725 private:
726  void *fRealDataObject;
727  TClass *fRealDataClass;
728 
729 public:
730  TBuildRealData(void *obj, TClass *cl) {
731  // Main constructor.
732  fRealDataObject = obj;
733  fRealDataClass = cl;
734  }
736  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
737 
738 };
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// This method is called from ShowMembers() via BuildRealdata().
742 
743 void TBuildRealData::Inspect(TClass* cl, const char* pname, const char* mname, const void* add, Bool_t isTransient)
744 {
745  TDataMember* dm = cl->GetDataMember(mname);
746  if (!dm) {
747  return;
748  }
749 
750  Bool_t isTransientMember = kFALSE;
751 
752  if (!dm->IsPersistent()) {
753  // For the DataModelEvolution we need access to the transient member.
754  // so we now record them in the list of RealData.
755  isTransientMember = kTRUE;
756  isTransient = kTRUE;
757  }
758 
759  TString rname( pname );
760  // Take into account cases like TPaveStats->TPaveText->TPave->TBox.
761  // Check that member is in a derived class or an object in the class.
762  if (cl != fRealDataClass) {
763  if (!fRealDataClass->InheritsFrom(cl)) {
764  Ssiz_t dot = rname.Index('.');
765  if (dot == kNPOS) {
766  return;
767  }
768  rname[dot] = '\0';
769  if (!fRealDataClass->GetDataMember(rname)) {
770  //could be a data member in a base class like in this example
771  // class Event : public Data {
772  // class Data : public TObject {
773  // EventHeader fEvtHdr;
774  // class EventHeader {
775  // Int_t fEvtNum;
776  // Int_t fRun;
777  // Int_t fDate;
778  // EventVertex fVertex;
779  // class EventVertex {
780  // EventTime fTime;
781  // class EventTime {
782  // Int_t fSec;
783  // Int_t fNanoSec;
784  if (!fRealDataClass->GetBaseDataMember(rname)) {
785  return;
786  }
787  }
788  rname[dot] = '.';
789  }
790  }
791 
792  Long_t offset = Long_t(((Long_t) add) - ((Long_t) fRealDataObject));
793 
794  if (TClassEdit::IsStdArray(dm->GetTypeName())){ // We tackle the std array case
795  TString rdName;
796  TRealData::GetName(rdName,dm);
797  rname += rdName;
798  TRealData* rd = new TRealData(rname.Data(), offset, dm);
799  fRealDataClass->GetListOfRealData()->Add(rd);
800  return;
801  }
802 
803  rname += mname;
804 
805  if (dm->IsaPointer()) {
806  // Data member is a pointer.
807  TRealData* rd = new TRealData(rname, offset, dm);
808  if (isTransientMember) { rd->SetBit(TRealData::kTransient); };
809  fRealDataClass->GetListOfRealData()->Add(rd);
810  } else {
811  // Data Member is a basic data type.
812  TRealData* rd = new TRealData(rname, offset, dm);
813  if (isTransientMember) { rd->SetBit(TRealData::kTransient); };
814  if (!dm->IsBasic()) {
815  rd->SetIsObject(kTRUE);
816 
817  // Make sure that BuildReadData is called for any abstract
818  // bases classes involved in this object, i.e for all the
819  // classes composing this object (base classes, type of
820  // embedded object and same for their data members).
821  //
822  TClass* dmclass = TClass::GetClass(dm->GetTypeName(), kTRUE, isTransient);
823  if (!dmclass) {
824  dmclass = TClass::GetClass(dm->GetTrueTypeName(), kTRUE, isTransient);
825  }
826  if (dmclass) {
827  if ((dmclass != cl) && !dm->IsaPointer()) {
828  if (dmclass->GetCollectionProxy()) {
829  TClass* valcl = dmclass->GetCollectionProxy()->GetValueClass();
830  // We create the real data for the content of the collection to help the case
831  // of split branches in a TTree (where the node for the data member itself
832  // might have been elided). However, in some cases, like transient members
833  // and/or classes, the content might not be create-able. An example is the
834  // case of a map<A,B> where either A or B does not have default constructor
835  // and thus the compilation of the default constructor for pair<A,B> will
836  // fail (noisily) [This could also apply to any template instance, where it
837  // might have a default constructor definition that can not be compiled due
838  // to the template parameter]
839  if (valcl) {
840  Bool_t wantBuild = kTRUE;
841  if (valcl->Property() & kIsAbstract) wantBuild = kFALSE;
842  if ( (isTransient)
844  && (!valcl->IsLoaded()) ) {
845  // Case where the collection dictionary was not requested and
846  // the content's dictionary was also not requested.
847  // [This is a super set of what we need, but we can't really detect it :(]
848  wantBuild = kFALSE;
849  }
850 
851  if (wantBuild) valcl->BuildRealData(0, isTransient);
852  }
853  } else {
854  void* addrForRecursion = 0;
855  if (GetObjectValidity() == kValidObjectGiven)
856  addrForRecursion = const_cast<void*>(add);
857 
858  dmclass->BuildRealData(addrForRecursion, isTransient);
859  }
860  }
861  }
862  }
863  fRealDataClass->GetListOfRealData()->Add(rd);
864  }
865 }
866 
867 //______________________________________________________________________________
868 //______________________________________________________________________________
869 //______________________________________________________________________________
870 
871 ////////////////////////////////////////////////////////////////////////////////
872 
873 class TAutoInspector : public TMemberInspector {
874 public:
875  Int_t fCount;
876  TBrowser *fBrowser;
877 
878  TAutoInspector(TBrowser *b) {
879  // main constructor.
880  fBrowser = b; fCount = 0; }
881  virtual ~TAutoInspector() { }
883  virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
884  virtual Bool_t IsTreatingNonAccessibleTypes() {return kFALSE;}
885 };
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 /// This method is called from ShowMembers() via AutoBrowse().
889 
890 void TAutoInspector::Inspect(TClass *cl, const char *tit, const char *name,
891  const void *addr, Bool_t /* isTransient */)
892 {
893  if(tit && strchr(tit,'.')) return ;
894  if (fCount && !fBrowser) return;
895 
896  TString ts;
897 
898  if (!cl) return;
899  //if (*(cl->GetName()) == 'T') return;
900  if (*name == '*') name++;
901  int ln = strcspn(name,"[ ");
902  TString iname(name,ln);
903 
904  ClassInfo_t *classInfo = cl->GetClassInfo();
905  if (!classInfo) return;
906 
907  // Browse data members
908  DataMemberInfo_t *m = gCling->DataMemberInfo_Factory(classInfo);
909  TString mname;
910 
911  int found=0;
912  while (gCling->DataMemberInfo_Next(m)) { // MemberLoop
913  mname = gCling->DataMemberInfo_Name(m);
914  mname.ReplaceAll("*","");
915  if ((found = (iname==mname))) break;
916  }
917  assert(found);
918 
919  // we skip: non static members and non objects
920  // - the member G__virtualinfo inserted by the CINT RTTI system
921 
922  //Long_t prop = m.Property() | m.Type()->Property();
924  if (prop & kIsStatic) return;
925  if (prop & kIsFundamental) return;
926  if (prop & kIsEnum) return;
927  if (mname == "G__virtualinfo") return;
928 
929  int size = sizeof(void*);
930 
931  int nmax = 1;
932  if (prop & kIsArray) {
933  for (int dim = 0; dim < gCling->DataMemberInfo_ArrayDim(m); dim++) nmax *= gCling->DataMemberInfo_MaxIndex(m,dim);
934  }
935 
936  std::string clmName(TClassEdit::ShortType(gCling->DataMemberInfo_TypeName(m),
937  TClassEdit::kDropTrailStar) );
938  TClass * clm = TClass::GetClass(clmName.c_str());
939  R__ASSERT(clm);
940  if (!(prop & kIsPointer)) {
941  size = clm->Size();
942  if (size==0) size = gCling->DataMemberInfo_TypeSize(m);
943  }
944 
945 
948 
949  for(int i=0; i<nmax; i++) {
950 
951  char *ptr = (char*)addr + i*size;
952 
953  void *obj = (prop & kIsPointer) ? *((void**)ptr) : (TObject*)ptr;
954 
955  if (!obj) continue;
956 
957  fCount++;
958  if (!fBrowser) return;
959 
960  TString bwname;
961  TClass *actualClass = clm->GetActualClass(obj);
962  if (clm->IsTObject()) {
963  TObject *tobj = (TObject*)clm->DynamicCast(TObject::Class(),obj);
964  bwname = tobj->GetName();
965  } else {
966  bwname = actualClass->GetName();
967  bwname += "::";
968  bwname += mname;
969  }
970 
971  if (!clm->IsTObject() ||
972  bwname.Length()==0 ||
973  strcmp(bwname.Data(),actualClass->GetName())==0) {
974  bwname = name;
975  int l = strcspn(bwname.Data(),"[ ");
976  if (l<bwname.Length() && bwname[l]=='[') {
977  char cbuf[13]; snprintf(cbuf,13,"[%02d]",i);
978  ts.Replace(0,999,bwname,l);
979  ts += cbuf;
980  bwname = (const char*)ts;
981  }
982  }
983 
984  if (proxy==0) {
985 
986  fBrowser->Add(obj,clm,bwname);
987 
988  } else {
989  TClass *valueCl = proxy->GetValueClass();
990 
991  if (valueCl==0) {
992 
993  fBrowser->Add( obj, clm, bwname );
994 
995  } else {
996  TVirtualCollectionProxy::TPushPop env(proxy, obj);
997  TClass *actualCl = 0;
998 
999  int sz = proxy->Size();
1000 
1001  char fmt[] = {"#%09d"};
1002  fmt[3] = '0'+(int)log10(double(sz))+1;
1003  char buf[20];
1004  for (int ii=0;ii<sz;ii++) {
1005  void *p = proxy->At(ii);
1006 
1007  if (proxy->HasPointers()) {
1008  p = *((void**)p);
1009  if(!p) continue;
1010  actualCl = valueCl->GetActualClass(p);
1011  p = actualCl->DynamicCast(valueCl,p,0);
1012  }
1013  fCount++;
1014  snprintf(buf,20,fmt,ii);
1015  ts = bwname;
1016  ts += buf;
1017  fBrowser->Add( p, actualCl, ts );
1018  }
1019  }
1020  }
1021  }
1022 }
1023 
1024 //______________________________________________________________________________
1025 //______________________________________________________________________________
1026 //______________________________________________________________________________
1027 
1029 
1030 ////////////////////////////////////////////////////////////////////////////////
1031 
1033  TDictionary(),
1034  fPersistentRef(0),
1036  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1039  fInstanceCount(0), fOnHeap(0),
1041  fTypeInfo(0), fShowMembers(0),
1042  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1043  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1047  fState(kNoInfo),
1050 
1051 {
1052  // Default ctor.
1053 
1054  R__LOCKGUARD2(gInterpreterMutex);
1055  {
1056  TMmallocDescTemp setreset;
1057  fStreamerInfo = new TObjArray(1, -2);
1058  }
1059  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1060 }
1061 
1062 ////////////////////////////////////////////////////////////////////////////////
1063 /// Create a TClass object. This object contains the full dictionary
1064 /// of a class. It has list to baseclasses, datamembers and methods.
1065 /// Use this ctor to create a standalone TClass object. Most useful
1066 /// to get a TClass interface to an interpreted class. Used by TTabCom.
1067 /// Normally you would use TClass::GetClass("class") to get access to a
1068 /// TClass object for a certain class.
1069 
1070 TClass::TClass(const char *name, Bool_t silent) :
1071  TDictionary(name),
1072  fPersistentRef(0),
1074  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1077  fInstanceCount(0), fOnHeap(0),
1079  fTypeInfo(0), fShowMembers(0),
1080  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1081  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1085  fState(kNoInfo),
1088 {
1089  R__LOCKGUARD2(gInterpreterMutex);
1090 
1091  if (!gROOT)
1092  ::Fatal("TClass::TClass", "ROOT system not initialized");
1093 
1094  {
1095  TMmallocDescTemp setreset;
1096  fStreamerInfo = new TObjArray(1, -2);
1097  }
1098  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1099 
1100  SetBit(kLoading);
1101  if (!gInterpreter)
1102  ::Fatal("TClass::TClass", "gInterpreter not initialized");
1103 
1104  gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1105  if (!silent && !fClassInfo && fName.First('@')==kNPOS)
1106  ::Warning("TClass::TClass", "no dictionary for class %s is available", name);
1107  ResetBit(kLoading);
1108 
1111 }
1112 
1113 ////////////////////////////////////////////////////////////////////////////////
1114 /// Create a TClass object. This object contains the full dictionary
1115 /// of a class. It has list to baseclasses, datamembers and methods.
1116 
1117 TClass::TClass(const char *name, Version_t cversion, Bool_t silent) :
1118  TDictionary(name),
1119  fPersistentRef(0),
1121  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1124  fInstanceCount(0), fOnHeap(0),
1126  fTypeInfo(0), fShowMembers(0),
1127  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1128  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1132  fState(kNoInfo),
1135 {
1136  R__LOCKGUARD2(gInterpreterMutex);
1137  Init(name, cversion, 0, 0, 0, 0, -1, -1, 0, silent);
1138 }
1139 
1140 ////////////////////////////////////////////////////////////////////////////////
1141 /// Create a TClass object. This object does not contain anything. We mimic
1142 /// the case of a class fwd declared in the interpreter.
1143 
1144 TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t silent) :
1145  TDictionary(name),
1146  fPersistentRef(0),
1148  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1151  fInstanceCount(0), fOnHeap(0),
1153  fTypeInfo(0), fShowMembers(0),
1154  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1155  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1159  fState(theState),
1162 {
1163  R__LOCKGUARD2(gInterpreterMutex);
1164 
1165  // Treat the case in which a TClass instance is created for a namespace
1166  if (theState == kNamespaceForMeta){
1168  theState = kForwardDeclared; // it immediately decays in kForwardDeclared
1169  }
1170 
1171  if (theState != kForwardDeclared && theState != kEmulated)
1172  ::Fatal("TClass::TClass",
1173  "A TClass entry cannot be initialized in a state different from kForwardDeclared or kEmulated.");
1174  Init(name, cversion, 0, 0, 0, 0, -1, -1, 0, silent);
1175 }
1176 
1177 ////////////////////////////////////////////////////////////////////////////////
1178 /// Create a TClass object. This object contains the full dictionary
1179 /// of a class. It has list to baseclasses, datamembers and methods.
1180 /// Use this ctor to create a standalone TClass object. Most useful
1181 /// to get a TClass interface to an interpreted class. Used by TTabCom.
1182 /// Normally you would use TClass::GetClass("class") to get access to a
1183 /// TClass object for a certain class.
1184 ///
1185 /// This copies the ClassInfo (i.e. does *not* take ownership of it).
1186 
1187 TClass::TClass(ClassInfo_t *classInfo, Version_t cversion,
1188  const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1189  TDictionary(""),
1190  fPersistentRef(0),
1192  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1195  fInstanceCount(0), fOnHeap(0),
1197  fTypeInfo(0), fShowMembers(0),
1198  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1199  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1203  fState(kNoInfo),
1206 {
1207  R__LOCKGUARD2(gInterpreterMutex);
1208 
1209  if (!gROOT)
1210  ::Fatal("TClass::TClass", "ROOT system not initialized");
1211 
1212  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1213 
1214  SetBit(kLoading);
1215  if (!gInterpreter)
1216  ::Fatal("TClass::TClass", "gInterpreter not initialized");
1217 
1218  if (!classInfo || !gInterpreter->ClassInfo_IsValid(classInfo)) {
1219  MakeZombie();
1220  fState = kNoInfo;
1221  } else {
1222  fName = gInterpreter->ClassInfo_FullName(classInfo);
1223 
1224  R__LOCKGUARD2(gInterpreterMutex);
1225  Init(fName, cversion, 0, 0, dfil, ifil, dl, il, classInfo, silent);
1226  }
1227  ResetBit(kLoading);
1228 
1230 }
1231 
1232 
1233 ////////////////////////////////////////////////////////////////////////////////
1234 /// Create a TClass object. This object contains the full dictionary
1235 /// of a class. It has list to baseclasses, datamembers and methods.
1236 
1237 TClass::TClass(const char *name, Version_t cversion,
1238  const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1239  TDictionary(name),
1240  fPersistentRef(0),
1242  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1245  fInstanceCount(0), fOnHeap(0),
1247  fTypeInfo(0), fShowMembers(0),
1248  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1249  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1253  fState(kNoInfo),
1256 {
1257  R__LOCKGUARD2(gInterpreterMutex);
1258  Init(name,cversion, 0, 0, dfil, ifil, dl, il, 0, silent);
1259 }
1260 
1261 ////////////////////////////////////////////////////////////////////////////////
1262 /// Create a TClass object. This object contains the full dictionary
1263 /// of a class. It has list to baseclasses, datamembers and methods.
1264 
1265 TClass::TClass(const char *name, Version_t cversion,
1266  const std::type_info &info, TVirtualIsAProxy *isa,
1267  const char *dfil, const char *ifil, Int_t dl, Int_t il,
1268  Bool_t silent) :
1269  TDictionary(name),
1270  fPersistentRef(0),
1272  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1273  fAllPubMethod(0),
1274  fClassMenuList(0),
1276  fInstanceCount(0), fOnHeap(0),
1278  fTypeInfo(0), fShowMembers(0),
1279  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1280  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1287 {
1288  R__LOCKGUARD2(gInterpreterMutex);
1289  // use info
1290  Init(name, cversion, &info, isa, dfil, ifil, dl, il, 0, silent);
1291 }
1292 
1293 ////////////////////////////////////////////////////////////////////////////////
1294 /// we found at least one equivalent.
1295 /// let's force a reload
1296 
1298 {
1299  TClass::RemoveClass(oldcl);
1300 
1301  if (oldcl->CanIgnoreTObjectStreamer()) {
1303  }
1304 
1305  TVirtualStreamerInfo *info;
1306  TIter next(oldcl->GetStreamerInfos());
1307  while ((info = (TVirtualStreamerInfo*)next())) {
1308  info->Clear("build");
1309  info->SetClass(this);
1311  }
1312  oldcl->fStreamerInfo->Clear();
1313 
1314  oldcl->ReplaceWith(this);
1315  delete oldcl;
1316 }
1317 
1318 ////////////////////////////////////////////////////////////////////////////////
1319 /// Initialize a TClass object. This object contains the full dictionary
1320 /// of a class. It has list to baseclasses, datamembers and methods.
1321 
1322 void TClass::Init(const char *name, Version_t cversion,
1323  const std::type_info *typeinfo, TVirtualIsAProxy *isa,
1324  const char *dfil, const char *ifil, Int_t dl, Int_t il,
1325  ClassInfo_t *givenInfo,
1326  Bool_t silent)
1327 {
1328  if (!gROOT)
1329  ::Fatal("TClass::TClass", "ROOT system not initialized");
1330 
1331  // Always strip the default STL template arguments (from any template argument or the class name)
1332  fName = TClassEdit::ShortType(name, TClassEdit::kDropStlDefault).c_str();
1333  fClassVersion = cversion;
1334  fDeclFileName = dfil ? dfil : "";
1335  fImplFileName = ifil ? ifil : "";
1336  fDeclFileLine = dl;
1337  fImplFileLine = il;
1338  fTypeInfo = typeinfo;
1339  fIsA = isa;
1340  if ( fIsA ) fIsA->SetClass(this);
1341  // See also TCling::GenerateTClass() which will update fClassVersion after creation!
1342  fStreamerInfo = new TObjArray(fClassVersion+2+10,-1); // +10 to read new data by old
1343  fProperty = -1;
1344  fClassProperty = 0;
1345 
1347 
1348  TClass *oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(fName.Data());
1349 
1351 
1352  if (oldcl && oldcl->TestBit(kLoading)) {
1353  // Do not recreate a class while it is already being created!
1354 
1355  // We can no longer reproduce this case, to check whether we are, we use
1356  // this code:
1357  // Fatal("Init","A bad replacement for %s was requested\n",name);
1358  return;
1359  }
1360 
1361  TClass **persistentRef = 0;
1362  if (oldcl) {
1363 
1364  persistentRef = oldcl->fPersistentRef.exchange(0);
1365 
1366  // The code from here is also in ForceReload.
1367  TClass::RemoveClass(oldcl);
1368  // move the StreamerInfo immediately so that there are
1369  // properly updated!
1370 
1371  if (oldcl->CanIgnoreTObjectStreamer()) {
1373  }
1374  TVirtualStreamerInfo *info;
1375 
1376  TIter next(oldcl->GetStreamerInfos());
1377  while ((info = (TVirtualStreamerInfo*)next())) {
1378  // We need to force a call to BuildOld
1379  info->Clear("build");
1380  info->SetClass(this);
1382  }
1383  oldcl->fStreamerInfo->Clear();
1384  // The code diverges here from ForceReload.
1385 
1386  // Move the Schema Rules too.
1387  fSchemaRules = oldcl->fSchemaRules;
1388  oldcl->fSchemaRules = 0;
1389  }
1390 
1391  SetBit(kLoading);
1392  // Advertise ourself as the loading class for this class name
1393  TClass::AddClass(this);
1394 
1395  Bool_t isStl = TClassEdit::IsSTLCont(fName);
1396 
1397  if (!gInterpreter) {
1398  ::Fatal("TClass::Init", "gInterpreter not initialized");
1399  }
1400 
1401  if (givenInfo) {
1402  if (!gInterpreter->ClassInfo_IsValid(givenInfo) ||
1403  !(gInterpreter->ClassInfo_Property(givenInfo) & (kIsClass | kIsStruct | kIsNamespace)) ||
1404  (!gInterpreter->ClassInfo_IsLoaded(givenInfo) && (gInterpreter->ClassInfo_Property(givenInfo) & (kIsNamespace))) )
1405  {
1406  if (!TClassEdit::IsSTLCont(fName.Data())) {
1407  MakeZombie();
1408  fState = kNoInfo;
1409  TClass::RemoveClass(this);
1410  return;
1411  }
1412  }
1413  fClassInfo = gInterpreter->ClassInfo_Factory(givenInfo);
1414  }
1415  // We need to check if the class it is not fwd declared for the cases where we
1416  // created a TClass directly in the kForwardDeclared state. Indeed in those cases
1417  // fClassInfo will always be nullptr.
1418  if (fState!=kForwardDeclared && !fClassInfo) {
1419 
1420  if (fState == kHasTClassInit) {
1421  // If the TClass is being generated from a ROOT dictionary,
1422  // even though we do not seem to have a CINT dictionary for
1423  // the class, we will will try to load it anyway UNLESS
1424  // the class is an STL container (or string).
1425  // This is because we do not expect the CINT dictionary
1426  // to be present for all STL classes (and we can handle
1427  // the lack of CINT dictionary in that cases).
1428  // However, the cling the dictionary no longer carries
1429  // an instantiation with it, unless we request the loading
1430  // here *or* the user explicitly instantiate the template
1431  // we would not have a ClassInfo for the template
1432  // instantiation.
1434  // Here we check and grab the info from the rootpcm.
1436  if (proto && proto->FillTClass(this)) {
1438  }
1439  }
1440  if (!fHasRootPcmInfo && gInterpreter->CheckClassInfo(fName, /* autoload = */ kTRUE)) {
1441  gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1442  if (fClassInfo) {
1443  // This should be moved out of GetCheckSum itself however the last time
1444  // we tried this cause problem, in particular in the end-of-process operation.
1445  // fCheckSum = GetCheckSum(kLatestCheckSum);
1446  } else {
1447  if (!fClassInfo) {
1448  if (IsZombie()) {
1449  TClass::RemoveClass(this);
1450  return;
1451  }
1452  }
1453  }
1454  }
1455  }
1456  if (!silent && (!fClassInfo && !fCanLoadClassInfo) && !isStl && fName.First('@')==kNPOS &&
1457  !TClassEdit::IsInterpreterDetail(fName.Data()) ) {
1458  if (fState == kHasTClassInit) {
1459  ::Error("TClass::Init", "no interpreter information for class %s is available even though it has a TClass initialization routine.", fName.Data());
1460  } else {
1461  // In this case we initialised this TClass instance starting from the fwd declared state
1462  // and we know we have no dictionary: no need to warn
1463  ::Warning("TClass::Init", "no dictionary for class %s is available", fName.Data());
1464  }
1465  }
1466 
1467  fgClassCount++;
1468  SetUniqueID(fgClassCount);
1469 
1470  // Make the typedef-expanded -> original hash table entries.
1471  // There may be several entries for any given key.
1472  // We only make entries if the typedef-expanded name
1473  // is different from the original name.
1474  TString resolvedThis;
1475  if (!givenInfo && strchr (name, '<')) {
1476  if ( fName != name) {
1477  if (!fgClassTypedefHash) {
1478  fgClassTypedefHash = new THashTable (100, 5);
1480  }
1481 
1482  fgClassTypedefHash->Add (new TNameMapNode (name, fName));
1484 
1485  }
1486  resolvedThis = TClassEdit::ResolveTypedef (name, kTRUE);
1487  if (resolvedThis != name) {
1488  if (!fgClassTypedefHash) {
1489  fgClassTypedefHash = new THashTable (100, 5);
1491  }
1492 
1493  fgClassTypedefHash->Add (new TNameMapNode (resolvedThis, fName));
1495  }
1496 
1497  }
1498 
1499  //In case a class with the same name had been created by TVirtualStreamerInfo
1500  //we must delete the old class, importing only the StreamerInfo structure
1501  //from the old dummy class.
1502  if (oldcl) {
1503 
1504  oldcl->ReplaceWith(this);
1505  delete oldcl;
1506 
1507  } else if (!givenInfo && resolvedThis.Length() > 0 && fgClassTypedefHash) {
1508 
1509  // Check for existing equivalent.
1510 
1511  if (resolvedThis != fName) {
1512  oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(resolvedThis);
1513  if (oldcl && oldcl != this) {
1514  persistentRef = oldcl->fPersistentRef.exchange(0);
1515  ForceReload (oldcl);
1516  }
1517  }
1518  TIter next( fgClassTypedefHash->GetListForObject(resolvedThis) );
1519  while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1520  if (resolvedThis != htmp->String()) continue;
1521  oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(htmp->fOrigName); // gROOT->GetClass (htmp->fOrigName, kFALSE);
1522  if (oldcl && oldcl != this) {
1523  persistentRef = oldcl->fPersistentRef.exchange(0);
1524  ForceReload (oldcl);
1525  }
1526  }
1527  }
1528  if (fClassInfo) {
1530  if ( fDeclFileName == 0 || fDeclFileName[0] == '\0' ) {
1531  fDeclFileName = gInterpreter->ClassInfo_FileName( fClassInfo );
1532  // Missing interface:
1533  // fDeclFileLine = gInterpreter->ClassInfo_FileLine( fClassInfo );
1534 
1535  // But really do not want to set ImplFileLine as it is currently the
1536  // marker of being 'loaded' or not (reminder loaded == has a TClass bootstrap).
1537  }
1538  }
1539 
1540  if (persistentRef) {
1541  fPersistentRef = persistentRef;
1542  } else {
1543  fPersistentRef = new TClass*;
1544  }
1545  *fPersistentRef = this;
1546 
1547  if ( isStl || !strncmp(GetName(),"stdext::hash_",13) || !strncmp(GetName(),"__gnu_cxx::hash_",16) ) {
1548  if (fState != kHasTClassInit) {
1549  // If we have a TClass compiled initialization, we can safely assume that
1550  // there will also be a collection proxy.
1552  if (fCollectionProxy) {
1554 
1555  // Numeric Collections have implicit conversions:
1557 
1558  } else if (!silent) {
1559  Warning("Init","Collection proxy for %s was not properly initialized!",GetName());
1560  }
1561  if (fStreamer==0) {
1563  }
1564  }
1565  } else if (!strncmp(GetName(),"std::pair<",10) || !strncmp(GetName(),"pair<",5) ) {
1566  // std::pairs have implicit conversions
1568  }
1569 
1570  ResetBit(kLoading);
1571 }
1572 
1573 ////////////////////////////////////////////////////////////////////////////////
1574 /// TClass dtor. Deletes all list that might have been created.
1575 
1577 {
1578  R__LOCKGUARD(gInterpreterMutex);
1579 
1580  // Remove from the typedef hashtables.
1582  TString resolvedThis = TClassEdit::ResolveTypedef (GetName(), kTRUE);
1583  TIter next (fgClassTypedefHash->GetListForObject (resolvedThis));
1584  while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1585  if (resolvedThis == htmp->String() && htmp->fOrigName == GetName()) {
1586  fgClassTypedefHash->Remove (htmp);
1587  delete htmp;
1588  break;
1589  }
1590  }
1591  }
1592 
1593  // Not owning lists, don't call Delete()
1594  // But this still need to be done first because the TList destructor
1595  // does access the object contained (via GetObject()->TestBit(kCanDelete))
1596  delete fStreamer; fStreamer =0;
1597  delete fAllPubData; fAllPubData =0;
1598  delete fAllPubMethod; fAllPubMethod=0;
1599 
1600  delete fPersistentRef.load();
1601 
1602  if (fBase.load())
1603  (*fBase).Delete();
1604  delete fBase.load(); fBase = 0;
1605 
1606  if (fData)
1607  fData->Delete();
1608  delete fData; fData = 0;
1609 
1610  if (fEnums.load())
1611  (*fEnums).Delete();
1612  delete fEnums.load(); fEnums = 0;
1613 
1614  if (fFuncTemplate)
1615  fFuncTemplate->Delete();
1616  delete fFuncTemplate; fFuncTemplate = 0;
1617 
1618  if (fMethod.load())
1619  (*fMethod).Delete();
1620  delete fMethod.load(); fMethod=0;
1621 
1622  if (fRealData)
1623  fRealData->Delete();
1624  delete fRealData; fRealData=0;
1625 
1626  if (fStreamerInfo)
1627  fStreamerInfo->Delete();
1628  delete fStreamerInfo; fStreamerInfo = nullptr;
1629 
1630  if (fDeclFileLine >= -1)
1631  TClass::RemoveClass(this);
1632 
1634  fClassInfo=0;
1635 
1636  if (fClassMenuList)
1638  delete fClassMenuList; fClassMenuList=0;
1639 
1641 
1642  if ( fIsA ) delete fIsA;
1643 
1644  if ( fRefProxy ) fRefProxy->Release();
1645  fRefProxy = 0;
1646 
1647  delete fStreamer;
1648  delete fCollectionProxy;
1649  delete fIsAMethod.load();
1650  delete fSchemaRules;
1651  if (fConversionStreamerInfo.load()) {
1652  std::map<std::string, TObjArray*>::iterator it;
1653  std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
1654  for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
1655  delete it->second;
1656  }
1657  delete fConversionStreamerInfo.load();
1658  }
1659 }
1660 
1661 ////////////////////////////////////////////////////////////////////////////////
1662 
1663 namespace {
1664  Int_t ReadRulesContent(FILE *f)
1665  {
1666  // Read a class.rules file which contains one rule per line with comment
1667  // starting with a #
1668  // Returns the number of rules loaded.
1669  // Returns -1 in case of error.
1670 
1671  R__ASSERT(f!=0);
1672  TString rule(1024);
1673  int c, state = 0;
1674  Int_t count = 0;
1675 
1676  while ((c = fgetc(f)) != EOF) {
1677  if (c == 13) // ignore CR
1678  continue;
1679  if (c == '\n') {
1680  if (state != 3) {
1681  state = 0;
1682  if (rule.Length() > 0) {
1683  if (TClass::AddRule(rule)) {
1684  ++count;
1685  }
1686  rule.Clear();
1687  }
1688  }
1689  continue;
1690  }
1691  switch (state) {
1692  case 0: // start of line
1693  switch (c) {
1694  case ' ':
1695  case '\t':
1696  break;
1697  case '#':
1698  state = 1;
1699  break;
1700  default:
1701  state = 2;
1702  break;
1703  }
1704  break;
1705 
1706  case 1: // comment
1707  break;
1708 
1709  case 2: // rule
1710  switch (c) {
1711  case '\\':
1712  state = 3; // Continuation request
1713  default:
1714  break;
1715  }
1716  break;
1717  }
1718  switch (state) {
1719  case 2:
1720  rule.Append(c);
1721  break;
1722  }
1723  }
1724  return count;
1725  }
1726 }
1727 
1728 ////////////////////////////////////////////////////////////////////////////////
1729 /// Read the class.rules files from the default location:.
1730 /// $ROOTSYS/etc/class.rules (or ROOTETCDIR/class.rules)
1731 
1733 {
1734  static const char *suffix = "class.rules";
1735  TString sname = suffix;
1737 
1738  Int_t res = -1;
1739 
1740  FILE * f = fopen(sname,"r");
1741  if (f != 0) {
1742  res = ReadRulesContent(f);
1743  fclose(f);
1744  } else {
1745  ::Error("TClass::ReadRules()", "Cannot find rules file %s", sname.Data());
1746  }
1747  return res;
1748 }
1749 
1750 ////////////////////////////////////////////////////////////////////////////////
1751 /// Read a class.rules file which contains one rule per line with comment
1752 /// starting with a #
1753 /// - Returns the number of rules loaded.
1754 /// - Returns -1 in case of error.
1755 
1756 Int_t TClass::ReadRules( const char *filename )
1757 {
1758  if (!filename || !filename[0]) {
1759  ::Error("TClass::ReadRules", "no file name specified");
1760  return -1;
1761  }
1762 
1763  FILE * f = fopen(filename,"r");
1764  if (f == 0) {
1765  ::Error("TClass::ReadRules","Failed to open %s\n",filename);
1766  return -1;
1767  }
1768  Int_t count = ReadRulesContent(f);
1769 
1770  fclose(f);
1771  return count;
1772 
1773 }
1774 
1775 ////////////////////////////////////////////////////////////////////////////////
1776 /// Add a schema evolution customization rule.
1777 /// The syntax of the rule can be either the short form:
1778 /// ~~~ {.cpp}
1779 /// [type=Read] classname membername [attributes=... ] [version=[...] ] [checksum=[...] ] [oldtype=...] [code={...}]
1780 /// ~~~
1781 /// or the long form
1782 /// ~~~ {.cpp}
1783 /// [type=Read] sourceClass=classname [targetclass=newClassname] [ source="type membername; [type2 membername2]" ]
1784 /// [target="membername3;membername4"] [attributes=... ] [version=...] [checksum=...] [code={...}|functionname]
1785 /// ~~~
1786 ///
1787 /// For example to set HepMC::GenVertex::m_event to _not_ owned the object it is pointing to:
1788 /// HepMC::GenVertex m_event attributes=NotOwner
1789 ///
1790 /// Semantic of the tags:
1791 /// - type : the type of the rule, valid values: Read, ReadRaw, Write, WriteRaw, the default is 'Read'.
1792 /// - sourceClass : the name of the class as it is on the rule file
1793 /// - targetClass : the name of the class as it is in the current code ; defaults to the value of sourceClass
1794 /// - source : the types and names of the data members from the class on file that are needed, the list is separated by semi-colons ';'
1795 /// - oldtype: in the short form only, indicates the type on disk of the data member.
1796 /// - target : the names of the data members updated by this rule, the list is separated by semi-colons ';'
1797 /// - attributes : list of possible qualifiers among: Owner, NotOwner
1798 /// - version : list of the version of the class layout that this rule applies to. The syntax can be [1,4,5] or [2-] or [1-3] or [-3]
1799 /// - checksum : comma delimited list of the checksums of the class layout that this rule applies to.
1800 /// - code={...} : code to be executed for the rule or name of the function implementing it.
1801 
1802 Bool_t TClass::AddRule( const char *rule )
1803 {
1804  ROOT::TSchemaRule *ruleobj = new ROOT::TSchemaRule();
1805  if (! ruleobj->SetFromRule( rule ) ) {
1806  delete ruleobj;
1807  return kFALSE;
1808  }
1809 
1810  R__LOCKGUARD(gInterpreterMutex);
1811 
1812  TClass *cl = TClass::GetClass( ruleobj->GetTargetClass() );
1813  if (!cl) {
1814  // Create an empty emulated class for now.
1815  cl = gInterpreter->GenerateTClass(ruleobj->GetTargetClass(), /* emulation = */ kTRUE, /*silent = */ kTRUE);
1816  }
1818 
1819  TString errmsg;
1820  if( !rset->AddRule( ruleobj, ROOT::Detail::TSchemaRuleSet::kCheckConflict, &errmsg ) ) {
1821  ::Warning( "TClass::AddRule", "The rule for class: \"%s\": version, \"%s\" and data members: \"%s\" has been skipped because it conflicts with one of the other rules (%s).",
1822  ruleobj->GetTargetClass(), ruleobj->GetVersion(), ruleobj->GetTargetString(), errmsg.Data() );
1823  delete ruleobj;
1824  return kFALSE;
1825  }
1826  return kTRUE;
1827 }
1828 
1829 ////////////////////////////////////////////////////////////////////////////////
1830 /// Adopt a new set of Data Model Evolution rules.
1831 
1833 {
1834  R__LOCKGUARD(gInterpreterMutex);
1835 
1836  delete fSchemaRules;
1837  fSchemaRules = rules;
1838  fSchemaRules->SetClass( this );
1839 }
1840 
1841 ////////////////////////////////////////////////////////////////////////////////
1842 /// Return the set of the schema rules if any.
1843 
1845 {
1846  return fSchemaRules;
1847 }
1848 
1849 ////////////////////////////////////////////////////////////////////////////////
1850 /// Return the set of the schema rules if any.
1851 /// If create is true, create an empty set
1852 
1854 {
1855  if (create && fSchemaRules == 0) {
1857  fSchemaRules->SetClass( this );
1858  }
1859  return fSchemaRules;
1860 }
1861 
1862 ////////////////////////////////////////////////////////////////////////////////
1863 
1864 void TClass::AddImplFile(const char* filename, int line) {
1865  // Currently reset the implementation file and line.
1866  // In the close future, it will actually add this file and line
1867  // to a "list" of implementation files.
1868 
1869  fImplFileName = filename;
1870  fImplFileLine = line;
1871 }
1872 
1873 ////////////////////////////////////////////////////////////////////////////////
1874 /// Browse external object inherited from TObject.
1875 /// It passes through inheritance tree and calls TBrowser::Add
1876 /// in appropriate cases. Static function.
1877 
1879 {
1880  if (!obj) return 0;
1881 
1882  TAutoInspector insp(b);
1883  obj->ShowMembers(insp);
1884  return insp.fCount;
1885 }
1886 
1887 ////////////////////////////////////////////////////////////////////////////////
1888 /// Browse objects of of the class described by this TClass object.
1889 
1890 Int_t TClass::Browse(void *obj, TBrowser *b) const
1891 {
1892  if (!obj) return 0;
1893 
1894  TClass *actual = GetActualClass(obj);
1895  if (IsTObject()) {
1896  // Call TObject::Browse.
1897 
1898  if (!fIsOffsetStreamerSet) {
1900  }
1901  TObject* realTObject = (TObject*)((size_t)obj + fOffsetStreamer);
1902  realTObject->Browse(b);
1903  return 1;
1904  } else if (actual != this) {
1905  return actual->Browse(obj, b);
1906  } else if (GetCollectionProxy()) {
1907 
1908  // do something useful.
1909 
1910  } else {
1911  TAutoInspector insp(b);
1912  CallShowMembers(obj,insp,kFALSE);
1913  return insp.fCount;
1914  }
1915 
1916  return 0;
1917 }
1918 
1919 ////////////////////////////////////////////////////////////////////////////////
1920 /// This method is called by a browser to get the class information.
1921 
1923 {
1924  if (!HasInterpreterInfo()) return;
1925 
1926  if (b) {
1927  if (!fRealData) BuildRealData();
1928 
1929  b->Add(GetListOfDataMembers(), "Data Members");
1930  b->Add(GetListOfRealData(), "Real Data Members");
1931  b->Add(GetListOfMethods(), "Methods");
1932  b->Add(GetListOfBases(), "Base Classes");
1933  }
1934 }
1935 
1936 ////////////////////////////////////////////////////////////////////////////////
1937 /// Build a full list of persistent data members.
1938 /// Scans the list of all data members in the class itself and also
1939 /// in all base classes. For each persistent data member, inserts a
1940 /// TRealData object in the list fRealData.
1941 ///
1942 
1943 void TClass::BuildRealData(void* pointer, Bool_t isTransient)
1944 {
1945 
1946  R__LOCKGUARD(gInterpreterMutex);
1947 
1948  // Only do this once.
1949  if (fRealData) {
1950  return;
1951  }
1952 
1953  if (fClassVersion == 0) {
1954  isTransient = kTRUE;
1955  }
1956 
1957  // When called via TMapFile (e.g. Update()) make sure that the dictionary
1958  // gets allocated on the heap and not in the mapped file.
1959  TMmallocDescTemp setreset;
1960 
1961  // Handle emulated classes and STL containers specially.
1962  if (!HasInterpreterInfo() || TClassEdit::IsSTLCont(GetName(), 0) || TClassEdit::IsSTLBitset(GetName())) {
1963  // We are an emulated class or an STL container.
1964  fRealData = new TList;
1965  BuildEmulatedRealData("", 0, this);
1966  return;
1967  }
1968 
1969  // return early on string
1970  static TClassRef clRefString("std::string");
1971  if (clRefString == this) {
1972  return;
1973  }
1974 
1975  // Complain about stl classes ending up here (unique_ptr etc) - except for
1976  // pair where we will build .first, .second just fine
1977  // and those for which the user explicitly requested a dictionary.
1978  if (!isTransient && GetState() != kHasTClassInit
1979  && TClassEdit::IsStdClass(GetName())
1980  && strncmp(GetName(), "pair<", 5) != 0) {
1981  Error("BuildRealData", "Inspection for %s not supported!", GetName());
1982  }
1983 
1984  // The following statement will recursively call
1985  // all the subclasses of this class.
1986  fRealData = new TList;
1987  TBuildRealData brd(pointer, this);
1988 
1989  // CallShowMember will force a call to InheritsFrom, which indirectly
1990  // calls TClass::GetClass. It forces the loading of new typedefs in
1991  // case some of them were not yet loaded.
1992  if ( ! CallShowMembers(pointer, brd, isTransient) ) {
1993  if ( isTransient ) {
1994  // This is a transient data member, so it is probably fine to not have
1995  // access to its content. However let's no mark it as definitively setup,
1996  // since another class might use this class for a persistent data member and
1997  // in this case we really want the error message.
1998  delete fRealData;
1999  fRealData = 0;
2000  } else {
2001  Error("BuildRealData", "Cannot find any ShowMembers function for %s!", GetName());
2002  }
2003  }
2004 
2005  // Take this opportunity to build the real data for base classes.
2006  // In case one base class is abstract, it would not be possible later
2007  // to create the list of real data for this abstract class.
2008  TBaseClass* base = 0;
2009  TIter next(GetListOfBases());
2010  while ((base = (TBaseClass*) next())) {
2011  if (base->IsSTLContainer()) {
2012  continue;
2013  }
2014  TClass* c = base->GetClassPointer();
2015  if (c) {
2016  c->BuildRealData(0, isTransient);
2017  }
2018  }
2019 }
2020 
2021 ////////////////////////////////////////////////////////////////////////////////
2022 /// Build the list of real data for an emulated class
2023 
2024 void TClass::BuildEmulatedRealData(const char *name, Long_t offset, TClass *cl)
2025 {
2026  R__LOCKGUARD(gInterpreterMutex);
2027 
2028  TVirtualStreamerInfo *info;
2029  if (Property() & kIsAbstract) {
2031  } else {
2032  info = GetStreamerInfo();
2033  }
2034  if (!info) {
2035  // This class is abstract, but we don't yet have a SteamerInfo for it ...
2036  Error("BuildEmulatedRealData","Missing StreamerInfo for %s",GetName());
2037  // Humm .. no information ... let's bail out
2038  return;
2039  }
2040 
2041  TIter next(info->GetElements());
2042  TStreamerElement *element;
2043  while ((element = (TStreamerElement*)next())) {
2044  Int_t etype = element->GetType();
2045  Long_t eoffset = element->GetOffset();
2046  TClass *cle = element->GetClassPointer();
2047  if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2048  //base class are skipped in this loop, they will be added at the end.
2049  continue;
2050  } else if (etype == TVirtualStreamerInfo::kTObject ||
2051  etype == TVirtualStreamerInfo::kTNamed ||
2052  etype == TVirtualStreamerInfo::kObject ||
2053  etype == TVirtualStreamerInfo::kAny) {
2054  //member class
2055  TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2056  TRealData *rd = new TRealData(rdname,offset+eoffset,0);
2057  if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2058  cl->GetListOfRealData()->Add(rd);
2059  // Now we a dot
2060  rdname.Form("%s%s.",name,element->GetFullName());
2061  if (cle) cle->BuildEmulatedRealData(rdname,offset+eoffset,cl);
2062  } else {
2063  //others
2064  TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2065  TRealData *rd = new TRealData(rdname,offset+eoffset,0);
2066  if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2067  cl->GetListOfRealData()->Add(rd);
2068  }
2069  //if (fClassInfo==0 && element->IsBase()) {
2070  // if (fBase==0) fBase = new TList;
2071  // TClass *base = element->GetClassPointer();
2072  // fBase->Add(new TBaseClass(this, cl, eoffset));
2073  //}
2074  }
2075  // The base classes must added last on the list of real data (to help with ambiguous data member names)
2076  next.Reset();
2077  while ((element = (TStreamerElement*)next())) {
2078  Int_t etype = element->GetType();
2079  if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2080  //base class
2081  Long_t eoffset = element->GetOffset();
2082  TClass *cle = element->GetClassPointer();
2083  if (cle) cle->BuildEmulatedRealData(name,offset+eoffset,cl);
2084  }
2085  }
2086 }
2087 
2088 
2089 ////////////////////////////////////////////////////////////////////////////////
2090 /// Calculate the offset between an object of this class to
2091 /// its base class TObject. The pointer can be adjusted by
2092 /// that offset to access any virtual method of TObject like
2093 /// Streamer() and ShowMembers().
2094 
2096 {
2097  R__LOCKGUARD(gInterpreterMutex);
2099  // When called via TMapFile (e.g. Update()) make sure that the dictionary
2100  // gets allocated on the heap and not in the mapped file.
2101 
2102  TMmallocDescTemp setreset;
2104  if (fStreamerType == kTObject) {
2106  }
2108  }
2109 }
2110 
2111 
2112 ////////////////////////////////////////////////////////////////////////////////
2113 /// Call ShowMembers() on the obj of this class type, passing insp and parent.
2114 /// isATObject is -1 if unknown, 0 if it is not a TObject, and 1 if it is a TObject.
2115 /// The function returns whether it was able to call ShowMembers().
2116 
2117 Bool_t TClass::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2118 {
2119  if (fShowMembers) {
2120  // This should always works since 'pointer' should be pointing
2121  // to an object of the actual type of this TClass object.
2122  fShowMembers(obj, insp, isTransient);
2123  return kTRUE;
2124  } else {
2125 
2127  if (fClassInfo) {
2128 
2129  if (strcmp(GetName(), "string") == 0) {
2130  // For std::string we know that we do not have a ShowMembers
2131  // function and that it's okay.
2132  return kTRUE;
2133  }
2134  // Since we do have some dictionary information, let's
2135  // call the interpreter's ShowMember.
2136  // This works with Cling to support interpreted classes.
2137  gInterpreter->InspectMembers(insp, obj, this, isTransient);
2138  return kTRUE;
2139 
2140  } else if (TVirtualStreamerInfo* sinfo = GetStreamerInfo()) {
2141  sinfo->CallShowMembers(obj, insp, isTransient);
2142  return kTRUE;
2143  } // isATObject
2144  } // fShowMembers is set
2145 
2146  return kFALSE;
2147 }
2148 
2149 ////////////////////////////////////////////////////////////////////////////////
2150 /// Do a ShowMembers() traversal of all members and base classes' members
2151 /// using the reflection information from the interpreter. Works also for
2152 /// interpreted objects.
2153 
2154 void TClass::InterpretedShowMembers(void* obj, TMemberInspector &insp, Bool_t isTransient)
2155 {
2156  return gInterpreter->InspectMembers(insp, obj, this, isTransient);
2157 }
2158 
2160 {
2161  if (fCanSplit >= 0) {
2162  return ! ( fCanSplit & 0x2 );
2163  }
2164 
2165  R__LOCKGUARD(gInterpreterMutex);
2166 
2167  if (GetCollectionProxy() != nullptr) {
2168  // A collection can never affect its derived class 'splittability'
2169  return kTRUE;
2170  }
2171 
2172  if (this == TRef::Class()) { fCanSplit = 2; return kFALSE; }
2173  if (this == TRefArray::Class()) { fCanSplit = 2; return kFALSE; }
2174  if (this == TArray::Class()) { fCanSplit = 2; return kFALSE; }
2175  if (this == TClonesArray::Class()) { fCanSplit = 1; return kTRUE; }
2176  if (this == TCollection::Class()) { fCanSplit = 2; return kFALSE; }
2177 
2178  // TTree is not always available (for example in rootcling), so we need
2179  // to grab it silently.
2180  auto refTreeClass( TClass::GetClass("TTree",kTRUE,kTRUE) );
2181  if (this == refTreeClass) { fCanSplit = 2; return kFALSE; }
2182 
2183  if (!HasDataMemberInfo()) {
2184  TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
2185  if (sinfo==0) sinfo = GetStreamerInfo();
2186  TIter next(sinfo->GetElements());
2187  TStreamerElement *element;
2188  while ((element = (TStreamerElement*)next())) {
2189  if (element->IsA() == TStreamerBase::Class()) {
2190  TClass *clbase = element->GetClassPointer();
2191  if (!clbase) {
2192  // If there is a missing base class, we can't split the immediate
2193  // derived class.
2194  fCanSplit = 0;
2195  return kFALSE;
2196  } else if (!clbase->CanSplitBaseAllow()) {
2197  fCanSplit = 2;
2198  return kFALSE;
2199  }
2200  }
2201  }
2202  }
2203 
2204  // If we don't have data member info there is no more information
2205  // we can find out.
2206  if (!HasDataMemberInfo()) return kTRUE;
2207 
2208  TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : 0;
2209 
2210  // Look at inheritance tree
2211  while (lnk) {
2212  TClass *c;
2213  TBaseClass *base = (TBaseClass*) lnk->GetObject();
2214  c = base->GetClassPointer();
2215  if(!c) {
2216  // If there is a missing base class, we can't split the immediate
2217  // derived class.
2218  fCanSplit = 0;
2219  return kFALSE;
2220  } else if (!c->CanSplitBaseAllow()) {
2221  fCanSplit = 2;
2222  return kFALSE;
2223  }
2224  lnk = lnk->Next();
2225  }
2226  return kTRUE;
2227 }
2228 
2229 ////////////////////////////////////////////////////////////////////////////////
2230 /// Return true if the data member of this TClass can be saved separately.
2231 
2233 {
2234  // Note: add the possibility to set it for the class and the derived class.
2235  // save the info in TVirtualStreamerInfo
2236  // deal with the info in MakeProject
2237  if (fCanSplit >= 0) {
2238  // The user explicitly set the value
2239  return (fCanSplit & 0x1) == 1;
2240  }
2241 
2242  R__LOCKGUARD(gInterpreterMutex);
2243  TClass *This = const_cast<TClass*>(this);
2244 
2245  if (this == TObject::Class()) { This->fCanSplit = 1; return kTRUE; }
2246  if (fName == "TClonesArray") { This->fCanSplit = 1; return kTRUE; }
2247  if (fRefProxy) { This->fCanSplit = 0; return kFALSE; }
2248  if (fName.BeginsWith("TVectorT<")) { This->fCanSplit = 0; return kFALSE; }
2249  if (fName.BeginsWith("TMatrixT<")) { This->fCanSplit = 0; return kFALSE; }
2250  if (fName == "string") { This->fCanSplit = 0; return kFALSE; }
2251  if (fName == "std::string") { This->fCanSplit = 0; return kFALSE; }
2252 
2253  if (GetCollectionProxy()!=0) {
2254  // For STL collection we need to look inside.
2255 
2256  // However we do not split collections of collections
2257  // nor collections of strings
2258  // nor collections of pointers (unless explicit request (see TBranchSTL)).
2259 
2260  if (GetCollectionProxy()->HasPointers()) { This->fCanSplit = 0; return kFALSE; }
2261 
2262  TClass *valueClass = GetCollectionProxy()->GetValueClass();
2263  if (valueClass == 0) { This->fCanSplit = 0; return kFALSE; }
2264  static TClassRef stdStringClass("std::string");
2265  if (valueClass==TString::Class() || valueClass==stdStringClass)
2266  { This->fCanSplit = 0; return kFALSE; }
2267  if (!valueClass->CanSplit()) { This->fCanSplit = 0; return kFALSE; }
2268  if (valueClass->GetCollectionProxy() != 0) { This->fCanSplit = 0; return kFALSE; }
2269 
2270  Int_t stl = -TClassEdit::IsSTLCont(GetName(), 0);
2271  if ((stl==ROOT::kSTLmap || stl==ROOT::kSTLmultimap)
2272  && !valueClass->HasDataMemberInfo()==0)
2273  {
2274  This->fCanSplit = 0;
2275  return kFALSE;
2276  }
2277 
2278  This->fCanSplit = 1;
2279  return kTRUE;
2280 
2281  }
2282 
2283  if (GetStreamer()!=0) {
2284 
2285  // We have an external custom streamer provided by the user, we must not
2286  // split it.
2287  This->fCanSplit = 0;
2288  return kFALSE;
2289 
2290  } else if ( TestBit(TClass::kHasCustomStreamerMember) ) {
2291 
2292  // We have a custom member function streamer or
2293  // an older (not StreamerInfo based) automatic streamer.
2294  This->fCanSplit = 0;
2295  return kFALSE;
2296  }
2297 
2298  if (Size()==1) {
2299  // 'Empty' class there is nothing to split!.
2300  This->fCanSplit = 0;
2301  return kFALSE;
2302  }
2303 
2304 
2305  if ( !This->CanSplitBaseAllow() ) {
2306  return kFALSE;
2307  }
2308 
2309  This->fCanSplit = 1;
2310  return kTRUE;
2311 }
2312 
2313 ////////////////////////////////////////////////////////////////////////////////
2314 /// Return the C++ property of this class, eg. is abstract, has virtual base
2315 /// class, see EClassProperty in TDictionary.h
2316 
2318 {
2319  if (fProperty == -1) Property();
2320  return fClassProperty;
2321 }
2322 
2323 ////////////////////////////////////////////////////////////////////////////////
2324 /// Create a Clone of this TClass object using a different name but using the same 'dictionary'.
2325 /// This effectively creates a hard alias for the class name.
2326 
2327 TObject *TClass::Clone(const char *new_name) const
2328 {
2329  if (new_name == 0 || new_name[0]=='\0' || fName == new_name) {
2330  Error("Clone","The name of the class must be changed when cloning a TClass object.");
2331  return 0;
2332  }
2333 
2334  // Need to lock access to TROOT::GetListOfClasses so the cloning happens atomically
2335  R__LOCKGUARD2(gInterpreterMutex);
2336  // Temporarily remove the original from the list of classes.
2337  TClass::RemoveClass(const_cast<TClass*>(this));
2338 
2339  TClass *copy;
2340  if (fTypeInfo) {
2341  copy = new TClass(GetName(),
2342  fClassVersion,
2343  *fTypeInfo,
2344  new TIsAProxy(*fTypeInfo),
2345  GetDeclFileName(),
2346  GetImplFileName(),
2347  GetDeclFileLine(),
2348  GetImplFileLine());
2349  } else {
2350  copy = new TClass(GetName(),
2351  fClassVersion,
2352  GetDeclFileName(),
2353  GetImplFileName(),
2354  GetDeclFileLine(),
2355  GetImplFileLine());
2356  }
2357  copy->fShowMembers = fShowMembers;
2358  // Remove the copy before renaming it
2359  TClass::RemoveClass(copy);
2360  copy->fName = new_name;
2361  TClass::AddClass(copy);
2362 
2363  copy->SetNew(fNew);
2364  copy->SetNewArray(fNewArray);
2365  copy->SetDelete(fDelete);
2367  copy->SetDestructor(fDestructor);
2369  copy->fStreamerFunc = fStreamerFunc;
2371  if (fStreamer) {
2372  copy->AdoptStreamer(fStreamer->Generate());
2373  }
2374  // If IsZombie is true, something went wrong and we will not be
2375  // able to properly copy the collection proxy
2376  if (fCollectionProxy && !copy->IsZombie()) {
2378  }
2379  copy->SetClassSize(fSizeof);
2380  if (fRefProxy) {
2381  copy->AdoptReferenceProxy( fRefProxy->Clone() );
2382  }
2383  TClass::AddClass(const_cast<TClass*>(this));
2384  return copy;
2385 }
2386 
2387 ////////////////////////////////////////////////////////////////////////////////
2388 /// Copy the argument.
2389 
2391 {
2392 // // This code was used too quickly test the STL Emulation layer
2393 // Int_t k = TClassEdit::IsSTLCont(GetName());
2394 // if (k==1||k==-1) return;
2395 
2396  delete fCollectionProxy;
2397  fCollectionProxy = orig.Generate();
2398 }
2399 
2400 ////////////////////////////////////////////////////////////////////////////////
2401 /// Draw detailed class inheritance structure.
2402 /// If a class B inherits from a class A, the description of B is drawn
2403 /// on the right side of the description of A.
2404 /// Member functions overridden by B are shown in class A with a blue line
2405 /// erasing the corresponding member function
2406 
2407 void TClass::Draw(Option_t *option)
2408 {
2409  if (!HasInterpreterInfo()) return;
2410 
2411  TVirtualPad *padsav = gPad;
2412 
2413  // Should we create a new canvas?
2414  TString opt=option;
2415  if (!padsav || !opt.Contains("same")) {
2416  TVirtualPad *padclass = (TVirtualPad*)(gROOT->GetListOfCanvases())->FindObject("R__class");
2417  if (!padclass) {
2418  gROOT->ProcessLine("new TCanvas(\"R__class\",\"class\",20,20,1000,750);");
2419  } else {
2420  padclass->cd();
2421  }
2422  }
2423 
2424  if (gPad) gPad->DrawClassObject(this,option);
2425 
2426  if (padsav) padsav->cd();
2427 }
2428 
2429 ////////////////////////////////////////////////////////////////////////////////
2430 /// Dump contents of object on stdout.
2431 /// Using the information in the object dictionary
2432 /// each data member is interpreted.
2433 /// If a data member is a pointer, the pointer value is printed
2434 /// 'obj' is assume to point to an object of the class describe by this TClass
2435 ///
2436 /// The following output is the Dump of a TArrow object:
2437 /// ~~~ {.cpp}
2438 /// fAngle 0 Arrow opening angle (degrees)
2439 /// fArrowSize 0.2 Arrow Size
2440 /// fOption.*fData
2441 /// fX1 0.1 X of 1st point
2442 /// fY1 0.15 Y of 1st point
2443 /// fX2 0.67 X of 2nd point
2444 /// fY2 0.83 Y of 2nd point
2445 /// fUniqueID 0 object unique identifier
2446 /// fBits 50331648 bit field status word
2447 /// fLineColor 1 line color
2448 /// fLineStyle 1 line style
2449 /// fLineWidth 1 line width
2450 /// fFillColor 19 fill area color
2451 /// fFillStyle 1001 fill area style
2452 /// ~~~
2453 ///
2454 /// If noAddr is true, printout of all pointer values is skipped.
2455 
2456 void TClass::Dump(const void *obj, Bool_t noAddr /*=kFALSE*/) const
2457 {
2458 
2459  Long_t prObj = noAddr ? 0 : (Long_t)obj;
2460  if (IsTObject()) {
2461  if (!fIsOffsetStreamerSet) {
2463  }
2464  TObject *tobj = (TObject*)((Long_t)obj + fOffsetStreamer);
2465 
2466 
2467  if (sizeof(this) == 4)
2468  Printf("==> Dumping object at: 0x%08lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2469  else
2470  Printf("==> Dumping object at: 0x%016lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2471  } else {
2472 
2473  if (sizeof(this) == 4)
2474  Printf("==> Dumping object at: 0x%08lx, class=%s\n",prObj,GetName());
2475  else
2476  Printf("==> Dumping object at: 0x%016lx, class=%s\n",prObj,GetName());
2477  }
2478 
2479  TDumpMembers dm(noAddr);
2480  if (!CallShowMembers(obj, dm, kFALSE)) {
2481  Info("Dump", "No ShowMembers function, dumping disabled");
2482  }
2483 }
2484 
2485 ////////////////////////////////////////////////////////////////////////////////
2486 /// Introduce an escape character (@) in front of a special chars.
2487 /// You need to use the result immediately before it is being overwritten.
2488 
2489 char *TClass::EscapeChars(const char *text) const
2490 {
2491  static const UInt_t maxsize = 255;
2492  static char name[maxsize+2]; //One extra if last char needs to be escaped
2493 
2494  UInt_t nch = strlen(text);
2495  UInt_t icur = 0;
2496  for (UInt_t i = 0; i < nch && icur < maxsize; ++i, ++icur) {
2497  if (text[i] == '\"' || text[i] == '[' || text[i] == '~' ||
2498  text[i] == ']' || text[i] == '&' || text[i] == '#' ||
2499  text[i] == '!' || text[i] == '^' || text[i] == '<' ||
2500  text[i] == '?' || text[i] == '>') {
2501  name[icur] = '@';
2502  ++icur;
2503  }
2504  name[icur] = text[i];
2505  }
2506  name[icur] = 0;
2507  return name;
2508 }
2509 
2510 ////////////////////////////////////////////////////////////////////////////////
2511 /// Return a pointer the the real class of the object.
2512 /// This is equivalent to object->IsA() when the class has a ClassDef.
2513 /// It is REQUIRED that object is coming from a proper pointer to the
2514 /// class represented by 'this'.
2515 /// Example: Special case:
2516 /// ~~~ {.cpp}
2517 /// class MyClass : public AnotherClass, public TObject
2518 /// ~~~
2519 /// then on return, one must do:
2520 /// ~~~ {.cpp}
2521 /// TObject *obj = (TObject*)((void*)myobject)directory->Get("some object of MyClass");
2522 /// MyClass::Class()->GetActualClass(obj); // this would be wrong!!!
2523 /// ~~~
2524 /// Also if the class represented by 'this' and NONE of its parents classes
2525 /// have a virtual ptr table, the result will be 'this' and NOT the actual
2526 /// class.
2527 
2528 TClass *TClass::GetActualClass(const void *object) const
2529 {
2530  if (object==0) return (TClass*)this;
2531  if (fIsA) {
2532  return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2533  } else if (fGlobalIsA) {
2534  return fGlobalIsA(this,object);
2535  } else {
2536  if (IsTObject()) {
2537 
2538  if (!fIsOffsetStreamerSet) {
2540  }
2541  TObject* realTObject = (TObject*)((size_t)object + fOffsetStreamer);
2542 
2543  return realTObject->IsA();
2544  }
2545 
2546  if (HasInterpreterInfo()) {
2547 
2548  TVirtualIsAProxy *isa = 0;
2550  isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TInstrumentedIsAProxy<%s>(0);",GetName()));
2551  }
2552  else {
2553  isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TIsAProxy(typeid(%s));",GetName()));
2554  }
2555  if (isa) {
2556  R__LOCKGUARD(gInterpreterMutex);
2557  const_cast<TClass*>(this)->fIsA = isa;
2558  }
2559  if (fIsA) {
2560  return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2561  }
2562  }
2564  if (sinfo) {
2565  return sinfo->GetActualClass(object);
2566  }
2567  return (TClass*)this;
2568  }
2569 }
2570 
2571 ////////////////////////////////////////////////////////////////////////////////
2572 /// Return pointer to the base class "classname". Returns 0 in case
2573 /// "classname" is not a base class. Takes care of multiple inheritance.
2574 
2575 TClass *TClass::GetBaseClass(const char *classname)
2576 {
2577  // check if class name itself is equal to classname
2578  if (strcmp(GetName(), classname) == 0) return this;
2579 
2580  if (!HasDataMemberInfo()) return 0;
2581 
2582  // Make sure we deal with possible aliases, we could also have normalized
2583  // the name.
2584  TClass *search = TClass::GetClass(classname,kTRUE,kTRUE);
2585 
2586  if (search) return GetBaseClass(search);
2587  else return 0;
2588 }
2589 
2590 ////////////////////////////////////////////////////////////////////////////////
2591 /// Return pointer to the base class "cl". Returns 0 in case "cl"
2592 /// is not a base class. Takes care of multiple inheritance.
2593 
2595 {
2596  // check if class name itself is equal to classname
2597  if (cl == this) return this;
2598 
2599  if (!HasDataMemberInfo()) return 0;
2600 
2601  TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : 0;
2602 
2603  // otherwise look at inheritance tree
2604  while (lnk) {
2605  TClass *c, *c1;
2606  TBaseClass *base = (TBaseClass*) lnk->GetObject();
2607  c = base->GetClassPointer();
2608  if (c) {
2609  if (cl == c) return c;
2610  c1 = c->GetBaseClass(cl);
2611  if (c1) return c1;
2612  }
2613  lnk = lnk->Next();
2614  }
2615  return 0;
2616 }
2617 
2618 ////////////////////////////////////////////////////////////////////////////////
2619 /// Return data member offset to the base class "cl".
2620 /// - Returns -1 in case "cl" is not a base class.
2621 /// - Returns -2 if cl is a base class, but we can't find the offset
2622 /// because it's virtual.
2623 /// Takes care of multiple inheritance.
2624 
2626 {
2627  // check if class name itself is equal to classname
2628  if (cl == this) return 0;
2629 
2630  if (!fBase.load()) {
2632  // If the information was not provided by the root pcm files and
2633  // if we can not find the ClassInfo, we have to fall back to the
2634  // StreamerInfo
2635  if (!fClassInfo) {
2637  if (!sinfo) return -1;
2638  TStreamerElement *element;
2639  Int_t offset = 0;
2640 
2641  TObjArray &elems = *(sinfo->GetElements());
2642  Int_t size = elems.GetLast()+1;
2643  for(Int_t i=0; i<size; i++) {
2644  element = (TStreamerElement*)elems[i];
2645  if (element->IsBase()) {
2646  if (element->IsA() == TStreamerBase::Class()) {
2647  TStreamerBase *base = (TStreamerBase*)element;
2648  TClass *baseclass = base->GetClassPointer();
2649  if (!baseclass) return -1;
2650  Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2651  if (subOffset == -2) return -2;
2652  if (subOffset != -1) return offset+subOffset;
2653  offset += baseclass->Size();
2654  } else if (element->IsA() == TStreamerSTL::Class()) {
2655  TStreamerSTL *base = (TStreamerSTL*)element;
2656  TClass *baseclass = base->GetClassPointer();
2657  if (!baseclass) return -1;
2658  Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2659  if (subOffset == -2) return -2;
2660  if (subOffset != -1) return offset+subOffset;
2661  offset += baseclass->Size();
2662 
2663  } else {
2664  Error("GetBaseClassOffsetRecurse","Unexpected element type for base class: %s\n",element->IsA()->GetName());
2665  }
2666  }
2667  }
2668  return -1;
2669  }
2670  }
2671 
2672  TClass *c;
2673  Int_t off;
2674  TBaseClass *inh;
2675  TObjLink *lnk = 0;
2676  if (fBase==0) lnk = GetListOfBases()->FirstLink();
2677  else lnk = fBase.load()->FirstLink();
2678 
2679  // otherwise look at inheritance tree
2680  while (lnk) {
2681  inh = (TBaseClass *)lnk->GetObject();
2682  //use option load=kFALSE to avoid a warning like:
2683  //"Warning in <TClass::TClass>: no dictionary for class TRefCnt is available"
2684  //We can not afford to not have the class if it exist, so we
2685  //use kTRUE.
2686  c = inh->GetClassPointer(kTRUE); // kFALSE);
2687  if (c) {
2688  if (cl == c) {
2689  if ((inh->Property() & kIsVirtualBase) != 0)
2690  return -2;
2691  return inh->GetDelta();
2692  }
2693  off = c->GetBaseClassOffsetRecurse(cl);
2694  if (off == -2) return -2;
2695  if (off != -1) {
2696  return off + inh->GetDelta();
2697  }
2698  }
2699  lnk = lnk->Next();
2700  }
2701  return -1;
2702 }
2703 
2704 ////////////////////////////////////////////////////////////////////////////////
2705 /// - Return data member offset to the base class "cl".
2706 /// - Returns -1 in case "cl" is not a base class.
2707 /// Takes care of multiple inheritance.
2708 
2709 Int_t TClass::GetBaseClassOffset(const TClass *toBase, void *address, bool isDerivedObject)
2710 {
2711  // Warning("GetBaseClassOffset","Requires the use of fClassInfo for %s to %s",GetName(),toBase->GetName());
2712 
2713  if (this == toBase) return 0;
2714 
2715  if ((!address /* || !has_virtual_base */) &&
2717  // At least of the ClassInfo have not been loaded in memory yet and
2718  // since there is no virtual base class (or we don't have enough so it
2719  // would not make a difference) we can use the 'static' information
2720  Int_t offset = GetBaseClassOffsetRecurse (toBase);
2721  if (offset != -2) {
2722  return offset;
2723  }
2724  return offset;
2725  }
2726 
2727  ClassInfo_t* derived = GetClassInfo();
2728  ClassInfo_t* base = toBase->GetClassInfo();
2729  if(derived && base) {
2730  return gCling->ClassInfo_GetBaseOffset(derived, base, address, isDerivedObject);
2731  }
2732  else {
2733  Int_t offset = GetBaseClassOffsetRecurse (toBase);
2734  if (offset != -2) {
2735  return offset;
2736  }
2737  }
2738  return -1;
2739 }
2740 
2741 ////////////////////////////////////////////////////////////////////////////////
2742 /// Return pointer to (base) class that contains datamember.
2743 
2744 TClass *TClass::GetBaseDataMember(const char *datamember)
2745 {
2746  if (!HasDataMemberInfo()) return 0;
2747 
2748  // Check if data member exists in class itself
2749  TDataMember *dm = GetDataMember(datamember);
2750  if (dm) return this;
2751 
2752  // if datamember not found in class, search in next base classes
2753  TBaseClass *inh;
2754  TIter next(GetListOfBases());
2755  while ((inh = (TBaseClass *) next())) {
2756  TClass *c = inh->GetClassPointer();
2757  if (c) {
2758  TClass *cdm = c->GetBaseDataMember(datamember);
2759  if (cdm) return cdm;
2760  }
2761  }
2762 
2763  return 0;
2764 }
2765 
2766 namespace {
2767  // A local Helper class used to keep 2 pointer (the collection proxy
2768  // and the class streamer) in the thread local storage.
2769 
2770  struct TClassLocalStorage {
2771  TClassLocalStorage() : fCollectionProxy(0), fStreamer(0) {};
2772 
2775 
2776  static TClassLocalStorage *GetStorage(const TClass *cl)
2777  {
2778  // Return the thread storage for the TClass.
2779 
2780  void **thread_ptr = (*gThreadTsd)(0,ROOT::kClassThreadSlot);
2781  if (thread_ptr) {
2782  if (*thread_ptr==0) *thread_ptr = new TExMap();
2783  TExMap *lmap = (TExMap*)(*thread_ptr);
2784  ULong_t hash = TString::Hash(&cl, sizeof(void*));
2785  ULong_t local = 0;
2786  UInt_t slot;
2787  if ((local = (ULong_t)lmap->GetValue(hash, (Long_t)cl, slot)) != 0) {
2788  } else {
2789  local = (ULong_t) new TClassLocalStorage();
2790  lmap->AddAt(slot, hash, (Long_t)cl, local);
2791  }
2792  return (TClassLocalStorage*)local;
2793  }
2794  return 0;
2795  }
2796  };
2797 }
2798 
2799 ////////////////////////////////////////////////////////////////////////////////
2800 /// Return the 'type' of the STL the TClass is representing.
2801 /// and return ROOT::kNotSTL if it is not representing an STL collection.
2802 
2803 ROOT::ESTLType TClass::GetCollectionType() const
2804 {
2805  auto proxy = GetCollectionProxy();
2806  if (proxy) return (ROOT::ESTLType)proxy->GetCollectionType();
2807  return ROOT::kNotSTL;
2808 }
2809 
2810 
2811 ////////////////////////////////////////////////////////////////////////////////
2812 /// Return the proxy describing the collection (if any).
2813 
2815 {
2816  // Use assert, so that this line (slow because of the TClassEdit) is completely
2817  // removed in optimized code.
2818  assert(TestBit(kLoading) || !TClassEdit::IsSTLCont(fName) || fCollectionProxy || 0 == "The TClass for the STL collection has no collection proxy!");
2819  if (gThreadTsd && fCollectionProxy) {
2820  TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2821  if (local == 0) return fCollectionProxy;
2822  if (local->fCollectionProxy==0) local->fCollectionProxy = fCollectionProxy->Generate();
2823  return local->fCollectionProxy;
2824  }
2825  return fCollectionProxy;
2826 }
2827 
2828 ////////////////////////////////////////////////////////////////////////////////
2829 /// Return the Streamer Class allowing streaming (if any).
2830 
2832 {
2833  if (gThreadTsd && fStreamer) {
2834  TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2835  if (local==0) return fStreamer;
2836  if (local->fStreamer==0) {
2837  local->fStreamer = fStreamer->Generate();
2838  const std::type_info &orig = ( typeid(*fStreamer) );
2839  if (!local->fStreamer) {
2840  Warning("GetStreamer","For %s, the TClassStreamer (%s) passed's call to Generate failed!",GetName(),orig.name());
2841  } else {
2842  const std::type_info &copy = ( typeid(*local->fStreamer) );
2843  if (strcmp(orig.name(),copy.name())!=0) {
2844  Warning("GetStreamer","For %s, the TClassStreamer passed does not properly implement the Generate method (%s vs %s)\n",GetName(),orig.name(),copy.name());
2845  }
2846  }
2847  }
2848  return local->fStreamer;
2849  }
2850  return fStreamer;
2851 }
2852 
2853 ////////////////////////////////////////////////////////////////////////////////
2854 /// Get a wrapper/accessor function around this class custom streamer (member function).
2855 
2857 {
2858  return fStreamerFunc;
2859 }
2860 
2861 ////////////////////////////////////////////////////////////////////////////////
2862 /// Get a wrapper/accessor function around this class custom conversion streamer (member function).
2863 
2865 {
2866  return fConvStreamerFunc;
2867 }
2868 
2869 ////////////////////////////////////////////////////////////////////////////////
2870 /// Return the proxy implementing the IsA functionality.
2871 
2873 {
2874  return fIsA;
2875 }
2876 
2877 ////////////////////////////////////////////////////////////////////////////////
2878 /// Static method returning pointer to TClass of the specified class name.
2879 /// If load is true an attempt is made to obtain the class by loading
2880 /// the appropriate shared library (directed by the rootmap file).
2881 /// If silent is 'true', do not warn about missing dictionary for the class.
2882 /// (typically used for class that are used only for transient members)
2883 /// Returns 0 in case class is not found.
2884 
2885 TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent)
2886 {
2887  if (!name || !name[0]) return 0;
2888 
2889  if (strstr(name, "(anonymous)")) return 0;
2890  if (strncmp(name,"class ",6)==0) name += 6;
2891  if (strncmp(name,"struct ",7)==0) name += 7;
2892 
2893  R__LOCKGUARD(gInterpreterMutex);
2894 
2895  if (!gROOT->GetListOfClasses()) return 0;
2896 
2897  TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2898 
2899  // Early return to release the lock without having to execute the
2900  // long-ish normalization.
2901  if (cl) {
2902  if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
2903 
2904  // We could speed-up some of the search by adding (the equivalent of)
2905  //
2906  // if (cl->GetState() == kInterpreter) return cl
2907  //
2908  // In this case, if a ROOT dictionary was available when the TClass
2909  // was first request it would have been used and if a ROOT dictionary is
2910  // loaded later on TClassTable::Add will take care of updating the TClass.
2911  // So as far as ROOT dictionary are concerned, if the current TClass is
2912  // in interpreted state, we are sure there is nothing to load.
2913  //
2914  // However (see TROOT::LoadClass), the TClass can also be loaded/provided
2915  // by a user provided TClassGenerator. We have no way of knowing whether
2916  // those do (or even can) behave the same way as the ROOT dictionary and
2917  // have the 'dictionary is now available for use' step informa the existing
2918  // TClass that their dictionary is now available.
2919 
2920  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
2921  load = kTRUE;
2922  }
2923 
2924  // To avoid spurious auto parsing, let's check if the name as-is is
2925  // known in the TClassTable.
2927  if (dict) {
2928  // The name is normalized, so the result of the first search is
2929  // authoritative.
2930  if (!cl && !load) return 0;
2931 
2932  TClass *loadedcl = (dict)();
2933  if (loadedcl) {
2934  loadedcl->PostLoadCheck();
2935  return loadedcl;
2936  }
2937 
2938  // We should really not fall through to here, but if we do, let's just
2939  // continue as before ...
2940  }
2941 
2942  std::string normalizedName;
2943  Bool_t checkTable = kFALSE;
2944 
2945  if (!cl) {
2946  int oldAutoloadVal = gCling->SetClassAutoloading(false);
2947  TClassEdit::GetNormalizedName(normalizedName, name);
2948  gCling->SetClassAutoloading(oldAutoloadVal);
2949  // Try the normalized name.
2950  if (normalizedName != name) {
2951  cl = (TClass*)gROOT->GetListOfClasses()->FindObject(normalizedName.c_str());
2952 
2953  if (cl) {
2954  if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
2955 
2956  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
2957  load = kTRUE;
2958  }
2959  checkTable = kTRUE;
2960  }
2961  } else {
2962  normalizedName = cl->GetName(); // Use the fact that all TClass names are normalized.
2963  checkTable = load && (normalizedName != name);
2964  }
2965 
2966  if (!load) return 0;
2967 
2968 // This assertion currently fails because of
2969 // TClass *c1 = TClass::GetClass("basic_iostream<char,char_traits<char> >");
2970 // TClass *c2 = TClass::GetClass("std::iostream");
2971 // where the TClassEdit normalized name of iostream is basic_iostream<char>
2972 // i.e missing the addition of the default parameter. This is because TClingLookupHelper
2973 // uses only 'part' of TMetaUtils::GetNormalizedName.
2974 
2975 // if (!cl) {
2976 // TDataType* dataType = (TDataType*)gROOT->GetListOfTypes()->FindObject(name);
2977 // TClass *altcl = dataType ? (TClass*)gROOT->GetListOfClasses()->FindObject(dataType->GetFullTypeName()) : 0;
2978 // if (altcl && normalizedName != altcl->GetName())
2979 // ::Fatal("TClass::GetClass","The existing name (%s) for %s is different from the normalized name: %s\n",
2980 // altcl->GetName(), name, normalizedName.c_str());
2981 // }
2982 
2983  TClass *loadedcl = 0;
2984  if (checkTable) {
2985  loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
2986  } else {
2987  if (gInterpreter->AutoLoad(normalizedName.c_str(),kTRUE)) {
2988  loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
2989  }
2990  // Maybe this was a typedef: let's try to see if this is the case
2991  if (!loadedcl){
2992  if (TDataType* theDataType = gROOT->GetType(normalizedName.c_str())){
2993  // We have a typedef: we get the name of the underlying type
2994  auto underlyingTypeName = theDataType->GetTypeName();
2995  // We see if we can bootstrap a class with it
2996  auto underlyingTypeDict = TClassTable::GetDictNorm(underlyingTypeName.Data());
2997  if (underlyingTypeDict){
2998  loadedcl = underlyingTypeDict();
2999  }
3000 
3001  }
3002  }
3003  }
3004  if (loadedcl) return loadedcl;
3005 
3006  // See if the TClassGenerator can produce the TClass we need.
3007  loadedcl = LoadClassCustom(normalizedName.c_str(),silent);
3008  if (loadedcl) return loadedcl;
3009 
3010  // We have not been able to find a loaded TClass, return the Emulated
3011  // TClass if we have one.
3012  if (cl) return cl;
3013 
3014  if (TClassEdit::IsSTLCont( normalizedName.c_str() )) {
3015 
3016  return gInterpreter->GenerateTClass(normalizedName.c_str(), kTRUE, silent);
3017  }
3018 
3019  // Check the interpreter only after autoparsing the template if any.
3020  {
3021  std::string::size_type posLess = normalizedName.find('<');
3022  if (posLess != std::string::npos) {
3023  gCling->AutoParse(normalizedName.substr(0, posLess).c_str());
3024  }
3025  }
3026 
3027  //last attempt. Look in CINT list of all (compiled+interpreted) classes
3028  if (gDebug>0){
3029  printf("TClass::GetClass: Header Parsing - The representation of %s was not found in the type system. A lookup in the interpreter is about to be tried: this can cause parsing. This can be avoided selecting %s in the linkdef/selection file.\n",normalizedName.c_str(), normalizedName.c_str());
3030  }
3031  if (normalizedName.length() &&
3032  gInterpreter->CheckClassInfo(normalizedName.c_str(), kTRUE /* autoload */, kTRUE /*Only class, structs and ns*/)) {
3033  // Get the normalized name based on the decl (currently the only way
3034  // to get the part to add or drop the default arguments as requested by the user)
3035  std::string alternative;
3036  gInterpreter->GetInterpreterTypeName(normalizedName.c_str(),alternative,kTRUE);
3037  const char *altname = alternative.c_str();
3038  if ( strncmp(altname,"std::",5)==0 ) {
3039  // For namespace (for example std::__1), GetInterpreterTypeName does
3040  // not strip std::, so we must do it explicitly here.
3041  altname += 5;
3042  }
3043  if (altname != normalizedName && strcmp(altname,name) != 0) {
3044  // altname now contains the full name of the class including a possible
3045  // namespace if there has been a using namespace statement.
3046 
3047  // At least in the case C<string [2]> (normalized) vs C<string[2]> (altname)
3048  // the TClassEdit normalization and the TMetaUtils normalization leads to
3049  // two different space layout. To avoid an infinite recursion, we also
3050  // add the test on (altname != name)
3051 
3052  return GetClass(altname,load);
3053  }
3054  TClass *ncl = gInterpreter->GenerateTClass(normalizedName.c_str(), /* emulation = */ kFALSE, silent);
3055  if (!ncl->IsZombie()) {
3056  return ncl;
3057  }
3058  delete ncl;
3059  }
3060  return 0;
3061 }
3062 
3063 ////////////////////////////////////////////////////////////////////////////////
3064 /// Return pointer to class with name.
3065 
3066 TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */)
3067 {
3068  //protect access to TROOT::GetListOfClasses
3069  R__LOCKGUARD2(gInterpreterMutex);
3070 
3071  if (!gROOT->GetListOfClasses()) return 0;
3072 
3073  TClass* cl = GetIdMap()->Find(typeinfo.name());
3074 
3075  if (cl) {
3076  if (cl->IsLoaded()) return cl;
3077  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3078  load = kTRUE;
3079  } else {
3080  // Note we might need support for typedefs and simple types!
3081 
3082  // TDataType *objType = GetType(name, load);
3083  //if (objType) {
3084  // const char *typdfName = objType->GetTypeName();
3085  // if (typdfName && strcmp(typdfName, name)) {
3086  // cl = GetClass(typdfName, load);
3087  // return cl;
3088  // }
3089  // }
3090  }
3091 
3092  if (!load) return 0;
3093 
3094  DictFuncPtr_t dict = TClassTable::GetDict(typeinfo);
3095  if (dict) {
3096  cl = (dict)();
3097  if (cl) cl->PostLoadCheck();
3098  return cl;
3099  }
3100  if (cl) return cl;
3101 
3102  TIter next(gROOT->GetListOfClassGenerators());
3103  TClassGenerator *gen;
3104  while( (gen = (TClassGenerator*) next()) ) {
3105  cl = gen->GetClass(typeinfo,load);
3106  if (cl) {
3107  cl->PostLoadCheck();
3108  return cl;
3109  }
3110  }
3111 
3112  // try autoloading the typeinfo
3113  int autoload_old = gCling->SetClassAutoloading(1);
3114  if (!autoload_old) {
3115  // Re-disable, we just meant to test
3117  }
3118  if (autoload_old && gInterpreter->AutoLoad(typeinfo,kTRUE)) {
3119  // Disable autoload to avoid potential infinite recursion
3121  cl = GetClass(typeinfo, load);
3123  if (cl) {
3124  return cl;
3125  }
3126  }
3127 
3128  // last attempt. Look in the interpreter list of all (compiled+interpreted)
3129  // classes
3130  cl = gInterpreter->GetClass(typeinfo, load);
3131 
3132  return cl; // Can be zero.
3133 }
3134 
3135 ////////////////////////////////////////////////////////////////////////////////
3136 /// Static method returning pointer to TClass of the specified ClassInfo.
3137 /// If load is true an attempt is made to obtain the class by loading
3138 /// the appropriate shared library (directed by the rootmap file).
3139 /// If silent is 'true', do not warn about missing dictionary for the class.
3140 /// (typically used for class that are used only for transient members)
3141 /// Returns 0 in case class is not found.
3142 
3143 TClass *TClass::GetClass(ClassInfo_t *info, Bool_t load, Bool_t silent)
3144 {
3145  if (!info || !gCling->ClassInfo_IsValid(info)) return 0;
3146  if (!gROOT->GetListOfClasses()) return 0;
3147 
3148  // Get the normalized name.
3149  TString name( gCling->ClassInfo_FullName(info) );
3150 
3151  TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
3152 
3153  if (cl) {
3154  if (cl->IsLoaded()) return cl;
3155 
3156  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3157  load = kTRUE;
3158 
3159  }
3160 
3161  if (!load) return 0;
3162 
3163  TClass *loadedcl = 0;
3164  if (cl) loadedcl = gROOT->LoadClass(cl->GetName(),silent);
3165  else loadedcl = gROOT->LoadClass(name,silent);
3166 
3167  if (loadedcl) return loadedcl;
3168 
3169  if (cl) return cl; // If we found the class but we already have a dummy class use it.
3170 
3171  // We did not find a proper TClass but we do know (we have a valid
3172  // ClassInfo) that the class is known to the interpreter.
3173  TClass *ncl = gInterpreter->GenerateTClass(info, silent);
3174  if (!ncl->IsZombie()) {
3175  return ncl;
3176  } else {
3177  delete ncl;
3178  return 0;
3179  }
3180 }
3181 
3182 ////////////////////////////////////////////////////////////////////////////////
3183 
3186 }
3187 
3188 ////////////////////////////////////////////////////////////////////////////////
3189 
3190 Bool_t TClass::GetClass(DeclId_t id, std::vector<TClass*> &classes)
3191 {
3192  if (!gROOT->GetListOfClasses()) return 0;
3193 
3194  DeclIdMap_t* map = GetDeclIdMap();
3195  // Get all the TClass pointer that have the same DeclId.
3196  DeclIdMap_t::equal_range iter = map->Find(id);
3197  if (iter.first == iter.second) return false;
3198  std::vector<TClass*>::iterator vectIt = classes.begin();
3199  for (DeclIdMap_t::const_iterator it = iter.first; it != iter.second; ++it)
3200  vectIt = classes.insert(vectIt, it->second);
3201  return true;
3202 }
3203 
3204 ////////////////////////////////////////////////////////////////////////////////
3205 /// Return a pointer to the dictionary loading function generated by
3206 /// rootcint
3207 
3208 DictFuncPtr_t TClass::GetDict (const char *cname)
3209 {
3210  return TClassTable::GetDict(cname);
3211 }
3212 
3213 ////////////////////////////////////////////////////////////////////////////////
3214 /// Return a pointer to the dictionary loading function generated by
3215 /// rootcint
3216 
3217 DictFuncPtr_t TClass::GetDict (const std::type_info& info)
3218 {
3219  return TClassTable::GetDict(info);
3220 }
3221 
3222 ////////////////////////////////////////////////////////////////////////////////
3223 /// Return pointer to datamember object with name "datamember".
3224 
3225 TDataMember *TClass::GetDataMember(const char *datamember) const
3226 {
3227  if ((!(fData && fData->IsLoaded()) && !HasInterpreterInfo())
3228  || datamember == 0) return 0;
3229 
3230  // Strip off leading *'s and trailing [
3231  const char *start_name = datamember;
3232  while (*start_name == '*') ++start_name;
3233 
3234  // Empty name are 'legal', they represent anonymous unions.
3235  // if (*start_name == 0) return 0;
3236 
3237  if (const char *s = strchr(start_name, '[')){
3238  UInt_t len = s-start_name;
3239  TString name(start_name,len);
3240  return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(name.Data());
3241  } else {
3242  return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(start_name);
3243  }
3244 }
3245 
3246 ////////////////////////////////////////////////////////////////////////////////
3247 /// return offset for member name. name can be a data member in
3248 /// the class itself, one of its base classes, or one member in
3249 /// one of the aggregated classes.
3250 ///
3251 /// In case of an emulated class, the list of emulated TRealData is built
3252 
3254 {
3255  TRealData *rd = GetRealData(name);
3256  if (rd) return rd->GetThisOffset();
3257  if (strchr(name,'[')==0) {
3258  // If this is a simple name there is a chance to find it in the
3259  // StreamerInfo even if we did not find it in the RealData.
3260  // For example an array name would be fArray[3] in RealData but
3261  // just fArray in the streamerInfo.
3262  TVirtualStreamerInfo *info = const_cast<TClass*>(this)->GetCurrentStreamerInfo();
3263  if (info) {
3264  return info->GetOffset(name);
3265  }
3266  }
3267  return 0;
3268 }
3269 
3270 ////////////////////////////////////////////////////////////////////////////////
3271 /// Return pointer to TRealData element with name "name".
3272 ///
3273 /// Name can be a data member in the class itself,
3274 /// one of its base classes, or a member in
3275 /// one of the aggregated classes.
3276 ///
3277 /// In case of an emulated class, the list of emulated TRealData is built.
3278 
3280 {
3281  if (!fRealData) {
3282  const_cast<TClass*>(this)->BuildRealData();
3283  }
3284 
3285  if (!fRealData) {
3286  return 0;
3287  }
3288 
3289  if (!name) {
3290  return 0;
3291  }
3292 
3293  // First try just the whole name.
3294  TRealData* rd = (TRealData*) fRealData->FindObject(name);
3295  if (rd) {
3296  return rd;
3297  }
3298 
3299  std::string givenName(name);
3300 
3301  // Try ignoring the array dimensions.
3302  std::string::size_type firstBracket = givenName.find_first_of("[");
3303  if (firstBracket != std::string::npos) {
3304  // -- We are looking for an array data member.
3305  std::string nameNoDim(givenName.substr(0, firstBracket));
3306  TObjLink* lnk = fRealData->FirstLink();
3307  while (lnk) {
3308  TObject* obj = lnk->GetObject();
3309  std::string objName(obj->GetName());
3310  std::string::size_type pos = objName.find_first_of("[");
3311  // Only match arrays to arrays for now.
3312  if (pos != std::string::npos) {
3313  objName.erase(pos);
3314  if (objName == nameNoDim) {
3315  return static_cast<TRealData*>(obj);
3316  }
3317  }
3318  lnk = lnk->Next();
3319  }
3320  }
3321 
3322  // Now try it as a pointer.
3323  std::ostringstream ptrname;
3324  ptrname << "*" << givenName;
3325  rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3326  if (rd) {
3327  return rd;
3328  }
3329 
3330  // Check for a dot in the name.
3331  std::string::size_type firstDot = givenName.find_first_of(".");
3332  if (firstDot == std::string::npos) {
3333  // -- Not found, a simple name, all done.
3334  return 0;
3335  }
3336 
3337  //
3338  // At this point the name has a dot in it, so it is the name
3339  // of some contained sub-object.
3340  //
3341 
3342  // May be a pointer like in TH1: fXaxis.fLabels (in TRealdata is named fXaxis.*fLabels)
3343  std::string::size_type lastDot = givenName.find_last_of(".");
3344  std::ostringstream starname;
3345  starname << givenName.substr(0, lastDot) << ".*" << givenName.substr(lastDot + 1);
3346  rd = (TRealData*) fRealData->FindObject(starname.str().c_str());
3347  if (rd) {
3348  return rd;
3349  }
3350 
3351  // Strip the first component, it may be the name of
3352  // the branch (old TBranchElement code), and try again.
3353  std::string firstDotName(givenName.substr(firstDot + 1));
3354 
3355  // New attempt starting after the first "." if any,
3356  // this allows for the case that the first component
3357  // may have been a branch name (for TBranchElement).
3358  rd = (TRealData*) fRealData->FindObject(firstDotName.c_str());
3359  if (rd) {
3360  return rd;
3361  }
3362 
3363  // New attempt starting after the first "." if any,
3364  // but this time try ignoring the array dimensions.
3365  // Again, we are allowing for the case that the first
3366  // component may have been a branch name (for TBranchElement).
3367  std::string::size_type firstDotBracket = firstDotName.find_first_of("[");
3368  if (firstDotBracket != std::string::npos) {
3369  // -- We are looking for an array data member.
3370  std::string nameNoDim(firstDotName.substr(0, firstDotBracket));
3371  TObjLink* lnk = fRealData->FirstLink();
3372  while (lnk) {
3373  TObject* obj = lnk->GetObject();
3374  std::string objName(obj->GetName());
3375  std::string::size_type pos = objName.find_first_of("[");
3376  // Only match arrays to arrays for now.
3377  if (pos != std::string::npos) {
3378  objName.erase(pos);
3379  if (objName == nameNoDim) {
3380  return static_cast<TRealData*>(obj);
3381  }
3382  }
3383  lnk = lnk->Next();
3384  }
3385  }
3386 
3387  // New attempt starting after the first "." if any,
3388  // but this time check for a pointer type. Again, we
3389  // are allowing for the case that the first component
3390  // may have been a branch name (for TBranchElement).
3391  ptrname.str("");
3392  ptrname << "*" << firstDotName;
3393  rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3394  if (rd) {
3395  return rd;
3396  }
3397 
3398  // Last attempt in case a member has been changed from
3399  // a static array to a pointer, for example the member
3400  // was arr[20] and is now *arr.
3401  //
3402  // Note: In principle, one could also take into account
3403  // the opposite situation where a member like *arr has
3404  // been converted to arr[20].
3405  //
3406  // FIXME: What about checking after the first dot as well?
3407  //
3408  std::string::size_type bracket = starname.str().find_first_of("[");
3409  if (bracket == std::string::npos) {
3410  return 0;
3411  }
3412  rd = (TRealData*) fRealData->FindObject(starname.str().substr(0, bracket).c_str());
3413  if (rd) {
3414  return rd;
3415  }
3416 
3417  // Not found;
3418  return 0;
3419 }
3420 
3421 ////////////////////////////////////////////////////////////////////////////////
3422 
3424 {
3425  if (!gInterpreter || !HasInterpreterInfo()) return 0;
3426 
3427  // The following
3429 
3430  return (TFunctionTemplate*)fFuncTemplate->FindObject(name);
3431 }
3432 
3433 ////////////////////////////////////////////////////////////////////////////////
3434 /// Get the list of shared libraries containing the code for class cls.
3435 /// The first library in the list is the one containing the class, the
3436 /// others are the libraries the first one depends on. Returns 0
3437 /// in case the library is not found.
3438 
3440 {
3441  if (!gInterpreter) return 0;
3442 
3443  if (fSharedLibs.IsNull())
3444  fSharedLibs = gInterpreter->GetClassSharedLibs(fName);
3445 
3446  return !fSharedLibs.IsNull() ? fSharedLibs.Data() : 0;
3447 }
3448 
3449 ////////////////////////////////////////////////////////////////////////////////
3450 /// Return list containing the TBaseClass(es) of a class.
3451 
3453 {
3454  if (!fBase) {
3455  if (fCanLoadClassInfo) {
3456  if (fState == kHasTClassInit) {
3457 
3458  R__LOCKGUARD(gInterpreterMutex);
3459  // NOTE: Add test to prevent redo if another thread has already done the work.
3460  // if (!fHasRootPcmInfo) {
3461 
3462  // The bases are in our ProtoClass; we don't need the class info.
3464  if (proto && proto->FillTClass(this)) {
3465  // Not sure this code is still needed
3466  // R__ASSERT(kFALSE);
3467 
3469  }
3470  }
3471  // We test again on fCanLoadClassInfo has another thread may have executed it.
3473  LoadClassInfo();
3474  }
3475  }
3476  if (!fClassInfo) return 0;
3477 
3478  if (!gInterpreter)
3479  Fatal("GetListOfBases", "gInterpreter not initialized");
3480 
3481  R__LOCKGUARD(gInterpreterMutex);
3482  if(!fBase) {
3483  gInterpreter->CreateListOfBaseClasses(this);
3484  }
3485  }
3486  return fBase;
3487 }
3488 
3489 ////////////////////////////////////////////////////////////////////////////////
3490 /// Return a list containing the TEnums of a class.
3491 ///
3492 /// The list returned is safe to use from multiple thread without explicitly
3493 /// taking the ROOT global lock.
3494 ///
3495 /// In the case the TClass represents a namespace, the returned list will
3496 /// implicit take the ROOT global lock upon any access (see TListOfEnumsWithLock)
3497 ///
3498 /// In the case the TClass represents a class or struct and requestListLoading
3499 /// is true, the list is immutable (and thus safe to access from multiple thread
3500 /// without taking the global lock at all).
3501 ///
3502 /// In the case the TClass represents a class or struct and requestListLoading
3503 /// is false, the list is mutable and thus we return a TListOfEnumsWithLock
3504 /// which will implicit take the ROOT global lock upon any access.
3505 
3506 TList *TClass::GetListOfEnums(Bool_t requestListLoading /* = kTRUE */)
3507 {
3508  auto temp = fEnums.load();
3509  if (temp) {
3510  if (requestListLoading) {
3511  if (fProperty == -1) Property();
3512  if (! ((kIsClass | kIsStruct | kIsUnion) & fProperty) ) {
3514  temp->Load();
3515  } else if ( temp->IsA() == TListOfEnumsWithLock::Class() ) {
3516  // We have a class for which the list was not loaded fully at
3517  // first use.
3519  temp->Load();
3520  }
3521  }
3522  return temp;
3523  }
3524 
3525  if (!requestListLoading) {
3526  if (fProperty == -1) Property();
3527  R__LOCKGUARD(gInterpreterMutex);
3528  if (fEnums.load()) {
3529  return fEnums.load();
3530  }
3531 
3532  static bool fromRootCling = dlsym(RTLD_DEFAULT, "usedToIdentifyRootClingByDlSym");
3533 
3534  if (fromRootCling) // rootcling is single thread (this save some space in the rootpcm).
3535  fEnums = new TListOfEnums(this);
3536  else
3537  fEnums = new TListOfEnumsWithLock(this);
3538  return fEnums;
3539  }
3540 
3541  R__LOCKGUARD(gInterpreterMutex);
3542  if (fEnums.load()) {
3543  (*fEnums).Load();
3544  return fEnums.load();
3545  }
3546  if (fProperty == -1) Property();
3547  if ( (kIsClass | kIsStruct | kIsUnion) & fProperty) {
3548  // For this case, the list will be immutable
3549  temp = new TListOfEnums(this);
3550  } else {
3551  //namespaces can have enums added to them
3552  temp = new TListOfEnumsWithLock(this);
3553  }
3554  temp->Load();
3555  fEnums = temp;
3556  return temp;
3557 }
3558 
3559 ////////////////////////////////////////////////////////////////////////////////
3560 /// Return list containing the TDataMembers of a class.
3561 
3563 {
3564  R__LOCKGUARD(gInterpreterMutex);
3565 
3566  if (!fData) {
3568  // NOTE: Add test to prevent redo if another thread has already done the work.
3569  // if (!fHasRootPcmInfo) {
3570 
3571  // The members are in our ProtoClass; we don't need the class info.
3573  if (proto && proto->FillTClass(this)) {
3574  // Not sure this code is still needed
3575  // R__ASSERT(kFALSE);
3576 
3578  return fData;
3579  }
3580  }
3581  fData = new TListOfDataMembers(this);
3582  }
3583  if (Property() & (kIsClass|kIsStruct|kIsUnion)) {
3584  // If the we have a class or struct or union, the order
3585  // of data members is the list is essential since it determines their
3586  // order on file. So we must always load. Also, the list is fixed
3587  // since the language does not allow to add members.
3588  if (!fData->IsLoaded()) fData->Load();
3589 
3590  } else if (load) fData->Load();
3591  return fData;
3592 }
3593 
3594 ////////////////////////////////////////////////////////////////////////////////
3595 /// Return list containing the TEnums of a class.
3596 
3598 {
3599  R__LOCKGUARD(gInterpreterMutex);
3600 
3602  if (load) fFuncTemplate->Load();
3603  return fFuncTemplate;
3604 }
3605 
3606 ////////////////////////////////////////////////////////////////////////////////
3607 /// Return list containing the TMethods of a class.
3608 /// If load is true, the list is populated with all the defined function
3609 /// and currently instantiated function template.
3610 
3612 {
3613  R__LOCKGUARD(gInterpreterMutex);
3614 
3615  if (!fMethod.load()) GetMethodList();
3616  if (load) {
3617  if (gDebug>0) Info("GetListOfMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3618  (*fMethod).Load();
3619  }
3620  return fMethod;
3621 }
3622 
3623 ////////////////////////////////////////////////////////////////////////////////
3624 /// Return the collection of functions named "name".
3625 
3627 {
3628  return const_cast<TClass*>(this)->GetMethodList()->GetListForObject(name);
3629 }
3630 
3631 
3632 ////////////////////////////////////////////////////////////////////////////////
3633 /// Returns a list of all public methods of this class and its base classes.
3634 /// Refers to a subset of the methods in GetListOfMethods() so don't do
3635 /// GetListOfAllPublicMethods()->Delete().
3636 /// Algorithm used to get the list is:
3637 /// - put all methods of the class in the list (also protected and private
3638 /// ones).
3639 /// - loop over all base classes and add only those methods not already in the
3640 /// list (also protected and private ones).
3641 /// - once finished, loop over resulting list and remove all private and
3642 /// protected methods.
3643 
3645 {
3646  R__LOCKGUARD(gInterpreterMutex);
3647 
3648  if (!fAllPubMethod) fAllPubMethod = new TViewPubFunctions(this);
3649  if (load) {
3650  if (gDebug>0) Info("GetListOfAllPublicMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3651  fAllPubMethod->Load();
3652  }
3653  return fAllPubMethod;
3654 }
3655 
3656 ////////////////////////////////////////////////////////////////////////////////
3657 /// Returns a list of all public data members of this class and its base
3658 /// classes. Refers to a subset of the data members in GetListOfDatamembers()
3659 /// so don't do GetListOfAllPublicDataMembers()->Delete().
3660 
3662 {
3663  R__LOCKGUARD(gInterpreterMutex);
3664 
3665  if (!fAllPubData) fAllPubData = new TViewPubDataMembers(this);
3666  if (load) fAllPubData->Load();
3667  return fAllPubData;
3668 }
3669 
3670 ////////////////////////////////////////////////////////////////////////////////
3671 /// Returns list of methods accessible by context menu.
3672 
3674 {
3675  if (!HasInterpreterInfo()) return;
3676 
3677  // get the base class
3678  TIter nextBase(GetListOfBases(), kIterBackward);
3679  TBaseClass *baseClass;
3680  while ((baseClass = (TBaseClass *) nextBase())) {
3681  TClass *base = baseClass->GetClassPointer();
3682  if (base) base->GetMenuItems(list);
3683  }
3684 
3685  // remove methods redefined in this class with no menu
3686  TMethod *method, *m;
3688  while ((method = (TMethod*)next())) {
3689  m = (TMethod*)list->FindObject(method->GetName());
3690  if (method->IsMenuItem() != kMenuNoMenu) {
3691  if (!m)
3692  list->AddFirst(method);
3693  } else {
3694  if (m && m->GetNargs() == method->GetNargs())
3695  list->Remove(m);
3696  }
3697  }
3698 }
3699 
3700 ////////////////////////////////////////////////////////////////////////////////
3701 /// Check whether a class has a dictionary or not.
3702 /// This is equivalent to ask if a class is coming from a bootstrapping
3703 /// procedure initiated during the loading of a library.
3704 
3706 {
3707  return IsLoaded();
3708 }
3709 
3710 ////////////////////////////////////////////////////////////////////////////////
3711 /// Check whether a class has a dictionary or ROOT can load one.
3712 /// This is equivalent to ask HasDictionary() or whether a library is known
3713 /// where it can be loaded from, or whether a Dictionary function is
3714 /// available because the class's dictionary library was already loaded.
3715 
3717 {
3718  if (TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject(clname))
3719  return cl->IsLoaded();
3720  return gClassTable->GetDict(clname) || gInterpreter->GetClassSharedLibs(clname);
3721 }
3722 
3723 ////////////////////////////////////////////////////////////////////////////////
3724 /// Verify the base classes always.
3725 
3727 {
3728  TList* lb = GetListOfBases();
3729  if (!lb) return;
3730  TIter nextBase(lb);
3731  TBaseClass* base = 0;
3732  while ((base = (TBaseClass*)nextBase())) {
3733  TClass* baseCl = base->GetClassPointer();
3734  if (baseCl) {
3735  baseCl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3736  }
3737  }
3738 }
3739 
3740 ////////////////////////////////////////////////////////////////////////////////
3741 /// Verify the Data Members.
3742 
3744 {
3746  if (!ldm) return ;
3747  TIter nextMemb(ldm);
3748  TDataMember * dm = 0;
3749  while ((dm = (TDataMember*)nextMemb())) {
3750  // If it is a transient
3751  if(!dm->IsPersistent()) {
3752  continue;
3753  }
3754  if (dm->Property() & kIsStatic) {
3755  continue;
3756  }
3757  // If it is a built-in data type.
3758  TClass* dmTClass = 0;
3759  if (dm->GetDataType()) {
3760  // We have a basic datatype.
3761  dmTClass = nullptr;
3762  // Otherwise get the string representing the type.
3763  } else if (dm->GetTypeName()) {
3764  dmTClass = TClass::GetClass(dm->GetTypeName());
3765  }
3766  if (dmTClass) {
3767  dmTClass->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3768  }
3769  }
3770 }
3771 
3773 {
3774  // Pair is a special case and we have to check its elements for missing dictionaries
3775  // Pair is a transparent container so we should always look at its.
3776 
3778  for (int i = 0; i < 2; i++) {
3779  TClass* pairElement = ((TStreamerElement*)SI->GetElements()->At(i))->GetClass();
3780  if (pairElement) {
3781  pairElement->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3782  }
3783  }
3784 }
3785 
3786 ////////////////////////////////////////////////////////////////////////////////
3787 /// From the second level of recursion onwards it is different state check.
3788 
3790 {
3791  if (result.FindObject(this) || visited.FindObject(this)) return;
3792 
3793  static TClassRef sCIString("string");
3794  if (this == sCIString) return;
3795 
3796  // Special treatment for pair.
3797  if (strncmp(fName, "pair<", 5) == 0) {
3798  GetMissingDictionariesForPairElements(result, visited, recurse);
3799  return;
3800  }
3801 
3802  if (!HasDictionary()) {
3803  result.Add(this);
3804  }
3805 
3806  visited.Add(this);
3807  //Check whether a custom streamer
3809  if (GetCollectionProxy()) {
3810  // We need to look at the collection's content
3811  // The collection has different kind of elements the check would be required.
3812  TClass* t = 0;
3813  if ((t = GetCollectionProxy()->GetValueClass())) {
3814  if (!t->HasDictionary()) {
3815  t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3816  }
3817  }
3818  } else {
3819  if (recurse) {
3820  GetMissingDictionariesForMembers(result, visited, recurse);
3821  }
3822  GetMissingDictionariesForBaseClasses(result, visited, recurse);
3823  }
3824  }
3825 }
3826 
3827 ////////////////////////////////////////////////////////////////////////////////
3828 /// Get the classes that have a missing dictionary starting from this one.
3829 /// - With recurse = false the classes checked for missing dictionaries are:
3830 /// the class itself, all base classes, direct data members,
3831 /// and for collection proxies the container's
3832 /// elements without iterating over the element's data members;
3833 /// - With recurse = true the classes checked for missing dictionaries are:
3834 /// the class itself, all base classes, recursing on the data members,
3835 /// and for the collection proxies recursion on the elements of the
3836 /// collection and iterating over the element's data members.
3837 
3839 {
3840  // Top level recursion it different from the following levels of recursion.
3841 
3842  if (result.FindObject(this)) return;
3843 
3844  static TClassRef sCIString("string");
3845  if (this == sCIString) return;
3846 
3847  THashTable visited;
3848 
3849  if (strncmp(fName, "pair<", 5) == 0) {
3850  GetMissingDictionariesForPairElements(result, visited, recurse);
3851  return;
3852  }
3853 
3854  if (!HasDictionary()) {
3855  result.Add(this);
3856  }
3857 
3858  visited.Add(this);
3859 
3860  //Check whether a custom streamer
3862  if (GetCollectionProxy()) {
3863  // We need to look at the collection's content
3864  // The collection has different kind of elements the check would be required.
3865  TClass* t = 0;
3866  if ((t = GetCollectionProxy()->GetValueClass())) {
3867  if (!t->HasDictionary()) {
3868  t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3869  }
3870  }
3871  } else {
3872  GetMissingDictionariesForMembers(result, visited, recurse);
3873  GetMissingDictionariesForBaseClasses(result, visited, recurse);
3874  }
3875  }
3876 }
3877 
3878 ////////////////////////////////////////////////////////////////////////////////
3879 /// Return kTRUE if the class has elements.
3880 
3881 Bool_t TClass::IsFolder(void *obj) const
3882 {
3883  return Browse(obj,(TBrowser*)0);
3884 }
3885 
3886 //______________________________________________________________________________
3887 //______________________________________________________________________________
3888 void TClass::ReplaceWith(TClass *newcl) const
3889 {
3890  // Inform the other objects to replace this object by the new TClass (newcl)
3891 
3892  R__LOCKGUARD(gInterpreterMutex);
3893  //we must update the class pointers pointing to 'this' in all TStreamerElements
3894  TIter nextClass(gROOT->GetListOfClasses());
3895  TClass *acl;
3896  TVirtualStreamerInfo *info;
3897  TList tobedeleted;
3898 
3899  // Since we are in the process of replacing a TClass by a TClass
3900  // coming from a dictionary, there is no point in loading any
3901  // libraries during this search.
3902  Bool_t autoload = gInterpreter->SetClassAutoloading(kFALSE);
3903 
3904  while ((acl = (TClass*)nextClass())) {
3905  if (acl == newcl) continue;
3906 
3907  TIter nextInfo(acl->GetStreamerInfos());
3908  while ((info = (TVirtualStreamerInfo*)nextInfo())) {
3909 
3910  info->Update(this, newcl);
3911  }
3912 
3913  if (acl->GetCollectionProxy()) {
3914  acl->GetCollectionProxy()->UpdateValueClass(this, newcl);
3915  }
3916  // We should also inform all the TBranchElement :( but we do not have a master list :(
3917  }
3918 
3919  TIter delIter( &tobedeleted );
3920  while ((acl = (TClass*)delIter())) {
3921  delete acl;
3922  }
3923  gInterpreter->UnRegisterTClassUpdate(this);
3924 
3925  gInterpreter->SetClassAutoloading(autoload);
3926 }
3927 
3928 ////////////////////////////////////////////////////////////////////////////////
3929 /// Make sure that the current ClassInfo is up to date.
3930 
3931 void TClass::ResetClassInfo(Long_t /* tagnum */)
3932 {
3933  Warning("ResetClassInfo(Long_t tagnum)","Call to deprecated interface (does nothing)");
3934 }
3935 
3936 ////////////////////////////////////////////////////////////////////////////////
3937 /// Make sure that the current ClassInfo is up to date.
3938 
3940 {
3941  R__LOCKGUARD2(gInterpreterMutex);
3942 
3944 
3945  if (fClassInfo) {
3947  gInterpreter->ClassInfo_Delete(fClassInfo);
3948  fClassInfo = 0;
3949  }
3950  // We can not check at this point whether after the unload there will
3951  // still be interpreter information about this class (as v5 was doing),
3952  // instead this function must only be called if the definition is (about)
3953  // to be unloaded.
3954 
3955  ResetCaches();
3956 
3957  // We got here because the definition Decl is about to be unloaded.
3958  if (fState != TClass::kHasTClassInit) {
3959  if (fStreamerInfo->GetEntries() != 0) {
3961  } else {
3963  }
3964  } else {
3965  // if the ClassInfo was loaded for a class with a TClass Init and it
3966  // gets unloaded, should we guess it can be reloaded?
3968  }
3969 }
3970 
3971 ////////////////////////////////////////////////////////////////////////////////
3972 /// To clean out all caches.
3973 
3975 {
3976  R__ASSERT(!TestBit(kLoading) && "Resetting the caches does not make sense during loading!" );
3977 
3978  // Not owning lists, don't call Delete(), but unload
3979  if (fData)
3980  fData->Unload();
3981  if (fEnums.load())
3982  (*fEnums).Unload();
3983  if (fMethod.load())
3984  (*fMethod).Unload();
3985 
3986  delete fAllPubData; fAllPubData = 0;
3987 
3988  if (fBase)
3989  (*fBase).Delete();
3990  delete fBase.load(); fBase = 0;
3991 
3992  if (fRealData)
3993  fRealData->Delete();
3994  delete fRealData; fRealData=0;
3995 }
3996 
3997 ////////////////////////////////////////////////////////////////////////////////
3998 /// Resets the menu list to it's standard value.
3999 
4001 {
4002  if (fClassMenuList)
4004  else
4005  fClassMenuList = new TList();
4007 }
4008 
4009 ////////////////////////////////////////////////////////////////////////////////
4010 /// The ls function lists the contents of a class on stdout. Ls output
4011 /// is typically much less verbose then Dump().
4012 /// If options contains 'streamerinfo', run ls on the list of streamerInfos
4013 /// and the list of conversion streamerInfos.
4014 
4015 void TClass::ls(Option_t *options) const
4016 {
4017  TNamed::ls(options);
4018  if (options==0 || options[0]==0) return;
4019 
4020  if (strstr(options,"streamerinfo")!=0) {
4021  GetStreamerInfos()->ls(options);
4022 
4023  if (fConversionStreamerInfo.load()) {
4024  std::map<std::string, TObjArray*>::iterator it;
4025  std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
4026  for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
4027  it->second->ls(options);
4028  }
4029  }
4030  }
4031 }
4032 
4033 ////////////////////////////////////////////////////////////////////////////////
4034 /// Makes a customizable version of the popup menu list, i.e. makes a list
4035 /// of TClassMenuItem objects of methods accessible by context menu.
4036 /// The standard (and different) way consists in having just one element
4037 /// in this list, corresponding to the whole standard list.
4038 /// Once the customizable version is done, one can remove or add elements.
4039 
4041 {
4042  R__LOCKGUARD(gInterpreterMutex);
4043  TClassMenuItem *menuItem;
4044 
4045  // Make sure fClassMenuList is initialized and empty.
4046  GetMenuList()->Delete();
4047 
4048  TList* methodList = new TList;
4049  GetMenuItems(methodList);
4050 
4051  TMethod *method;
4052  TMethodArg *methodArg;
4053  TClass *classPtr = 0;
4054  TIter next(methodList);
4055 
4056  while ((method = (TMethod*) next())) {
4057  // if go to a mother class method, add separator
4058  if (classPtr != method->GetClass()) {
4059  menuItem = new TClassMenuItem(TClassMenuItem::kPopupSeparator, this);
4060  fClassMenuList->AddLast(menuItem);
4061  classPtr = method->GetClass();
4062  }
4063  // Build the signature of the method
4064  TString sig;
4065  TList* margsList = method->GetListOfMethodArgs();
4066  TIter nextarg(margsList);
4067  while ((methodArg = (TMethodArg*)nextarg())) {
4068  sig = sig+","+methodArg->GetFullTypeName();
4069  }
4070  if (sig.Length()!=0) sig.Remove(0,1); // remove first comma
4072  method->GetName(), method->GetName(),0,
4073  sig.Data(),-1,TClassMenuItem::kIsSelf);
4074  if (method->IsMenuItem() == kMenuToggle) menuItem->SetToggle();
4075  fClassMenuList->Add(menuItem);
4076  }
4077  delete methodList;
4078 }
4079 
4080 ////////////////////////////////////////////////////////////////////////////////
4081 /// Register the fact that an object was moved from the memory location
4082 /// 'arenaFrom' to the memory location 'arenaTo'.
4083 
4084 void TClass::Move(void *arenaFrom, void *arenaTo) const
4085 {
4086  // If/when we have access to a copy constructor (or better to a move
4087  // constructor), this function should also perform the data move.
4088  // For now we just information the repository.
4089 
4090  if ((GetState() <= kEmulated) && !fCollectionProxy) {
4091  MoveAddressInRepository("TClass::Move",arenaFrom,arenaTo,this);
4092  }
4093 }
4094 
4095 ////////////////////////////////////////////////////////////////////////////////
4096 /// Return the list of menu items associated with the class.
4097 
4099  if (!fClassMenuList) {
4100  fClassMenuList = new TList();
4101  fClassMenuList->Add(new TClassMenuItem(TClassMenuItem::kPopupStandardList, const_cast<TClass*>(this)));
4102  }
4103  return fClassMenuList;
4104 }
4105 
4106 ////////////////////////////////////////////////////////////////////////////////
4107 /// Return (create an empty one if needed) the list of functions.
4108 /// The major difference with GetListOfMethod is that this returns
4109 /// the internal type of fMethod and thus can not be made public.
4110 /// It also never 'loads' the content of the list.
4111 
4113 {
4114  if (!fMethod.load()) {
4115  std::unique_ptr<TListOfFunctions> temp{ new TListOfFunctions(this) };
4116  TListOfFunctions* expected = nullptr;
4117  if(fMethod.compare_exchange_strong(expected, temp.get()) ) {
4118  temp.release();
4119  }
4120  }
4121  return fMethod;
4122 }
4123 
4124 
4125 ////////////////////////////////////////////////////////////////////////////////
4126 /// Return pointer to method without looking at parameters.
4127 /// Does not look in (possible) base classes.
4128 /// Has the side effect of loading all the TMethod object in the list
4129 /// of the class.
4130 
4131 TMethod *TClass::GetMethodAny(const char *method)
4132 {
4133  if (!HasInterpreterInfo()) return 0;
4134  return (TMethod*) GetMethodList()->FindObject(method);
4135 }
4136 
4137 ////////////////////////////////////////////////////////////////////////////////
4138 /// Return pointer to method without looking at parameters.
4139 /// Does look in all base classes.
4140 
4141 TMethod *TClass::GetMethodAllAny(const char *method)
4142 {
4143  if (!HasInterpreterInfo()) return 0;
4144 
4145  TMethod* m = GetMethodAny(method);
4146  if (m) return m;
4147 
4148  TBaseClass *base;
4149  TIter nextb(GetListOfBases());
4150  while ((base = (TBaseClass *) nextb())) {
4151  TClass *c = base->GetClassPointer();
4152  if (c) {
4153  m = c->GetMethodAllAny(method);
4154  if (m) return m;
4155  }
4156  }
4157 
4158  return 0;
4159 }
4160 
4161 ////////////////////////////////////////////////////////////////////////////////
4162 /// Find the best method (if there is one) matching the parameters.
4163 /// The params string must contain argument values, like "3189, \"aap\", 1.3".
4164 /// The function invokes GetClassMethod to search for a possible method
4165 /// in the class itself or in its base classes. Returns 0 in case method
4166 /// is not found.
4167 
4168 TMethod *TClass::GetMethod(const char *method, const char *params,
4169  Bool_t objectIsConst /* = kFALSE */)
4170 {
4172  if (!fClassInfo) return 0;
4173 
4174  if (!gInterpreter)
4175  Fatal("GetMethod", "gInterpreter not initialized");
4176 
4177  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4178  method, params,
4179  objectIsConst);
4180 
4181  if (!decl) return 0;
4182 
4183  // search recursively in this class or its base classes
4185  if (f) return f;
4186 
4187  Error("GetMethod",
4188  "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4189  method,params,objectIsConst ? "const " : "", GetName());
4190  return 0;
4191 }
4192 
4193 
4194 ////////////////////////////////////////////////////////////////////////////////
4195 /// Find a method with decl id in this class or its bases.
4196 
4198  TFunction *f = GetMethodList()->Get(declId);
4199  if (f) return (TMethod*)f;
4200 
4201  TBaseClass *base;
4202  TIter next(GetListOfBases());
4203  while ((base = (TBaseClass *) next())) {
4204  TClass *clBase = base->GetClassPointer();
4205  if (clBase) {
4206  f = clBase->FindClassOrBaseMethodWithId(declId);
4207  if (f) return (TMethod*)f;
4208  }
4209  }
4210  return 0;
4211 }
4212 
4213 ////////////////////////////////////////////////////////////////////////////////
4214 /// Find the method with a given prototype. The proto string must be of the
4215 /// form: "char*,int,double". Returns 0 in case method is not found.
4216 
4217 TMethod *TClass::GetMethodWithPrototype(const char *method, const char *proto,
4218  Bool_t objectIsConst /* = kFALSE */,
4219  ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4220 {
4222  if (!fClassInfo) return 0;
4223 
4224  if (!gInterpreter)
4225  Fatal("GetMethodWithPrototype", "gInterpreter not initialized");
4226 
4227  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4228  method, proto,
4229  objectIsConst, mode);
4230 
4231  if (!decl) return 0;
4233  if (f) return f;
4234  Error("GetMethodWithPrototype",
4235  "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4236  method,proto,objectIsConst ? "const " : "", GetName());
4237  return 0;
4238 }
4239 
4240 ////////////////////////////////////////////////////////////////////////////////
4241 /// Look for a method in this class that has the interface function
4242 /// address faddr.
4243 
4245 {
4246  if (!HasInterpreterInfo()) return 0;
4247 
4248  TMethod *m;
4249  TIter next(GetListOfMethods());
4250  while ((m = (TMethod *) next())) {
4251  if (faddr == (Long_t)m->InterfaceMethod())
4252  return m;
4253  }
4254  return 0;
4255 }
4256 
4257 ////////////////////////////////////////////////////////////////////////////////
4258 /// Look for a method in this class that has the name and matches the parameters.
4259 /// The params string must contain argument values, like "3189, \"aap\", 1.3".
4260 /// Returns 0 in case method is not found.
4261 /// See TClass::GetMethod to also search the base classes.
4262 
4263 TMethod *TClass::GetClassMethod(const char *name, const char* params,
4264  Bool_t objectIsConst /* = kFALSE */)
4265 {
4267  if (!fClassInfo) return 0;
4268 
4269  if (!gInterpreter)
4270  Fatal("GetClassMethod", "gInterpreter not initialized");
4271 
4272  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4273  name, params,
4274  objectIsConst);
4275 
4276  if (!decl) return 0;
4277 
4278  TFunction *f = GetMethodList()->Get(decl);
4279 
4280  return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4281 }
4282 
4283 ////////////////////////////////////////////////////////////////////////////////
4284 /// Find the method with a given prototype. The proto string must be of the
4285 /// form: "char*,int,double". Returns 0 in case method is not found.
4286 /// See TClass::GetMethodWithPrototype to also search the base classes.
4287 
4289  Bool_t objectIsConst /* = kFALSE */,
4290  ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4291 {
4293  if (!fClassInfo) return 0;
4294 
4295  if (!gInterpreter)
4296  Fatal("GetClassMethodWithPrototype", "gInterpreter not initialized");
4297 
4298  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4299  name, proto,
4300  objectIsConst,
4301  mode);
4302 
4303  if (!decl) return 0;
4304 
4305  TFunction *f = GetMethodList()->Get(decl);
4306 
4307  return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4308 }
4309 
4310 ////////////////////////////////////////////////////////////////////////////////
4311 /// Return the number of data members of this class
4312 /// Note that in case the list of data members is not yet created, it will be done
4313 /// by GetListOfDataMembers().
4314 
4316 {
4317  if (!HasDataMemberInfo()) return 0;
4318 
4319  TList *lm = GetListOfDataMembers();
4320  if (lm)
4321  return lm->GetSize();
4322  else
4323  return 0;
4324 }
4325 
4326 ////////////////////////////////////////////////////////////////////////////////
4327 /// Return the number of methods of this class
4328 /// Note that in case the list of methods is not yet created, it will be done
4329 /// by GetListOfMethods().
4330 /// This will also load/populate the list of methods, to get 'just' the
4331 /// number of currently loaded methods use:
4332 /// cl->GetListOfMethods(false)->GetSize();
4333 
4335 {
4336  if (!HasInterpreterInfo()) return 0;
4337 
4338  TList *lm = GetListOfMethods();
4339  if (lm)
4340  return lm->GetSize();
4341  else
4342  return 0;
4343 }
4344 
4345 ////////////////////////////////////////////////////////////////////////////////
4346 /// returns a pointer to the TVirtualStreamerInfo object for version
4347 /// If the object does not exist, it is created
4348 ///
4349 /// Note: There are two special version numbers:
4350 ///
4351 /// - 0: Use the class version from the currently loaded class library.
4352 /// - -1: Assume no class library loaded (emulated class).
4353 ///
4354 /// Warning: If we create a new streamer info, whether or not the build
4355 /// optimizes is controlled externally to us by a global variable!
4356 /// Don't call us unless you have set that variable properly
4357 /// with TStreamer::Optimize()!
4358 ///
4359 
4361 {
4363  if (guess && guess->GetClassVersion() == version) {
4364  // If the StreamerInfo is assigned to the fLastReadInfo, we are
4365  // guaranteed it was built and compiled.
4366  return guess;
4367  }
4368 
4369  R__LOCKGUARD(gInterpreterMutex);
4370 
4371  // Handle special version, 0 means currently loaded version.
4372  // Warning: This may be -1 for an emulated class.
4373  // If version == -2, the user is requested the emulated streamerInfo
4374  // for an abstract base class even though we have a dictionary for it.
4375  if (version == 0) {
4376  version = fClassVersion;
4377  }
4378  Int_t ninfos = fStreamerInfo->GetSize();
4379  if ((version < -1) || (version >= ninfos)) {
4380  Error("GetStreamerInfo", "class: %s, attempting to access a wrong version: %d", GetName(), version);
4381  // FIXME: Shouldn't we go to -1 here, or better just abort?
4382  version = 0;
4383  }
4385  if (!sinfo && (version != fClassVersion)) {
4386  // When the requested version does not exist we return
4387  // the TVirtualStreamerInfo for the currently loaded class version.
4388  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4389  // Note: This is done for STL collections
4390  // Note: fClassVersion could be -1 here (for an emulated class).
4391  // This is also the code path take for unversioned classes.
4393  }
4394  if (!sinfo) {
4395  // We just were not able to find a streamer info, we have to make a new one.
4396  TMmallocDescTemp setreset;
4397  sinfo = TVirtualStreamerInfo::Factory()->NewInfo(const_cast<TClass*>(this));
4399  if (gDebug > 0) {
4400  printf("Creating StreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
4401  }
4403  // If we do not have a StreamerInfo for this version and we do not
4404  // have dictionary information nor a proxy, there is nothing to build!
4405  //
4406  sinfo->Build();
4407  }
4408  } else {
4409  if (!sinfo->IsCompiled()) {
4410  // Streamer info has not been compiled, but exists.
4411  // Therefore it was read in from a file and we have to do schema evolution?
4412  // Or it didn't have a dictionary before, but does now?
4413  sinfo->BuildOld();
4414  }
4415  }
4416  // Cache the current info if we now have it.
4417  if (version == fClassVersion) {
4418  fCurrentInfo = sinfo;
4419  }
4420  // If the compilation succeeded, remember this StreamerInfo.
4421  if (sinfo->IsCompiled()) fLastReadInfo = sinfo;
4422  return sinfo;
4423 }
4424 
4425 ////////////////////////////////////////////////////////////////////////////////
4426 /// For the case where the requestor class is emulated and this class is abstract,
4427 /// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4428 /// representation whether or not the class is loaded.
4429 ///
4430 /// If the object does not exist, it is created
4431 ///
4432 /// Note: There are two special version numbers:
4433 ///
4434 /// - 0: Use the class version from the currently loaded class library.
4435 /// - -1: Assume no class library loaded (emulated class).
4436 ///
4437 /// Warning: If we create a new streamer info, whether or not the build
4438 /// optimizes is controlled externally to us by a global variable!
4439 /// Don't call us unless you have set that variable properly
4440 /// with TStreamer::Optimize()!
4441 ///
4442 
4444 {
4445  R__LOCKGUARD(gInterpreterMutex);
4446 
4447  TString newname( GetName() );
4448  newname += "@@emulated";
4449 
4450  TClass *emulated = TClass::GetClass(newname);
4451 
4452  TVirtualStreamerInfo* sinfo = 0;
4453 
4454  if (emulated) {
4455  sinfo = emulated->GetStreamerInfo(version);
4456  }
4457  if (!sinfo) {
4458  // The emulated version of the streamerInfo is explicitly requested and has
4459  // not been built yet.
4460 
4461  sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(version);
4462  if (!sinfo && (version != fClassVersion)) {
4463  // When the requested version does not exist we return
4464  // the TVirtualStreamerInfo for the currently loaded class version.
4465  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4467  }
4468  if (!sinfo) {
4469  // Let's take the first available StreamerInfo as a start
4470  Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4471  for (Int_t i = -1; sinfo == 0 && i < ninfos; ++i) {
4473  }
4474  }
4475  if (sinfo) {
4476  sinfo = dynamic_cast<TVirtualStreamerInfo*>( sinfo->Clone() );
4477  if (sinfo) {
4478  sinfo->SetClass(0);
4479  sinfo->SetName( newname );
4480  sinfo->BuildCheck();
4481  sinfo->BuildOld();
4482  sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4483  } else
4484  Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4485  }
4486  }
4487  return sinfo;
4488 }
4489 
4490 ////////////////////////////////////////////////////////////////////////////////
4491 /// For the case where the requestor class is emulated and this class is abstract,
4492 /// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4493 /// representation whether or not the class is loaded.
4494 ///
4495 /// If the object does not exist, it is created
4496 ///
4497 /// Warning: If we create a new streamer info, whether or not the build
4498 /// optimizes is controlled externally to us by a global variable!
4499 /// Don't call us unless you have set that variable properly
4500 /// with TStreamer::Optimize()!
4501 ///
4502 
4504 {
4505  R__LOCKGUARD(gInterpreterMutex);
4506 
4507  TString newname( GetName() );
4508  newname += "@@emulated";
4509 
4510  TClass *emulated = TClass::GetClass(newname);
4511 
4512  TVirtualStreamerInfo* sinfo = 0;
4513 
4514  if (emulated) {
4515  sinfo = emulated->FindStreamerInfo(checksum);
4516  }
4517  if (!sinfo) {
4518  // The emulated version of the streamerInfo is explicitly requested and has
4519  // not been built yet.
4520 
4521  sinfo = (TVirtualStreamerInfo*) FindStreamerInfo(checksum);
4522  if (!sinfo && (checksum != fCheckSum)) {
4523  // When the requested version does not exist we return
4524  // the TVirtualStreamerInfo for the currently loaded class version.
4525  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4527  }
4528  if (!sinfo) {
4529  // Let's take the first available StreamerInfo as a start
4530  Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4531  for (Int_t i = -1; sinfo == 0 && i < ninfos; ++i) {
4533  }
4534  }
4535  if (sinfo) {
4536  sinfo = dynamic_cast<TVirtualStreamerInfo*>( sinfo->Clone() );
4537  if (sinfo) {
4538  sinfo->SetClass(0);
4539  sinfo->SetName( newname );
4540  sinfo->BuildCheck();
4541  sinfo->BuildOld();
4542  sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4543  } else
4544  Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4545  }
4546  }
4547  return sinfo;
4548 }
4549 
4550 ////////////////////////////////////////////////////////////////////////////////
4551 /// When the class kIgnoreTObjectStreamer bit is set, the automatically
4552 /// generated Streamer will not call TObject::Streamer.
4553 /// This option saves the TObject space overhead on the file.
4554 /// However, the information (fBits, fUniqueID) of TObject is lost.
4555 ///
4556 /// Note that to be effective for objects streamed object-wise this function
4557 /// must be called for the class deriving directly from TObject, eg, assuming
4558 /// that BigTrack derives from Track and Track derives from TObject, one must do:
4559 /// ~~~ {.cpp}
4560 /// Track::Class()->IgnoreTObjectStreamer();
4561 /// ~~~
4562 /// and not:
4563 /// ~~~ {.cpp}
4564 /// BigTrack::Class()->IgnoreTObjectStreamer();
4565 /// ~~~
4566 /// To be effective for object streamed member-wise or split in a TTree,
4567 /// this function must be called for the most derived class (i.e. BigTrack).
4568 
4570 {
4571  // We need to tak the lock since we are test and then setting fBits
4572  // and TStreamerInfo::fBits (and the StreamerInfo state in general)
4573  // which can also be modified by another thread.
4574  R__LOCKGUARD2(gInterpreterMutex);
4575 
4576  if ( doIgnore && TestBit(kIgnoreTObjectStreamer)) return;
4577  if (!doIgnore && !TestBit(kIgnoreTObjectStreamer)) return;
4579  if (sinfo) {
4580  if (sinfo->IsCompiled()) {
4581  // -- Warn the user that what they are doing cannot work.
4582  // Note: The reason is that TVirtualStreamerInfo::Build() examines
4583  // the kIgnoreTObjectStreamer bit and sets the TStreamerElement
4584  // type for the TObject base class streamer element it creates
4585  // to -1 as a flag. Later on the TStreamerInfo::Compile()
4586  // member function sees the flag and does not insert the base
4587  // class element into the compiled streamer info. None of this
4588  // machinery works correctly if we are called after the streamer
4589  // info has already been built and compiled.
4590  Error("IgnoreTObjectStreamer","Must be called before the creation of StreamerInfo");
4591  return;
4592  }
4593  }
4594  if (doIgnore) SetBit (kIgnoreTObjectStreamer);
4596 }
4597 
4598 ////////////////////////////////////////////////////////////////////////////////
4599 /// Return kTRUE if this class inherits from a class with name "classname".
4600 /// note that the function returns kTRUE in case classname is the class itself
4601 
4602 Bool_t TClass::InheritsFrom(const char *classname) const
4603 {
4604  if (strcmp(GetName(), classname) == 0) return kTRUE;
4605 
4606  return InheritsFrom(TClass::GetClass(classname,kTRUE,kTRUE));
4607 }
4608 
4609 ////////////////////////////////////////////////////////////////////////////////
4610 /// Return kTRUE if this class inherits from class cl.
4611 /// note that the function returns KTRUE in case cl is the class itself
4612 
4614 {
4615  if (!cl) return kFALSE;
4616  if (cl == this) return kTRUE;
4617 
4618  if (!HasDataMemberInfo()) {
4619  TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
4620  if (sinfo==0) sinfo = GetStreamerInfo();
4621  TIter next(sinfo->GetElements());
4622  TStreamerElement *element;
4623  while ((element = (TStreamerElement*)next())) {
4624  if (element->IsA() == TStreamerBase::Class()) {
4625  TClass *clbase = element->GetClassPointer();
4626  if (!clbase) return kFALSE; //missing class
4627  if (clbase->InheritsFrom(cl)) return kTRUE;
4628  }
4629  }
4630  return kFALSE;
4631  }
4632  // cast const away (only for member fBase which can be set in GetListOfBases())
4633  if (((TClass *)this)->GetBaseClass(cl)) return kTRUE;
4634  return kFALSE;
4635 }
4636 
4637 ////////////////////////////////////////////////////////////////////////////////
4638 /// Cast obj of this class type up to baseclass cl if up is true.
4639 /// Cast obj of this class type down from baseclass cl if up is false.
4640 /// If this class is not a baseclass of cl return 0, else the pointer
4641 /// to the cl part of this (up) or to this (down).
4642 
4643 void *TClass::DynamicCast(const TClass *cl, void *obj, Bool_t up)
4644 {
4645  if (cl == this) return obj;
4646 
4647  if (!HasDataMemberInfo()) return 0;
4648 
4649  Int_t off;
4650  if ((off = GetBaseClassOffset(cl, obj)) != -1) {
4651  if (up)
4652  return (void*)((Long_t)obj+off);
4653  else
4654  return (void*)((Long_t)obj-off);
4655  }
4656  return 0;
4657 }
4658 
4659 ////////////////////////////////////////////////////////////////////////////////
4660 /// Cast obj of this class type up to baseclass cl if up is true.
4661 /// Cast obj of this class type down from baseclass cl if up is false.
4662 /// If this class is not a baseclass of cl return 0, else the pointer
4663 /// to the cl part of this (up) or to this (down).
4664 
4665 const void *TClass::DynamicCast(const TClass *cl, const void *obj, Bool_t up)
4666 {
4667  return DynamicCast(cl,const_cast<void*>(obj),up);
4668 }
4669 
4670 ////////////////////////////////////////////////////////////////////////////////
4671 /// Return a pointer to a newly allocated object of this class.
4672 /// The class must have a default constructor. For meaning of
4673 /// defConstructor, see TClass::IsCallingNew().
4674 ///
4675 /// If quiet is true, do no issue a message via Error on case
4676 /// of problems, just return 0.
4677 ///
4678 /// The constructor actually called here can be customized by
4679 /// using the rootcint pragma:
4680 /// ~~~ {.cpp}
4681 /// #pragma link C++ ioctortype UserClass;
4682 /// ~~~
4683 /// For example, with this pragma and a class named MyClass,
4684 /// this method will called the first of the following 3
4685 /// constructors which exists and is public:
4686 /// ~~~ {.cpp}
4687 /// MyClass(UserClass*);
4688 /// MyClass(TRootIOCtor*);
4689 /// MyClass(); // Or a constructor with all its arguments defaulted.
4690 /// ~~~
4691 ///
4692 /// When more than one pragma ioctortype is used, the first seen as priority
4693 /// For example with:
4694 /// ~~~ {.cpp}
4695 /// #pragma link C++ ioctortype UserClass1;
4696 /// #pragma link C++ ioctortype UserClass2;
4697 /// ~~~
4698 /// We look in the following order:
4699 /// ~~~ {.cpp}
4700 /// MyClass(UserClass1*);
4701 /// MyClass(UserClass2*);
4702 /// MyClass(TRootIOCtor*);
4703 /// MyClass(); // Or a constructor with all its arguments defaulted.
4704 /// ~~~
4705 
4706 void *TClass::New(ENewType defConstructor, Bool_t quiet) const
4707 {
4708  void* p = 0;
4709 
4710  if (fNew) {
4711  // We have the new operator wrapper function,
4712  // so there is a dictionary and it was generated
4713  // by rootcint, so there should be a default
4714  // constructor we can call through the wrapper.
4715  TClass__GetCallingNew() = defConstructor;
4716  p = fNew(0);
4718  if (!p && !quiet) {
4719  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4720  Error("New", "cannot create object of class %s", GetName());
4721  }
4722  } else if (HasInterpreterInfo()) {
4723  // We have the dictionary but do not have the
4724  // constructor wrapper, so the dictionary was
4725  // not generated by rootcint. Let's try to
4726  // create the object by having the interpreter
4727  // call the new operator, hopefully the class
4728  // library is loaded and there will be a default
4729  // constructor we can call.
4730  // [This is very unlikely to work, but who knows!]
4731  TClass__GetCallingNew() = defConstructor;
4734  if (!p && !quiet) {
4735  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4736  Error("New", "cannot create object of class %s", GetName());
4737  }
4738  } else if (!HasInterpreterInfo() && fCollectionProxy) {
4739  // There is no dictionary at all, so this is an emulated
4740  // class; however we do have the services of a collection proxy,
4741  // so this is an emulated STL class.
4742  TClass__GetCallingNew() = defConstructor;
4743  p = fCollectionProxy->New();
4745  if (!p && !quiet) {
4746  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4747  Error("New", "cannot create object of class %s", GetName());
4748  }
4749  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
4750  // There is no dictionary at all and we do not have
4751  // the services of a collection proxy available, so
4752  // use the streamer info to approximate calling a
4753  // constructor (basically we just make sure that the
4754  // pointer data members are null, unless they are marked
4755  // as preallocated with the "->" comment, in which case
4756  // we default-construct an object to point at).
4757 
4758  // Do not register any TObject's that we create
4759  // as a result of creating this object.
4760  // FIXME: Why do we do this?
4761  // FIXME: Partial Answer: Is this because we may never actually deregister them???
4762 
4763  Bool_t statsave = GetObjectStat();
4764  if(statsave) {
4766  }
4768  if (!sinfo && !quiet) {
4769  Error("New", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion);
4770  return 0;
4771  }
4772 
4773  TClass__GetCallingNew() = defConstructor;
4774  p = sinfo->New();
4776 
4777  // FIXME: Mistake? See note above at the GetObjectStat() call.
4778  // Allow TObject's to be registered again.
4779  if(statsave) {
4780  SetObjectStat(statsave);
4781  }
4782 
4783  // Register the object for special handling in the destructor.
4784  if (p) {
4785  RegisterAddressInRepository("New",p,this);
4786  } else {
4787  Error("New", "Failed to construct class '%s' using streamer info", GetName());
4788  }
4789  } else {
4790  Fatal("New", "This cannot happen!");
4791  }
4792 
4793  return p;
4794 }
4795 
4796 ////////////////////////////////////////////////////////////////////////////////
4797 /// Return a pointer to a newly allocated object of this class.
4798 /// The class must have a default constructor. For meaning of
4799 /// defConstructor, see TClass::IsCallingNew().
4800 
4801 void *TClass::New(void *arena, ENewType defConstructor) const
4802 {
4803  void* p = 0;
4804 
4805  if (fNew) {
4806  // We have the new operator wrapper function,
4807  // so there is a dictionary and it was generated
4808  // by rootcint, so there should be a default
4809  // constructor we can call through the wrapper.
4810  TClass__GetCallingNew() = defConstructor;
4811  p = fNew(arena);
4813  if (!p) {
4814  Error("New with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
4815  }
4816  } else if (HasInterpreterInfo()) {
4817  // We have the dictionary but do not have the
4818  // constructor wrapper, so the dictionary was
4819  // not generated by rootcint. Let's try to
4820  // create the object by having the interpreter
4821  // call the new operator, hopefully the class
4822  // library is loaded and there will be a default
4823  // constructor we can call.
4824  // [This is very unlikely to work, but who knows!]
4825  TClass__GetCallingNew() = defConstructor;
4826  p = gCling->ClassInfo_New(GetClassInfo(),arena);
4828  if (!p) {
4829  Error("New with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
4830  }
4831  } else if (!HasInterpreterInfo() && fCollectionProxy) {
4832  // There is no dictionary at all, so this is an emulated
4833  // class; however we do have the services of a collection proxy,
4834  // so this is an emulated STL class.
4835  TClass__GetCallingNew() = defConstructor;
4836  p = fCollectionProxy->New(arena);
4838  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
4839  // There is no dictionary at all and we do not have
4840  // the services of a collection proxy available, so
4841  // use the streamer info to approximate calling a
4842  // constructor (basically we just make sure that the
4843  // pointer data members are null, unless they are marked
4844  // as preallocated with the "->" comment, in which case
4845  // we default-construct an object to point at).
4846 
4847  // ???BUG??? ???WHY???
4848  // Do not register any TObject's that we create
4849  // as a result of creating this object.
4850  Bool_t statsave = GetObjectStat();
4851  if(statsave) {
4853  }
4854 
4856  if (!sinfo) {
4857  Error("New with placement", "Cannot construct class '%s' version %d at address %p, no streamer info available!", GetName(), fClassVersion, arena);
4858  return 0;
4859  }
4860 
4861  TClass__GetCallingNew() = defConstructor;
4862  p = sinfo->New(arena);
4864 
4865  // ???BUG???
4866  // Allow TObject's to be registered again.
4867  if(statsave) {
4868  SetObjectStat(statsave);
4869  }
4870 
4871  // Register the object for special handling in the destructor.
4872  if (p) {
4873  RegisterAddressInRepository("TClass::New with placement",p,this);
4874  }
4875  } else {
4876  Error("New with placement", "This cannot happen!");
4877  }
4878 
4879  return p;
4880 }
4881 
4882 ////////////////////////////////////////////////////////////////////////////////
4883 /// Return a pointer to a newly allocated array of objects
4884 /// of this class.
4885 /// The class must have a default constructor. For meaning of
4886 /// defConstructor, see TClass::IsCallingNew().
4887 
4888 void *TClass::NewArray(Long_t nElements, ENewType defConstructor) const
4889 {
4890  void* p = 0;
4891 
4892  if (fNewArray) {
4893  // We have the new operator wrapper function,
4894  // so there is a dictionary and it was generated
4895  // by rootcint, so there should be a default
4896  // constructor we can call through the wrapper.
4897  TClass__GetCallingNew() = defConstructor;
4898  p = fNewArray(nElements, 0);
4900  if (!p) {
4901  Error("NewArray", "cannot create object of class %s version %d", GetName(), fClassVersion);
4902  }
4903  } else if (HasInterpreterInfo()) {
4904  // We have the dictionary but do not have the
4905  // constructor wrapper, so the dictionary was
4906  // not generated by rootcint. Let's try to
4907  // create the object by having the interpreter
4908  // call the new operator, hopefully the class
4909  // library is loaded and there will be a default
4910  // constructor we can call.
4911  // [This is very unlikely to work, but who knows!]
4912  TClass__GetCallingNew() = defConstructor;
4913  p = gCling->ClassInfo_New(GetClassInfo(),nElements);
4915  if (!p) {
4916  Error("NewArray", "cannot create object of class %s version %d", GetName(), fClassVersion);
4917  }
4918  } else if (!HasInterpreterInfo() && fCollectionProxy) {
4919  // There is no dictionary at all, so this is an emulated
4920  // class; however we do have the services of a collection proxy,
4921  // so this is an emulated STL class.
4922  TClass__GetCallingNew() = defConstructor;
4923  p = fCollectionProxy->NewArray(nElements);
4925  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
4926  // There is no dictionary at all and we do not have
4927  // the services of a collection proxy available, so
4928  // use the streamer info to approximate calling a
4929  // constructor (basically we just make sure that the
4930  // pointer data members are null, unless they are marked
4931  // as preallocated with the "->" comment, in which case
4932  // we default-construct an object to point at).
4933 
4934  // ???BUG??? ???WHY???
4935  // Do not register any TObject's that we create
4936  // as a result of creating this object.
4937  Bool_t statsave = GetObjectStat();
4938  if(statsave) {
4940  }
4941 
4943  if (!sinfo) {
4944  Error("NewArray", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion);
4945  return 0;
4946  }
4947 
4948  TClass__GetCallingNew() = defConstructor;
4949  p = sinfo->NewArray(nElements);
4951 
4952  // ???BUG???
4953  // Allow TObject's to be registered again.
4954  if(statsave) {
4955  SetObjectStat(statsave);
4956  }
4957 
4958  // Register the object for special handling in the destructor.
4959  if (p) {
4960  RegisterAddressInRepository("TClass::NewArray",p,this);
4961  }
4962  } else {
4963  Error("NewArray", "This cannot happen!");
4964  }
4965 
4966  return p;
4967 }
4968 
4969 ////////////////////////////////////////////////////////////////////////////////
4970 /// Return a pointer to a newly allocated object of this class.
4971 /// The class must have a default constructor. For meaning of
4972 /// defConstructor, see TClass::IsCallingNew().
4973 
4974 void *TClass::NewArray(Long_t nElements, void *arena, ENewType defConstructor) const
4975 {
4976  void* p = 0;
4977 
4978  if (fNewArray) {
4979  // We have the new operator wrapper function,
4980  // so there is a dictionary and it was generated
4981  // by rootcint, so there should be a default
4982  // constructor we can call through the wrapper.
4983  TClass__GetCallingNew() = defConstructor;
4984  p = fNewArray(nElements, arena);
4986  if (!p) {
4987  Error("NewArray with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
4988  }
4989  } else if (HasInterpreterInfo()) {
4990  // We have the dictionary but do not have the constructor wrapper,
4991  // so the dictionary was not generated by rootcint (it was made either
4992  // by cint or by some external mechanism). Let's try to create the
4993  // object by having the interpreter call the new operator, either the
4994  // class library is loaded and there is a default constructor we can
4995  // call, or the class is interpreted and we will call the default
4996  // constructor that way, or no default constructor is available and
4997  // we fail.
4998  TClass__GetCallingNew() = defConstructor;
4999  p = gCling->ClassInfo_New(GetClassInfo(),nElements, arena);
5001  if (!p) {
5002  Error("NewArray with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
5003  }
5004  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5005  // There is no dictionary at all, so this is an emulated
5006  // class; however we do have the services of a collection proxy,
5007  // so this is an emulated STL class.
5008  TClass__GetCallingNew() = defConstructor;
5009  p = fCollectionProxy->NewArray(nElements, arena);
5011  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5012  // There is no dictionary at all and we do not have
5013  // the services of a collection proxy available, so
5014  // use the streamer info to approximate calling a
5015  // constructor (basically we just make sure that the
5016  // pointer data members are null, unless they are marked
5017  // as preallocated with the "->" comment, in which case
5018  // we default-construct an object to point at).
5019 
5020  // ???BUG??? ???WHY???
5021  // Do not register any TObject's that we create
5022  // as a result of creating this object.
5023  Bool_t statsave = GetObjectStat();
5024  if(statsave) {
5026  }
5027 
5029  if (!sinfo) {
5030  Error("NewArray with placement", "Cannot construct class '%s' version %d at address %p, no streamer info available!", GetName(), fClassVersion, arena);
5031  return 0;
5032  }
5033 
5034  TClass__GetCallingNew() = defConstructor;
5035  p = sinfo->NewArray(nElements, arena);
5037 
5038  // ???BUG???
5039  // Allow TObject's to be registered again.
5040  if(statsave) {
5041  SetObjectStat(statsave);
5042  }
5043 
5045  // We always register emulated objects, we need to always
5046  // use the streamer info to destroy them.
5047  }
5048 
5049  // Register the object for special handling in the destructor.
5050  if (p) {
5051  RegisterAddressInRepository("TClass::NewArray with placement",p,this);
5052  }
5053  } else {
5054  Error("NewArray with placement", "This cannot happen!");
5055  }
5056 
5057  return p;
5058 }
5059 
5060 ////////////////////////////////////////////////////////////////////////////////
5061 /// Explicitly call destructor for object.
5062 
5063 void TClass::Destructor(void *obj, Bool_t dtorOnly)
5064 {
5065  // Do nothing if passed a null pointer.
5066  if (obj == 0) return;
5067 
5068  void* p = obj;
5069 
5070  if (dtorOnly && fDestructor) {
5071  // We have the destructor wrapper, use it.
5072  fDestructor(p);
5073  } else if ((!dtorOnly) && fDelete) {
5074  // We have the delete wrapper, use it.
5075  fDelete(p);
5076  } else if (HasInterpreterInfo()) {
5077  // We have the dictionary but do not have the
5078  // destruct/delete wrapper, so the dictionary was
5079  // not generated by rootcint (it could have been
5080  // created by cint or by some external mechanism).
5081  // Let's have the interpreter call the destructor,
5082  // either the code will be in a loaded library,
5083  // or it will be interpreted, otherwise we fail
5084  // because there is no destructor code at all.
5085  if (dtorOnly) {
5087  } else {
5089  }
5090  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5091  // There is no dictionary at all, so this is an emulated
5092  // class; however we do have the services of a collection proxy,
5093  // so this is an emulated STL class.
5094  fCollectionProxy->Destructor(p, dtorOnly);
5095  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5096  // There is no dictionary at all and we do not have
5097  // the services of a collection proxy available, so
5098  // use the streamer info to approximate calling a
5099  // destructor.
5100 
5101  Bool_t inRepo = kTRUE;
5102  Bool_t verFound = kFALSE;
5103 
5104  // Was this object allocated through TClass?
5105  std::multiset<Version_t> knownVersions;
5106  R__LOCKGUARD2(gOVRMutex);
5107 
5108  {
5109  RepoCont_t::iterator iter = gObjectVersionRepository.find(p);
5110  if (iter == gObjectVersionRepository.end()) {
5111  // No, it wasn't, skip special version handling.
5112  //Error("Destructor2", "Attempt to delete unregistered object of class '%s' at address %p!", GetName(), p);
5113  inRepo = kFALSE;
5114  } else {
5115  //objVer = iter->second;
5116  for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) {
5117  Version_t ver = iter->second.fVersion;
5118  knownVersions.insert(ver);
5119  if (ver == fClassVersion && this == iter->second.fClass) {
5120  verFound = kTRUE;
5121  }
5122  }
5123  }
5124  }
5125 
5126  if (!inRepo || verFound) {
5127  // The object was allocated using code for the same class version
5128  // as is loaded now. We may proceed without worry.
5130  if (si) {
5131  si->Destructor(p, dtorOnly);
5132  } else {
5133  Error("Destructor", "No streamer info available for class '%s' version %d at address %p, cannot destruct emulated object!", GetName(), fClassVersion, p);
5134  Error("Destructor", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5136  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5137  Error("Destructor", "fStreamerInfo->At(%d): %p", i, fStreamerInfo->At(i));
5138  if (fStreamerInfo->At(i) != 0) {
5139  Error("Destructor", "Doing Dump() ...");
5141  }
5142  }
5143  }
5144  } else {
5145  // The loaded class version is not the same as the version of the code
5146  // which was used to allocate this object. The best we can do is use
5147  // the TVirtualStreamerInfo to try to free up some of the allocated memory.
5148  Error("Destructor", "Loaded class %s version %d is not registered for addr %p", GetName(), fClassVersion, p);
5149 #if 0
5151  if (si) {
5152  si->Destructor(p, dtorOnly);
5153  } else {
5154  Error("Destructor2", "No streamer info available for class '%s' version %d, cannot destruct object at addr: %p", GetName(), objVer, p);
5155  Error("Destructor2", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5157  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5158  Error("Destructor2", "fStreamerInfo->At(%d): %p", i, fStreamerInfo->At(i));
5159  if (fStreamerInfo->At(i) != 0) {
5160  // Do some debugging output.
5161  Error("Destructor2", "Doing Dump() ...");
5163  }
5164  }
5165  }
5166 #endif
5167  }
5168 
5169  if (inRepo && verFound && p) {
5170  UnregisterAddressInRepository("TClass::Destructor",p,this);
5171  }
5172  } else {
5173  Error("Destructor", "This cannot happen! (class %s)", GetName());
5174  }
5175 }
5176 
5177 ////////////////////////////////////////////////////////////////////////////////
5178 /// Explicitly call operator delete[] for an array.
5179 
5180 void TClass::DeleteArray(void *ary, Bool_t dtorOnly)
5181 {
5182  // Do nothing if passed a null pointer.
5183  if (ary == 0) return;
5184 
5185  // Make a copy of the address.
5186  void* p = ary;
5187 
5188  if (fDeleteArray) {
5189  if (dtorOnly) {
5190  Error("DeleteArray", "Destructor only is not supported!");
5191  } else {
5192  // We have the array delete wrapper, use it.
5193  fDeleteArray(ary);
5194  }
5195  } else if (HasInterpreterInfo()) {
5196  // We have the dictionary but do not have the
5197  // array delete wrapper, so the dictionary was
5198  // not generated by rootcint. Let's try to
5199  // delete the array by having the interpreter
5200  // call the array delete operator, hopefully
5201  // the class library is loaded and there will be
5202  // a destructor we can call.
5203  gCling->ClassInfo_DeleteArray(GetClassInfo(),ary, dtorOnly);
5204  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5205  // There is no dictionary at all, so this is an emulated
5206  // class; however we do have the services of a collection proxy,
5207  // so this is an emulated STL class.
5208  fCollectionProxy->DeleteArray(ary, dtorOnly);
5209  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5210  // There is no dictionary at all and we do not have
5211  // the services of a collection proxy available, so
5212  // use the streamer info to approximate calling the
5213  // array destructor.
5214 
5215  Bool_t inRepo = kTRUE;
5216  Bool_t verFound = kFALSE;
5217 
5218  // Was this array object allocated through TClass?
5219  std::multiset<Version_t> knownVersions;
5220  {
5221  R__LOCKGUARD2(gOVRMutex);
5222  RepoCont_t::iterator iter = gObjectVersionRepository.find(p);
5223  if (iter == gObjectVersionRepository.end()) {
5224  // No, it wasn't, we cannot know what to do.
5225  //Error("DeleteArray", "Attempt to delete unregistered array object, element type '%s', at address %p!", GetName(), p);
5226  inRepo = kFALSE;
5227  } else {
5228  for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) {
5229  Version_t ver = iter->second.fVersion;
5230  knownVersions.insert(ver);
5231  if (ver == fClassVersion && this == iter->second.fClass ) {
5232  verFound = kTRUE;
5233  }
5234  }
5235  }
5236  }
5237 
5238  if (!inRepo || verFound) {
5239  // The object was allocated using code for the same class version
5240  // as is loaded now. We may proceed without worry.
5242  if (si) {
5243  si->DeleteArray(ary, dtorOnly);
5244  } else {
5245  Error("DeleteArray", "No streamer info available for class '%s' version %d at address %p, cannot destruct object!", GetName(), fClassVersion, ary);
5246  Error("DeleteArray", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5248  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5249  Error("DeleteArray", "fStreamerInfo->At(%d): %p", v, fStreamerInfo->At(i));
5250  if (fStreamerInfo->At(i)) {
5251  Error("DeleteArray", "Doing Dump() ...");
5253  }
5254  }
5255  }
5256  } else {
5257  // The loaded class version is not the same as the version of the code
5258  // which was used to allocate this array. The best we can do is use
5259  // the TVirtualStreamerInfo to try to free up some of the allocated memory.
5260  Error("DeleteArray", "Loaded class version %d is not registered for addr %p", fClassVersion, p);
5261 
5262 
5263 
5264 #if 0
5266  if (si) {
5267  si->DeleteArray(ary, dtorOnly);
5268  } else {
5269  Error("DeleteArray", "No streamer info available for class '%s' version %d at address %p, cannot destruct object!", GetName(), objVer, ary);
5270  Error("DeleteArray", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5272  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5273  Error("DeleteArray", "fStreamerInfo->At(%d): %p", v, fStreamerInfo->At(i));
5274  if (fStreamerInfo->At(i)) {
5275  // Print some debugging info.
5276  Error("DeleteArray", "Doing Dump() ...");
5278  }
5279  }
5280  }
5281 #endif
5282 
5283 
5284  }
5285 
5286  // Deregister the object for special handling in the destructor.
5287  if (inRepo && verFound && p) {
5288  UnregisterAddressInRepository("TClass::DeleteArray",p,this);
5289  }
5290  } else {
5291  Error("DeleteArray", "This cannot happen! (class '%s')", GetName());
5292  }
5293 }
5294 
5295 ////////////////////////////////////////////////////////////////////////////////
5296 /// Set the splitability of this class:
5297 /// -1: Use the default calculation
5298 /// 0: Disallow splitting
5299 /// 1: Always allow splitting.
5300 /// 2: Disallow splitting of the class and splitting of any it's derived classes.
5301 
5303 {
5304  fCanSplit = splitmode;
5305 }
5306 
5307 ////////////////////////////////////////////////////////////////////////////////
5308 /// Private function. Set the class version for the 'class' represented by
5309 /// this TClass object. See the public interface:
5310 /// ROOT::ResetClassVersion
5311 /// defined in TClassTable.cxx
5312 ///
5313 /// Note on class version numbers:
5314 /// - If no class number has been specified, TClass::GetVersion will return -1
5315 /// - The Class Version 0 request the whole object to be transient
5316 /// - The Class Version 1, unless specified via ClassDef indicates that the
5317 /// I/O should use the TClass checksum to distinguish the layout of the class
5318 
5320 {
5321  fClassVersion = version;
5322  fCurrentInfo = 0;
5323 }
5324 
5325 ////////////////////////////////////////////////////////////////////////////////
5326 /// Determine and set pointer to current TVirtualStreamerInfo
5327 
5329 {
5330  R__LOCKGUARD2(gInterpreterMutex);
5331  if(!fCurrentInfo.load()) {
5333  }
5334  return fCurrentInfo;
5335 }
5336 
5337 ////////////////////////////////////////////////////////////////////////////////
5338 /// Set pointer to current TVirtualStreamerInfo
5339 
5341 {
5342  fCurrentInfo = info;
5343 }
5344 
5345 ////////////////////////////////////////////////////////////////////////////////
5346 /// Return size of object of this class.
5347 
5349 {
5350  if (fSizeof!=-1) return fSizeof;
5351  if (fCollectionProxy) return fCollectionProxy->Sizeof();
5353  return GetStreamerInfo()->GetSize();
5354 }
5355 
5356 ////////////////////////////////////////////////////////////////////////////////
5357 /// Load class description from I/O buffer and return class object.
5358 
5360 {
5361  UInt_t maxsize = 256;
5362  char *s = new char[maxsize];
5363 
5364  Int_t pos = b.Length();
5365 
5366  b.ReadString(s, maxsize); // Reads at most maxsize - 1 characters, plus null at end.
5367  while (strlen(s) == (maxsize - 1)) {
5368  // The classname is too large, try again with a large buffer.
5369  b.SetBufferOffset(pos);
5370  maxsize = 2*maxsize;
5371  delete [] s;
5372  s = new char[maxsize];
5373  b.ReadString(s, maxsize); // Reads at most maxsize - 1 characters, plus null at end.
5374  }
5375 
5376  TClass *cl = TClass::GetClass(s, kTRUE);
5377  if (!cl)
5378  ::Error("TClass::Load", "dictionary of class %s not found", s);
5379 
5380  delete [] s;
5381  return cl;
5382 }
5383 
5384 ////////////////////////////////////////////////////////////////////////////////
5385 /// Helper function used by TClass::GetClass().
5386 /// This function attempts to load the dictionary for 'classname'
5387 /// either from the TClassTable or from the list of generator.
5388 /// If silent is 'true', do not warn about missing dictionary for the class.
5389 /// (typically used for class that are used only for transient members)
5390 ///
5391 /// The 'requestedname' is expected to be already normalized.
5392 
5393 TClass *TClass::LoadClass(const char *requestedname, Bool_t silent)
5394 {
5395  // This function does not (and should not) attempt to check in the
5396  // list of loaded classes or in the typedef.
5397 
5398  R__LOCKGUARD(gInterpreterMutex);
5399 
5400  TClass *result = LoadClassDefault(requestedname, silent);
5401 
5402  if (result) return result;
5403  else return LoadClassCustom(requestedname,silent);
5404 }
5405 
5406 ////////////////////////////////////////////////////////////////////////////////
5407 /// Helper function used by TClass::GetClass().
5408 /// This function attempts to load the dictionary for 'classname' from
5409 /// the TClassTable or the autoloader.
5410 /// If silent is 'true', do not warn about missing dictionary for the class.
5411 /// (typically used for class that are used only for transient members)
5412 ///
5413 /// The 'requestedname' is expected to be already normalized.
5414 
5415 TClass *TClass::LoadClassDefault(const char *requestedname, Bool_t /* silent */)
5416 {
5417  // This function does not (and should not) attempt to check in the
5418  // list of loaded classes or in the typedef.
5419 
5420  DictFuncPtr_t dict = TClassTable::GetDictNorm(requestedname);
5421 
5422  if (!dict) {
5423  if (gInterpreter->AutoLoad(requestedname,kTRUE)) {
5424  dict = TClassTable::GetDictNorm(requestedname);
5425  }
5426  }
5427 
5428  if (dict) {
5429  TClass *ncl = (dict)();
5430  if (ncl) ncl->PostLoadCheck();
5431  return ncl;
5432  }
5433  return 0;
5434 }
5435 
5436 ////////////////////////////////////////////////////////////////////////////////
5437 /// Helper function used by TClass::GetClass().
5438 /// This function attempts to load the dictionary for 'classname'
5439 /// from the list of generator.
5440 /// If silent is 'true', do not warn about missing dictionary for the class.
5441 /// (typically used for class that are used only for transient members)
5442 ///
5443 /// The 'requestedname' is expected to be alr