Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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 TClass instances represent classes, structs and namespaces in the ROOT type system.
14 
15 TClass instances are created starting from different sources of information:
16 1. TStreamerInfo instances saved in a ROOT file which is opened. This is called in jargon an *emulated TClass*.
17 2. From TProtoClass instances saved in a ROOT pcm file created by the dictionary generator and the dictionary itself.
18 3. From a lookup in the AST built by cling.
19 
20 If a TClass instance is built through the mechanisms 1. and 2., it does not contain information about methods of the
21 class/struct/namespace it represents. Conversely, if built through 3. or 1., it does not carry the information which is necessary
22 to ROOT to perform I/O of instances of the class/struct it represents.
23 The mechanisms 1., 2. and 3. are not mutually exclusive: it can happen that during the execution of the program, all
24 the three are triggered, modifying the state of the TClass instance.
25 
26 In order to retrieve a TClass instance from the type system, a query can be executed as follows through the static
27 TClass::GetClass method:
28 
29 ~~~ {.cpp}
30 auto myClassTClass_0 = TClass::GetClass("myClass");
31 auto myClassTClass_1 = TClass::GetClass<myClass>();
32 auto myClassTClass_2 = TClass::GetClass(myClassTypeInfo);
33 ~~~
34 
35 The name of classes is crucial for ROOT. A careful procedure of *name normalization* is carried out for
36 each and every class. A *normalized name* is a valid C++ class name.
37 In order to access the name of a class within the ROOT type system, the method TClass::GetName() can be used.
38 */
39 
40 //*-*x7.5 macros/layout_class
41 
42 #include "TClass.h"
43 
44 #include "Riostream.h"
45 #include "TBaseClass.h"
46 #include "TBrowser.h"
47 #include "TBuffer.h"
48 #include "TClassGenerator.h"
49 #include "TClassEdit.h"
50 #include "TClassMenuItem.h"
51 #include "TClassRef.h"
52 #include "TClassTable.h"
53 #include "TDataMember.h"
54 #include "TDataType.h"
55 #include "TError.h"
56 #include "TExMap.h"
57 #include "TFunctionTemplate.h"
58 #include "THashList.h"
59 #include "TInterpreter.h"
60 #include "TMemberInspector.h"
61 #include "TMethod.h"
62 #include "TMethodArg.h"
63 #include "TMethodCall.h"
64 #include "TObjArray.h"
65 #include "TProtoClass.h"
66 #include "TROOT.h"
67 #include "TRealData.h"
68 #include "TCheckHashRecursiveRemoveConsistency.h" // Private header
69 #include "TStreamer.h"
70 #include "TStreamerElement.h"
71 #include "TVirtualStreamerInfo.h"
73 #include "TVirtualIsAProxy.h"
74 #include "TVirtualRefProxy.h"
75 #include "TVirtualMutex.h"
76 #include "TVirtualPad.h"
77 #include "THashTable.h"
78 #include "TSchemaRuleSet.h"
79 #include "TGenericClassInfo.h"
80 #include "TIsAProxy.h"
81 #include "TSchemaRule.h"
82 #include "TSystem.h"
83 #include "TThreadSlots.h"
84 
85 #include <cstdio>
86 #include <cctype>
87 #include <set>
88 #include <sstream>
89 #include <string>
90 #include <map>
91 #include <typeinfo>
92 #include <cmath>
93 #include <assert.h>
94 #include <vector>
95 #include <memory>
96 
97 #include "TSpinLockGuard.h"
98 
99 #ifdef WIN32
100 #include <io.h>
101 #include "Windows4Root.h"
102 #include <Psapi.h>
103 #define RTLD_DEFAULT ((void *)::GetModuleHandle(NULL))
104 #define dlsym(library, function_name) ::GetProcAddress((HMODULE)library, function_name)
105 #else
106 #include <dlfcn.h>
107 #endif
108 
109 #include "TListOfDataMembers.h"
110 #include "TListOfFunctions.h"
112 #include "TListOfEnums.h"
113 #include "TListOfEnumsWithLock.h"
114 #include "TViewPubDataMembers.h"
115 #include "TViewPubFunctions.h"
116 #include "TArray.h"
117 #include "TClonesArray.h"
118 #include "TRef.h"
119 #include "TRefArray.h"
120 
121 using namespace std;
122 
123 // Mutex to protect CINT and META operations
124 // (exported to be used for similar cases in related classes)
125 
126 TVirtualMutex* gInterpreterMutex = 0;
127 
128 namespace {
129 
130  static constexpr const char kUndeterminedClassInfoName[] = "<NOT YET DETERMINED FROM fClassInfo>";
131 
132  class TMmallocDescTemp {
133  private:
134  void *fSave;
135  public:
136  TMmallocDescTemp(void *value = 0) :
137  fSave(ROOT::Internal::gMmallocDesc) { ROOT::Internal::gMmallocDesc = value; }
138  ~TMmallocDescTemp() { ROOT::Internal::gMmallocDesc = fSave; }
139  };
140 }
141 
142 std::atomic<Int_t> TClass::fgClassCount;
143 
144 // Implementation of the TDeclNameRegistry
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// TDeclNameRegistry class constructor.
148 
149 TClass::TDeclNameRegistry::TDeclNameRegistry(Int_t verbLevel): fVerbLevel(verbLevel)
150 {
151  // MSVC doesn't support fSpinLock=ATOMIC_FLAG_INIT; in the class definition
152  std::atomic_flag_clear( &fSpinLock );
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Extract this part of the name
157 /// 1. Templates ns::ns2::,,,::THISPART<...
158 /// 2. Namespaces,classes ns::ns2::,,,::THISPART
159 
160 void TClass::TDeclNameRegistry::AddQualifiedName(const char *name)
161 {
162  // Sanity check
163  auto strLen = strlen(name);
164  if (strLen == 0) return;
165  // find <. If none, put end of string
166  const char* endCharPtr = strchr(name, '<');
167  endCharPtr = !endCharPtr ? &name[strLen] : endCharPtr;
168  // find last : before the <. If not found, put begin of string
169  const char* beginCharPtr = endCharPtr;
170  while (beginCharPtr!=name){
171  if (*beginCharPtr==':'){
172  beginCharPtr++;
173  break;
174  }
175  beginCharPtr--;
176  }
177  beginCharPtr = beginCharPtr!=endCharPtr ? beginCharPtr : name;
178  std::string s(beginCharPtr, endCharPtr);
179  if (fVerbLevel>1)
180  printf("TDeclNameRegistry::AddQualifiedName Adding key %s for class/namespace %s\n", s.c_str(), name);
181  ROOT::Internal::TSpinLockGuard slg(fSpinLock);
182  fClassNamesSet.insert(s);
183 }
184 
185 ////////////////////////////////////////////////////////////////////////////////
186 
187 Bool_t TClass::TDeclNameRegistry::HasDeclName(const char *name) const
188 {
189  Bool_t found = false;
190  {
191  ROOT::Internal::TSpinLockGuard slg(fSpinLock);
192  found = fClassNamesSet.find(name) != fClassNamesSet.end();
193  }
194  return found;
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 
199 TClass::TDeclNameRegistry::~TDeclNameRegistry()
200 {
201  if (fVerbLevel > 1) {
202  printf("TDeclNameRegistry Destructor. List of %lu names:\n",
203  (long unsigned int)fClassNamesSet.size());
204  for (auto const & key: fClassNamesSet) {
205  printf(" - %s\n", key.c_str());
206  }
207  }
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 
212 TClass::InsertTClassInRegistryRAII::InsertTClassInRegistryRAII(TClass::EState &state,
213  const char *name,
214  TDeclNameRegistry &emuRegistry): fState(state),fName(name), fNoInfoOrEmuOrFwdDeclNameRegistry(emuRegistry) {}
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 
218 TClass::InsertTClassInRegistryRAII::~InsertTClassInRegistryRAII() {
219  if (fState == TClass::kNoInfo ||
220  fState == TClass::kEmulated ||
221  fState == TClass::kForwardDeclared){
222  fNoInfoOrEmuOrFwdDeclNameRegistry.AddQualifiedName(fName);
223  }
224  }
225 
226 // Initialise the global member of TClass
227 TClass::TDeclNameRegistry TClass::fNoInfoOrEmuOrFwdDeclNameRegistry;
228 
229 //Intent of why/how TClass::New() is called
230 //[Not a static data member because MacOS does not support static thread local data member ... who knows why]
231 TClass::ENewType &TClass__GetCallingNew() {
232  TTHREAD_TLS(TClass::ENewType) fgCallingNew = TClass::kRealNew;
233  return fgCallingNew;
234 }
235 
236 struct ObjRepoValue {
237  ObjRepoValue(const TClass *what, Version_t version) : fClass(what),fVersion(version) {}
238  const TClass *fClass;
239  Version_t fVersion;
240 };
241 
242 static TVirtualMutex* gOVRMutex = 0;
243 typedef std::multimap<void*, ObjRepoValue> RepoCont_t;
244 static RepoCont_t gObjectVersionRepository;
245 
246 static void RegisterAddressInRepository(const char * /*where*/, void *location, const TClass *what)
247 {
248  // Register the object for special handling in the destructor.
249 
250  Version_t version = what->GetClassVersion();
251 // if (!gObjectVersionRepository.count(location)) {
252 // Info(where, "Registering address %p of class '%s' version %d", location, what->GetName(), version);
253 // } else {
254 // Warning(where, "Registering address %p again of class '%s' version %d", location, what->GetName(), version);
255 // }
256  {
257  R__LOCKGUARD2(gOVRMutex);
258  gObjectVersionRepository.insert(RepoCont_t::value_type(location, RepoCont_t::mapped_type(what,version)));
259  }
260 #if 0
261  // This code could be used to prevent an address to be registered twice.
262  std::pair<RepoCont_t::iterator, Bool_t> tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version)));
263  if (!tmp.second) {
264  Warning(where, "Reregistering an object of class '%s' version %d at address %p", what->GetName(), version, p);
265  gObjectVersionRepository.erase(tmp.first);
266  tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version)));
267  if (!tmp.second) {
268  Warning(where, "Failed to reregister an object of class '%s' version %d at address %p", what->GetName(), version, location);
269  }
270  }
271 #endif
272 }
273 
274 static void UnregisterAddressInRepository(const char * /*where*/, void *location, const TClass *what)
275 {
276  // Remove an address from the repository of address/object.
277 
278  R__LOCKGUARD2(gOVRMutex);
279  RepoCont_t::iterator cur = gObjectVersionRepository.find(location);
280  for (; cur != gObjectVersionRepository.end();) {
281  RepoCont_t::iterator tmp = cur++;
282  if ((tmp->first == location) && (tmp->second.fVersion == what->GetClassVersion())) {
283  // -- We still have an address, version match.
284  // Info(where, "Unregistering address %p of class '%s' version %d", location, what->GetName(), what->GetClassVersion());
285  gObjectVersionRepository.erase(tmp);
286  } else {
287  // -- No address, version match, we've reached the end.
288  break;
289  }
290  }
291 }
292 
293 static void MoveAddressInRepository(const char * /*where*/, void *oldadd, void *newadd, const TClass *what)
294 {
295  // Register in the repository that an object has moved.
296 
297  // Move not only the object itself but also any base classes or sub-objects.
298  size_t objsize = what->Size();
299  long delta = (char*)newadd - (char*)oldadd;
300  R__LOCKGUARD2(gOVRMutex);
301  RepoCont_t::iterator cur = gObjectVersionRepository.find(oldadd);
302  for (; cur != gObjectVersionRepository.end();) {
303  RepoCont_t::iterator tmp = cur++;
304  if (oldadd <= tmp->first && tmp->first < ( ((char*)oldadd) + objsize) ) {
305  // The location is within the object, let's move it.
306 
307  gObjectVersionRepository.insert(RepoCont_t::value_type(((char*)tmp->first)+delta, RepoCont_t::mapped_type(tmp->second.fClass,tmp->second.fVersion)));
308  gObjectVersionRepository.erase(tmp);
309 
310  } else {
311  // -- No address, version match, we've reached the end.
312  break;
313  }
314  }
315 }
316 
317 //______________________________________________________________________________
318 //______________________________________________________________________________
319 namespace ROOT {
320 #define R__USE_STD_MAP
321  class TMapTypeToTClass {
322 #if defined R__USE_STD_MAP
323  // This wrapper class allow to avoid putting #include <map> in the
324  // TROOT.h header file.
325  public:
326  typedef std::map<std::string,TClass*> IdMap_t;
327  typedef IdMap_t::key_type key_type;
328  typedef IdMap_t::const_iterator const_iterator;
329  typedef IdMap_t::size_type size_type;
330 #ifdef R__WIN32
331  // Window's std::map does NOT defined mapped_type
332  typedef TClass* mapped_type;
333 #else
334  typedef IdMap_t::mapped_type mapped_type;
335 #endif
336 
337  private:
338  IdMap_t fMap;
339 
340  public:
341  void Add(const key_type &key, mapped_type &obj)
342  {
343  // Add the <key,obj> pair to the map.
344  fMap[key] = obj;
345  }
346  mapped_type Find(const key_type &key) const
347  {
348  // Find the type corresponding to the key.
349  IdMap_t::const_iterator iter = fMap.find(key);
350  mapped_type cl = 0;
351  if (iter != fMap.end()) cl = iter->second;
352  return cl;
353  }
354  void Remove(const key_type &key) {
355  // Remove the type corresponding to the key.
356  fMap.erase(key);
357  }
358 #else
359  private:
360  TMap fMap;
361 
362  public:
363 #ifdef R__COMPLETE_MEM_TERMINATION
364  TMapTypeToTClass() {
365  TIter next(&fMap);
366  TObjString *key;
367  while((key = (TObjString*)next())) {
368  delete key;
369  }
370  }
371 #endif
372  void Add(const char *key, TClass *&obj) {
373  TObjString *realkey = new TObjString(key);
374  fMap.Add(realkey, obj);
375  }
376  TClass* Find(const char *key) const {
377  const TPair *a = (const TPair *)fMap.FindObject(key);
378  if (a) return (TClass*) a->Value();
379  return 0;
380  }
381  void Remove(const char *key) {
382  TObjString realkey(key);
383  TObject *actual = fMap.Remove(&realkey);
384  delete actual;
385  }
386 #endif
387  };
388 
389  class TMapDeclIdToTClass {
390  // Wrapper class for the multimap of DeclId_t and TClass.
391  public:
392  typedef multimap<TDictionary::DeclId_t, TClass*> DeclIdMap_t;
393  typedef DeclIdMap_t::key_type key_type;
394  typedef DeclIdMap_t::mapped_type mapped_type;
395  typedef DeclIdMap_t::const_iterator const_iterator;
396  typedef std::pair <const_iterator, const_iterator> equal_range;
397  typedef DeclIdMap_t::size_type size_type;
398 
399  private:
400  DeclIdMap_t fMap;
401 
402  public:
403  void Add(const key_type &key, mapped_type obj)
404  {
405  // Add the <key,obj> pair to the map.
406  std::pair<const key_type, mapped_type> pair = make_pair(key, obj);
407  fMap.insert(pair);
408  }
409  size_type CountElementsWithKey(const key_type &key)
410  {
411  return fMap.count(key);
412  }
413  equal_range Find(const key_type &key) const
414  {
415  // Find the type corresponding to the key.
416  return fMap.equal_range(key);
417  }
418  void Remove(const key_type &key) {
419  // Remove the type corresponding to the key.
420  fMap.erase(key);
421  }
422  };
423 }
424 
425 IdMap_t *TClass::GetIdMap() {
426 
427 #ifdef R__COMPLETE_MEM_TERMINATION
428  static IdMap_t gIdMapObject;
429  return &gIdMapObject;
430 #else
431  static IdMap_t *gIdMap = new IdMap_t;
432  return gIdMap;
433 #endif
434 }
435 
436 DeclIdMap_t *TClass::GetDeclIdMap() {
437 
438 #ifdef R__COMPLETE_MEM_TERMINATION
439  static DeclIdMap_t gDeclIdMapObject;
440  return &gDeclIdMapObject;
441 #else
442  static DeclIdMap_t *gDeclIdMap = new DeclIdMap_t;
443  return gDeclIdMap;
444 #endif
445 }
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// static: Add a class to the list and map of classes.
449 
450 void TClass::AddClass(TClass *cl)
451 {
452  if (!cl) return;
453 
454  R__LOCKGUARD(gInterpreterMutex);
455  gROOT->GetListOfClasses()->Add(cl);
456  if (cl->GetTypeInfo()) {
457  GetIdMap()->Add(cl->GetTypeInfo()->name(),cl);
458  }
459  if (cl->fClassInfo) {
460  GetDeclIdMap()->Add((void*)(cl->fClassInfo), cl);
461  }
462 }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// static: Add a TClass* to the map of classes.
466 
467 void TClass::AddClassToDeclIdMap(TDictionary::DeclId_t id, TClass* cl)
468 {
469  if (!cl || !id) return;
470  GetDeclIdMap()->Add(id, cl);
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// static: Remove a class from the list and map of classes
475 
476 void TClass::RemoveClass(TClass *oldcl)
477 {
478  if (!oldcl) return;
479 
480  R__LOCKGUARD(gInterpreterMutex);
481  gROOT->GetListOfClasses()->Remove(oldcl);
482  if (oldcl->GetTypeInfo()) {
483  GetIdMap()->Remove(oldcl->GetTypeInfo()->name());
484  }
485  if (oldcl->fClassInfo) {
486  //GetDeclIdMap()->Remove((void*)(oldcl->fClassInfo));
487  }
488 }
489 
490 ////////////////////////////////////////////////////////////////////////////////
491 
492 void TClass::RemoveClassDeclId(TDictionary::DeclId_t id)
493 {
494  if (!id) return;
495  GetDeclIdMap()->Remove(id);
496 }
497 
498 ////////////////////////////////////////////////////////////////////////////////
499 /// Indirect call to the implementation of ShowMember allowing [forward]
500 /// declaration with out a full definition of the TClass class.
501 
502 void ROOT::Class_ShowMembers(TClass *cl, const void *obj, TMemberInspector&insp)
503 {
504  gInterpreter->InspectMembers(insp, obj, cl, kFALSE);
505 }
506 
507 //______________________________________________________________________________
508 //______________________________________________________________________________
509 
510 class TDumpMembers : public TMemberInspector {
511  bool fNoAddr;
512 public:
513  TDumpMembers(bool noAddr): fNoAddr(noAddr) { }
514 
515  using TMemberInspector::Inspect;
516  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
517 };
518 
519 ////////////////////////////////////////////////////////////////////////////////
520 /// Print value of member mname.
521 ///
522 /// This method is called by the ShowMembers() method for each
523 /// data member when object.Dump() is invoked.
524 ///
525 /// - cl is the pointer to the current class
526 /// - pname is the parent name (in case of composed objects)
527 /// - mname is the data member name
528 /// - add is the data member address
529 
530 void TDumpMembers::Inspect(TClass *cl, const char *pname, const char *mname, const void *add, Bool_t /* isTransient */)
531 {
532  const Int_t kvalue = 30;
533 #ifdef R__B64
534  const Int_t ktitle = 50;
535 #else
536  const Int_t ktitle = 42;
537 #endif
538  const Int_t kline = 1024;
539  Int_t cdate = 0;
540  Int_t ctime = 0;
541  UInt_t *cdatime = 0;
542  char line[kline];
543 
544  TDataType *membertype;
545  EDataType memberDataType = kNoType_t;
546  const char *memberName;
547  const char *memberFullTypeName;
548  const char *memberTitle;
549  Bool_t isapointer;
550  Bool_t isbasic;
551 
552  if (TDataMember *member = cl->GetDataMember(mname)) {
553  if (member->GetDataType()) {
554  memberDataType = (EDataType)member->GetDataType()->GetType();
555  }
556  memberName = member->GetName();
557  memberFullTypeName = member->GetFullTypeName();
558  memberTitle = member->GetTitle();
559  isapointer = member->IsaPointer();
560  isbasic = member->IsBasic();
561  membertype = member->GetDataType();
562  } else if (!cl->IsLoaded()) {
563  // The class is not loaded, hence it is 'emulated' and the main source of
564  // information is the StreamerInfo.
565  TVirtualStreamerInfo *info = cl->GetStreamerInfo();
566  if (!info) return;
567  const char *cursor = mname;
568  while ( (*cursor)=='*' ) ++cursor;
569  TString elname( cursor );
570  Ssiz_t pos = elname.Index("[");
571  if ( pos != kNPOS ) {
572  elname.Remove( pos );
573  }
574  TStreamerElement *element = (TStreamerElement*)info->GetElements()->FindObject(elname.Data());
575  if (!element) return;
576  memberFullTypeName = element->GetTypeName();
577 
578  memberDataType = (EDataType)element->GetType();
579 
580  memberName = element->GetName();
581  memberTitle = element->GetTitle();
582  isapointer = element->IsaPointer() || element->GetType() == TVirtualStreamerInfo::kCharStar;
583  membertype = gROOT->GetType(memberFullTypeName);
584 
585  isbasic = membertype !=0;
586  } else {
587  return;
588  }
589 
590 
591  Bool_t isdate = kFALSE;
592  if (strcmp(memberName,"fDatime") == 0 && memberDataType == kUInt_t) {
593  isdate = kTRUE;
594  }
595  Bool_t isbits = kFALSE;
596  if (strcmp(memberName,"fBits") == 0 && memberDataType == kUInt_t) {
597  isbits = kTRUE;
598  }
599  TClass * dataClass = TClass::GetClass(memberFullTypeName);
600  Bool_t isTString = (dataClass == TString::Class());
601  static TClassRef stdClass("std::string");
602  Bool_t isStdString = (dataClass == stdClass);
603 
604  Int_t i;
605  for (i = 0;i < kline; i++) line[i] = ' ';
606  line[kline-1] = 0;
607  snprintf(line,kline,"%s%s ",pname,mname);
608  i = strlen(line); line[i] = ' ';
609 
610  // Encode data value or pointer value
611  char *pointer = (char*)add;
612  char **ppointer = (char**)(pointer);
613 
614  if (isapointer) {
615  char **p3pointer = (char**)(*ppointer);
616  if (!p3pointer)
617  snprintf(&line[kvalue],kline-kvalue,"->0");
618  else if (!isbasic) {
619  if (!fNoAddr) {
620  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)p3pointer);
621  }
622  } else if (membertype) {
623  if (!strcmp(membertype->GetTypeName(), "char")) {
624  i = strlen(*ppointer);
625  if (kvalue+i > kline) i=kline-1-kvalue;
626  Bool_t isPrintable = kTRUE;
627  for (Int_t j = 0; j < i; j++) {
628  if (!std::isprint((*ppointer)[j])) {
629  isPrintable = kFALSE;
630  break;
631  }
632  }
633  if (isPrintable) {
634  strncpy(line + kvalue, *ppointer, i);
635  line[kvalue+i] = 0;
636  } else {
637  line[kvalue] = 0;
638  }
639  } else {
640  strncpy(&line[kvalue], membertype->AsString(p3pointer), TMath::Min(kline-1-kvalue,(int)strlen(membertype->AsString(p3pointer))));
641  }
642  } else if (!strcmp(memberFullTypeName, "char*") ||
643  !strcmp(memberFullTypeName, "const char*")) {
644  i = strlen(*ppointer);
645  if (kvalue+i >= kline) i=kline-1-kvalue;
646  Bool_t isPrintable = kTRUE;
647  for (Int_t j = 0; j < i; j++) {
648  if (!std::isprint((*ppointer)[j])) {
649  isPrintable = kFALSE;
650  break;
651  }
652  }
653  if (isPrintable) {
654  strncpy(line + kvalue, *ppointer, std::min( i, kline - kvalue));
655  line[kvalue+i] = 0;
656  } else {
657  line[kvalue] = 0;
658  }
659  } else {
660  if (!fNoAddr) {
661  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)p3pointer);
662  }
663  }
664  } else if (membertype) {
665  if (isdate) {
666  cdatime = (UInt_t*)pointer;
667  TDatime::GetDateTime(cdatime[0],cdate,ctime);
668  snprintf(&line[kvalue],kline-kvalue,"%d/%d",cdate,ctime);
669  } else if (isbits) {
670  snprintf(&line[kvalue],kline-kvalue,"0x%08x", *(UInt_t*)pointer);
671  } else {
672  strncpy(&line[kvalue], membertype->AsString(pointer), TMath::Min(kline-1-kvalue,(int)strlen(membertype->AsString(pointer))));
673  }
674  } else {
675  if (isStdString) {
676  std::string *str = (std::string*)pointer;
677  snprintf(&line[kvalue],kline-kvalue,"%s",str->c_str());
678  } else if (isTString) {
679  TString *str = (TString*)pointer;
680  snprintf(&line[kvalue],kline-kvalue,"%s",str->Data());
681  } else {
682  if (!fNoAddr) {
683  snprintf(&line[kvalue],kline-kvalue,"->%lx ", (Long_t)pointer);
684  }
685  }
686  }
687  // Encode data member title
688  if (isdate == kFALSE && strcmp(memberFullTypeName, "char*") && strcmp(memberFullTypeName, "const char*")) {
689  i = strlen(&line[0]); line[i] = ' ';
690  assert(250 > ktitle);
691  strlcpy(&line[ktitle],memberTitle,250-ktitle+1); // strlcpy copy 'size-1' characters.
692  }
693  Printf("%s", line);
694 }
695 
696 THashTable* TClass::fgClassTypedefHash = 0;
697 
698 //______________________________________________________________________________
699 //______________________________________________________________________________
700 ////////////////////////////////////////////////////////////////////////////////
701 
702 TClass::TNameMapNode::TNameMapNode (const char* typedf, const char* orig)
703  : TObjString (typedf),
704  fOrigName (orig)
705 {
706 }
707 
708 //______________________________________________________________________________
709 
710 class TBuildRealData : public TMemberInspector {
711 
712 private:
713  void *fRealDataObject;
714  TClass *fRealDataClass;
715 
716 public:
717  TBuildRealData(void *obj, TClass *cl) {
718  // Main constructor.
719  fRealDataObject = obj;
720  fRealDataClass = cl;
721  }
722  using TMemberInspector::Inspect;
723  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
724 
725 };
726 
727 ////////////////////////////////////////////////////////////////////////////////
728 /// This method is called from ShowMembers() via BuildRealdata().
729 
730 void TBuildRealData::Inspect(TClass* cl, const char* pname, const char* mname, const void* add, Bool_t isTransient)
731 {
732  TDataMember* dm = cl->GetDataMember(mname);
733  if (!dm) {
734  return;
735  }
736 
737  Bool_t isTransientMember = kFALSE;
738 
739  if (!dm->IsPersistent()) {
740  // For the DataModelEvolution we need access to the transient member.
741  // so we now record them in the list of RealData.
742  isTransientMember = kTRUE;
743  isTransient = kTRUE;
744  }
745 
746  TString rname( pname );
747  // Take into account cases like TPaveStats->TPaveText->TPave->TBox.
748  // Check that member is in a derived class or an object in the class.
749  if (cl != fRealDataClass) {
750  if (!fRealDataClass->InheritsFrom(cl)) {
751  Ssiz_t dot = rname.Index('.');
752  if (dot == kNPOS) {
753  return;
754  }
755  rname[dot] = '\0';
756  if (!fRealDataClass->GetDataMember(rname)) {
757  //could be a data member in a base class like in this example
758  // class Event : public Data {
759  // class Data : public TObject {
760  // EventHeader fEvtHdr;
761  // class EventHeader {
762  // Int_t fEvtNum;
763  // Int_t fRun;
764  // Int_t fDate;
765  // EventVertex fVertex;
766  // class EventVertex {
767  // EventTime fTime;
768  // class EventTime {
769  // Int_t fSec;
770  // Int_t fNanoSec;
771  if (!fRealDataClass->GetBaseDataMember(rname)) {
772  return;
773  }
774  }
775  rname[dot] = '.';
776  }
777  }
778 
779  Long_t offset = Long_t(((Long_t) add) - ((Long_t) fRealDataObject));
780 
781  if (TClassEdit::IsStdArray(dm->GetTypeName())){ // We tackle the std array case
782  TString rdName;
783  TRealData::GetName(rdName,dm);
784  rname += rdName;
785  TRealData* rd = new TRealData(rname.Data(), offset, dm);
786  fRealDataClass->GetListOfRealData()->Add(rd);
787  return;
788  }
789 
790  rname += mname;
791 
792  if (dm->IsaPointer()) {
793  // Data member is a pointer.
794  TRealData* rd = new TRealData(rname, offset, dm);
795  if (isTransientMember) { rd->SetBit(TRealData::kTransient); };
796  fRealDataClass->GetListOfRealData()->Add(rd);
797  } else {
798  // Data Member is a basic data type.
799  TRealData* rd = new TRealData(rname, offset, dm);
800  if (isTransientMember) { rd->SetBit(TRealData::kTransient); };
801  if (!dm->IsBasic()) {
802  rd->SetIsObject(kTRUE);
803 
804  // Make sure that BuildReadData is called for any abstract
805  // bases classes involved in this object, i.e for all the
806  // classes composing this object (base classes, type of
807  // embedded object and same for their data members).
808  //
809  TClass* dmclass = TClass::GetClass(dm->GetTypeName(), kTRUE, isTransient);
810  if (!dmclass) {
811  dmclass = TClass::GetClass(dm->GetTrueTypeName(), kTRUE, isTransient);
812  }
813  if (dmclass) {
814  if ((dmclass != cl) && !dm->IsaPointer()) {
815  if (dmclass->GetCollectionProxy()) {
816  TClass* valcl = dmclass->GetCollectionProxy()->GetValueClass();
817  // We create the real data for the content of the collection to help the case
818  // of split branches in a TTree (where the node for the data member itself
819  // might have been elided). However, in some cases, like transient members
820  // and/or classes, the content might not be create-able. An example is the
821  // case of a map<A,B> where either A or B does not have default constructor
822  // and thus the compilation of the default constructor for pair<A,B> will
823  // fail (noisily) [This could also apply to any template instance, where it
824  // might have a default constructor definition that can not be compiled due
825  // to the template parameter]
826  if (valcl) {
827  Bool_t wantBuild = kTRUE;
828  if (valcl->Property() & kIsAbstract) wantBuild = kFALSE;
829  if ( (isTransient)
830  && (dmclass->GetCollectionProxy()->GetProperties() & TVirtualCollectionProxy::kIsEmulated)
831  && (!valcl->IsLoaded()) ) {
832  // Case where the collection dictionary was not requested and
833  // the content's dictionary was also not requested.
834  // [This is a super set of what we need, but we can't really detect it :(]
835  wantBuild = kFALSE;
836  }
837 
838  if (wantBuild) valcl->BuildRealData(0, isTransient);
839  }
840  } else {
841  void* addrForRecursion = 0;
842  if (GetObjectValidity() == kValidObjectGiven)
843  addrForRecursion = const_cast<void*>(add);
844 
845  dmclass->BuildRealData(addrForRecursion, isTransient);
846  }
847  }
848  }
849  }
850  fRealDataClass->GetListOfRealData()->Add(rd);
851  }
852 }
853 
854 //______________________________________________________________________________
855 //______________________________________________________________________________
856 //______________________________________________________________________________
857 
858 ////////////////////////////////////////////////////////////////////////////////
859 
860 class TAutoInspector : public TMemberInspector {
861 public:
862  Int_t fCount;
863  TBrowser *fBrowser;
864 
865  TAutoInspector(TBrowser *b) {
866  // main constructor.
867  fBrowser = b; fCount = 0; }
868  virtual ~TAutoInspector() { }
869  using TMemberInspector::Inspect;
870  virtual void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
871  virtual Bool_t IsTreatingNonAccessibleTypes() {return kFALSE;}
872 };
873 
874 ////////////////////////////////////////////////////////////////////////////////
875 /// This method is called from ShowMembers() via AutoBrowse().
876 
877 void TAutoInspector::Inspect(TClass *cl, const char *tit, const char *name,
878  const void *addr, Bool_t /* isTransient */)
879 {
880  if(tit && strchr(tit,'.')) return ;
881  if (fCount && !fBrowser) return;
882 
883  TString ts;
884 
885  if (!cl) return;
886  //if (*(cl->GetName()) == 'T') return;
887  if (*name == '*') name++;
888  int ln = strcspn(name,"[ ");
889  TString iname(name,ln);
890 
891  ClassInfo_t *classInfo = cl->GetClassInfo();
892  if (!classInfo) return;
893 
894  // Browse data members
895  DataMemberInfo_t *m = gCling->DataMemberInfo_Factory(classInfo);
896  TString mname;
897 
898  int found=0;
899  while (gCling->DataMemberInfo_Next(m)) { // MemberLoop
900  mname = gCling->DataMemberInfo_Name(m);
901  mname.ReplaceAll("*","");
902  if ((found = (iname==mname))) break;
903  }
904  assert(found);
905 
906  // we skip: non static members and non objects
907  // - the member G__virtualinfo inserted by the CINT RTTI system
908 
909  //Long_t prop = m.Property() | m.Type()->Property();
910  Long_t prop = gCling->DataMemberInfo_Property(m) | gCling->DataMemberInfo_TypeProperty(m);
911  if (prop & kIsStatic) return;
912  if (prop & kIsFundamental) return;
913  if (prop & kIsEnum) return;
914  if (mname == "G__virtualinfo") return;
915 
916  int size = sizeof(void*);
917 
918  int nmax = 1;
919  if (prop & kIsArray) {
920  for (int dim = 0; dim < gCling->DataMemberInfo_ArrayDim(m); dim++) nmax *= gCling->DataMemberInfo_MaxIndex(m,dim);
921  }
922 
923  std::string clmName(TClassEdit::ShortType(gCling->DataMemberInfo_TypeName(m),
924  TClassEdit::kDropTrailStar) );
925  TClass * clm = TClass::GetClass(clmName.c_str());
926  R__ASSERT(clm);
927  if (!(prop & kIsPointer)) {
928  size = clm->Size();
929  if (size==0) size = gCling->DataMemberInfo_TypeSize(m);
930  }
931 
932 
933  gCling->DataMemberInfo_Delete(m);
934  TVirtualCollectionProxy *proxy = clm->GetCollectionProxy();
935 
936  for(int i=0; i<nmax; i++) {
937 
938  char *ptr = (char*)addr + i*size;
939 
940  void *obj = (prop & kIsPointer) ? *((void**)ptr) : (TObject*)ptr;
941 
942  if (!obj) continue;
943 
944  fCount++;
945  if (!fBrowser) return;
946 
947  TString bwname;
948  TClass *actualClass = clm->GetActualClass(obj);
949  if (clm->IsTObject()) {
950  TObject *tobj = (TObject*)clm->DynamicCast(TObject::Class(),obj);
951  bwname = tobj->GetName();
952  } else {
953  bwname = actualClass->GetName();
954  bwname += "::";
955  bwname += mname;
956  }
957 
958  if (!clm->IsTObject() ||
959  bwname.Length()==0 ||
960  strcmp(bwname.Data(),actualClass->GetName())==0) {
961  bwname = name;
962  int l = strcspn(bwname.Data(),"[ ");
963  if (l<bwname.Length() && bwname[l]=='[') {
964  char cbuf[13]; snprintf(cbuf,13,"[%02d]",i);
965  ts.Replace(0,999,bwname,l);
966  ts += cbuf;
967  bwname = (const char*)ts;
968  }
969  }
970 
971  if (proxy==0) {
972 
973  fBrowser->Add(obj,clm,bwname);
974 
975  } else {
976  TClass *valueCl = proxy->GetValueClass();
977 
978  if (valueCl==0) {
979 
980  fBrowser->Add( obj, clm, bwname );
981 
982  } else {
983  TVirtualCollectionProxy::TPushPop env(proxy, obj);
984  TClass *actualCl = 0;
985 
986  int sz = proxy->Size();
987 
988  char fmt[] = {"#%09d"};
989  fmt[3] = '0'+(int)log10(double(sz))+1;
990  char buf[20];
991  for (int ii=0;ii<sz;ii++) {
992  void *p = proxy->At(ii);
993 
994  if (proxy->HasPointers()) {
995  p = *((void**)p);
996  if(!p) continue;
997  actualCl = valueCl->GetActualClass(p);
998  p = actualCl->DynamicCast(valueCl,p,0);
999  }
1000  fCount++;
1001  snprintf(buf,20,fmt,ii);
1002  ts = bwname;
1003  ts += buf;
1004  fBrowser->Add( p, actualCl, ts );
1005  }
1006  }
1007  }
1008  }
1009 }
1010 
1011 //______________________________________________________________________________
1012 //______________________________________________________________________________
1013 //______________________________________________________________________________
1014 
1015 ClassImp(TClass);
1016 
1017 ////////////////////////////////////////////////////////////////////////////////
1018 
1019 TClass::TClass() :
1020  TDictionary(),
1021  fPersistentRef(0),
1022  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1023  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1024  fAllPubMethod(0), fClassMenuList(0),
1025  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1026  fInstanceCount(0), fOnHeap(0),
1027  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1028  fTypeInfo(0), fShowMembers(0),
1029  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1030  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1031  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1032  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1033  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1034  fState(kNoInfo),
1035  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1036  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1037 
1038 {
1039  // Default ctor.
1040 
1041  R__LOCKGUARD(gInterpreterMutex);
1042  {
1043  TMmallocDescTemp setreset;
1044  fStreamerInfo = new TObjArray(1, -2);
1045  }
1046  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1047 }
1048 
1049 ////////////////////////////////////////////////////////////////////////////////
1050 /// Create a TClass object. This object contains the full dictionary
1051 /// of a class. It has list to baseclasses, datamembers and methods.
1052 /// Use this ctor to create a standalone TClass object. Most useful
1053 /// to get a TClass interface to an interpreted class. Used by TTabCom.
1054 /// Normally you would use TClass::GetClass("class") to get access to a
1055 /// TClass object for a certain class.
1056 
1057 TClass::TClass(const char *name, Bool_t silent) :
1058  TDictionary(name),
1059  fPersistentRef(0),
1060  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1061  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1062  fAllPubMethod(0), fClassMenuList(0),
1063  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1064  fInstanceCount(0), fOnHeap(0),
1065  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1066  fTypeInfo(0), fShowMembers(0),
1067  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1068  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1069  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1070  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1071  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1072  fState(kNoInfo),
1073  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1074  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1075 {
1076  R__LOCKGUARD(gInterpreterMutex);
1077 
1078  if (!gROOT)
1079  ::Fatal("TClass::TClass", "ROOT system not initialized");
1080 
1081  {
1082  TMmallocDescTemp setreset;
1083  fStreamerInfo = new TObjArray(1, -2);
1084  }
1085  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1086 
1087  SetBit(kLoading);
1088  if (!gInterpreter)
1089  ::Fatal("TClass::TClass", "gInterpreter not initialized");
1090 
1091  gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1092  if (!silent && !fClassInfo && fName.First('@')==kNPOS)
1093  ::Warning("TClass::TClass", "no dictionary for class %s is available", name);
1094  ResetBit(kLoading);
1095 
1096  if (fClassInfo) SetTitle(gCling->ClassInfo_Title(fClassInfo));
1097  fConversionStreamerInfo = 0;
1098 }
1099 
1100 ////////////////////////////////////////////////////////////////////////////////
1101 /// Create a TClass object. This object contains the full dictionary
1102 /// of a class. It has list to baseclasses, datamembers and methods.
1103 
1104 TClass::TClass(const char *name, Version_t cversion, Bool_t silent) :
1105  TDictionary(name),
1106  fPersistentRef(0),
1107  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1108  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1109  fAllPubMethod(0), fClassMenuList(0),
1110  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1111  fInstanceCount(0), fOnHeap(0),
1112  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1113  fTypeInfo(0), fShowMembers(0),
1114  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1115  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1116  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1117  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1118  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1119  fState(kNoInfo),
1120  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1121  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1122 {
1123  R__LOCKGUARD(gInterpreterMutex);
1124  Init(name, cversion, 0, 0, 0, 0, -1, -1, 0, silent);
1125 }
1126 
1127 ////////////////////////////////////////////////////////////////////////////////
1128 /// Create a TClass object. This object does not contain anything. We mimic
1129 /// the case of a class fwd declared in the interpreter.
1130 
1131 TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t silent) :
1132  TDictionary(name),
1133  fPersistentRef(0),
1134  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1135  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1136  fAllPubMethod(0), fClassMenuList(0),
1137  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1138  fInstanceCount(0), fOnHeap(0),
1139  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1140  fTypeInfo(0), fShowMembers(0),
1141  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1142  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1143  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1144  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1145  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1146  fState(theState),
1147  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1148  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1149 {
1150  R__LOCKGUARD(gInterpreterMutex);
1151 
1152  // Treat the case in which a TClass instance is created for a namespace
1153  if (theState == kNamespaceForMeta){
1154  fProperty = kIsNamespace;
1155  theState = kForwardDeclared; // it immediately decays in kForwardDeclared
1156  }
1157 
1158  if (theState != kForwardDeclared && theState != kEmulated)
1159  ::Fatal("TClass::TClass",
1160  "A TClass entry cannot be initialized in a state different from kForwardDeclared or kEmulated.");
1161  Init(name, cversion, 0, 0, 0, 0, -1, -1, 0, silent);
1162 }
1163 
1164 ////////////////////////////////////////////////////////////////////////////////
1165 /// Create a TClass object. This object contains the full dictionary
1166 /// of a class. It has list to baseclasses, datamembers and methods.
1167 /// Use this ctor to create a standalone TClass object. Most useful
1168 /// to get a TClass interface to an interpreted class. Used by TTabCom.
1169 /// Normally you would use TClass::GetClass("class") to get access to a
1170 /// TClass object for a certain class.
1171 ///
1172 /// This copies the ClassInfo (i.e. does *not* take ownership of it).
1173 
1174 TClass::TClass(ClassInfo_t *classInfo, Version_t cversion,
1175  const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1176  TDictionary(""),
1177  fPersistentRef(0),
1178  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1179  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1180  fAllPubMethod(0), fClassMenuList(0),
1181  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1182  fInstanceCount(0), fOnHeap(0),
1183  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1184  fTypeInfo(0), fShowMembers(0),
1185  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1186  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1187  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1188  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1189  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1190  fState(kNoInfo),
1191  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1192  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1193 {
1194  R__LOCKGUARD(gInterpreterMutex);
1195 
1196  if (!gROOT)
1197  ::Fatal("TClass::TClass", "ROOT system not initialized");
1198 
1199  fDeclFileLine = -2; // -2 for standalone TClass (checked in dtor)
1200 
1201  SetBit(kLoading);
1202  if (!gInterpreter)
1203  ::Fatal("TClass::TClass", "gInterpreter not initialized");
1204 
1205  if (!classInfo || !gInterpreter->ClassInfo_IsValid(classInfo)) {
1206  MakeZombie();
1207  fState = kNoInfo;
1208  } else {
1209  fName = gInterpreter->ClassInfo_FullName(classInfo);
1210 
1211  R__LOCKGUARD(gInterpreterMutex);
1212  Init(fName, cversion, 0, 0, dfil, ifil, dl, il, classInfo, silent);
1213  }
1214  ResetBit(kLoading);
1215 
1216  fConversionStreamerInfo = 0;
1217 }
1218 
1219 
1220 ////////////////////////////////////////////////////////////////////////////////
1221 /// Create a TClass object. This object contains the full dictionary
1222 /// of a class. It has list to baseclasses, datamembers and methods.
1223 
1224 TClass::TClass(const char *name, Version_t cversion,
1225  const char *dfil, const char *ifil, Int_t dl, Int_t il, Bool_t silent) :
1226  TDictionary(name),
1227  fPersistentRef(0),
1228  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1229  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1230  fAllPubMethod(0), fClassMenuList(0),
1231  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1232  fInstanceCount(0), fOnHeap(0),
1233  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1234  fTypeInfo(0), fShowMembers(0),
1235  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1236  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1237  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1238  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1239  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1240  fState(kNoInfo),
1241  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1242  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1243 {
1244  R__LOCKGUARD(gInterpreterMutex);
1245  Init(name,cversion, 0, 0, dfil, ifil, dl, il, 0, silent);
1246 }
1247 
1248 ////////////////////////////////////////////////////////////////////////////////
1249 /// Create a TClass object. This object contains the full dictionary
1250 /// of a class. It has list to baseclasses, datamembers and methods.
1251 
1252 TClass::TClass(const char *name, Version_t cversion,
1253  const std::type_info &info, TVirtualIsAProxy *isa,
1254  const char *dfil, const char *ifil, Int_t dl, Int_t il,
1255  Bool_t silent) :
1256  TDictionary(name),
1257  fPersistentRef(0),
1258  fStreamerInfo(0), fConversionStreamerInfo(0), fRealData(0),
1259  fBase(0), fData(0), fEnums(0), fFuncTemplate(0), fMethod(0), fAllPubData(0),
1260  fAllPubMethod(0),
1261  fClassMenuList(0),
1262  fDeclFileName(""), fImplFileName(""), fDeclFileLine(0), fImplFileLine(0),
1263  fInstanceCount(0), fOnHeap(0),
1264  fCheckSum(0), fCollectionProxy(0), fClassVersion(0), fClassInfo(0),
1265  fTypeInfo(0), fShowMembers(0),
1266  fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0),
1267  fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0),
1268  fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1),
1269  fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE),
1270  fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault),
1271  fState(kHasTClassInit),
1272  fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0),
1273  fSchemaRules(0), fStreamerImpl(&TClass::StreamerDefault)
1274 {
1275  R__LOCKGUARD(gInterpreterMutex);
1276  // use info
1277  Init(name, cversion, &info, isa, dfil, ifil, dl, il, 0, silent);
1278 }
1279 
1280 ////////////////////////////////////////////////////////////////////////////////
1281 /// we found at least one equivalent.
1282 /// let's force a reload
1283 
1284 void TClass::ForceReload (TClass* oldcl)
1285 {
1286  TClass::RemoveClass(oldcl);
1287 
1288  if (oldcl->CanIgnoreTObjectStreamer()) {
1289  IgnoreTObjectStreamer();
1290  }
1291 
1292  TVirtualStreamerInfo *info;
1293  TIter next(oldcl->GetStreamerInfos());
1294  while ((info = (TVirtualStreamerInfo*)next())) {
1295  info->Clear("build");
1296  info->SetClass(this);
1297  fStreamerInfo->AddAtAndExpand(info,info->GetClassVersion());
1298  }
1299  oldcl->fStreamerInfo->Clear();
1300 
1301  oldcl->ReplaceWith(this);
1302  delete oldcl;
1303 }
1304 
1305 ////////////////////////////////////////////////////////////////////////////////
1306 /// Initialize a TClass object. This object contains the full dictionary
1307 /// of a class. It has list to baseclasses, datamembers and methods.
1308 
1309 void TClass::Init(const char *name, Version_t cversion,
1310  const std::type_info *typeinfo, TVirtualIsAProxy *isa,
1311  const char *dfil, const char *ifil, Int_t dl, Int_t il,
1312  ClassInfo_t *givenInfo,
1313  Bool_t silent)
1314 {
1315  if (!gROOT)
1316  ::Fatal("TClass::TClass", "ROOT system not initialized");
1317  if (!name || !name[0]) {
1318  ::Error("TClass::Init", "The name parameter is invalid (null or empty)");
1319  MakeZombie();
1320  return;
1321  }
1322  // Always strip the default STL template arguments (from any template argument or the class name)
1323  fName = TClassEdit::ShortType(name, TClassEdit::kDropStlDefault).c_str();
1324  fClassVersion = cversion;
1325  fDeclFileName = dfil ? dfil : "";
1326  fImplFileName = ifil ? ifil : "";
1327  fDeclFileLine = dl;
1328  fImplFileLine = il;
1329  fTypeInfo = typeinfo;
1330  fIsA = isa;
1331  if ( fIsA ) fIsA->SetClass(this);
1332  // See also TCling::GenerateTClass() which will update fClassVersion after creation!
1333  fStreamerInfo = new TObjArray(fClassVersion+2+10,-1); // +10 to read new data by old
1334  fProperty = -1;
1335  fClassProperty = 0;
1336 
1337  ResetInstanceCount();
1338 
1339  TClass *oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(fName.Data());
1340 
1341  InsertTClassInRegistryRAII insertRAII(fState,fName,fNoInfoOrEmuOrFwdDeclNameRegistry);
1342 
1343  if (oldcl && oldcl->TestBit(kLoading)) {
1344  // Do not recreate a class while it is already being created!
1345 
1346  // We can no longer reproduce this case, to check whether we are, we use
1347  // this code:
1348  // Fatal("Init","A bad replacement for %s was requested\n",name);
1349  return;
1350  }
1351 
1352  TClass **persistentRef = 0;
1353  if (oldcl) {
1354 
1355  persistentRef = oldcl->fPersistentRef.exchange(0);
1356 
1357  // The code from here is also in ForceReload.
1358  TClass::RemoveClass(oldcl);
1359  // move the StreamerInfo immediately so that there are
1360  // properly updated!
1361 
1362  if (oldcl->CanIgnoreTObjectStreamer()) {
1363  IgnoreTObjectStreamer();
1364  }
1365  TVirtualStreamerInfo *info;
1366 
1367  TIter next(oldcl->GetStreamerInfos());
1368  while ((info = (TVirtualStreamerInfo*)next())) {
1369  // We need to force a call to BuildOld
1370  info->Clear("build");
1371  info->SetClass(this);
1372  fStreamerInfo->AddAtAndExpand(info,info->GetClassVersion());
1373  }
1374  oldcl->fStreamerInfo->Clear();
1375  // The code diverges here from ForceReload.
1376 
1377  // Move the Schema Rules too.
1378  fSchemaRules = oldcl->fSchemaRules;
1379  oldcl->fSchemaRules = 0;
1380 
1381  // Move the TFunctions.
1382  fFuncTemplate = oldcl->fFuncTemplate;
1383  if (fFuncTemplate)
1384  fFuncTemplate->fClass = this;
1385  oldcl->fFuncTemplate = nullptr;
1386  fMethod.store( oldcl->fMethod );
1387  if (fMethod)
1388  (*fMethod).fClass = this;
1389  oldcl->fMethod = nullptr;
1390 
1391  }
1392 
1393  SetBit(kLoading);
1394  // Advertise ourself as the loading class for this class name
1395  TClass::AddClass(this);
1396 
1397  Bool_t isStl = TClassEdit::IsSTLCont(fName);
1398 
1399  if (!gInterpreter)
1400  ::Fatal("TClass::Init", "gInterpreter not initialized");
1401 
1402  if (givenInfo) {
1403  bool invalid = !gInterpreter->ClassInfo_IsValid(givenInfo);
1404  bool notloaded = !gInterpreter->ClassInfo_IsLoaded(givenInfo);
1405  auto property = gInterpreter->ClassInfo_Property(givenInfo);
1406 
1407  if (invalid || (notloaded && (property & kIsNamespace)) ||
1408  !(property & (kIsClass | kIsStruct | kIsNamespace))) {
1409  if (!TClassEdit::IsSTLCont(fName.Data())) {
1410  MakeZombie();
1411  fState = kNoInfo;
1412  TClass::RemoveClass(this);
1413  return;
1414  }
1415  }
1416 
1417  if (!invalid) {
1418  fClassInfo = gInterpreter->ClassInfo_Factory(givenInfo);
1419  fCanLoadClassInfo = false; // avoids calls to LoadClassInfo() if info is already loaded
1420  if (fState <= kEmulated)
1421  fState = kInterpreted;
1422  }
1423  }
1424 
1425  // We need to check if the class it is not fwd declared for the cases where we
1426  // created a TClass directly in the kForwardDeclared state. Indeed in those cases
1427  // fClassInfo will always be nullptr.
1428  if (fState!=kForwardDeclared && !fClassInfo) {
1429 
1430  if (fState == kHasTClassInit) {
1431  // If the TClass is being generated from a ROOT dictionary,
1432  // even though we do not seem to have a CINT dictionary for
1433  // the class, we will will try to load it anyway UNLESS
1434  // the class is an STL container (or string).
1435  // This is because we do not expect the CINT dictionary
1436  // to be present for all STL classes (and we can handle
1437  // the lack of CINT dictionary in that cases).
1438  // However, the cling the dictionary no longer carries
1439  // an instantiation with it, unless we request the loading
1440  // here *or* the user explicitly instantiate the template
1441  // we would not have a ClassInfo for the template
1442  // instantiation.
1443  fCanLoadClassInfo = kTRUE;
1444  // Here we check and grab the info from the rootpcm.
1445  TProtoClass *proto = TClassTable::GetProtoNorm(GetName());
1446  if (proto && proto->FillTClass(this)) {
1447  fHasRootPcmInfo = kTRUE;
1448  }
1449  }
1450  if (!fHasRootPcmInfo && gInterpreter->CheckClassInfo(fName, /* autoload = */ kTRUE)) {
1451  gInterpreter->SetClassInfo(this); // sets fClassInfo pointer
1452  if (fClassInfo) {
1453  // This should be moved out of GetCheckSum itself however the last time
1454  // we tried this cause problem, in particular in the end-of-process operation.
1455  // fCheckSum = GetCheckSum(kLatestCheckSum);
1456  } else {
1457  if (!fClassInfo) {
1458  if (IsZombie()) {
1459  TClass::RemoveClass(this);
1460  return;
1461  }
1462  }
1463  }
1464  }
1465  }
1466  if (!silent && (!fClassInfo && !fCanLoadClassInfo) && !isStl && fName.First('@')==kNPOS &&
1467  !TClassEdit::IsInterpreterDetail(fName.Data()) ) {
1468  if (fState == kHasTClassInit) {
1469  if (fImplFileLine == -1 && fClassVersion == 0) {
1470  // We have a 'transient' class with a ClassDefInline and apparently no interpreter
1471  // information. Since it is transient, it is more than likely that the lack
1472  // will be harmles.
1473  } else {
1474  ::Error("TClass::Init", "no interpreter information for class %s is available even though it has a TClass "
1475  "initialization routine.",
1476  fName.Data());
1477  }
1478  } else {
1479  // In this case we initialised this TClass instance starting from the fwd declared state
1480  // and we know we have no dictionary: no need to warn
1481  ::Warning("TClass::Init", "no dictionary for class %s is available", fName.Data());
1482  }
1483  }
1484 
1485  fgClassCount++;
1486  SetUniqueID(fgClassCount);
1487 
1488  // Make the typedef-expanded -> original hash table entries.
1489  // There may be several entries for any given key.
1490  // We only make entries if the typedef-expanded name
1491  // is different from the original name.
1492  TString resolvedThis;
1493  if (!givenInfo && strchr (name, '<')) {
1494  if ( fName != name) {
1495  if (!fgClassTypedefHash) {
1496  fgClassTypedefHash = new THashTable (100, 5);
1497  fgClassTypedefHash->SetOwner (kTRUE);
1498  }
1499 
1500  fgClassTypedefHash->Add (new TNameMapNode (name, fName));
1501  SetBit (kHasNameMapNode);
1502 
1503  }
1504  resolvedThis = TClassEdit::ResolveTypedef (name, kTRUE);
1505  if (resolvedThis != name) {
1506  if (!fgClassTypedefHash) {
1507  fgClassTypedefHash = new THashTable (100, 5);
1508  fgClassTypedefHash->SetOwner (kTRUE);
1509  }
1510 
1511  fgClassTypedefHash->Add (new TNameMapNode (resolvedThis, fName));
1512  SetBit (kHasNameMapNode);
1513  }
1514 
1515  }
1516 
1517  //In case a class with the same name had been created by TVirtualStreamerInfo
1518  //we must delete the old class, importing only the StreamerInfo structure
1519  //from the old dummy class.
1520  if (oldcl) {
1521 
1522  oldcl->ReplaceWith(this);
1523  delete oldcl;
1524 
1525  } else if (!givenInfo && resolvedThis.Length() > 0 && fgClassTypedefHash) {
1526 
1527  // Check for existing equivalent.
1528 
1529  if (resolvedThis != fName) {
1530  oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(resolvedThis);
1531  if (oldcl && oldcl != this) {
1532  persistentRef = oldcl->fPersistentRef.exchange(0);
1533  ForceReload (oldcl);
1534  }
1535  }
1536  TIter next( fgClassTypedefHash->GetListForObject(resolvedThis) );
1537  while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1538  if (resolvedThis != htmp->String()) continue;
1539  oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(htmp->fOrigName); // gROOT->GetClass (htmp->fOrigName, kFALSE);
1540  if (oldcl && oldcl != this) {
1541  persistentRef = oldcl->fPersistentRef.exchange(0);
1542  ForceReload (oldcl);
1543  }
1544  }
1545  }
1546  if (fClassInfo) {
1547  SetTitle(gCling->ClassInfo_Title(fClassInfo));
1548  if ( fDeclFileName == 0 || fDeclFileName[0] == '\0' ) {
1549  fDeclFileName = kUndeterminedClassInfoName;
1550  // Missing interface:
1551  // fDeclFileLine = gInterpreter->ClassInfo_FileLine( fClassInfo );
1552 
1553  // But really do not want to set ImplFileLine as it is currently the
1554  // marker of being 'loaded' or not (reminder loaded == has a TClass bootstrap).
1555  }
1556  }
1557 
1558  if (persistentRef) {
1559  fPersistentRef = persistentRef;
1560  } else {
1561  fPersistentRef = new TClass*;
1562  }
1563  *fPersistentRef = this;
1564 
1565  if ( isStl || !strncmp(GetName(),"stdext::hash_",13) || !strncmp(GetName(),"__gnu_cxx::hash_",16) ) {
1566  if (fState != kHasTClassInit) {
1567  // If we have a TClass compiled initialization, we can safely assume that
1568  // there will also be a collection proxy.
1569  fCollectionProxy = TVirtualStreamerInfo::Factory()->GenEmulatedProxy( GetName(), silent );
1570  if (fCollectionProxy) {
1571  fSizeof = fCollectionProxy->Sizeof();
1572 
1573  // Numeric Collections have implicit conversions:
1574  GetSchemaRules(kTRUE);
1575 
1576  } else if (!silent) {
1577  Warning("Init","Collection proxy for %s was not properly initialized!",GetName());
1578  }
1579  if (fStreamer==0) {
1580  fStreamer = TVirtualStreamerInfo::Factory()->GenEmulatedClassStreamer( GetName(), silent );
1581  }
1582  }
1583  } else if (!strncmp(GetName(),"std::pair<",10) || !strncmp(GetName(),"pair<",5) ) {
1584  // std::pairs have implicit conversions
1585  GetSchemaRules(kTRUE);
1586  }
1587 
1588  ResetBit(kLoading);
1589 }
1590 
1591 ////////////////////////////////////////////////////////////////////////////////
1592 /// TClass dtor. Deletes all list that might have been created.
1593 
1594 TClass::~TClass()
1595 {
1596  R__LOCKGUARD(gInterpreterMutex);
1597 
1598  // Remove from the typedef hashtables.
1599  if (fgClassTypedefHash && TestBit (kHasNameMapNode)) {
1600  TString resolvedThis = TClassEdit::ResolveTypedef (GetName(), kTRUE);
1601  TIter next (fgClassTypedefHash->GetListForObject (resolvedThis));
1602  while ( TNameMapNode* htmp = static_cast<TNameMapNode*> (next()) ) {
1603  if (resolvedThis == htmp->String() && htmp->fOrigName == GetName()) {
1604  fgClassTypedefHash->Remove (htmp);
1605  delete htmp;
1606  break;
1607  }
1608  }
1609  }
1610 
1611  // Not owning lists, don't call Delete()
1612  // But this still need to be done first because the TList destructor
1613  // does access the object contained (via GetObject()->TestBit(kCanDelete))
1614  delete fStreamer; fStreamer =0;
1615  delete fAllPubData; fAllPubData =0;
1616  delete fAllPubMethod; fAllPubMethod=0;
1617 
1618  delete fPersistentRef.load();
1619 
1620  if (fBase.load())
1621  (*fBase).Delete();
1622  delete fBase.load(); fBase = 0;
1623 
1624  if (fData)
1625  fData->Delete();
1626  delete fData; fData = 0;
1627 
1628  if (fEnums.load())
1629  (*fEnums).Delete();
1630  delete fEnums.load(); fEnums = 0;
1631 
1632  if (fFuncTemplate)
1633  fFuncTemplate->Delete();
1634  delete fFuncTemplate; fFuncTemplate = 0;
1635 
1636  if (fMethod.load())
1637  (*fMethod).Delete();
1638  delete fMethod.load(); fMethod=0;
1639 
1640  if (fRealData)
1641  fRealData->Delete();
1642  delete fRealData; fRealData=0;
1643 
1644  if (fStreamerInfo)
1645  fStreamerInfo->Delete();
1646  delete fStreamerInfo; fStreamerInfo = nullptr;
1647 
1648  if (fDeclFileLine >= -1)
1649  TClass::RemoveClass(this);
1650 
1651  gCling->ClassInfo_Delete(fClassInfo);
1652  fClassInfo=0;
1653 
1654  if (fClassMenuList)
1655  fClassMenuList->Delete();
1656  delete fClassMenuList; fClassMenuList=0;
1657 
1658  fIsOffsetStreamerSet=kFALSE;
1659 
1660  if ( fIsA ) delete fIsA;
1661 
1662  if ( fRefProxy ) fRefProxy->Release();
1663  fRefProxy = 0;
1664 
1665  delete fStreamer;
1666  delete fCollectionProxy;
1667  delete fIsAMethod.load();
1668  delete fSchemaRules;
1669  if (fConversionStreamerInfo.load()) {
1670  std::map<std::string, TObjArray*>::iterator it;
1671  std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
1672  for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
1673  delete it->second;
1674  }
1675  delete fConversionStreamerInfo.load();
1676  }
1677 }
1678 
1679 ////////////////////////////////////////////////////////////////////////////////
1680 
1681 namespace {
1682  Int_t ReadRulesContent(FILE *f)
1683  {
1684  // Read a class.rules file which contains one rule per line with comment
1685  // starting with a #
1686  // Returns the number of rules loaded.
1687  // Returns -1 in case of error.
1688 
1689  R__ASSERT(f!=0);
1690  TString rule(1024);
1691  int c, state = 0;
1692  Int_t count = 0;
1693 
1694  while ((c = fgetc(f)) != EOF) {
1695  if (c == 13) // ignore CR
1696  continue;
1697  if (c == '\n') {
1698  if (state != 3) {
1699  state = 0;
1700  if (rule.Length() > 0) {
1701  if (TClass::AddRule(rule)) {
1702  ++count;
1703  }
1704  rule.Clear();
1705  }
1706  }
1707  continue;
1708  }
1709  switch (state) {
1710  case 0: // start of line
1711  switch (c) {
1712  case ' ':
1713  case '\t':
1714  break;
1715  case '#':
1716  state = 1;
1717  break;
1718  default:
1719  state = 2;
1720  break;
1721  }
1722  break;
1723 
1724  case 1: // comment
1725  break;
1726 
1727  case 2: // rule
1728  switch (c) {
1729  case '\\':
1730  state = 3; // Continuation request
1731  default:
1732  break;
1733  }
1734  break;
1735  }
1736  switch (state) {
1737  case 2:
1738  rule.Append(c);
1739  break;
1740  }
1741  }
1742  return count;
1743  }
1744 }
1745 
1746 ////////////////////////////////////////////////////////////////////////////////
1747 /// Read the class.rules files from the default location:.
1748 /// $ROOTSYS/etc/class.rules (or ROOTETCDIR/class.rules)
1749 
1750 Int_t TClass::ReadRules()
1751 {
1752  static const char *suffix = "class.rules";
1753  TString sname = suffix;
1754  gSystem->PrependPathName(TROOT::GetEtcDir(), sname);
1755 
1756  Int_t res = -1;
1757 
1758  FILE * f = fopen(sname,"r");
1759  if (f != 0) {
1760  res = ReadRulesContent(f);
1761  fclose(f);
1762  } else {
1763  ::Error("TClass::ReadRules()", "Cannot find rules file %s", sname.Data());
1764  }
1765  return res;
1766 }
1767 
1768 ////////////////////////////////////////////////////////////////////////////////
1769 /// Read a class.rules file which contains one rule per line with comment
1770 /// starting with a #
1771 /// - Returns the number of rules loaded.
1772 /// - Returns -1 in case of error.
1773 
1774 Int_t TClass::ReadRules( const char *filename )
1775 {
1776  if (!filename || !filename[0]) {
1777  ::Error("TClass::ReadRules", "no file name specified");
1778  return -1;
1779  }
1780 
1781  FILE * f = fopen(filename,"r");
1782  if (f == 0) {
1783  ::Error("TClass::ReadRules","Failed to open %s\n",filename);
1784  return -1;
1785  }
1786  Int_t count = ReadRulesContent(f);
1787 
1788  fclose(f);
1789  return count;
1790 
1791 }
1792 
1793 ////////////////////////////////////////////////////////////////////////////////
1794 /// Add a schema evolution customization rule.
1795 /// The syntax of the rule can be either the short form:
1796 /// ~~~ {.cpp}
1797 /// [type=Read] classname membername [attributes=... ] [version=[...] ] [checksum=[...] ] [oldtype=...] [code={...}]
1798 /// ~~~
1799 /// or the long form
1800 /// ~~~ {.cpp}
1801 /// [type=Read] sourceClass=classname [targetclass=newClassname] [ source="type membername; [type2 membername2]" ]
1802 /// [target="membername3;membername4"] [attributes=... ] [version=...] [checksum=...] [code={...}|functionname]
1803 /// ~~~
1804 ///
1805 /// For example to set HepMC::GenVertex::m_event to _not_ owned the object it is pointing to:
1806 /// HepMC::GenVertex m_event attributes=NotOwner
1807 ///
1808 /// Semantic of the tags:
1809 /// - type : the type of the rule, valid values: Read, ReadRaw, Write, WriteRaw, the default is 'Read'.
1810 /// - sourceClass : the name of the class as it is on the rule file
1811 /// - targetClass : the name of the class as it is in the current code ; defaults to the value of sourceClass
1812 /// - source : the types and names of the data members from the class on file that are needed, the list is separated by semi-colons ';'
1813 /// - oldtype: in the short form only, indicates the type on disk of the data member.
1814 /// - target : the names of the data members updated by this rule, the list is separated by semi-colons ';'
1815 /// - attributes : list of possible qualifiers among: Owner, NotOwner
1816 /// - 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]
1817 /// - checksum : comma delimited list of the checksums of the class layout that this rule applies to.
1818 /// - code={...} : code to be executed for the rule or name of the function implementing it.
1819 
1820 Bool_t TClass::AddRule( const char *rule )
1821 {
1822  ROOT::TSchemaRule *ruleobj = new ROOT::TSchemaRule();
1823  if (! ruleobj->SetFromRule( rule ) ) {
1824  delete ruleobj;
1825  return kFALSE;
1826  }
1827 
1828  R__LOCKGUARD(gInterpreterMutex);
1829 
1830  TClass *cl = TClass::GetClass( ruleobj->GetTargetClass() );
1831  if (!cl) {
1832  // Create an empty emulated class for now.
1833  cl = gInterpreter->GenerateTClass(ruleobj->GetTargetClass(), /* emulation = */ kTRUE, /*silent = */ kTRUE);
1834  }
1835  ROOT::Detail::TSchemaRuleSet* rset = cl->GetSchemaRules( kTRUE );
1836 
1837  TString errmsg;
1838  if( !rset->AddRule( ruleobj, ROOT::Detail::TSchemaRuleSet::kCheckConflict, &errmsg ) ) {
1839  ::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).",
1840  ruleobj->GetTargetClass(), ruleobj->GetVersion(), ruleobj->GetTargetString(), errmsg.Data() );
1841  delete ruleobj;
1842  return kFALSE;
1843  }
1844  return kTRUE;
1845 }
1846 
1847 ////////////////////////////////////////////////////////////////////////////////
1848 /// Adopt a new set of Data Model Evolution rules.
1849 
1850 void TClass::AdoptSchemaRules( ROOT::Detail::TSchemaRuleSet *rules )
1851 {
1852  R__LOCKGUARD(gInterpreterMutex);
1853 
1854  delete fSchemaRules;
1855  fSchemaRules = rules;
1856  fSchemaRules->SetClass( this );
1857 }
1858 
1859 ////////////////////////////////////////////////////////////////////////////////
1860 /// Return the set of the schema rules if any.
1861 
1862 const ROOT::Detail::TSchemaRuleSet* TClass::GetSchemaRules() const
1863 {
1864  return fSchemaRules;
1865 }
1866 
1867 ////////////////////////////////////////////////////////////////////////////////
1868 /// Return the set of the schema rules if any.
1869 /// If create is true, create an empty set
1870 
1871 ROOT::Detail::TSchemaRuleSet* TClass::GetSchemaRules(Bool_t create)
1872 {
1873  if (create && fSchemaRules == 0) {
1874  fSchemaRules = new ROOT::Detail::TSchemaRuleSet();
1875  fSchemaRules->SetClass( this );
1876  }
1877  return fSchemaRules;
1878 }
1879 
1880 ////////////////////////////////////////////////////////////////////////////////
1881 
1882 void TClass::AddImplFile(const char* filename, int line) {
1883  // Currently reset the implementation file and line.
1884  // In the close future, it will actually add this file and line
1885  // to a "list" of implementation files.
1886 
1887  fImplFileName = filename;
1888  fImplFileLine = line;
1889 }
1890 
1891 ////////////////////////////////////////////////////////////////////////////////
1892 /// Browse external object inherited from TObject.
1893 /// It passes through inheritance tree and calls TBrowser::Add
1894 /// in appropriate cases. Static function.
1895 
1896 Int_t TClass::AutoBrowse(TObject *obj, TBrowser *b)
1897 {
1898  if (!obj) return 0;
1899 
1900  TAutoInspector insp(b);
1901  obj->ShowMembers(insp);
1902  return insp.fCount;
1903 }
1904 
1905 ////////////////////////////////////////////////////////////////////////////////
1906 /// Browse objects of of the class described by this TClass object.
1907 
1908 Int_t TClass::Browse(void *obj, TBrowser *b) const
1909 {
1910  if (!obj) return 0;
1911 
1912  TClass *actual = GetActualClass(obj);
1913  if (IsTObject()) {
1914  // Call TObject::Browse.
1915 
1916  if (!fIsOffsetStreamerSet) {
1917  CalculateStreamerOffset();
1918  }
1919  TObject* realTObject = (TObject*)((size_t)obj + fOffsetStreamer);
1920  realTObject->Browse(b);
1921  return 1;
1922  } else if (actual != this) {
1923  return actual->Browse(obj, b);
1924  } else if (GetCollectionProxy()) {
1925 
1926  // do something useful.
1927 
1928  } else {
1929  TAutoInspector insp(b);
1930  CallShowMembers(obj,insp,kFALSE);
1931  return insp.fCount;
1932  }
1933 
1934  return 0;
1935 }
1936 
1937 ////////////////////////////////////////////////////////////////////////////////
1938 /// This method is called by a browser to get the class information.
1939 
1940 void TClass::Browse(TBrowser *b)
1941 {
1942  if (!HasInterpreterInfo()) return;
1943 
1944  if (b) {
1945  if (!fRealData) BuildRealData();
1946 
1947  b->Add(GetListOfDataMembers(), "Data Members");
1948  b->Add(GetListOfRealData(), "Real Data Members");
1949  b->Add(GetListOfMethods(), "Methods");
1950  b->Add(GetListOfBases(), "Base Classes");
1951  }
1952 }
1953 
1954 ////////////////////////////////////////////////////////////////////////////////
1955 /// Build a full list of persistent data members.
1956 /// Scans the list of all data members in the class itself and also
1957 /// in all base classes. For each persistent data member, inserts a
1958 /// TRealData object in the list fRealData.
1959 ///
1960 
1961 void TClass::BuildRealData(void* pointer, Bool_t isTransient)
1962 {
1963 
1964  R__LOCKGUARD(gInterpreterMutex);
1965 
1966  // Only do this once.
1967  if (fRealData) {
1968  return;
1969  }
1970 
1971  if (fClassVersion == 0) {
1972  isTransient = kTRUE;
1973  }
1974 
1975  // When called via TMapFile (e.g. Update()) make sure that the dictionary
1976  // gets allocated on the heap and not in the mapped file.
1977  TMmallocDescTemp setreset;
1978 
1979  // Handle emulated classes and STL containers specially.
1980  if (!HasInterpreterInfo() || TClassEdit::IsSTLCont(GetName(), 0) || TClassEdit::IsSTLBitset(GetName())) {
1981  // We are an emulated class or an STL container.
1982  fRealData = new TList;
1983  BuildEmulatedRealData("", 0, this);
1984  return;
1985  }
1986 
1987  // return early on string
1988  static TClassRef clRefString("std::string");
1989  if (clRefString == this) {
1990  return;
1991  }
1992 
1993  // Complain about stl classes ending up here (unique_ptr etc) - except for
1994  // pair where we will build .first, .second just fine
1995  // and those for which the user explicitly requested a dictionary.
1996  if (!isTransient && GetState() != kHasTClassInit
1997  && TClassEdit::IsStdClass(GetName())
1998  && strncmp(GetName(), "pair<", 5) != 0) {
1999  Error("BuildRealData", "Inspection for %s not supported!", GetName());
2000  }
2001 
2002  // The following statement will recursively call
2003  // all the subclasses of this class.
2004  fRealData = new TList;
2005  TBuildRealData brd(pointer, this);
2006 
2007  // CallShowMember will force a call to InheritsFrom, which indirectly
2008  // calls TClass::GetClass. It forces the loading of new typedefs in
2009  // case some of them were not yet loaded.
2010  if ( ! CallShowMembers(pointer, brd, isTransient) ) {
2011  if ( isTransient ) {
2012  // This is a transient data member, so it is probably fine to not have
2013  // access to its content. However let's no mark it as definitively setup,
2014  // since another class might use this class for a persistent data member and
2015  // in this case we really want the error message.
2016  delete fRealData;
2017  fRealData = 0;
2018  } else {
2019  Error("BuildRealData", "Cannot find any ShowMembers function for %s!", GetName());
2020  }
2021  }
2022 
2023  // Take this opportunity to build the real data for base classes.
2024  // In case one base class is abstract, it would not be possible later
2025  // to create the list of real data for this abstract class.
2026  TBaseClass* base = 0;
2027  TIter next(GetListOfBases());
2028  while ((base = (TBaseClass*) next())) {
2029  if (base->IsSTLContainer()) {
2030  continue;
2031  }
2032  TClass* c = base->GetClassPointer();
2033  if (c) {
2034  c->BuildRealData(0, isTransient);
2035  }
2036  }
2037 }
2038 
2039 ////////////////////////////////////////////////////////////////////////////////
2040 /// Build the list of real data for an emulated class
2041 
2042 void TClass::BuildEmulatedRealData(const char *name, Long_t offset, TClass *cl)
2043 {
2044  R__LOCKGUARD(gInterpreterMutex);
2045 
2046  TVirtualStreamerInfo *info;
2047  if (Property() & kIsAbstract) {
2048  info = GetStreamerInfoAbstractEmulated();
2049  } else {
2050  info = GetStreamerInfo();
2051  }
2052  if (!info) {
2053  // This class is abstract, but we don't yet have a SteamerInfo for it ...
2054  Error("BuildEmulatedRealData","Missing StreamerInfo for %s",GetName());
2055  // Humm .. no information ... let's bail out
2056  return;
2057  }
2058 
2059  TIter next(info->GetElements());
2060  TStreamerElement *element;
2061  while ((element = (TStreamerElement*)next())) {
2062  Int_t etype = element->GetType();
2063  Long_t eoffset = element->GetOffset();
2064  TClass *cle = element->GetClassPointer();
2065  if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2066  //base class are skipped in this loop, they will be added at the end.
2067  continue;
2068  } else if (etype == TVirtualStreamerInfo::kTObject ||
2069  etype == TVirtualStreamerInfo::kTNamed ||
2070  etype == TVirtualStreamerInfo::kObject ||
2071  etype == TVirtualStreamerInfo::kAny) {
2072  //member class
2073  TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2074  TRealData *rd = new TRealData(rdname,offset+eoffset,0);
2075  if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2076  cl->GetListOfRealData()->Add(rd);
2077  // Now we a dot
2078  rdname.Form("%s%s.",name,element->GetFullName());
2079  if (cle) cle->BuildEmulatedRealData(rdname,offset+eoffset,cl);
2080  } else {
2081  //others
2082  TString rdname; rdname.Form("%s%s",name,element->GetFullName());
2083  TRealData *rd = new TRealData(rdname,offset+eoffset,0);
2084  if (gDebug > 0) printf(" Class: %s, adding TRealData=%s, offset=%ld\n",cl->GetName(),rd->GetName(),rd->GetThisOffset());
2085  cl->GetListOfRealData()->Add(rd);
2086  }
2087  //if (fClassInfo==0 && element->IsBase()) {
2088  // if (fBase==0) fBase = new TList;
2089  // TClass *base = element->GetClassPointer();
2090  // fBase->Add(new TBaseClass(this, cl, eoffset));
2091  //}
2092  }
2093  // The base classes must added last on the list of real data (to help with ambiguous data member names)
2094  next.Reset();
2095  while ((element = (TStreamerElement*)next())) {
2096  Int_t etype = element->GetType();
2097  if (element->IsBase() || etype == TVirtualStreamerInfo::kBase) {
2098  //base class
2099  Long_t eoffset = element->GetOffset();
2100  TClass *cle = element->GetClassPointer();
2101  if (cle) cle->BuildEmulatedRealData(name,offset+eoffset,cl);
2102  }
2103  }
2104 }
2105 
2106 
2107 ////////////////////////////////////////////////////////////////////////////////
2108 /// Calculate the offset between an object of this class to
2109 /// its base class TObject. The pointer can be adjusted by
2110 /// that offset to access any virtual method of TObject like
2111 /// Streamer() and ShowMembers().
2112 
2113 void TClass::CalculateStreamerOffset() const
2114 {
2115  R__LOCKGUARD(gInterpreterMutex);
2116  if (!fIsOffsetStreamerSet && HasInterpreterInfo()) {
2117  // When called via TMapFile (e.g. Update()) make sure that the dictionary
2118  // gets allocated on the heap and not in the mapped file.
2119 
2120  TMmallocDescTemp setreset;
2121  fOffsetStreamer = const_cast<TClass*>(this)->GetBaseClassOffsetRecurse(TObject::Class());
2122  if (fStreamerType == kTObject) {
2123  fStreamerImpl = &TClass::StreamerTObjectInitialized;
2124  }
2125  fIsOffsetStreamerSet = kTRUE;
2126  }
2127 }
2128 
2129 
2130 ////////////////////////////////////////////////////////////////////////////////
2131 /// Call ShowMembers() on the obj of this class type, passing insp and parent.
2132 /// isATObject is -1 if unknown, 0 if it is not a TObject, and 1 if it is a TObject.
2133 /// The function returns whether it was able to call ShowMembers().
2134 
2135 Bool_t TClass::CallShowMembers(const void* obj, TMemberInspector &insp, Bool_t isTransient) const
2136 {
2137  if (fShowMembers) {
2138  // This should always works since 'pointer' should be pointing
2139  // to an object of the actual type of this TClass object.
2140  fShowMembers(obj, insp, isTransient);
2141  return kTRUE;
2142  } else {
2143 
2144  if (fCanLoadClassInfo) LoadClassInfo();
2145  if (fClassInfo) {
2146 
2147  if (strcmp(GetName(), "string") == 0) {
2148  // For std::string we know that we do not have a ShowMembers
2149  // function and that it's okay.
2150  return kTRUE;
2151  }
2152  // Since we do have some dictionary information, let's
2153  // call the interpreter's ShowMember.
2154  // This works with Cling to support interpreted classes.
2155  gInterpreter->InspectMembers(insp, obj, this, isTransient);
2156  return kTRUE;
2157 
2158  } else if (TVirtualStreamerInfo* sinfo = GetStreamerInfo()) {
2159  sinfo->CallShowMembers(obj, insp, isTransient);
2160  return kTRUE;
2161  } // isATObject
2162  } // fShowMembers is set
2163 
2164  return kFALSE;
2165 }
2166 
2167 ////////////////////////////////////////////////////////////////////////////////
2168 /// Do a ShowMembers() traversal of all members and base classes' members
2169 /// using the reflection information from the interpreter. Works also for
2170 /// interpreted objects.
2171 
2172 void TClass::InterpretedShowMembers(void* obj, TMemberInspector &insp, Bool_t isTransient)
2173 {
2174  return gInterpreter->InspectMembers(insp, obj, this, isTransient);
2175 }
2176 
2177 Bool_t TClass::CanSplitBaseAllow()
2178 {
2179  if (fCanSplit >= 0) {
2180  return ! ( fCanSplit & 0x2 );
2181  }
2182 
2183  R__LOCKGUARD(gInterpreterMutex);
2184 
2185  if (GetCollectionProxy() != nullptr) {
2186  // A collection can never affect its derived class 'splittability'
2187  return kTRUE;
2188  }
2189 
2190  if (this == TRef::Class()) { fCanSplit = 2; return kFALSE; }
2191  if (this == TRefArray::Class()) { fCanSplit = 2; return kFALSE; }
2192  if (this == TArray::Class()) { fCanSplit = 2; return kFALSE; }
2193  if (this == TClonesArray::Class()) { fCanSplit = 1; return kTRUE; }
2194  if (this == TCollection::Class()) { fCanSplit = 2; return kFALSE; }
2195 
2196  // TTree is not always available (for example in rootcling), so we need
2197  // to grab it silently.
2198  auto refTreeClass( TClass::GetClass("TTree",kTRUE,kTRUE) );
2199  if (this == refTreeClass) { fCanSplit = 2; return kFALSE; }
2200 
2201  if (!HasDataMemberInfo()) {
2202  TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
2203  if (sinfo==0) sinfo = GetStreamerInfo();
2204  TIter next(sinfo->GetElements());
2205  TStreamerElement *element;
2206  while ((element = (TStreamerElement*)next())) {
2207  if (element->IsA() == TStreamerBase::Class()) {
2208  TClass *clbase = element->GetClassPointer();
2209  if (!clbase) {
2210  // If there is a missing base class, we can't split the immediate
2211  // derived class.
2212  fCanSplit = 0;
2213  return kFALSE;
2214  } else if (!clbase->CanSplitBaseAllow()) {
2215  fCanSplit = 2;
2216  return kFALSE;
2217  }
2218  }
2219  }
2220  }
2221 
2222  // If we don't have data member info there is no more information
2223  // we can find out.
2224  if (!HasDataMemberInfo()) return kTRUE;
2225 
2226  TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : 0;
2227 
2228  // Look at inheritance tree
2229  while (lnk) {
2230  TClass *c;
2231  TBaseClass *base = (TBaseClass*) lnk->GetObject();
2232  c = base->GetClassPointer();
2233  if(!c) {
2234  // If there is a missing base class, we can't split the immediate
2235  // derived class.
2236  fCanSplit = 0;
2237  return kFALSE;
2238  } else if (!c->CanSplitBaseAllow()) {
2239  fCanSplit = 2;
2240  return kFALSE;
2241  }
2242  lnk = lnk->Next();
2243  }
2244  return kTRUE;
2245 }
2246 
2247 ////////////////////////////////////////////////////////////////////////////////
2248 /// Return true if the data member of this TClass can be saved separately.
2249 
2250 Bool_t TClass::CanSplit() const
2251 {
2252  // Note: add the possibility to set it for the class and the derived class.
2253  // save the info in TVirtualStreamerInfo
2254  // deal with the info in MakeProject
2255  if (fCanSplit >= 0) {
2256  // The user explicitly set the value
2257  return (fCanSplit & 0x1) == 1;
2258  }
2259 
2260  R__LOCKGUARD(gInterpreterMutex);
2261  TClass *This = const_cast<TClass*>(this);
2262 
2263  if (this == TObject::Class()) { This->fCanSplit = 1; return kTRUE; }
2264  if (fName == "TClonesArray") { This->fCanSplit = 1; return kTRUE; }
2265  if (fRefProxy) { This->fCanSplit = 0; return kFALSE; }
2266  if (fName.BeginsWith("TVectorT<")) { This->fCanSplit = 0; return kFALSE; }
2267  if (fName.BeginsWith("TMatrixT<")) { This->fCanSplit = 0; return kFALSE; }
2268  if (fName == "string") { This->fCanSplit = 0; return kFALSE; }
2269  if (fName == "std::string") { This->fCanSplit = 0; return kFALSE; }
2270 
2271  if (GetCollectionProxy()!=0) {
2272  // For STL collection we need to look inside.
2273 
2274  // However we do not split collections of collections
2275  // nor collections of strings
2276  // nor collections of pointers (unless explicit request (see TBranchSTL)).
2277 
2278  if (GetCollectionProxy()->HasPointers()) { This->fCanSplit = 0; return kFALSE; }
2279 
2280  TClass *valueClass = GetCollectionProxy()->GetValueClass();
2281  if (valueClass == 0) { This->fCanSplit = 0; return kFALSE; }
2282  static TClassRef stdStringClass("std::string");
2283  if (valueClass==TString::Class() || valueClass==stdStringClass)
2284  { This->fCanSplit = 0; return kFALSE; }
2285  if (!valueClass->CanSplit()) { This->fCanSplit = 0; return kFALSE; }
2286  if (valueClass->GetCollectionProxy() != 0) { This->fCanSplit = 0; return kFALSE; }
2287 
2288  Int_t stl = -TClassEdit::IsSTLCont(GetName(), 0);
2289  if ((stl==ROOT::kSTLmap || stl==ROOT::kSTLmultimap)
2290  && !valueClass->HasDataMemberInfo())
2291  {
2292  This->fCanSplit = 0;
2293  return kFALSE;
2294  }
2295 
2296  This->fCanSplit = 1;
2297  return kTRUE;
2298 
2299  }
2300 
2301  if (GetStreamer() != nullptr || fStreamerFunc != nullptr) {
2302 
2303  // We have an external custom streamer provided by the user, we must not
2304  // split it.
2305  This->fCanSplit = 0;
2306  return kFALSE;
2307 
2308  } else if ( TestBit(TClass::kHasCustomStreamerMember) ) {
2309 
2310  // We have a custom member function streamer or
2311  // an older (not StreamerInfo based) automatic streamer.
2312  This->fCanSplit = 0;
2313  return kFALSE;
2314  }
2315 
2316  if (Size()==1) {
2317  // 'Empty' class there is nothing to split!.
2318  This->fCanSplit = 0;
2319  return kFALSE;
2320  }
2321 
2322 
2323  if ( !This->CanSplitBaseAllow() ) {
2324  return kFALSE;
2325  }
2326 
2327  This->fCanSplit = 1;
2328  return kTRUE;
2329 }
2330 
2331 ////////////////////////////////////////////////////////////////////////////////
2332 /// Return the C++ property of this class, eg. is abstract, has virtual base
2333 /// class, see EClassProperty in TDictionary.h
2334 
2335 Long_t TClass::ClassProperty() const
2336 {
2337  if (fProperty == -1) Property();
2338  return fClassProperty;
2339 }
2340 
2341 ////////////////////////////////////////////////////////////////////////////////
2342 /// Create a Clone of this TClass object using a different name but using the same 'dictionary'.
2343 /// This effectively creates a hard alias for the class name.
2344 
2345 TObject *TClass::Clone(const char *new_name) const
2346 {
2347  if (new_name == 0 || new_name[0]=='\0' || fName == new_name) {
2348  Error("Clone","The name of the class must be changed when cloning a TClass object.");
2349  return 0;
2350  }
2351 
2352  // Need to lock access to TROOT::GetListOfClasses so the cloning happens atomically
2353  R__LOCKGUARD(gInterpreterMutex);
2354  // Temporarily remove the original from the list of classes.
2355  TClass::RemoveClass(const_cast<TClass*>(this));
2356 
2357  TClass *copy;
2358  if (fTypeInfo) {
2359  copy = new TClass(GetName(),
2360  fClassVersion,
2361  *fTypeInfo,
2362  new TIsAProxy(*fTypeInfo),
2363  GetDeclFileName(),
2364  GetImplFileName(),
2365  GetDeclFileLine(),
2366  GetImplFileLine());
2367  } else {
2368  copy = new TClass(GetName(),
2369  fClassVersion,
2370  GetDeclFileName(),
2371  GetImplFileName(),
2372  GetDeclFileLine(),
2373  GetImplFileLine());
2374  }
2375  copy->fShowMembers = fShowMembers;
2376  // Remove the copy before renaming it
2377  TClass::RemoveClass(copy);
2378  copy->fName = new_name;
2379  TClass::AddClass(copy);
2380 
2381  copy->SetNew(fNew);
2382  copy->SetNewArray(fNewArray);
2383  copy->SetDelete(fDelete);
2384  copy->SetDeleteArray(fDeleteArray);
2385  copy->SetDestructor(fDestructor);
2386  copy->SetDirectoryAutoAdd(fDirAutoAdd);
2387  copy->fStreamerFunc = fStreamerFunc;
2388  copy->fConvStreamerFunc = fConvStreamerFunc;
2389  if (fStreamer) {
2390  copy->AdoptStreamer(fStreamer->Generate());
2391  }
2392  // If IsZombie is true, something went wrong and we will not be
2393  // able to properly copy the collection proxy
2394  if (fCollectionProxy && !copy->IsZombie()) {
2395  copy->CopyCollectionProxy(*fCollectionProxy);
2396  }
2397  copy->SetClassSize(fSizeof);
2398  if (fRefProxy) {
2399  copy->AdoptReferenceProxy( fRefProxy->Clone() );
2400  }
2401  TClass::AddClass(const_cast<TClass*>(this));
2402  return copy;
2403 }
2404 
2405 ////////////////////////////////////////////////////////////////////////////////
2406 /// Copy the argument.
2407 
2408 void TClass::CopyCollectionProxy(const TVirtualCollectionProxy &orig)
2409 {
2410 // // This code was used too quickly test the STL Emulation layer
2411 // Int_t k = TClassEdit::IsSTLCont(GetName());
2412 // if (k==1||k==-1) return;
2413 
2414  delete fCollectionProxy;
2415  fCollectionProxy = orig.Generate();
2416 }
2417 
2418 ////////////////////////////////////////////////////////////////////////////////
2419 /// Draw detailed class inheritance structure.
2420 /// If a class B inherits from a class A, the description of B is drawn
2421 /// on the right side of the description of A.
2422 /// Member functions overridden by B are shown in class A with a blue line
2423 /// erasing the corresponding member function
2424 
2425 void TClass::Draw(Option_t *option)
2426 {
2427  if (!HasInterpreterInfo()) return;
2428 
2429  TVirtualPad *padsav = gPad;
2430 
2431  // Should we create a new canvas?
2432  TString opt=option;
2433  if (!padsav || !opt.Contains("same")) {
2434  TVirtualPad *padclass = (TVirtualPad*)(gROOT->GetListOfCanvases())->FindObject("R__class");
2435  if (!padclass) {
2436  gROOT->ProcessLine("new TCanvas(\"R__class\",\"class\",20,20,1000,750);");
2437  } else {
2438  padclass->cd();
2439  }
2440  }
2441 
2442  if (gPad) gPad->DrawClassObject(this,option);
2443 
2444  if (padsav) padsav->cd();
2445 }
2446 
2447 ////////////////////////////////////////////////////////////////////////////////
2448 /// Dump contents of object on stdout.
2449 /// Using the information in the object dictionary
2450 /// each data member is interpreted.
2451 /// If a data member is a pointer, the pointer value is printed
2452 /// 'obj' is assume to point to an object of the class describe by this TClass
2453 ///
2454 /// The following output is the Dump of a TArrow object:
2455 /// ~~~ {.cpp}
2456 /// fAngle 0 Arrow opening angle (degrees)
2457 /// fArrowSize 0.2 Arrow Size
2458 /// fOption.*fData
2459 /// fX1 0.1 X of 1st point
2460 /// fY1 0.15 Y of 1st point
2461 /// fX2 0.67 X of 2nd point
2462 /// fY2 0.83 Y of 2nd point
2463 /// fUniqueID 0 object unique identifier
2464 /// fBits 50331648 bit field status word
2465 /// fLineColor 1 line color
2466 /// fLineStyle 1 line style
2467 /// fLineWidth 1 line width
2468 /// fFillColor 19 fill area color
2469 /// fFillStyle 1001 fill area style
2470 /// ~~~
2471 ///
2472 /// If noAddr is true, printout of all pointer values is skipped.
2473 
2474 void TClass::Dump(const void *obj, Bool_t noAddr /*=kFALSE*/) const
2475 {
2476 
2477  Long_t prObj = noAddr ? 0 : (Long_t)obj;
2478  if (IsTObject()) {
2479  if (!fIsOffsetStreamerSet) {
2480  CalculateStreamerOffset();
2481  }
2482  TObject *tobj = (TObject*)((Long_t)obj + fOffsetStreamer);
2483 
2484 
2485  if (sizeof(this) == 4)
2486  Printf("==> Dumping object at: 0x%08lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2487  else
2488  Printf("==> Dumping object at: 0x%016lx, name=%s, class=%s\n",prObj,tobj->GetName(),GetName());
2489  } else {
2490 
2491  if (sizeof(this) == 4)
2492  Printf("==> Dumping object at: 0x%08lx, class=%s\n",prObj,GetName());
2493  else
2494  Printf("==> Dumping object at: 0x%016lx, class=%s\n",prObj,GetName());
2495  }
2496 
2497  TDumpMembers dm(noAddr);
2498  if (!CallShowMembers(obj, dm, kFALSE)) {
2499  Info("Dump", "No ShowMembers function, dumping disabled");
2500  }
2501 }
2502 
2503 ////////////////////////////////////////////////////////////////////////////////
2504 /// Introduce an escape character (@) in front of a special chars.
2505 /// You need to use the result immediately before it is being overwritten.
2506 
2507 char *TClass::EscapeChars(const char *text) const
2508 {
2509  static const UInt_t maxsize = 255;
2510  static char name[maxsize+2]; //One extra if last char needs to be escaped
2511 
2512  UInt_t nch = strlen(text);
2513  UInt_t icur = 0;
2514  for (UInt_t i = 0; i < nch && icur < maxsize; ++i, ++icur) {
2515  if (text[i] == '\"' || text[i] == '[' || text[i] == '~' ||
2516  text[i] == ']' || text[i] == '&' || text[i] == '#' ||
2517  text[i] == '!' || text[i] == '^' || text[i] == '<' ||
2518  text[i] == '?' || text[i] == '>') {
2519  name[icur] = '@';
2520  ++icur;
2521  }
2522  name[icur] = text[i];
2523  }
2524  name[icur] = 0;
2525  return name;
2526 }
2527 
2528 ////////////////////////////////////////////////////////////////////////////////
2529 /// Return a pointer the the real class of the object.
2530 /// This is equivalent to object->IsA() when the class has a ClassDef.
2531 /// It is REQUIRED that object is coming from a proper pointer to the
2532 /// class represented by 'this'.
2533 /// Example: Special case:
2534 /// ~~~ {.cpp}
2535 /// class MyClass : public AnotherClass, public TObject
2536 /// ~~~
2537 /// then on return, one must do:
2538 /// ~~~ {.cpp}
2539 /// TObject *obj = (TObject*)((void*)myobject)directory->Get("some object of MyClass");
2540 /// MyClass::Class()->GetActualClass(obj); // this would be wrong!!!
2541 /// ~~~
2542 /// Also if the class represented by 'this' and NONE of its parents classes
2543 /// have a virtual ptr table, the result will be 'this' and NOT the actual
2544 /// class.
2545 
2546 TClass *TClass::GetActualClass(const void *object) const
2547 {
2548  if (object==0) return (TClass*)this;
2549  if (fIsA) {
2550  return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2551  } else if (fGlobalIsA) {
2552  return fGlobalIsA(this,object);
2553  } else {
2554  if (IsTObject()) {
2555 
2556  if (!fIsOffsetStreamerSet) {
2557  CalculateStreamerOffset();
2558  }
2559  TObject* realTObject = (TObject*)((size_t)object + fOffsetStreamer);
2560 
2561  return realTObject->IsA();
2562  }
2563 
2564  if (HasInterpreterInfo()) {
2565 
2566  TVirtualIsAProxy *isa = 0;
2567  if (GetClassInfo() && gCling->ClassInfo_HasMethod(fClassInfo,"IsA")) {
2568  isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TInstrumentedIsAProxy<%s>(0);",GetName()));
2569  }
2570  else {
2571  isa = (TVirtualIsAProxy*)gROOT->ProcessLineFast(TString::Format("new ::TIsAProxy(typeid(%s));",GetName()));
2572  }
2573  if (isa) {
2574  R__LOCKGUARD(gInterpreterMutex);
2575  const_cast<TClass*>(this)->fIsA = isa;
2576  }
2577  if (fIsA) {
2578  return (*fIsA)(object); // ROOT::IsA((ThisClass*)object);
2579  }
2580  }
2581  TVirtualStreamerInfo* sinfo = GetStreamerInfo();
2582  if (sinfo) {
2583  return sinfo->GetActualClass(object);
2584  }
2585  return (TClass*)this;
2586  }
2587 }
2588 
2589 ////////////////////////////////////////////////////////////////////////////////
2590 /// Return pointer to the base class "classname". Returns 0 in case
2591 /// "classname" is not a base class. Takes care of multiple inheritance.
2592 
2593 TClass *TClass::GetBaseClass(const char *classname)
2594 {
2595  // check if class name itself is equal to classname
2596  if (strcmp(GetName(), classname) == 0) return this;
2597 
2598  if (!HasDataMemberInfo()) return 0;
2599 
2600  // Make sure we deal with possible aliases, we could also have normalized
2601  // the name.
2602  TClass *search = TClass::GetClass(classname,kTRUE,kTRUE);
2603 
2604  if (search) return GetBaseClass(search);
2605  else return 0;
2606 }
2607 
2608 ////////////////////////////////////////////////////////////////////////////////
2609 /// Return pointer to the base class "cl". Returns 0 in case "cl"
2610 /// is not a base class. Takes care of multiple inheritance.
2611 
2612 TClass *TClass::GetBaseClass(const TClass *cl)
2613 {
2614  // check if class name itself is equal to classname
2615  if (cl == this) return this;
2616 
2617  if (!HasDataMemberInfo()) return 0;
2618 
2619  TObjLink *lnk = GetListOfBases() ? fBase.load()->FirstLink() : 0;
2620 
2621  // otherwise look at inheritance tree
2622  while (lnk) {
2623  TClass *c, *c1;
2624  TBaseClass *base = (TBaseClass*) lnk->GetObject();
2625  c = base->GetClassPointer();
2626  if (c) {
2627  if (cl == c) return c;
2628  c1 = c->GetBaseClass(cl);
2629  if (c1) return c1;
2630  }
2631  lnk = lnk->Next();
2632  }
2633  return 0;
2634 }
2635 
2636 ////////////////////////////////////////////////////////////////////////////////
2637 /// Return data member offset to the base class "cl".
2638 /// - Returns -1 in case "cl" is not a base class.
2639 /// - Returns -2 if cl is a base class, but we can't find the offset
2640 /// because it's virtual.
2641 /// Takes care of multiple inheritance.
2642 
2643 Int_t TClass::GetBaseClassOffsetRecurse(const TClass *cl)
2644 {
2645  // check if class name itself is equal to classname
2646  if (cl == this) return 0;
2647 
2648  if (!fBase.load()) {
2649  if (fCanLoadClassInfo) LoadClassInfo();
2650  // If the information was not provided by the root pcm files and
2651  // if we can not find the ClassInfo, we have to fall back to the
2652  // StreamerInfo
2653  if (!fClassInfo) {
2654  TVirtualStreamerInfo *sinfo = GetCurrentStreamerInfo();
2655  if (!sinfo) return -1;
2656  TStreamerElement *element;
2657  Int_t offset = 0;
2658 
2659  TObjArray &elems = *(sinfo->GetElements());
2660  Int_t size = elems.GetLast()+1;
2661  for(Int_t i=0; i<size; i++) {
2662  element = (TStreamerElement*)elems[i];
2663  if (element->IsBase()) {
2664  if (element->IsA() == TStreamerBase::Class()) {
2665  TStreamerBase *base = (TStreamerBase*)element;
2666  TClass *baseclass = base->GetClassPointer();
2667  if (!baseclass) return -1;
2668  Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2669  if (subOffset == -2) return -2;
2670  if (subOffset != -1) return offset+subOffset;
2671  offset += baseclass->Size();
2672  } else if (element->IsA() == TStreamerSTL::Class()) {
2673  TStreamerSTL *base = (TStreamerSTL*)element;
2674  TClass *baseclass = base->GetClassPointer();
2675  if (!baseclass) return -1;
2676  Int_t subOffset = baseclass->GetBaseClassOffsetRecurse(cl);
2677  if (subOffset == -2) return -2;
2678  if (subOffset != -1) return offset+subOffset;
2679  offset += baseclass->Size();
2680 
2681  } else {
2682  Error("GetBaseClassOffsetRecurse","Unexpected element type for base class: %s\n",element->IsA()->GetName());
2683  }
2684  }
2685  }
2686  return -1;
2687  }
2688  }
2689 
2690  TClass *c;
2691  Int_t off;
2692  TBaseClass *inh;
2693  TObjLink *lnk = 0;
2694  if (fBase.load() == 0)
2695  lnk = GetListOfBases()->FirstLink();
2696  else
2697  lnk = fBase.load()->FirstLink();
2698 
2699  // otherwise look at inheritance tree
2700  while (lnk) {
2701  inh = (TBaseClass *)lnk->GetObject();
2702  //use option load=kFALSE to avoid a warning like:
2703  //"Warning in <TClass::TClass>: no dictionary for class TRefCnt is available"
2704  //We can not afford to not have the class if it exist, so we
2705  //use kTRUE.
2706  c = inh->GetClassPointer(kTRUE); // kFALSE);
2707  if (c) {
2708  if (cl == c) {
2709  if ((inh->Property() & kIsVirtualBase) != 0)
2710  return -2;
2711  return inh->GetDelta();
2712  }
2713  off = c->GetBaseClassOffsetRecurse(cl);
2714  if (off == -2) return -2;
2715  if (off != -1) {
2716  return off + inh->GetDelta();
2717  }
2718  }
2719  lnk = lnk->Next();
2720  }
2721  return -1;
2722 }
2723 
2724 ////////////////////////////////////////////////////////////////////////////////
2725 /// - Return data member offset to the base class "cl".
2726 /// - Returns -1 in case "cl" is not a base class.
2727 /// Takes care of multiple inheritance.
2728 
2729 Int_t TClass::GetBaseClassOffset(const TClass *toBase, void *address, bool isDerivedObject)
2730 {
2731  // Warning("GetBaseClassOffset","Requires the use of fClassInfo for %s to %s",GetName(),toBase->GetName());
2732 
2733  if (this == toBase) return 0;
2734 
2735  if ((!address /* || !has_virtual_base */) &&
2736  (!HasInterpreterInfoInMemory() || !toBase->HasInterpreterInfoInMemory())) {
2737  // At least of the ClassInfo have not been loaded in memory yet and
2738  // since there is no virtual base class (or we don't have enough so it
2739  // would not make a difference) we can use the 'static' information
2740  Int_t offset = GetBaseClassOffsetRecurse (toBase);
2741  if (offset != -2) {
2742  return offset;
2743  }
2744  return offset;
2745  }
2746 
2747  ClassInfo_t* derived = GetClassInfo();
2748  ClassInfo_t* base = toBase->GetClassInfo();
2749  if(derived && base) {
2750  // TClingClassInfo::GetBaseOffset takes the lock.
2751  return gCling->ClassInfo_GetBaseOffset(derived, base, address, isDerivedObject);
2752  }
2753  else {
2754  Int_t offset = GetBaseClassOffsetRecurse (toBase);
2755  if (offset != -2) {
2756  return offset;
2757  }
2758  }
2759  return -1;
2760 }
2761 
2762 ////////////////////////////////////////////////////////////////////////////////
2763 /// Return pointer to (base) class that contains datamember.
2764 
2765 TClass *TClass::GetBaseDataMember(const char *datamember)
2766 {
2767  if (!HasDataMemberInfo()) return 0;
2768 
2769  // Check if data member exists in class itself
2770  TDataMember *dm = GetDataMember(datamember);
2771  if (dm) return this;
2772 
2773  // if datamember not found in class, search in next base classes
2774  TBaseClass *inh;
2775  TIter next(GetListOfBases());
2776  while ((inh = (TBaseClass *) next())) {
2777  TClass *c = inh->GetClassPointer();
2778  if (c) {
2779  TClass *cdm = c->GetBaseDataMember(datamember);
2780  if (cdm) return cdm;
2781  }
2782  }
2783 
2784  return 0;
2785 }
2786 
2787 namespace {
2788  // A local Helper class used to keep 2 pointer (the collection proxy
2789  // and the class streamer) in the thread local storage.
2790 
2791  struct TClassLocalStorage {
2792  TClassLocalStorage() : fCollectionProxy(0), fStreamer(0) {};
2793 
2794  TVirtualCollectionProxy *fCollectionProxy;
2795  TClassStreamer *fStreamer;
2796 
2797  static TClassLocalStorage *GetStorage(const TClass *cl)
2798  {
2799  // Return the thread storage for the TClass.
2800 
2801  void **thread_ptr = (*gThreadTsd)(0,ROOT::kClassThreadSlot);
2802  if (thread_ptr) {
2803  if (*thread_ptr==0) *thread_ptr = new TExMap();
2804  TExMap *lmap = (TExMap*)(*thread_ptr);
2805  ULong_t hash = TString::Hash(&cl, sizeof(void*));
2806  ULong_t local = 0;
2807  UInt_t slot;
2808  if ((local = (ULong_t)lmap->GetValue(hash, (Long_t)cl, slot)) != 0) {
2809  } else {
2810  local = (ULong_t) new TClassLocalStorage();
2811  lmap->AddAt(slot, hash, (Long_t)cl, local);
2812  }
2813  return (TClassLocalStorage*)local;
2814  }
2815  return 0;
2816  }
2817  };
2818 }
2819 
2820 ////////////////////////////////////////////////////////////////////////////////
2821 /// Return the 'type' of the STL the TClass is representing.
2822 /// and return ROOT::kNotSTL if it is not representing an STL collection.
2823 
2824 ROOT::ESTLType TClass::GetCollectionType() const
2825 {
2826  auto proxy = GetCollectionProxy();
2827  if (proxy) return (ROOT::ESTLType)proxy->GetCollectionType();
2828  return ROOT::kNotSTL;
2829 }
2830 
2831 
2832 ////////////////////////////////////////////////////////////////////////////////
2833 /// Return the proxy describing the collection (if any).
2834 
2835 TVirtualCollectionProxy *TClass::GetCollectionProxy() const
2836 {
2837  // Use assert, so that this line (slow because of the TClassEdit) is completely
2838  // removed in optimized code.
2839  assert(TestBit(kLoading) || !TClassEdit::IsSTLCont(fName) || fCollectionProxy || 0 == "The TClass for the STL collection has no collection proxy!");
2840  if (gThreadTsd && fCollectionProxy) {
2841  TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2842  if (local == 0) return fCollectionProxy;
2843  if (local->fCollectionProxy==0) local->fCollectionProxy = fCollectionProxy->Generate();
2844  return local->fCollectionProxy;
2845  }
2846  return fCollectionProxy;
2847 }
2848 
2849 ////////////////////////////////////////////////////////////////////////////////
2850 /// Return the Streamer Class allowing streaming (if any).
2851 
2852 TClassStreamer *TClass::GetStreamer() const
2853 {
2854  if (gThreadTsd && fStreamer) {
2855  TClassLocalStorage *local = TClassLocalStorage::GetStorage(this);
2856  if (local==0) return fStreamer;
2857  if (local->fStreamer==0) {
2858  local->fStreamer = fStreamer->Generate();
2859  const std::type_info &orig = ( typeid(*fStreamer) );
2860  if (!local->fStreamer) {
2861  Warning("GetStreamer","For %s, the TClassStreamer (%s) passed's call to Generate failed!",GetName(),orig.name());
2862  } else {
2863  const std::type_info &copy = ( typeid(*local->fStreamer) );
2864  if (strcmp(orig.name(),copy.name())!=0) {
2865  Warning("GetStreamer","For %s, the TClassStreamer passed does not properly implement the Generate method (%s vs %s)\n",GetName(),orig.name(),copy.name());
2866  }
2867  }
2868  }
2869  return local->fStreamer;
2870  }
2871  return fStreamer;
2872 }
2873 
2874 ////////////////////////////////////////////////////////////////////////////////
2875 /// Get a wrapper/accessor function around this class custom streamer (member function).
2876 
2877 ClassStreamerFunc_t TClass::GetStreamerFunc() const
2878 {
2879  return fStreamerFunc;
2880 }
2881 
2882 ////////////////////////////////////////////////////////////////////////////////
2883 /// Get a wrapper/accessor function around this class custom conversion streamer (member function).
2884 
2885 ClassConvStreamerFunc_t TClass::GetConvStreamerFunc() const
2886 {
2887  return fConvStreamerFunc;
2888 }
2889 
2890 ////////////////////////////////////////////////////////////////////////////////
2891 /// Return the proxy implementing the IsA functionality.
2892 
2893 TVirtualIsAProxy* TClass::GetIsAProxy() const
2894 {
2895  return fIsA;
2896 }
2897 
2898 ////////////////////////////////////////////////////////////////////////////////
2899 /// Static method returning pointer to TClass of the specified class name.
2900 /// If load is true an attempt is made to obtain the class by loading
2901 /// the appropriate shared library (directed by the rootmap file).
2902 /// If silent is 'true', do not warn about missing dictionary for the class.
2903 /// (typically used for class that are used only for transient members)
2904 /// Returns 0 in case class is not found.
2905 
2906 TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent)
2907 {
2908  if (!name || !name[0]) return 0;
2909 
2910  if (strstr(name, "(anonymous)")) return 0;
2911  if (strncmp(name,"class ",6)==0) name += 6;
2912  if (strncmp(name,"struct ",7)==0) name += 7;
2913 
2914  if (!gROOT->GetListOfClasses()) return 0;
2915 
2916  // FindObject will take the read lock before actually getting the
2917  // TClass pointer so we will need not get a partially initialized
2918  // object.
2919  TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2920 
2921  // Early return to release the lock without having to execute the
2922  // long-ish normalization.
2923  if (cl && (cl->IsLoaded() || cl->TestBit(kUnloading))) return cl;
2924 
2925  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
2926 
2927  // Now that we got the write lock, another thread may have constructed the
2928  // TClass while we were waiting, so we need to do the checks again.
2929 
2930  cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
2931  if (cl) {
2932  if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
2933 
2934  // We could speed-up some of the search by adding (the equivalent of)
2935  //
2936  // if (cl->GetState() == kInterpreter) return cl
2937  //
2938  // In this case, if a ROOT dictionary was available when the TClass
2939  // was first requested it would have been used and if a ROOT dictionary is
2940  // loaded later on TClassTable::Add will take care of updating the TClass.
2941  // So as far as ROOT dictionary are concerned, if the current TClass is
2942  // in interpreted state, we are sure there is nothing to load.
2943  //
2944  // However (see TROOT::LoadClass), the TClass can also be loaded/provided
2945  // by a user provided TClassGenerator. We have no way of knowing whether
2946  // those do (or even can) behave the same way as the ROOT dictionary and
2947  // have the 'dictionary is now available for use' step informs the existing
2948  // TClass that their dictionary is now available.
2949 
2950  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
2951  load = kTRUE;
2952  }
2953 
2954  // To avoid spurious auto parsing, let's check if the name as-is is
2955  // known in the TClassTable.
2956  DictFuncPtr_t dict = TClassTable::GetDictNorm(name);
2957  if (dict) {
2958  // The name is normalized, so the result of the first search is
2959  // authoritative.
2960  if (!cl && !load) return 0;
2961 
2962  TClass *loadedcl = (dict)();
2963  if (loadedcl) {
2964  loadedcl->PostLoadCheck();
2965  return loadedcl;
2966  }
2967 
2968  // We should really not fall through to here, but if we do, let's just
2969  // continue as before ...
2970  }
2971 
2972  std::string normalizedName;
2973  Bool_t checkTable = kFALSE;
2974 
2975  if (!cl) {
2976  {
2977  TInterpreter::SuspendAutoloadingRAII autoloadOff(gInterpreter);
2978  TClassEdit::GetNormalizedName(normalizedName, name);
2979  }
2980  // Try the normalized name.
2981  if (normalizedName != name) {
2982  cl = (TClass*)gROOT->GetListOfClasses()->FindObject(normalizedName.c_str());
2983 
2984  if (cl) {
2985  if (cl->IsLoaded() || cl->TestBit(kUnloading)) return cl;
2986 
2987  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
2988  load = kTRUE;
2989  }
2990  checkTable = kTRUE;
2991  }
2992  } else {
2993  normalizedName = cl->GetName(); // Use the fact that all TClass names are normalized.
2994  checkTable = load && (normalizedName != name);
2995  }
2996 
2997  if (!load) return 0;
2998 
2999 // This assertion currently fails because of
3000 // TClass *c1 = TClass::GetClass("basic_iostream<char,char_traits<char> >");
3001 // TClass *c2 = TClass::GetClass("std::iostream");
3002 // where the TClassEdit normalized name of iostream is basic_iostream<char>
3003 // i.e missing the addition of the default parameter. This is because TClingLookupHelper
3004 // uses only 'part' of TMetaUtils::GetNormalizedName.
3005 
3006 // if (!cl) {
3007 // TDataType* dataType = (TDataType*)gROOT->GetListOfTypes()->FindObject(name);
3008 // TClass *altcl = dataType ? (TClass*)gROOT->GetListOfClasses()->FindObject(dataType->GetFullTypeName()) : 0;
3009 // if (altcl && normalizedName != altcl->GetName())
3010 // ::Fatal("TClass::GetClass","The existing name (%s) for %s is different from the normalized name: %s\n",
3011 // altcl->GetName(), name, normalizedName.c_str());
3012 // }
3013 
3014  TClass *loadedcl = 0;
3015  if (checkTable) {
3016  loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
3017  } else {
3018  if (gInterpreter->AutoLoad(normalizedName.c_str(),kTRUE)) {
3019  loadedcl = LoadClassDefault(normalizedName.c_str(),silent);
3020  }
3021  // Maybe this was a typedef: let's try to see if this is the case
3022  if (!loadedcl){
3023  if (TDataType* theDataType = gROOT->GetType(normalizedName.c_str())){
3024  // We have a typedef: we get the name of the underlying type
3025  auto underlyingTypeName = theDataType->GetTypeName();
3026  // We see if we can bootstrap a class with it
3027  auto underlyingTypeDict = TClassTable::GetDictNorm(underlyingTypeName.Data());
3028  if (underlyingTypeDict){
3029  loadedcl = underlyingTypeDict();
3030  }
3031 
3032  }
3033  }
3034  }
3035  if (loadedcl) return loadedcl;
3036 
3037  // See if the TClassGenerator can produce the TClass we need.
3038  loadedcl = LoadClassCustom(normalizedName.c_str(),silent);
3039  if (loadedcl) return loadedcl;
3040 
3041  // We have not been able to find a loaded TClass, return the Emulated
3042  // TClass if we have one.
3043  if (cl) return cl;
3044 
3045  if (TClassEdit::IsSTLCont( normalizedName.c_str() )) {
3046 
3047  return gInterpreter->GenerateTClass(normalizedName.c_str(), kTRUE, silent);
3048  }
3049 
3050  // Check the interpreter only after autoparsing the template if any.
3051  {
3052  std::string::size_type posLess = normalizedName.find('<');
3053  if (posLess != std::string::npos) {
3054  gCling->AutoParse(normalizedName.substr(0, posLess).c_str());
3055  }
3056  }
3057 
3058  //last attempt. Look in CINT list of all (compiled+interpreted) classes
3059  if (gDebug>0){
3060  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());
3061  }
3062  if (normalizedName.length()) {
3063  auto cci = gInterpreter->CheckClassInfo(normalizedName.c_str(), kTRUE /* autoload */,
3064  kTRUE /*Only class, structs and ns*/);
3065 
3066  // We could have an interpreted class with an inline ClassDef, in this case we do not
3067  // want to create an 'interpreted' TClass but we want the one triggered via the call to
3068  // the Dictionary member. If we go ahead and generate the 'interpreted' version it will
3069  // replace if/when there is a call to IsA on an object of this type.
3070 
3071  if (cci == TInterpreter::kWithClassDefInline) {
3072  auto ci = gInterpreter->ClassInfo_Factory(normalizedName.c_str());
3073  auto funcDecl = gInterpreter->GetFunctionWithPrototype(ci, "Dictionary", "", false, ROOT::kExactMatch);
3074  auto method = gInterpreter->MethodInfo_Factory(funcDecl);
3075  typedef void (*tcling_callfunc_Wrapper_t)(void *, int, void **, void *);
3076  auto funcPtr = (tcling_callfunc_Wrapper_t)gInterpreter->MethodInfo_InterfaceMethod(method);
3077 
3078  TClass *res = nullptr;
3079  if (funcPtr)
3080  funcPtr(0, 0, nullptr, &res);
3081  // else
3082  // We could fallback to the interpreted case ...
3083  // For now just 'fail' (return nullptr)
3084 
3085  gInterpreter->MethodInfo_Delete(method);
3086  gInterpreter->ClassInfo_Delete(ci);
3087 
3088  return res;
3089  } else if (cci) {
3090  // Get the normalized name based on the decl (currently the only way
3091  // to get the part to add or drop the default arguments as requested by the user)
3092  std::string alternative;
3093  gInterpreter->GetInterpreterTypeName(normalizedName.c_str(), alternative, kTRUE);
3094  const char *altname = alternative.c_str();
3095  if (strncmp(altname, "std::", 5) == 0) {
3096  // For namespace (for example std::__1), GetInterpreterTypeName does
3097  // not strip std::, so we must do it explicitly here.
3098  altname += 5;
3099  }
3100  if (altname != normalizedName && strcmp(altname, name) != 0) {
3101  // altname now contains the full name of the class including a possible
3102  // namespace if there has been a using namespace statement.
3103 
3104  // At least in the case C<string [2]> (normalized) vs C<string[2]> (altname)
3105  // the TClassEdit normalization and the TMetaUtils normalization leads to
3106  // two different space layout. To avoid an infinite recursion, we also
3107  // add the test on (altname != name)
3108 
3109  return GetClass(altname, load);
3110  }
3111 
3112  TClass *ncl = gInterpreter->GenerateTClass(normalizedName.c_str(), /* emulation = */ kFALSE, silent);
3113  if (!ncl->IsZombie()) {
3114  return ncl;
3115  }
3116  delete ncl;
3117  }
3118  }
3119  return nullptr;
3120 }
3121 
3122 ////////////////////////////////////////////////////////////////////////////////
3123 /// Return pointer to class with name.
3124 
3125 TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */)
3126 {
3127  if (!gROOT->GetListOfClasses())
3128  return 0;
3129 
3130  //protect access to TROOT::GetIdMap
3131  R__READ_LOCKGUARD(ROOT::gCoreMutex);
3132 
3133  TClass* cl = GetIdMap()->Find(typeinfo.name());
3134 
3135  if (cl && cl->IsLoaded()) return cl;
3136 
3137  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
3138 
3139  // Now that we got the write lock, another thread may have constructed the
3140  // TClass while we were waiting, so we need to do the checks again.
3141 
3142  cl = GetIdMap()->Find(typeinfo.name());
3143 
3144  if (cl) {
3145  if (cl->IsLoaded()) return cl;
3146  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3147  load = kTRUE;
3148  } else {
3149  // Note we might need support for typedefs and simple types!
3150 
3151  // TDataType *objType = GetType(name, load);
3152  //if (objType) {
3153  // const char *typdfName = objType->GetTypeName();
3154  // if (typdfName && strcmp(typdfName, name)) {
3155  // cl = GetClass(typdfName, load);
3156  // return cl;
3157  // }
3158  // }
3159  }
3160 
3161  if (!load) return 0;
3162 
3163  DictFuncPtr_t dict = TClassTable::GetDict(typeinfo);
3164  if (dict) {
3165  cl = (dict)();
3166  if (cl) cl->PostLoadCheck();
3167  return cl;
3168  }
3169  if (cl) return cl;
3170 
3171  TIter next(gROOT->GetListOfClassGenerators());
3172  TClassGenerator *gen;
3173  while( (gen = (TClassGenerator*) next()) ) {
3174  cl = gen->GetClass(typeinfo,load);
3175  if (cl) {
3176  cl->PostLoadCheck();
3177  return cl;
3178  }
3179  }
3180 
3181  // try autoloading the typeinfo
3182  int autoload_old = gCling->SetClassAutoloading(1);
3183  if (!autoload_old) {
3184  // Re-disable, we just meant to test
3185  gCling->SetClassAutoloading(0);
3186  }
3187  if (autoload_old && gInterpreter->AutoLoad(typeinfo,kTRUE)) {
3188  // Disable autoload to avoid potential infinite recursion
3189  TInterpreter::SuspendAutoloadingRAII autoloadOff(gInterpreter);
3190  cl = GetClass(typeinfo, load);
3191  if (cl) {
3192  return cl;
3193  }
3194  }
3195 
3196  // last attempt. Look in the interpreter list of all (compiled+interpreted)
3197  // classes
3198  cl = gInterpreter->GetClass(typeinfo, load);
3199 
3200  return cl; // Can be zero.
3201 }
3202 
3203 ////////////////////////////////////////////////////////////////////////////////
3204 /// Static method returning pointer to TClass of the specified ClassInfo.
3205 /// If load is true an attempt is made to obtain the class by loading
3206 /// the appropriate shared library (directed by the rootmap file).
3207 /// If silent is 'true', do not warn about missing dictionary for the class.
3208 /// (typically used for class that are used only for transient members)
3209 /// Returns 0 in case class is not found.
3210 
3211 TClass *TClass::GetClass(ClassInfo_t *info, Bool_t load, Bool_t silent)
3212 {
3213  if (!info || !gCling->ClassInfo_IsValid(info)) return 0;
3214  if (!gROOT->GetListOfClasses()) return 0;
3215 
3216  // Technically we need the write lock only for the call to ClassInfo_FullName
3217  // and GenerateTClass but FindObject will take the read lock (and LoadClass will
3218  // take the write lock). Since taking/releasing the lock is expensive, let just
3219  // take the write guard and keep it.
3220  R__WRITE_LOCKGUARD(ROOT::gCoreMutex);
3221 
3222  // Get the normalized name.
3223  TString name( gCling->ClassInfo_FullName(info) );
3224 
3225  TClass *cl = (TClass*)gROOT->GetListOfClasses()->FindObject(name);
3226 
3227  if (cl) {
3228  if (cl->IsLoaded()) return cl;
3229 
3230  //we may pass here in case of a dummy class created by TVirtualStreamerInfo
3231  load = kTRUE;
3232 
3233  }
3234 
3235  if (!load) return 0;
3236 
3237  TClass *loadedcl = 0;
3238  if (cl) loadedcl = gROOT->LoadClass(cl->GetName(),silent);
3239  else loadedcl = gROOT->LoadClass(name,silent);
3240 
3241  if (loadedcl) return loadedcl;
3242 
3243  if (cl) return cl; // If we found the class but we already have a dummy class use it.
3244 
3245  // We did not find a proper TClass but we do know (we have a valid
3246  // ClassInfo) that the class is known to the interpreter.
3247  TClass *ncl = gInterpreter->GenerateTClass(info, silent);
3248  if (!ncl->IsZombie()) {
3249  return ncl;
3250  } else {
3251  delete ncl;
3252  return 0;
3253  }
3254 }
3255 
3256 ////////////////////////////////////////////////////////////////////////////////
3257 
3258 Bool_t TClass::HasNoInfoOrEmuOrFwdDeclaredDecl(const char* name){
3259  return fNoInfoOrEmuOrFwdDeclNameRegistry.HasDeclName(name);
3260 }
3261 
3262 ////////////////////////////////////////////////////////////////////////////////
3263 
3264 Bool_t TClass::GetClass(DeclId_t id, std::vector<TClass*> &classes)
3265 {
3266  if (!gROOT->GetListOfClasses()) return 0;
3267 
3268  DeclIdMap_t* map = GetDeclIdMap();
3269  // Get all the TClass pointer that have the same DeclId.
3270  DeclIdMap_t::equal_range iter = map->Find(id);
3271  if (iter.first == iter.second) return false;
3272  std::vector<TClass*>::iterator vectIt = classes.begin();
3273  for (DeclIdMap_t::const_iterator it = iter.first; it != iter.second; ++it)
3274  vectIt = classes.insert(vectIt, it->second);
3275  return true;
3276 }
3277 
3278 ////////////////////////////////////////////////////////////////////////////////
3279 /// Return a pointer to the dictionary loading function generated by
3280 /// rootcint
3281 
3282 DictFuncPtr_t TClass::GetDict (const char *cname)
3283 {
3284  return TClassTable::GetDict(cname);
3285 }
3286 
3287 ////////////////////////////////////////////////////////////////////////////////
3288 /// Return a pointer to the dictionary loading function generated by
3289 /// rootcint
3290 
3291 DictFuncPtr_t TClass::GetDict (const std::type_info& info)
3292 {
3293  return TClassTable::GetDict(info);
3294 }
3295 
3296 ////////////////////////////////////////////////////////////////////////////////
3297 /// Return pointer to datamember object with name "datamember".
3298 
3299 TDataMember *TClass::GetDataMember(const char *datamember) const
3300 {
3301  if ((!(fData && fData->IsLoaded()) && !HasInterpreterInfo())
3302  || datamember == 0) return 0;
3303 
3304  // Strip off leading *'s and trailing [
3305  const char *start_name = datamember;
3306  while (*start_name == '*') ++start_name;
3307 
3308  // Empty name are 'legal', they represent anonymous unions.
3309  // if (*start_name == 0) return 0;
3310 
3311  if (const char *s = strchr(start_name, '[')){
3312  UInt_t len = s-start_name;
3313  TString name(start_name,len);
3314  return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(name.Data());
3315  } else {
3316  return (TDataMember *)((TClass*)this)->GetListOfDataMembers(kFALSE)->FindObject(start_name);
3317  }
3318 }
3319 
3320 ////////////////////////////////////////////////////////////////////////////////
3321 /// Return name of the file containing the declaration of this class.
3322 
3323 const char *TClass::GetDeclFileName() const
3324 {
3325  if (fDeclFileName == kUndeterminedClassInfoName)
3326  return gInterpreter->ClassInfo_FileName( fClassInfo );
3327  return fDeclFileName;
3328 }
3329 
3330 ////////////////////////////////////////////////////////////////////////////////
3331 /// return offset for member name. name can be a data member in
3332 /// the class itself, one of its base classes, or one member in
3333 /// one of the aggregated classes.
3334 ///
3335 /// In case of an emulated class, the list of emulated TRealData is built
3336 
3337 Long_t TClass::GetDataMemberOffset(const char *name) const
3338 {
3339  TRealData *rd = GetRealData(name);
3340  if (rd) return rd->GetThisOffset();
3341  if (strchr(name,'[')==0) {
3342  // If this is a simple name there is a chance to find it in the
3343  // StreamerInfo even if we did not find it in the RealData.
3344  // For example an array name would be fArray[3] in RealData but
3345  // just fArray in the streamerInfo.
3346  TVirtualStreamerInfo *info = const_cast<TClass*>(this)->GetCurrentStreamerInfo();
3347  if (info) {
3348  return info->GetOffset(name);
3349  }
3350  }
3351  return 0;
3352 }
3353 
3354 ////////////////////////////////////////////////////////////////////////////////
3355 /// Return pointer to TRealData element with name "name".
3356 ///
3357 /// Name can be a data member in the class itself,
3358 /// one of its base classes, or a member in
3359 /// one of the aggregated classes.
3360 ///
3361 /// In case of an emulated class, the list of emulated TRealData is built.
3362 
3363 TRealData* TClass::GetRealData(const char* name) const
3364 {
3365  if (!fRealData) {
3366  const_cast<TClass*>(this)->BuildRealData();
3367  }
3368 
3369  if (!fRealData) {
3370  return 0;
3371  }
3372 
3373  if (!name) {
3374  return 0;
3375  }
3376 
3377  // First try just the whole name.
3378  TRealData* rd = (TRealData*) fRealData->FindObject(name);
3379  if (rd) {
3380  return rd;
3381  }
3382 
3383  std::string givenName(name);
3384 
3385  // Try ignoring the array dimensions.
3386  std::string::size_type firstBracket = givenName.find_first_of("[");
3387  if (firstBracket != std::string::npos) {
3388  // -- We are looking for an array data member.
3389  std::string nameNoDim(givenName.substr(0, firstBracket));
3390  TObjLink* lnk = fRealData->FirstLink();
3391  while (lnk) {
3392  TObject* obj = lnk->GetObject();
3393  std::string objName(obj->GetName());
3394  std::string::size_type pos = objName.find_first_of("[");
3395  // Only match arrays to arrays for now.
3396  if (pos != std::string::npos) {
3397  objName.erase(pos);
3398  if (objName == nameNoDim) {
3399  return static_cast<TRealData*>(obj);
3400  }
3401  }
3402  lnk = lnk->Next();
3403  }
3404  }
3405 
3406  // Now try it as a pointer.
3407  std::ostringstream ptrname;
3408  ptrname << "*" << givenName;
3409  rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3410  if (rd) {
3411  return rd;
3412  }
3413 
3414  // Check for a dot in the name.
3415  std::string::size_type firstDot = givenName.find_first_of(".");
3416  if (firstDot == std::string::npos) {
3417  // -- Not found, a simple name, all done.
3418  return 0;
3419  }
3420 
3421  //
3422  // At this point the name has a dot in it, so it is the name
3423  // of some contained sub-object.
3424  //
3425 
3426  // May be a pointer like in TH1: fXaxis.fLabels (in TRealdata is named fXaxis.*fLabels)
3427  std::string::size_type lastDot = givenName.find_last_of(".");
3428  std::ostringstream starname;
3429  starname << givenName.substr(0, lastDot) << ".*" << givenName.substr(lastDot + 1);
3430  rd = (TRealData*) fRealData->FindObject(starname.str().c_str());
3431  if (rd) {
3432  return rd;
3433  }
3434 
3435  // Strip the first component, it may be the name of
3436  // the branch (old TBranchElement code), and try again.
3437  std::string firstDotName(givenName.substr(firstDot + 1));
3438 
3439  // New attempt starting after the first "." if any,
3440  // this allows for the case that the first component
3441  // may have been a branch name (for TBranchElement).
3442  rd = (TRealData*) fRealData->FindObject(firstDotName.c_str());
3443  if (rd) {
3444  return rd;
3445  }
3446 
3447  // New attempt starting after the first "." if any,
3448  // but this time try ignoring the array dimensions.
3449  // Again, we are allowing for the case that the first
3450  // component may have been a branch name (for TBranchElement).
3451  std::string::size_type firstDotBracket = firstDotName.find_first_of("[");
3452  if (firstDotBracket != std::string::npos) {
3453  // -- We are looking for an array data member.
3454  std::string nameNoDim(firstDotName.substr(0, firstDotBracket));
3455  TObjLink* lnk = fRealData->FirstLink();
3456  while (lnk) {
3457  TObject* obj = lnk->GetObject();
3458  std::string objName(obj->GetName());
3459  std::string::size_type pos = objName.find_first_of("[");
3460  // Only match arrays to arrays for now.
3461  if (pos != std::string::npos) {
3462  objName.erase(pos);
3463  if (objName == nameNoDim) {
3464  return static_cast<TRealData*>(obj);
3465  }
3466  }
3467  lnk = lnk->Next();
3468  }
3469  }
3470 
3471  // New attempt starting after the first "." if any,
3472  // but this time check for a pointer type. Again, we
3473  // are allowing for the case that the first component
3474  // may have been a branch name (for TBranchElement).
3475  ptrname.str("");
3476  ptrname << "*" << firstDotName;
3477  rd = (TRealData*) fRealData->FindObject(ptrname.str().c_str());
3478  if (rd) {
3479  return rd;
3480  }
3481 
3482  // Last attempt in case a member has been changed from
3483  // a static array to a pointer, for example the member
3484  // was arr[20] and is now *arr.
3485  //
3486  // Note: In principle, one could also take into account
3487  // the opposite situation where a member like *arr has
3488  // been converted to arr[20].
3489  //
3490  // FIXME: What about checking after the first dot as well?
3491  //
3492  std::string::size_type bracket = starname.str().find_first_of("[");
3493  if (bracket == std::string::npos) {
3494  return 0;
3495  }
3496  rd = (TRealData*) fRealData->FindObject(starname.str().substr(0, bracket).c_str());
3497  if (rd) {
3498  return rd;
3499  }
3500 
3501  // Not found;
3502  return 0;
3503 }
3504 
3505 ////////////////////////////////////////////////////////////////////////////////
3506 
3507 TFunctionTemplate *TClass::GetFunctionTemplate(const char *name)
3508 {
3509  if (!gInterpreter || !HasInterpreterInfo()) return 0;
3510 
3511  // The following
3512  if (!fFuncTemplate) fFuncTemplate = new TListOfFunctionTemplates(this);
3513 
3514  return (TFunctionTemplate*)fFuncTemplate->FindObject(name);
3515 }
3516 
3517 ////////////////////////////////////////////////////////////////////////////////
3518 /// Get the list of shared libraries containing the code for class cls.
3519 /// The first library in the list is the one containing the class, the
3520 /// others are the libraries the first one depends on. Returns 0
3521 /// in case the library is not found.
3522 
3523 const char *TClass::GetSharedLibs()
3524 {
3525  if (!gInterpreter) return 0;
3526 
3527  if (fSharedLibs.IsNull())
3528  fSharedLibs = gInterpreter->GetClassSharedLibs(fName);
3529 
3530  return !fSharedLibs.IsNull() ? fSharedLibs.Data() : 0;
3531 }
3532 
3533 ////////////////////////////////////////////////////////////////////////////////
3534 /// Return list containing the TBaseClass(es) of a class.
3535 
3536 TList *TClass::GetListOfBases()
3537 {
3538  if (!fBase.load()) {
3539  if (fCanLoadClassInfo) {
3540  if (fState == kHasTClassInit) {
3541 
3542  R__LOCKGUARD(gInterpreterMutex);
3543  // NOTE: Add test to prevent redo if another thread has already done the work.
3544  // if (!fHasRootPcmInfo) {
3545 
3546  // The bases are in our ProtoClass; we don't need the class info.
3547  TProtoClass *proto = TClassTable::GetProtoNorm(GetName());
3548  if (proto && proto->FillTClass(this)) {
3549  // Not sure this code is still needed
3550  // R__ASSERT(kFALSE);
3551 
3552  fHasRootPcmInfo = kTRUE;
3553  }
3554  }
3555  // We test again on fCanLoadClassInfo has another thread may have executed it.
3556  if (!fHasRootPcmInfo && !fCanLoadClassInfo) {
3557  LoadClassInfo();
3558  }
3559  }
3560  if (!fClassInfo) return 0;
3561 
3562  if (!gInterpreter)
3563  Fatal("GetListOfBases", "gInterpreter not initialized");
3564 
3565  R__LOCKGUARD(gInterpreterMutex);
3566  if (!fBase.load()) {
3567  gInterpreter->CreateListOfBaseClasses(this);
3568  }
3569  }
3570  return fBase;
3571 }
3572 
3573 ////////////////////////////////////////////////////////////////////////////////
3574 /// Return a list containing the TEnums of a class.
3575 ///
3576 /// The list returned is safe to use from multiple thread without explicitly
3577 /// taking the ROOT global lock.
3578 ///
3579 /// In the case the TClass represents a namespace, the returned list will
3580 /// implicit take the ROOT global lock upon any access (see TListOfEnumsWithLock)
3581 ///
3582 /// In the case the TClass represents a class or struct and requestListLoading
3583 /// is true, the list is immutable (and thus safe to access from multiple thread
3584 /// without taking the global lock at all).
3585 ///
3586 /// In the case the TClass represents a class or struct and requestListLoading
3587 /// is false, the list is mutable and thus we return a TListOfEnumsWithLock
3588 /// which will implicit take the ROOT global lock upon any access.
3589 
3590 TList *TClass::GetListOfEnums(Bool_t requestListLoading /* = kTRUE */)
3591 {
3592  auto temp = fEnums.load();
3593  if (temp) {
3594  if (requestListLoading) {
3595  if (fProperty == -1) Property();
3596  if (! ((kIsClass | kIsStruct | kIsUnion) & fProperty) ) {
3597  R__LOCKGUARD(gROOTMutex);
3598  temp->Load();
3599  } else if ( temp->IsA() == TListOfEnumsWithLock::Class() ) {
3600  // We have a class for which the list was not loaded fully at
3601  // first use.
3602  R__LOCKGUARD(gROOTMutex);
3603  temp->Load();
3604  }
3605  }
3606  return temp;
3607  }
3608 
3609  if (!requestListLoading) {
3610  if (fProperty == -1) Property();
3611  R__LOCKGUARD(gInterpreterMutex);
3612  if (fEnums.load()) {
3613  return fEnums.load();
3614  }
3615 
3616  static bool fromRootCling = dlsym(RTLD_DEFAULT, "usedToIdentifyRootClingByDlSym");
3617 
3618  if (fromRootCling) // rootcling is single thread (this save some space in the rootpcm).
3619  fEnums = new TListOfEnums(this);
3620  else
3621  fEnums = new TListOfEnumsWithLock(this);
3622  return fEnums;
3623  }
3624 
3625  R__LOCKGUARD(gInterpreterMutex);
3626  if (fEnums.load()) {
3627  (*fEnums).Load();
3628  return fEnums.load();
3629  }
3630  if (fProperty == -1) Property();
3631  if ( (kIsClass | kIsStruct | kIsUnion) & fProperty) {
3632  // For this case, the list will be immutable
3633  temp = new TListOfEnums(this);
3634  } else {
3635  //namespaces can have enums added to them
3636  temp = new TListOfEnumsWithLock(this);
3637  }
3638  temp->Load();
3639  fEnums = temp;
3640  return temp;
3641 }
3642 
3643 ////////////////////////////////////////////////////////////////////////////////
3644 /// Return list containing the TDataMembers of a class.
3645 
3646 TList *TClass::GetListOfDataMembers(Bool_t load /* = kTRUE */)
3647 {
3648  R__LOCKGUARD(gInterpreterMutex);
3649 
3650  if (!fData) {
3651  if (fCanLoadClassInfo && fState == kHasTClassInit) {
3652  // NOTE: Add test to prevent redo if another thread has already done the work.
3653  // if (!fHasRootPcmInfo) {
3654 
3655  // The members are in our ProtoClass; we don't need the class info.
3656  TProtoClass *proto = TClassTable::GetProtoNorm(GetName());
3657  if (proto && proto->FillTClass(this)) {
3658  // Not sure this code is still needed
3659  // R__ASSERT(kFALSE);
3660 
3661  fHasRootPcmInfo = kTRUE;
3662  return fData;
3663  }
3664  }
3665  fData = new TListOfDataMembers(this);
3666  }
3667  if (Property() & (kIsClass|kIsStruct|kIsUnion)) {
3668  // If the we have a class or struct or union, the order
3669  // of data members is the list is essential since it determines their
3670  // order on file. So we must always load. Also, the list is fixed
3671  // since the language does not allow to add members.
3672  if (!fData->IsLoaded()) fData->Load();
3673 
3674  } else if (load) fData->Load();
3675  return fData;
3676 }
3677 
3678 ////////////////////////////////////////////////////////////////////////////////
3679 /// Return list containing the TEnums of a class.
3680 
3681 TList *TClass::GetListOfFunctionTemplates(Bool_t load /* = kTRUE */)
3682 {
3683  R__LOCKGUARD(gInterpreterMutex);
3684 
3685  if (!fFuncTemplate) fFuncTemplate = new TListOfFunctionTemplates(this);
3686  if (load) fFuncTemplate->Load();
3687  return fFuncTemplate;
3688 }
3689 
3690 ////////////////////////////////////////////////////////////////////////////////
3691 /// Return list containing the TMethods of a class.
3692 /// If load is true, the list is populated with all the defined function
3693 /// and currently instantiated function template.
3694 
3695 TList *TClass::GetListOfMethods(Bool_t load /* = kTRUE */)
3696 {
3697  R__LOCKGUARD(gInterpreterMutex);
3698 
3699  if (!fMethod.load()) GetMethodList();
3700  if (load) {
3701  if (gDebug>0) Info("GetListOfMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3702  (*fMethod).Load();
3703  }
3704  return fMethod;
3705 }
3706 
3707 ////////////////////////////////////////////////////////////////////////////////
3708 /// Return the collection of functions named "name".
3709 
3710 TCollection *TClass::GetListOfMethodOverloads(const char* name) const
3711 {
3712  return const_cast<TClass*>(this)->GetMethodList()->GetListForObject(name);
3713 }
3714 
3715 
3716 ////////////////////////////////////////////////////////////////////////////////
3717 /// Returns a list of all public methods of this class and its base classes.
3718 /// Refers to a subset of the methods in GetListOfMethods() so don't do
3719 /// GetListOfAllPublicMethods()->Delete().
3720 /// Algorithm used to get the list is:
3721 /// - put all methods of the class in the list (also protected and private
3722 /// ones).
3723 /// - loop over all base classes and add only those methods not already in the
3724 /// list (also protected and private ones).
3725 /// - once finished, loop over resulting list and remove all private and
3726 /// protected methods.
3727 
3728 const TList *TClass::GetListOfAllPublicMethods(Bool_t load /* = kTRUE */)
3729 {
3730  R__LOCKGUARD(gInterpreterMutex);
3731 
3732  if (!fAllPubMethod) fAllPubMethod = new TViewPubFunctions(this);
3733  if (load) {
3734  if (gDebug>0) Info("GetListOfAllPublicMethods","Header Parsing - Asking for all the methods of class %s: this can involve parsing.",GetName());
3735  fAllPubMethod->Load();
3736  }
3737  return fAllPubMethod;
3738 }
3739 
3740 ////////////////////////////////////////////////////////////////////////////////
3741 /// Returns a list of all public data members of this class and its base
3742 /// classes. Refers to a subset of the data members in GetListOfDatamembers()
3743 /// so don't do GetListOfAllPublicDataMembers()->Delete().
3744 
3745 TList *TClass::GetListOfAllPublicDataMembers(Bool_t load /* = kTRUE */)
3746 {
3747  R__LOCKGUARD(gInterpreterMutex);
3748 
3749  if (!fAllPubData) fAllPubData = new TViewPubDataMembers(this);
3750  if (load) fAllPubData->Load();
3751  return fAllPubData;
3752 }
3753 
3754 ////////////////////////////////////////////////////////////////////////////////
3755 /// Returns list of methods accessible by context menu.
3756 
3757 void TClass::GetMenuItems(TList *list)
3758 {
3759  if (!HasInterpreterInfo()) return;
3760 
3761  // get the base class
3762  TIter nextBase(GetListOfBases(), kIterBackward);
3763  TBaseClass *baseClass;
3764  while ((baseClass = (TBaseClass *) nextBase())) {
3765  TClass *base = baseClass->GetClassPointer();
3766  if (base) base->GetMenuItems(list);
3767  }
3768 
3769  // remove methods redefined in this class with no menu
3770  TMethod *method, *m;
3771  TIter next(GetListOfMethods(), kIterBackward);
3772  while ((method = (TMethod*)next())) {
3773  m = (TMethod*)list->FindObject(method->GetName());
3774  if (method->IsMenuItem() != kMenuNoMenu) {
3775  if (!m)
3776  list->AddFirst(method);
3777  } else {
3778  if (m && m->GetNargs() == method->GetNargs())
3779  list->Remove(m);
3780  }
3781  }
3782 }
3783 
3784 ////////////////////////////////////////////////////////////////////////////////
3785 /// Check whether a class has a dictionary or not.
3786 /// This is equivalent to ask if a class is coming from a bootstrapping
3787 /// procedure initiated during the loading of a library.
3788 
3789 Bool_t TClass::HasDictionary() const
3790 {
3791  return IsLoaded();
3792 }
3793 
3794 ////////////////////////////////////////////////////////////////////////////////
3795 /// Check whether a class has a dictionary or ROOT can load one.
3796 /// This is equivalent to ask HasDictionary() or whether a library is known
3797 /// where it can be loaded from, or whether a Dictionary function is
3798 /// available because the class's dictionary library was already loaded.
3799 
3800 Bool_t TClass::HasDictionarySelection(const char* clname)
3801 {
3802  if (TClass* cl = (TClass*)gROOT->GetListOfClasses()->FindObject(clname))
3803  return cl->IsLoaded();
3804  return gClassTable->GetDict(clname) || gInterpreter->GetClassSharedLibs(clname);
3805 }
3806 
3807 ////////////////////////////////////////////////////////////////////////////////
3808 /// Verify the base classes always.
3809 
3810 void TClass::GetMissingDictionariesForBaseClasses(TCollection& result, TCollection& visited, bool recurse)
3811 {
3812  TList* lb = GetListOfBases();
3813  if (!lb) return;
3814  TIter nextBase(lb);
3815  TBaseClass* base = 0;
3816  while ((base = (TBaseClass*)nextBase())) {
3817  TClass* baseCl = base->GetClassPointer();
3818  if (baseCl) {
3819  baseCl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3820  }
3821  }
3822 }
3823 
3824 ////////////////////////////////////////////////////////////////////////////////
3825 /// Verify the Data Members.
3826 
3827 void TClass::GetMissingDictionariesForMembers(TCollection& result, TCollection& visited, bool recurse)
3828 {
3829  TListOfDataMembers* ldm = (TListOfDataMembers*)GetListOfDataMembers();
3830  if (!ldm) return ;
3831  TIter nextMemb(ldm);
3832  TDataMember * dm = 0;
3833  while ((dm = (TDataMember*)nextMemb())) {
3834  // If it is a transient
3835  if(!dm->IsPersistent()) {
3836  continue;
3837  }
3838  if (dm->Property() & kIsStatic) {
3839  continue;
3840  }
3841  // If it is a built-in data type.
3842  TClass* dmTClass = 0;
3843  if (dm->GetDataType()) {
3844  // We have a basic datatype.
3845  dmTClass = nullptr;
3846  // Otherwise get the string representing the type.
3847  } else if (dm->GetTypeName()) {
3848  dmTClass = TClass::GetClass(dm->GetTypeName());
3849  }
3850  if (dmTClass) {
3851  dmTClass->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3852  }
3853  }
3854 }
3855 
3856 void TClass::GetMissingDictionariesForPairElements(TCollection& result, TCollection& visited, bool recurse)
3857 {
3858  // Pair is a special case and we have to check its elements for missing dictionaries
3859  // Pair is a transparent container so we should always look at its.
3860 
3861  TVirtualStreamerInfo *SI = (TVirtualStreamerInfo*)this->GetStreamerInfo();
3862  for (int i = 0; i < 2; i++) {
3863  TClass* pairElement = ((TStreamerElement*)SI->GetElements()->At(i))->GetClass();
3864  if (pairElement) {
3865  pairElement->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3866  }
3867  }
3868 }
3869 
3870 ////////////////////////////////////////////////////////////////////////////////
3871 /// From the second level of recursion onwards it is different state check.
3872 
3873 void TClass::GetMissingDictionariesWithRecursionCheck(TCollection& result, TCollection& visited, bool recurse)
3874 {
3875  if (result.FindObject(this) || visited.FindObject(this)) return;
3876 
3877  static TClassRef sCIString("string");
3878  if (this == sCIString) return;
3879 
3880  TClassEdit::TSplitType splitType(fName);
3881  if (splitType.IsTemplate()) {
3882  // We now treat special cases:
3883  // - pair
3884  // - unique_ptr
3885  // - array
3886  // - tuple
3887 
3888  // Small helper to get the TClass instance from a classname and recursively
3889  // investigate it
3890  auto checkDicts = [&](const string &clName){
3891  auto cl = TClass::GetClass(clName.c_str());
3892  if (!cl) {
3893  // We try to remove * and const from the type name if any
3894  const auto clNameShortType = TClassEdit::ShortType(clName.c_str(), 1);
3895  cl = TClass::GetClass(clNameShortType.c_str());
3896  }
3897  if (cl && !cl->HasDictionary()) {
3898  cl->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3899  }
3900  };
3901 
3902  const auto &elements = splitType.fElements;
3903  const auto &templName = elements[0];
3904 
3905  // Special treatment for pair.
3906  if (templName == "pair") {
3907  GetMissingDictionariesForPairElements(result, visited, recurse);
3908  return;
3909  }
3910 
3911  // Special treatment of unique_ptr or array
3912  // They are treated together since they have 1 single template argument
3913  // which is interesting when checking for missing dictionaries.
3914  if (templName == "unique_ptr" || templName == "array") {
3915  checkDicts(elements[1]);
3916  return;
3917  }
3918 
3919  // Special treatment of tuple
3920  // This type must be treated separately since it can have N template
3921  // arguments which are interesting, unlike unique_ptr or array.
3922  if (templName == "tuple") {
3923  // -1 because the elements end with a list of the "stars", i.e. number of
3924  // * after the type name
3925  const auto nTemplArgs = elements.size() - 1;
3926  // loop starts at 1 because the first element is the template name
3927  for (auto iTemplArg = 1U; iTemplArg < nTemplArgs; ++iTemplArg) {
3928  checkDicts(elements[iTemplArg]);
3929  }
3930  return;
3931  }
3932  } // this is not a template
3933 
3934  if (!HasDictionary()) {
3935  result.Add(this);
3936  }
3937 
3938  visited.Add(this);
3939  //Check whether a custom streamer
3940  if (!TestBit(TClass::kHasCustomStreamerMember)) {
3941  if (GetCollectionProxy()) {
3942  // We need to look at the collection's content
3943  // The collection has different kind of elements the check would be required.
3944  TClass* t = 0;
3945  if ((t = GetCollectionProxy()->GetValueClass())) {
3946  if (!t->HasDictionary()) {
3947  t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
3948  }
3949  }
3950  } else {
3951  if (recurse) {
3952  GetMissingDictionariesForMembers(result, visited, recurse);
3953  }
3954  GetMissingDictionariesForBaseClasses(result, visited, recurse);
3955  }
3956  }
3957 }
3958 
3959 ////////////////////////////////////////////////////////////////////////////////
3960 /// Get the classes that have a missing dictionary starting from this one.
3961 /// - With recurse = false the classes checked for missing dictionaries are:
3962 /// the class itself, all base classes, direct data members,
3963 /// and for collection proxies the container's
3964 /// elements without iterating over the element's data members;
3965 /// - With recurse = true the classes checked for missing dictionaries are:
3966 /// the class itself, all base classes, recursing on the data members,
3967 /// and for the collection proxies recursion on the elements of the
3968 /// collection and iterating over the element's data members.
3969 
3970 void TClass::GetMissingDictionaries(THashTable& result, bool recurse)
3971 {
3972  // Top level recursion it different from the following levels of recursion.
3973 
3974  if (result.FindObject(this)) return;
3975 
3976  static TClassRef sCIString("string");
3977  if (this == sCIString) return;
3978 
3979  THashTable visited;
3980 
3981  if (strncmp(fName, "pair<", 5) == 0) {
3982  GetMissingDictionariesForPairElements(result, visited, recurse);
3983  return;
3984  }
3985 
3986  if (!HasDictionary()) {
3987  result.Add(this);
3988  }
3989 
3990  visited.Add(this);
3991 
3992  //Check whether a custom streamer
3993  if (!TestBit(TClass::kHasCustomStreamerMember)) {
3994  if (GetCollectionProxy()) {
3995  // We need to look at the collection's content
3996  // The collection has different kind of elements the check would be required.
3997  TClass* t = 0;
3998  if ((t = GetCollectionProxy()->GetValueClass())) {
3999  if (!t->HasDictionary()) {
4000  t->GetMissingDictionariesWithRecursionCheck(result, visited, recurse);
4001  }
4002  }
4003  } else {
4004  GetMissingDictionariesForMembers(result, visited, recurse);
4005  GetMissingDictionariesForBaseClasses(result, visited, recurse);
4006  }
4007  }
4008 }
4009 
4010 ////////////////////////////////////////////////////////////////////////////////
4011 /// Return kTRUE if the class has elements.
4012 
4013 Bool_t TClass::IsFolder(void *obj) const
4014 {
4015  return Browse(obj,(TBrowser*)0);
4016 }
4017 
4018 //______________________________________________________________________________
4019 //______________________________________________________________________________
4020 void TClass::ReplaceWith(TClass *newcl) const
4021 {
4022  // Inform the other objects to replace this object by the new TClass (newcl)
4023 
4024  R__LOCKGUARD(gInterpreterMutex);
4025  //we must update the class pointers pointing to 'this' in all TStreamerElements
4026  TIter nextClass(gROOT->GetListOfClasses());
4027  TClass *acl;
4028  TVirtualStreamerInfo *info;
4029  TList tobedeleted;
4030 
4031  // Since we are in the process of replacing a TClass by a TClass
4032  // coming from a dictionary, there is no point in loading any
4033  // libraries during this search.
4034  TInterpreter::SuspendAutoloadingRAII autoloadOff(gInterpreter);
4035  while ((acl = (TClass*)nextClass())) {
4036  if (acl == newcl) continue;
4037 
4038  TIter nextInfo(acl->GetStreamerInfos());
4039  while ((info = (TVirtualStreamerInfo*)nextInfo())) {
4040 
4041  info->Update(this, newcl);
4042  }
4043 
4044  if (acl->GetCollectionProxy()) {
4045  acl->GetCollectionProxy()->UpdateValueClass(this, newcl);
4046  }
4047  // We should also inform all the TBranchElement :( but we do not have a master list :(
4048  }
4049 
4050  TIter delIter( &tobedeleted );
4051  while ((acl = (TClass*)delIter())) {
4052  delete acl;
4053  }
4054  gInterpreter->UnRegisterTClassUpdate(this);
4055 }
4056 
4057 ////////////////////////////////////////////////////////////////////////////////
4058 /// Make sure that the current ClassInfo is up to date.
4059 
4060 void TClass::ResetClassInfo(Long_t /* tagnum */)
4061 {
4062  Warning("ResetClassInfo(Long_t tagnum)","Call to deprecated interface (does nothing)");
4063 }
4064 
4065 ////////////////////////////////////////////////////////////////////////////////
4066 /// Make sure that the current ClassInfo is up to date.
4067 
4068 void TClass::ResetClassInfo()
4069 {
4070  R__LOCKGUARD(gInterpreterMutex);
4071 
4072  InsertTClassInRegistryRAII insertRAII(fState,fName,fNoInfoOrEmuOrFwdDeclNameRegistry);
4073 
4074  if (fClassInfo) {
4075  TClass::RemoveClassDeclId(gInterpreter->GetDeclId(fClassInfo));
4076  gInterpreter->ClassInfo_Delete(fClassInfo);
4077  fClassInfo = 0;
4078  }
4079  // We can not check at this point whether after the unload there will
4080  // still be interpreter information about this class (as v5 was doing),
4081  // instead this function must only be called if the definition is (about)
4082  // to be unloaded.
4083 
4084  ResetCaches();
4085 
4086  // We got here because the definition Decl is about to be unloaded.
4087  if (fState != TClass::kHasTClassInit) {
4088  if (fStreamerInfo->GetEntries() != 0) {
4089  fState = TClass::kEmulated;
4090  } else {
4091  fState = TClass::kForwardDeclared;
4092  }
4093  } else {
4094  // if the ClassInfo was loaded for a class with a TClass Init and it
4095  // gets unloaded, should we guess it can be reloaded?
4096  fCanLoadClassInfo = kTRUE;
4097  }
4098 }
4099 
4100 ////////////////////////////////////////////////////////////////////////////////
4101 /// To clean out all caches.
4102 
4103 void TClass::ResetCaches()
4104 {
4105  R__ASSERT(!TestBit(kLoading) && "Resetting the caches does not make sense during loading!" );
4106 
4107  // Not owning lists, don't call Delete(), but unload
4108  if (fData)
4109  fData->Unload();
4110  if (fEnums.load())
4111  (*fEnums).Unload();
4112  if (fMethod.load())
4113  (*fMethod).Unload();
4114 
4115  delete fAllPubData; fAllPubData = 0;
4116 
4117  if (fBase.load())
4118  (*fBase).Delete();
4119  delete fBase.load(); fBase = 0;
4120 
4121  if (fRealData)
4122  fRealData->Delete();
4123  delete fRealData; fRealData=0;
4124 }
4125 
4126 ////////////////////////////////////////////////////////////////////////////////
4127 /// Resets the menu list to it's standard value.
4128 
4129 void TClass::ResetMenuList()
4130 {
4131  if (fClassMenuList)
4132  fClassMenuList->Delete();
4133  else
4134  fClassMenuList = new TList();
4135  fClassMenuList->Add(new TClassMenuItem(TClassMenuItem::kPopupStandardList, this));
4136 }
4137 
4138 ////////////////////////////////////////////////////////////////////////////////
4139 /// The ls function lists the contents of a class on stdout. Ls output
4140 /// is typically much less verbose then Dump().
4141 /// If options contains 'streamerinfo', run ls on the list of streamerInfos
4142 /// and the list of conversion streamerInfos.
4143 
4144 void TClass::ls(Option_t *options) const
4145 {
4146  TNamed::ls(options);
4147  if (options==0 || options[0]==0) return;
4148 
4149  if (strstr(options,"streamerinfo")!=0) {
4150  GetStreamerInfos()->ls(options);
4151 
4152  if (fConversionStreamerInfo.load()) {
4153  std::map<std::string, TObjArray*>::iterator it;
4154  std::map<std::string, TObjArray*>::iterator end = (*fConversionStreamerInfo).end();
4155  for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) {
4156  it->second->ls(options);
4157  }
4158  }
4159  }
4160 }
4161 
4162 ////////////////////////////////////////////////////////////////////////////////
4163 /// Makes a customizable version of the popup menu list, i.e. makes a list
4164 /// of TClassMenuItem objects of methods accessible by context menu.
4165 /// The standard (and different) way consists in having just one element
4166 /// in this list, corresponding to the whole standard list.
4167 /// Once the customizable version is done, one can remove or add elements.
4168 
4169 void TClass::MakeCustomMenuList()
4170 {
4171  R__LOCKGUARD(gInterpreterMutex);
4172  TClassMenuItem *menuItem;
4173 
4174  // Make sure fClassMenuList is initialized and empty.
4175  GetMenuList()->Delete();
4176 
4177  TList* methodList = new TList;
4178  GetMenuItems(methodList);
4179 
4180  TMethod *method;
4181  TMethodArg *methodArg;
4182  TClass *classPtr = 0;
4183  TIter next(methodList);
4184 
4185  while ((method = (TMethod*) next())) {
4186  // if go to a mother class method, add separator
4187  if (classPtr != method->GetClass()) {
4188  menuItem = new TClassMenuItem(TClassMenuItem::kPopupSeparator, this);
4189  fClassMenuList->AddLast(menuItem);
4190  classPtr = method->GetClass();
4191  }
4192  // Build the signature of the method
4193  TString sig;
4194  TList* margsList = method->GetListOfMethodArgs();
4195  TIter nextarg(margsList);
4196  while ((methodArg = (TMethodArg*)nextarg())) {
4197  sig = sig+","+methodArg->GetFullTypeName();
4198  }
4199  if (sig.Length()!=0) sig.Remove(0,1); // remove first comma
4200  menuItem = new TClassMenuItem(TClassMenuItem::kPopupUserFunction, this,
4201  method->GetName(), method->GetName(),0,
4202  sig.Data(),-1,TClassMenuItem::kIsSelf);
4203  if (method->IsMenuItem() == kMenuToggle) menuItem->SetToggle();
4204  fClassMenuList->Add(menuItem);
4205  }
4206  delete methodList;
4207 }
4208 
4209 ////////////////////////////////////////////////////////////////////////////////
4210 /// Register the fact that an object was moved from the memory location
4211 /// 'arenaFrom' to the memory location 'arenaTo'.
4212 
4213 void TClass::Move(void *arenaFrom, void *arenaTo) const
4214 {
4215  // If/when we have access to a copy constructor (or better to a move
4216  // constructor), this function should also perform the data move.
4217  // For now we just information the repository.
4218 
4219  if ((GetState() <= kEmulated) && !fCollectionProxy) {
4220  MoveAddressInRepository("TClass::Move",arenaFrom,arenaTo,this);
4221  }
4222 }
4223 
4224 ////////////////////////////////////////////////////////////////////////////////
4225 /// Return the list of menu items associated with the class.
4226 
4227 TList *TClass::GetMenuList() const {
4228  if (!fClassMenuList) {
4229  fClassMenuList = new TList();
4230  fClassMenuList->Add(new TClassMenuItem(TClassMenuItem::kPopupStandardList, const_cast<TClass*>(this)));
4231  }
4232  return fClassMenuList;
4233 }
4234 
4235 ////////////////////////////////////////////////////////////////////////////////
4236 /// Return (create an empty one if needed) the list of functions.
4237 /// The major difference with GetListOfMethod is that this returns
4238 /// the internal type of fMethod and thus can not be made public.
4239 /// It also never 'loads' the content of the list.
4240 
4241 TListOfFunctions *TClass::GetMethodList()
4242 {
4243  if (!fMethod.load()) {
4244  std::unique_ptr<TListOfFunctions> temp{ new TListOfFunctions(this) };
4245  TListOfFunctions* expected = nullptr;
4246  if(fMethod.compare_exchange_strong(expected, temp.get()) ) {
4247  temp.release();
4248  }
4249  }
4250  return fMethod;
4251 }
4252 
4253 
4254 ////////////////////////////////////////////////////////////////////////////////
4255 /// Return pointer to method without looking at parameters.
4256 /// Does not look in (possible) base classes.
4257 /// Has the side effect of loading all the TMethod object in the list
4258 /// of the class.
4259 
4260 TMethod *TClass::GetMethodAny(const char *method)
4261 {
4262  if (!HasInterpreterInfo()) return 0;
4263  return (TMethod*) GetMethodList()->FindObject(method);
4264 }
4265 
4266 ////////////////////////////////////////////////////////////////////////////////
4267 /// Return pointer to method without looking at parameters.
4268 /// Does look in all base classes.
4269 
4270 TMethod *TClass::GetMethodAllAny(const char *method)
4271 {
4272  if (!HasInterpreterInfo()) return 0;
4273 
4274  TMethod* m = GetMethodAny(method);
4275  if (m) return m;
4276 
4277  TBaseClass *base;
4278  TIter nextb(GetListOfBases());
4279  while ((base = (TBaseClass *) nextb())) {
4280  TClass *c = base->GetClassPointer();
4281  if (c) {
4282  m = c->GetMethodAllAny(method);
4283  if (m) return m;
4284  }
4285  }
4286 
4287  return 0;
4288 }
4289 
4290 ////////////////////////////////////////////////////////////////////////////////
4291 /// Find the best method (if there is one) matching the parameters.
4292 /// The params string must contain argument values, like "3189, \"aap\", 1.3".
4293 /// The function invokes GetClassMethod to search for a possible method
4294 /// in the class itself or in its base classes. Returns 0 in case method
4295 /// is not found.
4296 
4297 TMethod *TClass::GetMethod(const char *method, const char *params,
4298  Bool_t objectIsConst /* = kFALSE */)
4299 {
4300  if (fCanLoadClassInfo) LoadClassInfo();
4301  if (!fClassInfo) return 0;
4302 
4303  if (!gInterpreter)
4304  Fatal("GetMethod", "gInterpreter not initialized");
4305 
4306  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4307  method, params,
4308  objectIsConst);
4309 
4310  if (!decl) return 0;
4311 
4312  // search recursively in this class or its base classes
4313  TMethod* f = FindClassOrBaseMethodWithId(decl);
4314  if (f) return f;
4315 
4316  Error("GetMethod",
4317  "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4318  method,params,objectIsConst ? "const " : "", GetName());
4319  return 0;
4320 }
4321 
4322 
4323 ////////////////////////////////////////////////////////////////////////////////
4324 /// Find a method with decl id in this class or its bases.
4325 
4326 TMethod* TClass::FindClassOrBaseMethodWithId(DeclId_t declId) {
4327  if (TFunction* method = GetMethodList()->Get(declId))
4328  return static_cast<TMethod *>(method);
4329 
4330  for (auto item : *GetListOfBases())
4331  if (auto base = static_cast<TBaseClass *>(item)->GetClassPointer())
4332  if (TFunction* method = base->FindClassOrBaseMethodWithId(declId))
4333  return static_cast<TMethod *>(method);
4334 
4335  return nullptr;
4336 }
4337 
4338 ////////////////////////////////////////////////////////////////////////////////
4339 /// Find the method with a given prototype. The proto string must be of the
4340 /// form: "char*,int,double". Returns 0 in case method is not found.
4341 
4342 TMethod *TClass::GetMethodWithPrototype(const char *method, const char *proto,
4343  Bool_t objectIsConst /* = kFALSE */,
4344  ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4345 {
4346  if (fCanLoadClassInfo) LoadClassInfo();
4347  if (!fClassInfo) return 0;
4348 
4349  if (!gInterpreter)
4350  Fatal("GetMethodWithPrototype", "gInterpreter not initialized");
4351 
4352  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4353  method, proto,
4354  objectIsConst, mode);
4355 
4356  if (!decl) return 0;
4357  TMethod* f = FindClassOrBaseMethodWithId(decl);
4358  if (f) return f;
4359  Error("GetMethodWithPrototype",
4360  "\nDid not find matching TMethod <%s> with \"%s\" %sfor %s",
4361  method,proto,objectIsConst ? "const " : "", GetName());
4362  return 0;
4363 }
4364 
4365 ////////////////////////////////////////////////////////////////////////////////
4366 /// Look for a method in this class that has the interface function
4367 /// address faddr.
4368 
4369 TMethod *TClass::GetClassMethod(Long_t faddr)
4370 {
4371  if (!HasInterpreterInfo()) return 0;
4372 
4373  TMethod *m;
4374  TIter next(GetListOfMethods());
4375  while ((m = (TMethod *) next())) {
4376  if (faddr == (Long_t)m->InterfaceMethod())
4377  return m;
4378  }
4379  return 0;
4380 }
4381 
4382 ////////////////////////////////////////////////////////////////////////////////
4383 /// Look for a method in this class that has the name and matches the parameters.
4384 /// The params string must contain argument values, like "3189, \"aap\", 1.3".
4385 /// Returns 0 in case method is not found.
4386 /// See TClass::GetMethod to also search the base classes.
4387 
4388 TMethod *TClass::GetClassMethod(const char *name, const char* params,
4389  Bool_t objectIsConst /* = kFALSE */)
4390 {
4391  if (fCanLoadClassInfo) LoadClassInfo();
4392  if (!fClassInfo) return 0;
4393 
4394  if (!gInterpreter)
4395  Fatal("GetClassMethod", "gInterpreter not initialized");
4396 
4397  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithValues(fClassInfo,
4398  name, params,
4399  objectIsConst);
4400 
4401  if (!decl) return 0;
4402 
4403  TFunction *f = GetMethodList()->Get(decl);
4404 
4405  return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4406 }
4407 
4408 ////////////////////////////////////////////////////////////////////////////////
4409 /// Find the method with a given prototype. The proto string must be of the
4410 /// form: "char*,int,double". Returns 0 in case method is not found.
4411 /// See TClass::GetMethodWithPrototype to also search the base classes.
4412 
4413 TMethod *TClass::GetClassMethodWithPrototype(const char *name, const char* proto,
4414  Bool_t objectIsConst /* = kFALSE */,
4415  ROOT::EFunctionMatchMode mode /* = ROOT::kConversionMatch */)
4416 {
4417  if (fCanLoadClassInfo) LoadClassInfo();
4418  if (!fClassInfo) return 0;
4419 
4420  if (!gInterpreter)
4421  Fatal("GetClassMethodWithPrototype", "gInterpreter not initialized");
4422 
4423  TInterpreter::DeclId_t decl = gInterpreter->GetFunctionWithPrototype(fClassInfo,
4424  name, proto,
4425  objectIsConst,
4426  mode);
4427 
4428  if (!decl) return 0;
4429 
4430  TFunction *f = GetMethodList()->Get(decl);
4431 
4432  return (TMethod*)f; // Could be zero if the decl is actually in a base class.
4433 }
4434 
4435 ////////////////////////////////////////////////////////////////////////////////
4436 /// Return the number of data members of this class
4437 /// Note that in case the list of data members is not yet created, it will be done
4438 /// by GetListOfDataMembers().
4439 
4440 Int_t TClass::GetNdata()
4441 {
4442  if (!HasDataMemberInfo()) return 0;
4443 
4444  TList *lm = GetListOfDataMembers();
4445  if (lm)
4446  return lm->GetSize();
4447  else
4448  return 0;
4449 }
4450 
4451 ////////////////////////////////////////////////////////////////////////////////
4452 /// Return the number of methods of this class
4453 /// Note that in case the list of methods is not yet created, it will be done
4454 /// by GetListOfMethods().
4455 /// This will also load/populate the list of methods, to get 'just' the
4456 /// number of currently loaded methods use:
4457 /// cl->GetListOfMethods(false)->GetSize();
4458 
4459 Int_t TClass::GetNmethods()
4460 {
4461  if (!HasInterpreterInfo()) return 0;
4462 
4463  TList *lm = GetListOfMethods();
4464  if (lm)
4465  return lm->GetSize();
4466  else
4467  return 0;
4468 }
4469 
4470 ////////////////////////////////////////////////////////////////////////////////
4471 /// returns a pointer to the TVirtualStreamerInfo object for version
4472 /// If the object does not exist, it is created
4473 ///
4474 /// Note: There are two special version numbers:
4475 ///
4476 /// - 0: Use the class version from the currently loaded class library.
4477 /// - -1: Assume no class library loaded (emulated class).
4478 ///
4479 /// Warning: If we create a new streamer info, whether or not the build
4480 /// optimizes is controlled externally to us by a global variable!
4481 /// Don't call us unless you have set that variable properly
4482 /// with TStreamer::Optimize()!
4483 ///
4484 
4485 TVirtualStreamerInfo* TClass::GetStreamerInfo(Int_t version /* = 0 */) const
4486 {
4487  TVirtualStreamerInfo *sinfo = fLastReadInfo;
4488 
4489  // Version 0 is special, it means the currently loaded version.
4490  // We need to set it at the beginning to be able to guess it correctly.
4491 
4492  if (version == 0)
4493  version = fClassVersion;
4494 
4495  // If the StreamerInfo is assigned to the fLastReadInfo, we are
4496  // guaranteed it was built and compiled.
4497  if (sinfo && sinfo->GetClassVersion() == version)
4498  return sinfo;
4499 
4500  // Note that the access to fClassVersion above is technically not thread-safe with a low probably of problems.
4501  // fClassVersion is not an atomic and is modified TClass::SetClassVersion (called from RootClassVersion via
4502  // ROOT::ResetClassVersion) and is 'somewhat' protected by the atomic fVersionUsed.
4503  // However, direct access to fClassVersion should be replaced by calls to GetClassVersion to set fVersionUsed.
4504  // Even with such a change the code here and in these functions need to be reviewed as a cursory look seem
4505  // to indicates they are not yet properly protection against mutli-thread access.
4506  //
4507  // However, the use of these functions is rare and mostly done at library loading time which should
4508  // in almost all cases preceeds the possibility of GetStreamerInfo being called from multiple thread
4509  // on that same TClass object.
4510  //
4511  // Summary: need careful review but risk of problem is extremely low.
4512 
4513  R__LOCKGUARD(gInterpreterMutex);
4514 
4515  // Warning: version may be -1 for an emulated class, or -2 if the
4516  // user requested the emulated streamerInfo for an abstract
4517  // base class, even though we have a dictionary for it.
4518 
4519  if ((version < -1) || (version >= fStreamerInfo->GetSize())) {
4520  Error("GetStreamerInfo", "class: %s, attempting to access a wrong version: %d", GetName(), version);
4521  // FIXME: Shouldn't we go to -1 here, or better just abort?
4522  version = fClassVersion;
4523  }
4524 
4525  sinfo = (TVirtualStreamerInfo *)fStreamerInfo->At(version);
4526 
4527  if (!sinfo && (version != fClassVersion)) {
4528  // When the requested version does not exist we return
4529  // the TVirtualStreamerInfo for the currently loaded class version.
4530  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4531  // Note: This is done for STL collections
4532  // Note: fClassVersion could be -1 here (for an emulated class).
4533  // This is also the code path take for unversioned classes.
4534  sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(fClassVersion);
4535  }
4536 
4537  if (!sinfo) {
4538  // We just were not able to find a streamer info, we have to make a new one.
4539  TMmallocDescTemp setreset;
4540  sinfo = TVirtualStreamerInfo::Factory()->NewInfo(const_cast<TClass*>(this));
4541  fStreamerInfo->AddAtAndExpand(sinfo, fClassVersion);
4542  if (gDebug > 0) {
4543  printf("Creating StreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion);
4544  }
4545  if (HasDataMemberInfo() || fCollectionProxy) {
4546  // If we do not have a StreamerInfo for this version and we do not
4547  // have dictionary information nor a proxy, there is nothing to build!
4548  sinfo->Build();
4549  }
4550  } else {
4551  if (!sinfo->IsCompiled()) {
4552  // Streamer info has not been compiled, but exists.
4553  // Therefore it was read in from a file and we have to do schema evolution?
4554  // Or it didn't have a dictionary before, but does now?
4555  sinfo->BuildOld();
4556  }
4557  }
4558 
4559  // Cache the current info if we now have it.
4560  if (version == fClassVersion)
4561  fCurrentInfo = sinfo;
4562 
4563  // If the compilation succeeded, remember this StreamerInfo.
4564  if (sinfo->IsCompiled())
4565  fLastReadInfo = sinfo;
4566 
4567  return sinfo;
4568 }
4569 
4570 ////////////////////////////////////////////////////////////////////////////////
4571 /// For the case where the requestor class is emulated and this class is abstract,
4572 /// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4573 /// representation whether or not the class is loaded.
4574 ///
4575 /// If the object does not exist, it is created
4576 ///
4577 /// Note: There are two special version numbers:
4578 ///
4579 /// - 0: Use the class version from the currently loaded class library.
4580 /// - -1: Assume no class library loaded (emulated class).
4581 ///
4582 /// Warning: If we create a new streamer info, whether or not the build
4583 /// optimizes is controlled externally to us by a global variable!
4584 /// Don't call us unless you have set that variable properly
4585 /// with TStreamer::Optimize()!
4586 ///
4587 
4588 TVirtualStreamerInfo* TClass::GetStreamerInfoAbstractEmulated(Int_t version /* = 0 */) const
4589 {
4590  TVirtualStreamerInfo *sinfo = nullptr;
4591 
4592  TString newname(GetName());
4593  newname += "@@emulated";
4594 
4595  R__LOCKGUARD(gInterpreterMutex);
4596 
4597  TClass *emulated = TClass::GetClass(newname);
4598 
4599  if (emulated)
4600  sinfo = emulated->GetStreamerInfo(version);
4601 
4602  if (!sinfo) {
4603  // The emulated version of the streamerInfo is explicitly requested and has
4604  // not been built yet.
4605 
4606  sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(version);
4607 
4608  if (!sinfo && (version != fClassVersion)) {
4609  // When the requested version does not exist we return
4610  // the TVirtualStreamerInfo for the currently loaded class version.
4611  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4612  sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(fClassVersion);
4613  }
4614 
4615  if (!sinfo) {
4616  // Let's take the first available StreamerInfo as a start
4617  Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4618  for (Int_t i = -1; sinfo == 0 && i < ninfos; ++i)
4619  sinfo = (TVirtualStreamerInfo *)fStreamerInfo->UncheckedAt(i);
4620  }
4621 
4622  if (sinfo) {
4623  sinfo = dynamic_cast<TVirtualStreamerInfo *>(sinfo->Clone());
4624  if (sinfo) {
4625  sinfo->SetClass(0);
4626  sinfo->SetName(newname);
4627  sinfo->BuildCheck();
4628  sinfo->BuildOld();
4629  sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4630  } else {
4631  Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4632  }
4633  }
4634  }
4635  return sinfo;
4636 }
4637 
4638 ////////////////////////////////////////////////////////////////////////////////
4639 /// For the case where the requestor class is emulated and this class is abstract,
4640 /// returns a pointer to the TVirtualStreamerInfo object for version with an emulated
4641 /// representation whether or not the class is loaded.
4642 ///
4643 /// If the object does not exist, it is created
4644 ///
4645 /// Warning: If we create a new streamer info, whether or not the build
4646 /// optimizes is controlled externally to us by a global variable!
4647 /// Don't call us unless you have set that variable properly
4648 /// with TStreamer::Optimize()!
4649 ///
4650 
4651 TVirtualStreamerInfo* TClass::FindStreamerInfoAbstractEmulated(UInt_t checksum) const
4652 {
4653  TVirtualStreamerInfo *sinfo = nullptr;
4654 
4655  TString newname(GetName());
4656  newname += "@@emulated";
4657 
4658  R__LOCKGUARD(gInterpreterMutex);
4659 
4660  TClass *emulated = TClass::GetClass(newname);
4661 
4662  if (emulated)
4663  sinfo = emulated->FindStreamerInfo(checksum);
4664 
4665  if (!sinfo) {
4666  // The emulated version of the streamerInfo is explicitly requested and has
4667  // not been built yet.
4668 
4669  sinfo = (TVirtualStreamerInfo*) FindStreamerInfo(checksum);
4670 
4671  if (!sinfo && (checksum != fCheckSum)) {
4672  // When the requested version does not exist we return
4673  // the TVirtualStreamerInfo for the currently loaded class version.
4674  // FIXME: This arguably makes no sense, we should warn and return nothing instead.
4675  sinfo = (TVirtualStreamerInfo*) fStreamerInfo->At(fClassVersion);
4676  }
4677 
4678  if (!sinfo) {
4679  // Let's take the first available StreamerInfo as a start
4680  Int_t ninfos = fStreamerInfo->GetEntriesFast() - 1;
4681  for (Int_t i = -1; sinfo == 0 && i < ninfos; ++i)
4682  sinfo = (TVirtualStreamerInfo *)fStreamerInfo->UncheckedAt(i);
4683  }
4684 
4685  if (sinfo) {
4686  sinfo = dynamic_cast<TVirtualStreamerInfo*>( sinfo->Clone() );
4687  if (sinfo) {
4688  sinfo->SetClass(0);
4689  sinfo->SetName( newname );
4690  sinfo->BuildCheck();
4691  sinfo->BuildOld();
4692  sinfo->GetClass()->AddRule(TString::Format("sourceClass=%s targetClass=%s",GetName(),newname.Data()));
4693  } else {
4694  Error("GetStreamerInfoAbstractEmulated", "could not create TVirtualStreamerInfo");
4695  }
4696  }
4697  }
4698  return sinfo;
4699 }
4700 
4701 ////////////////////////////////////////////////////////////////////////////////
4702 /// When the class kIgnoreTObjectStreamer bit is set, the automatically
4703 /// generated Streamer will not call TObject::Streamer.
4704 /// This option saves the TObject space overhead on the file.
4705 /// However, the information (fBits, fUniqueID) of TObject is lost.
4706 ///
4707 /// Note that to be effective for objects streamed object-wise this function
4708 /// must be called for the class deriving directly from TObject, eg, assuming
4709 /// that BigTrack derives from Track and Track derives from TObject, one must do:
4710 /// ~~~ {.cpp}
4711 /// Track::Class()->IgnoreTObjectStreamer();
4712 /// ~~~
4713 /// and not:
4714 /// ~~~ {.cpp}
4715 /// BigTrack::Class()->IgnoreTObjectStreamer();
4716 /// ~~~
4717 /// To be effective for object streamed member-wise or split in a TTree,
4718 /// this function must be called for the most derived class (i.e. BigTrack).
4719 
4720 void TClass::IgnoreTObjectStreamer(Bool_t doIgnore)
4721 {
4722  // We need to tak the lock since we are test and then setting fBits
4723  // and TStreamerInfo::fBits (and the StreamerInfo state in general)
4724  // which can also be modified by another thread.
4725  R__LOCKGUARD(gInterpreterMutex);
4726 
4727  if ( doIgnore && TestBit(kIgnoreTObjectStreamer)) return;
4728  if (!doIgnore && !TestBit(kIgnoreTObjectStreamer)) return;
4729  TVirtualStreamerInfo *sinfo = GetCurrentStreamerInfo();
4730  if (sinfo) {
4731  if (sinfo->IsCompiled()) {
4732  // -- Warn the user that what they are doing cannot work.
4733  // Note: The reason is that TVirtualStreamerInfo::Build() examines
4734  // the kIgnoreTObjectStreamer bit and sets the TStreamerElement
4735  // type for the TObject base class streamer element it creates
4736  // to -1 as a flag. Later on the TStreamerInfo::Compile()
4737  // member function sees the flag and does not insert the base
4738  // class element into the compiled streamer info. None of this
4739  // machinery works correctly if we are called after the streamer
4740  // info has already been built and compiled.
4741  Error("IgnoreTObjectStreamer","Must be called before the creation of StreamerInfo");
4742  return;
4743  }
4744  }
4745  if (doIgnore) SetBit (kIgnoreTObjectStreamer);
4746  else ResetBit(kIgnoreTObjectStreamer);
4747 }
4748 
4749 ////////////////////////////////////////////////////////////////////////////////
4750 /// Return kTRUE if this class inherits from a class with name "classname".
4751 /// note that the function returns kTRUE in case classname is the class itself
4752 
4753 Bool_t TClass::InheritsFrom(const char *classname) const
4754 {
4755  if (strcmp(GetName(), classname) == 0) return kTRUE;
4756 
4757  return InheritsFrom(TClass::GetClass(classname,kTRUE,kTRUE));
4758 }
4759 
4760 ////////////////////////////////////////////////////////////////////////////////
4761 /// Return kTRUE if this class inherits from class cl.
4762 /// note that the function returns KTRUE in case cl is the class itself
4763 
4764 Bool_t TClass::InheritsFrom(const TClass *cl) const
4765 {
4766  if (!cl) return kFALSE;
4767  if (cl == this) return kTRUE;
4768 
4769  if (!HasDataMemberInfo()) {
4770  TVirtualStreamerInfo *sinfo = ((TClass *)this)->GetCurrentStreamerInfo();
4771  if (sinfo==0) sinfo = GetStreamerInfo();
4772  TIter next(sinfo->GetElements());
4773  TStreamerElement *element;
4774  while ((element = (TStreamerElement*)next())) {
4775  if (element->IsA() == TStreamerBase::Class()) {
4776  TClass *clbase = element->GetClassPointer();
4777  if (!clbase) return kFALSE; //missing class
4778  if (clbase->InheritsFrom(cl)) return kTRUE;
4779  }
4780  }
4781  return kFALSE;
4782  }
4783  // cast const away (only for member fBase which can be set in GetListOfBases())
4784  if (((TClass *)this)->GetBaseClass(cl)) return kTRUE;
4785  return kFALSE;
4786 }
4787 
4788 ////////////////////////////////////////////////////////////////////////////////
4789 /// Cast obj of this class type up to baseclass cl if up is true.
4790 /// Cast obj of this class type down from baseclass cl if up is false.
4791 /// If this class is not a baseclass of cl return 0, else the pointer
4792 /// to the cl part of this (up) or to this (down).
4793 
4794 void *TClass::DynamicCast(const TClass *cl, void *obj, Bool_t up)
4795 {
4796  if (cl == this) return obj;
4797 
4798  if (!HasDataMemberInfo()) return 0;
4799 
4800  Int_t off;
4801  if ((off = GetBaseClassOffset(cl, obj)) != -1) {
4802  if (up)
4803  return (void*)((Long_t)obj+off);
4804  else
4805  return (void*)((Long_t)obj-off);
4806  }
4807  return 0;
4808 }
4809 
4810 ////////////////////////////////////////////////////////////////////////////////
4811 /// Cast obj of this class type up to baseclass cl if up is true.
4812 /// Cast obj of this class type down from baseclass cl if up is false.
4813 /// If this class is not a baseclass of cl return 0, else the pointer
4814 /// to the cl part of this (up) or to this (down).
4815 
4816 const void *TClass::DynamicCast(const TClass *cl, const void *obj, Bool_t up)
4817 {
4818  return DynamicCast(cl,const_cast<void*>(obj),up);
4819 }
4820 
4821 ////////////////////////////////////////////////////////////////////////////////
4822 /// Return a pointer to a newly allocated object of this class.
4823 /// The class must have a default constructor. For meaning of
4824 /// defConstructor, see TClass::IsCallingNew().
4825 ///
4826 /// If quiet is true, do no issue a message via Error on case
4827 /// of problems, just return 0.
4828 ///
4829 /// The constructor actually called here can be customized by
4830 /// using the rootcint pragma:
4831 /// ~~~ {.cpp}
4832 /// #pragma link C++ ioctortype UserClass;
4833 /// ~~~
4834 /// For example, with this pragma and a class named MyClass,
4835 /// this method will called the first of the following 3
4836 /// constructors which exists and is public:
4837 /// ~~~ {.cpp}
4838 /// MyClass(UserClass*);
4839 /// MyClass(TRootIOCtor*);
4840 /// MyClass(); // Or a constructor with all its arguments defaulted.
4841 /// ~~~
4842 ///
4843 /// When more than one pragma ioctortype is used, the first seen as priority
4844 /// For example with:
4845 /// ~~~ {.cpp}
4846 /// #pragma link C++ ioctortype UserClass1;
4847 /// #pragma link C++ ioctortype UserClass2;
4848 /// ~~~
4849 /// We look in the following order:
4850 /// ~~~ {.cpp}
4851 /// MyClass(UserClass1*);
4852 /// MyClass(UserClass2*);
4853 /// MyClass(TRootIOCtor*);
4854 /// MyClass(); // Or a constructor with all its arguments defaulted.
4855 /// ~~~
4856 
4857 void *TClass::New(ENewType defConstructor, Bool_t quiet) const
4858 {
4859  void* p = 0;
4860 
4861  if (fNew) {
4862  // We have the new operator wrapper function,
4863  // so there is a dictionary and it was generated
4864  // by rootcint, so there should be a default
4865  // constructor we can call through the wrapper.
4866  TClass__GetCallingNew() = defConstructor;
4867  p = fNew(0);
4868  TClass__GetCallingNew() = kRealNew;
4869  if (!p && !quiet) {
4870  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4871  Error("New", "cannot create object of class %s", GetName());
4872  }
4873  } else if (HasInterpreterInfo()) {
4874  // We have the dictionary but do not have the
4875  // constructor wrapper, so the dictionary was
4876  // not generated by rootcint. Let's try to
4877  // create the object by having the interpreter
4878  // call the new operator, hopefully the class
4879  // library is loaded and there will be a default
4880  // constructor we can call.
4881  // [This is very unlikely to work, but who knows!]
4882  TClass__GetCallingNew() = defConstructor;
4883  p = gCling->ClassInfo_New(GetClassInfo());
4884  TClass__GetCallingNew() = kRealNew;
4885  if (!p && !quiet) {
4886  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4887  Error("New", "cannot create object of class %s", GetName());
4888  }
4889  } else if (!HasInterpreterInfo() && fCollectionProxy) {
4890  // There is no dictionary at all, so this is an emulated
4891  // class; however we do have the services of a collection proxy,
4892  // so this is an emulated STL class.
4893  TClass__GetCallingNew() = defConstructor;
4894  p = fCollectionProxy->New();
4895  TClass__GetCallingNew() = kRealNew;
4896  if (!p && !quiet) {
4897  //Error("New", "cannot create object of class %s version %d", GetName(), fClassVersion);
4898  Error("New", "cannot create object of class %s", GetName());
4899  }
4900  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
4901  // There is no dictionary at all and we do not have
4902  // the services of a collection proxy available, so
4903  // use the streamer info to approximate calling a
4904  // constructor (basically we just make sure that the
4905  // pointer data members are null, unless they are marked
4906  // as preallocated with the "->" comment, in which case
4907  // we default-construct an object to point at).
4908 
4909  // Do not register any TObject's that we create
4910  // as a result of creating this object.
4911  // FIXME: Why do we do this?
4912  // FIXME: Partial Answer: Is this because we may never actually deregister them???
4913 
4914  Bool_t statsave = GetObjectStat();
4915  if(statsave) {
4916  SetObjectStat(kFALSE);
4917  }
4918  TVirtualStreamerInfo* sinfo = GetStreamerInfo();
4919  if (!sinfo && !quiet) {
4920  Error("New", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion);
4921  return 0;
4922  }
4923 
4924  TClass__GetCallingNew() = defConstructor;
4925  p = sinfo->New();
4926  TClass__GetCallingNew() = kRealNew;
4927 
4928  // FIXME: Mistake? See note above at the GetObjectStat() call.
4929  // Allow TObject's to be registered again.
4930  if(statsave) {
4931  SetObjectStat(statsave);
4932  }
4933 
4934  // Register the object for special handling in the destructor.
4935  if (p) {
4936  RegisterAddressInRepository("New",p,this);
4937  } else {
4938  Error("New", "Failed to construct class '%s' using streamer info", GetName());
4939  }
4940  } else {
4941  Fatal("New", "This cannot happen!");
4942  }
4943 
4944  return p;
4945 }
4946 
4947 ////////////////////////////////////////////////////////////////////////////////
4948 /// Return a pointer to a newly allocated object of this class.
4949 /// The class must have a default constructor. For meaning of
4950 /// defConstructor, see TClass::IsCallingNew().
4951 
4952 void *TClass::New(void *arena, ENewType defConstructor) const
4953 {
4954  void* p = 0;
4955 
4956  if (fNew) {
4957  // We have the new operator wrapper function,
4958  // so there is a dictionary and it was generated
4959  // by rootcint, so there should be a default
4960  // constructor we can call through the wrapper.
4961  TClass__GetCallingNew() = defConstructor;
4962  p = fNew(arena);
4963  TClass__GetCallingNew() = kRealNew;
4964  if (!p) {
4965  Error("New with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
4966  }
4967  } else if (HasInterpreterInfo()) {
4968  // We have the dictionary but do not have the
4969  // constructor wrapper, so the dictionary was
4970  // not generated by rootcint. Let's try to
4971  // create the object by having the interpreter
4972  // call the new operator, hopefully the class
4973  // library is loaded and there will be a default
4974  // constructor we can call.
4975  // [This is very unlikely to work, but who knows!]
4976  TClass__GetCallingNew() = defConstructor;
4977  p = gCling->ClassInfo_New(GetClassInfo(),arena);
4978  TClass__GetCallingNew() = kRealNew;
4979  if (!p) {
4980  Error("New with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
4981  }
4982  } else if (!HasInterpreterInfo() && fCollectionProxy) {
4983  // There is no dictionary at all, so this is an emulated
4984  // class; however we do have the services of a collection proxy,
4985  // so this is an emulated STL class.
4986  TClass__GetCallingNew() = defConstructor;
4987  p = fCollectionProxy->New(arena);
4988  TClass__GetCallingNew() = kRealNew;
4989  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
4990  // There is no dictionary at all and we do not have
4991  // the services of a collection proxy available, so
4992  // use the streamer info to approximate calling a
4993  // constructor (basically we just make sure that the
4994  // pointer data members are null, unless they are marked
4995  // as preallocated with the "->" comment, in which case
4996  // we default-construct an object to point at).
4997 
4998  // ???BUG??? ???WHY???
4999  // Do not register any TObject's that we create
5000  // as a result of creating this object.
5001  Bool_t statsave = GetObjectStat();
5002  if(statsave) {
5003  SetObjectStat(kFALSE);
5004  }
5005 
5006  TVirtualStreamerInfo* sinfo = GetStreamerInfo();
5007  if (!sinfo) {
5008  Error("New with placement", "Cannot construct class '%s' version %d at address %p, no streamer info available!", GetName(), fClassVersion, arena);
5009  return 0;
5010  }
5011 
5012  TClass__GetCallingNew() = defConstructor;
5013  p = sinfo->New(arena);
5014  TClass__GetCallingNew() = kRealNew;
5015 
5016  // ???BUG???
5017  // Allow TObject's to be registered again.
5018  if(statsave) {
5019  SetObjectStat(statsave);
5020  }
5021 
5022  // Register the object for special handling in the destructor.
5023  if (p) {
5024  RegisterAddressInRepository("TClass::New with placement",p,this);
5025  }
5026  } else {
5027  Error("New with placement", "This cannot happen!");
5028  }
5029 
5030  return p;
5031 }
5032 
5033 ////////////////////////////////////////////////////////////////////////////////
5034 /// Return a pointer to a newly allocated array of objects
5035 /// of this class.
5036 /// The class must have a default constructor. For meaning of
5037 /// defConstructor, see TClass::IsCallingNew().
5038 
5039 void *TClass::NewArray(Long_t nElements, ENewType defConstructor) const
5040 {
5041  void* p = 0;
5042 
5043  if (fNewArray) {
5044  // We have the new operator wrapper function,
5045  // so there is a dictionary and it was generated
5046  // by rootcint, so there should be a default
5047  // constructor we can call through the wrapper.
5048  TClass__GetCallingNew() = defConstructor;
5049  p = fNewArray(nElements, 0);
5050  TClass__GetCallingNew() = kRealNew;
5051  if (!p) {
5052  Error("NewArray", "cannot create object of class %s version %d", GetName(), fClassVersion);
5053  }
5054  } else if (HasInterpreterInfo()) {
5055  // We have the dictionary but do not have the
5056  // constructor wrapper, so the dictionary was
5057  // not generated by rootcint. Let's try to
5058  // create the object by having the interpreter
5059  // call the new operator, hopefully the class
5060  // library is loaded and there will be a default
5061  // constructor we can call.
5062  // [This is very unlikely to work, but who knows!]
5063  TClass__GetCallingNew() = defConstructor;
5064  p = gCling->ClassInfo_New(GetClassInfo(),nElements);
5065  TClass__GetCallingNew() = kRealNew;
5066  if (!p) {
5067  Error("NewArray", "cannot create object of class %s version %d", GetName(), fClassVersion);
5068  }
5069  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5070  // There is no dictionary at all, so this is an emulated
5071  // class; however we do have the services of a collection proxy,
5072  // so this is an emulated STL class.
5073  TClass__GetCallingNew() = defConstructor;
5074  p = fCollectionProxy->NewArray(nElements);
5075  TClass__GetCallingNew() = kRealNew;
5076  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5077  // There is no dictionary at all and we do not have
5078  // the services of a collection proxy available, so
5079  // use the streamer info to approximate calling a
5080  // constructor (basically we just make sure that the
5081  // pointer data members are null, unless they are marked
5082  // as preallocated with the "->" comment, in which case
5083  // we default-construct an object to point at).
5084 
5085  // ???BUG??? ???WHY???
5086  // Do not register any TObject's that we create
5087  // as a result of creating this object.
5088  Bool_t statsave = GetObjectStat();
5089  if(statsave) {
5090  SetObjectStat(kFALSE);
5091  }
5092 
5093  TVirtualStreamerInfo* sinfo = GetStreamerInfo();
5094  if (!sinfo) {
5095  Error("NewArray", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion);
5096  return 0;
5097  }
5098 
5099  TClass__GetCallingNew() = defConstructor;
5100  p = sinfo->NewArray(nElements);
5101  TClass__GetCallingNew() = kRealNew;
5102 
5103  // ???BUG???
5104  // Allow TObject's to be registered again.
5105  if(statsave) {
5106  SetObjectStat(statsave);
5107  }
5108 
5109  // Register the object for special handling in the destructor.
5110  if (p) {
5111  RegisterAddressInRepository("TClass::NewArray",p,this);
5112  }
5113  } else {
5114  Error("NewArray", "This cannot happen!");
5115  }
5116 
5117  return p;
5118 }
5119 
5120 ////////////////////////////////////////////////////////////////////////////////
5121 /// Return a pointer to a newly allocated object of this class.
5122 /// The class must have a default constructor. For meaning of
5123 /// defConstructor, see TClass::IsCallingNew().
5124 
5125 void *TClass::NewArray(Long_t nElements, void *arena, ENewType defConstructor) const
5126 {
5127  void* p = 0;
5128 
5129  if (fNewArray) {
5130  // We have the new operator wrapper function,
5131  // so there is a dictionary and it was generated
5132  // by rootcint, so there should be a default
5133  // constructor we can call through the wrapper.
5134  TClass__GetCallingNew() = defConstructor;
5135  p = fNewArray(nElements, arena);
5136  TClass__GetCallingNew() = kRealNew;
5137  if (!p) {
5138  Error("NewArray with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
5139  }
5140  } else if (HasInterpreterInfo()) {
5141  // We have the dictionary but do not have the constructor wrapper,
5142  // so the dictionary was not generated by rootcint (it was made either
5143  // by cint or by some external mechanism). Let's try to create the
5144  // object by having the interpreter call the new operator, either the
5145  // class library is loaded and there is a default constructor we can
5146  // call, or the class is interpreted and we will call the default
5147  // constructor that way, or no default constructor is available and
5148  // we fail.
5149  TClass__GetCallingNew() = defConstructor;
5150  p = gCling->ClassInfo_New(GetClassInfo(),nElements, arena);
5151  TClass__GetCallingNew() = kRealNew;
5152  if (!p) {
5153  Error("NewArray with placement", "cannot create object of class %s version %d at address %p", GetName(), fClassVersion, arena);
5154  }
5155  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5156  // There is no dictionary at all, so this is an emulated
5157  // class; however we do have the services of a collection proxy,
5158  // so this is an emulated STL class.
5159  TClass__GetCallingNew() = defConstructor;
5160  p = fCollectionProxy->NewArray(nElements, arena);
5161  TClass__GetCallingNew() = kRealNew;
5162  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5163  // There is no dictionary at all and we do not have
5164  // the services of a collection proxy available, so
5165  // use the streamer info to approximate calling a
5166  // constructor (basically we just make sure that the
5167  // pointer data members are null, unless they are marked
5168  // as preallocated with the "->" comment, in which case
5169  // we default-construct an object to point at).
5170 
5171  // ???BUG??? ???WHY???
5172  // Do not register any TObject's that we create
5173  // as a result of creating this object.
5174  Bool_t statsave = GetObjectStat();
5175  if(statsave) {
5176  SetObjectStat(kFALSE);
5177  }
5178 
5179  TVirtualStreamerInfo* sinfo = GetStreamerInfo();
5180  if (!sinfo) {
5181  Error("NewArray with placement", "Cannot construct class '%s' version %d at address %p, no streamer info available!", GetName(), fClassVersion, arena);
5182  return 0;
5183  }
5184 
5185  TClass__GetCallingNew() = defConstructor;
5186  p = sinfo->NewArray(nElements, arena);
5187  TClass__GetCallingNew() = kRealNew;
5188 
5189  // ???BUG???
5190  // Allow TObject's to be registered again.
5191  if(statsave) {
5192  SetObjectStat(statsave);
5193  }
5194 
5195  if (fStreamerType & kEmulatedStreamer) {
5196  // We always register emulated objects, we need to always
5197  // use the streamer info to destroy them.
5198  }
5199 
5200  // Register the object for special handling in the destructor.
5201  if (p) {
5202  RegisterAddressInRepository("TClass::NewArray with placement",p,this);
5203  }
5204  } else {
5205  Error("NewArray with placement", "This cannot happen!");
5206  }
5207 
5208  return p;
5209 }
5210 
5211 ////////////////////////////////////////////////////////////////////////////////
5212 /// Explicitly call destructor for object.
5213 
5214 void TClass::Destructor(void *obj, Bool_t dtorOnly)
5215 {
5216  // Do nothing if passed a null pointer.
5217  if (obj == 0) return;
5218 
5219  void* p = obj;
5220 
5221  if (dtorOnly && fDestructor) {
5222  // We have the destructor wrapper, use it.
5223  fDestructor(p);
5224  } else if ((!dtorOnly) && fDelete) {
5225  // We have the delete wrapper, use it.
5226  fDelete(p);
5227  } else if (HasInterpreterInfo()) {
5228  // We have the dictionary but do not have the
5229  // destruct/delete wrapper, so the dictionary was
5230  // not generated by rootcint (it could have been
5231  // created by cint or by some external mechanism).
5232  // Let's have the interpreter call the destructor,
5233  // either the code will be in a loaded library,
5234  // or it will be interpreted, otherwise we fail
5235  // because there is no destructor code at all.
5236  if (dtorOnly) {
5237  gCling->ClassInfo_Destruct(fClassInfo,p);
5238  } else {
5239  gCling->ClassInfo_Delete(fClassInfo,p);
5240  }
5241  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5242  // There is no dictionary at all, so this is an emulated
5243  // class; however we do have the services of a collection proxy,
5244  // so this is an emulated STL class.
5245  fCollectionProxy->Destructor(p, dtorOnly);
5246  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5247  // There is no dictionary at all and we do not have
5248  // the services of a collection proxy available, so
5249  // use the streamer info to approximate calling a
5250  // destructor.
5251 
5252  Bool_t inRepo = kTRUE;
5253  Bool_t verFound = kFALSE;
5254 
5255  // Was this object allocated through TClass?
5256  std::multiset<Version_t> knownVersions;
5257  R__LOCKGUARD2(gOVRMutex);
5258 
5259  {
5260  RepoCont_t::iterator iter = gObjectVersionRepository.find(p);
5261  if (iter == gObjectVersionRepository.end()) {
5262  // No, it wasn't, skip special version handling.
5263  //Error("Destructor2", "Attempt to delete unregistered object of class '%s' at address %p!", GetName(), p);
5264  inRepo = kFALSE;
5265  } else {
5266  //objVer = iter->second;
5267  for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) {
5268  Version_t ver = iter->second.fVersion;
5269  knownVersions.insert(ver);
5270  if (ver == fClassVersion && this == iter->second.fClass) {
5271  verFound = kTRUE;
5272  }
5273  }
5274  }
5275  }
5276 
5277  if (!inRepo || verFound) {
5278  // The object was allocated using code for the same class version
5279  // as is loaded now. We may proceed without worry.
5280  TVirtualStreamerInfo* si = GetStreamerInfo();
5281  if (si) {
5282  si->Destructor(p, dtorOnly);
5283  } else {
5284  Error("Destructor", "No streamer info available for class '%s' version %d at address %p, cannot destruct emulated object!", GetName(), fClassVersion, p);
5285  Error("Destructor", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5286  Int_t i = fStreamerInfo->LowerBound();
5287  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5288  Error("Destructor", "fStreamerInfo->At(%d): %p", i, fStreamerInfo->At(i));
5289  if (fStreamerInfo->At(i) != 0) {
5290  Error("Destructor", "Doing Dump() ...");
5291  ((TVirtualStreamerInfo*)fStreamerInfo->At(i))->Dump();
5292  }
5293  }
5294  }
5295  } else {
5296  // The loaded class version is not the same as the version of the code
5297  // which was used to allocate this object. The best we can do is use
5298  // the TVirtualStreamerInfo to try to free up some of the allocated memory.
5299  Error("Destructor", "Loaded class %s version %d is not registered for addr %p", GetName(), fClassVersion, p);
5300 #if 0
5301  TVirtualStreamerInfo* si = (TVirtualStreamerInfo*) fStreamerInfo->At(objVer);
5302  if (si) {
5303  si->Destructor(p, dtorOnly);
5304  } else {
5305  Error("Destructor2", "No streamer info available for class '%s' version %d, cannot destruct object at addr: %p", GetName(), objVer, p);
5306  Error("Destructor2", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5307  Int_t i = fStreamerInfo->LowerBound();
5308  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5309  Error("Destructor2", "fStreamerInfo->At(%d): %p", i, fStreamerInfo->At(i));
5310  if (fStreamerInfo->At(i) != 0) {
5311  // Do some debugging output.
5312  Error("Destructor2", "Doing Dump() ...");
5313  ((TVirtualStreamerInfo*)fStreamerInfo->At(i))->Dump();
5314  }
5315  }
5316  }
5317 #endif
5318  }
5319 
5320  if (inRepo && verFound && p) {
5321  UnregisterAddressInRepository("TClass::Destructor",p,this);
5322  }
5323  } else {
5324  Error("Destructor", "This cannot happen! (class %s)", GetName());
5325  }
5326 }
5327 
5328 ////////////////////////////////////////////////////////////////////////////////
5329 /// Explicitly call operator delete[] for an array.
5330 
5331 void TClass::DeleteArray(void *ary, Bool_t dtorOnly)
5332 {
5333  // Do nothing if passed a null pointer.
5334  if (ary == 0) return;
5335 
5336  // Make a copy of the address.
5337  void* p = ary;
5338 
5339  if (fDeleteArray) {
5340  if (dtorOnly) {
5341  Error("DeleteArray", "Destructor only is not supported!");
5342  } else {
5343  // We have the array delete wrapper, use it.
5344  fDeleteArray(ary);
5345  }
5346  } else if (HasInterpreterInfo()) {
5347  // We have the dictionary but do not have the
5348  // array delete wrapper, so the dictionary was
5349  // not generated by rootcint. Let's try to
5350  // delete the array by having the interpreter
5351  // call the array delete operator, hopefully
5352  // the class library is loaded and there will be
5353  // a destructor we can call.
5354  gCling->ClassInfo_DeleteArray(GetClassInfo(),ary, dtorOnly);
5355  } else if (!HasInterpreterInfo() && fCollectionProxy) {
5356  // There is no dictionary at all, so this is an emulated
5357  // class; however we do have the services of a collection proxy,
5358  // so this is an emulated STL class.
5359  fCollectionProxy->DeleteArray(ary, dtorOnly);
5360  } else if (!HasInterpreterInfo() && !fCollectionProxy) {
5361  // There is no dictionary at all and we do not have
5362  // the services of a collection proxy available, so
5363  // use the streamer info to approximate calling the
5364  // array destructor.
5365 
5366  Bool_t inRepo = kTRUE;
5367  Bool_t verFound = kFALSE;
5368 
5369  // Was this array object allocated through TClass?
5370  std::multiset<Version_t> knownVersions;
5371  {
5372  R__LOCKGUARD2(gOVRMutex);
5373  RepoCont_t::iterator iter = gObjectVersionRepository.find(p);
5374  if (iter == gObjectVersionRepository.end()) {
5375  // No, it wasn't, we cannot know what to do.
5376  //Error("DeleteArray", "Attempt to delete unregistered array object, element type '%s', at address %p!", GetName(), p);
5377  inRepo = kFALSE;
5378  } else {
5379  for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) {
5380  Version_t ver = iter->second.fVersion;
5381  knownVersions.insert(ver);
5382  if (ver == fClassVersion && this == iter->second.fClass ) {
5383  verFound = kTRUE;
5384  }
5385  }
5386  }
5387  }
5388 
5389  if (!inRepo || verFound) {
5390  // The object was allocated using code for the same class version
5391  // as is loaded now. We may proceed without worry.
5392  TVirtualStreamerInfo* si = GetStreamerInfo();
5393  if (si) {
5394  si->DeleteArray(ary, dtorOnly);
5395  } else {
5396  Error("DeleteArray", "No streamer info available for class '%s' version %d at address %p, cannot destruct object!", GetName(), fClassVersion, ary);
5397  Error("DeleteArray", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5398  Int_t i = fStreamerInfo->LowerBound();
5399  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5400  Error("DeleteArray", "fStreamerInfo->At(%d): %p", v, fStreamerInfo->At(i));
5401  if (fStreamerInfo->At(i)) {
5402  Error("DeleteArray", "Doing Dump() ...");
5403  ((TVirtualStreamerInfo*)fStreamerInfo->At(i))->Dump();
5404  }
5405  }
5406  }
5407  } else {
5408  // The loaded class version is not the same as the version of the code
5409  // which was used to allocate this array. The best we can do is use
5410  // the TVirtualStreamerInfo to try to free up some of the allocated memory.
5411  Error("DeleteArray", "Loaded class version %d is not registered for addr %p", fClassVersion, p);
5412 
5413 
5414 
5415 #if 0
5416  TVirtualStreamerInfo* si = (TVirtualStreamerInfo*) fStreamerInfo->At(objVer);
5417  if (si) {
5418  si->DeleteArray(ary, dtorOnly);
5419  } else {
5420  Error("DeleteArray", "No streamer info available for class '%s' version %d at address %p, cannot destruct object!", GetName(), objVer, ary);
5421  Error("DeleteArray", "length of fStreamerInfo is %d", fStreamerInfo->GetSize());
5422  Int_t i = fStreamerInfo->LowerBound();
5423  for (Int_t v = 0; v < fStreamerInfo->GetSize(); ++v, ++i) {
5424  Error("DeleteArray", "fStreamerInfo->At(%d): %p", v, fStreamerInfo->At(i));
5425  if (fStreamerInfo->At(i)) {
5426  // Print some debugging info.
5427  Error("DeleteArray", "Doing Dump() ...");
5428  ((TVirtualStreamerInfo*)fStreamerInfo->At(i))->Dump();
5429  }
5430  }
5431  }
5432 #endif
5433 
5434 
5435  }
5436 
5437  // Deregister the object for special handling in the destructor.
5438  if (inRepo && verFound && p) {
5439  UnregisterAddressInRepository("TClass::DeleteArray",p,this);
5440  }
5441  } else {
5442  Error("DeleteArray", "This cannot happen! (class '%s')", GetName());
5443  }
5444 }
5445 
5446 ////////////////////////////////////////////////////////////////////////////////
5447 /// Set the splitability of this class:
5448 /// - -1: Use the default calculation
5449 /// - 0: Disallow splitting
5450 /// - 1: Always allow splitting.
5451 /// - 2: Disallow splitting of the class and splitting of any it's derived classes.
5452 
5453 void TClass::SetCanSplit(Int_t splitmode)
5454 {
5455  fCanSplit = splitmode;
5456 }
5457 
5458 ////////////////////////////////////////////////////////////////////////////////
5459 /// Private function. Set the class version for the 'class' represented by
5460 /// this TClass object. See the public interface:
5461 /// ROOT::ResetClassVersion
5462 /// defined in TClassTable.cxx
5463 ///
5464 /// Note on class version numbers:
5465 /// - If no class number has been specified, TClass::GetVersion will return -1
5466 /// - The Class Version 0 request the whole object to be transient
5467 /// - The Class Version 1, unless specified via ClassDef indicates that the
5468 /// I/O should use the TClass checksum to distinguish the layout of the class
5469 
5470 void TClass::SetClassVersion(Version_t version)
5471 {
5472  fClassVersion = version;
5473  fCurrentInfo = 0;
5474 }
5475 
5476 ////////////////////////////////////////////////////////////////////////////////
5477 /// Determine and set pointer to current TVirtualStreamerInfo
5478 
5479 TVirtualStreamerInfo* TClass::DetermineCurrentStreamerInfo()
5480 {
5481  if(!fCurrentInfo.load()) {
5482  R__READ_LOCKGUARD(ROOT::gCoreMutex);
5483  fCurrentInfo = (TVirtualStreamerInfo *)(fStreamerInfo->At(fClassVersion));
5484  }
5485  return fCurrentInfo;
5486 }
5487 
5488 ////////////////////////////////////////////////////////////////////////////////
5489 /// Set pointer to current TVirtualStreamerInfo
5490 
5491 void TClass::SetCurrentStreamerInfo(TVirtualStreamerInfo *info)
5492 {
5493  fCurrentInfo = info;
5494 }
5495 
5496 ////////////////////////////////////////////////////////////////////////////////
5497 /// Return size of object of this class.
5498 
5499 Int_t TClass::Size() const
5500 {
5501  if (fSizeof!=-1) return fSizeof;
5502  if (fCollectionProxy) return fCollectionProxy->Sizeof();
5503  if (HasInterpreterInfo()) return gCling->ClassInfo_Size(GetClassInfo());
5504  return GetStreamerInfo()->GetSize();
5505 }
5506 
5507 ////////////////////////////////////////////////////////////////////////////////
5508 /// Load class description from I/O buffer and return class object.
5509 
5510 TClass *TClass::Load(TBuffer &b)
5511 {
5512  UInt_t maxsize = 256;
5513  char *s = new char[maxsize];
5514 
5515  Int_t pos = b.Length();
5516 
5517  b.ReadString(s, maxsize); // Reads at most maxsize - 1 characters, plus null at end.
5518  while (strlen(s) == (maxsize - 1)) {
5519  // The classname is too large, try again with a large buffer.
5520  b.SetBufferOffset(pos);
5521  maxsize = 2*maxsize;
5522  delete [] s;
5523  s = new char[maxsize];
5524  b.ReadString(s, maxsize); // Reads at most maxsize - 1 characters, plus null at end.
5525  }
5526 
5527  TClass *cl = TClass::GetClass(s, kTRUE);
5528  if (!cl)
5529  ::Error("TClass::Load", "dictionary of class %s not found", s);
5530 
5531  delete [] s;
5532  return cl;
5533 }
5534 
5535 ////////////////////////////////////////////////////////////////////////////////
5536 /// Helper function used by TClass::GetClass().
5537 /// This function attempts to load the dictionary for 'classname'
5538 /// either from the TClassTable or from the list of generator.
5539 /// If silent is 'true', do not warn about missing dictionary for the class.
5540 /// (typically used for class that are used only for transient members)
5541 ///
5542 /// The 'requestedname' is expected to be already normalized.
5543 
5544 TClass *TClass::LoadClass(const char *requestedname, Bool_t silent)
5545 {
5546  // This function does not (and should not) attempt to check in the
5547  // list of loaded classes or in the typedef.
5548 
5549  R__LOCKGUARD(gInterpreterMutex);
5550 
5551  TClass *result = LoadClassDefault(requestedname, silent);
5552 
5553  if (result) return result;
5554  else return LoadClassCustom(requestedname,silent);
5555 }
5556 
5557 ////////////////////////////////////////////////////////////////////////////////
5558 /// Helper function used by TClass::GetClass().
5559 /// This function attempts to load the dictionary for 'classname' from
5560 /// the TClassTable or the autoloader.
5561 /// If silent is 'true', do not warn about missing dictionary for the class.
5562 /// (typically used for class that are used only for transient members)
5563 ///
5564 /// The 'requestedname' is expected to be already normalized.
5565 
5566 TClass *TClass::LoadClassDefault(const char *requestedname, Bool_t /* silent */)
5567 {
5568  // This function does not (and should not) attempt to check in the
5569  // list of loaded classes or in the typedef.
5570 
5571  DictFuncPtr_t dict = TClassTable::GetDictNorm(requestedname);
5572 
5573  if (!dict) {
5574  if (gInterpreter->AutoLoad(requestedname,kTRUE)) {
5575  dict = TClassTable::GetDictNorm(requestedname);
5576  }
5577  }
5578 
5579  if (dict) {
5580  TClass *ncl = (dict)();
5581  if (ncl) ncl->PostLoadCheck();
5582  return ncl;
5583  }
5584  return 0;
5585 }
5586 
5587 ////////////////////////////////////////////////////////////////////////////////
5588 /// Helper function used by TClass::GetClass().
5589 /// This function attempts to load the dictionary for 'classname'
5590 /// from the list of generator.
5591 /// If silent is 'true', do not warn about missing dictionary for the class.
5592 /// (typically used for class that are used only for transient members)
5593 ///
5594 /// The 'requestedname' is expected to be already normalized.
5595 
5596 TClass *TClass::LoadClassCustom(const char *requestedname, Bool_t silent)
5597 {
5598  // This function does not (and should not) attempt to check in the
5599  // list of loaded classes or in the typedef.
5600 
5601  TIter next(gROOT->GetListOfClassGenerators());
5602  TClassGenerator *gen;
5603  while ((gen = (TClassGenerator*) next())) {
5604  TClass *cl = gen->GetClass(requestedname, kTRUE, silent);
5605  if (cl) {
5606  cl->PostLoadCheck();
5607  return cl;
5608  }
5609  }
5610  return 0;
5611 }
5612 
5613 ////////////////////////////////////////////////////////////////////////////////
5614 /// Try to load the ClassInfo if available. This function may require parsing
5615 /// the header file and/or loading data from the clang pcm. If further calls to
5616 /// this function cannot affect the value of fClassInfo, fCanLoadClassInfo is set
5617 /// to false.
5618 
5619 void TClass::LoadClassInfo() const
5620 {
5621  R__LOCKGUARD(gInterpreterMutex);
5622 
5623  // Return if another thread already loaded the info
5624  // while we were waiting for the lock
5625  if (!fCanLoadClassInfo)
5626  return;
5627 
5628  bool autoParse = !gInterpreter->IsAutoParsingSuspended();
5629 
5630  if (autoParse)
5631  gInterpreter->AutoParse(GetName());
5632 
5633  if (!fClassInfo)
5634  gInterpreter->SetClassInfo(const_cast<TClass *>(this));
5635 
5636  if (autoParse && !fClassInfo) {
5637  if (fImplFileLine == -1 && fClassVersion == 0) {
5638  // We have a 'transient' class with a ClassDefInline and apparently no interpreter
5639  // information. Since it is transient, it is more than likely that the lack
5640  // will be harmles.
5641  } else {
5642  ::Error("TClass::LoadClassInfo", "no interpreter information for class %s is available"
5643  " even though it has a TClass initialization routine.",
5644  fName.Data());
5645  }
5646  return;
5647  }
5648 
5649  fCanLoadClassInfo = false;
5650 }
5651 
5652 ////////////////////////////////////////////////////////////////////////////////
5653 /// Store class description on I/O buffer.
5654 
5655 void TClass::Store(TBuffer &b) const
5656 {
5657  b.WriteString(GetName());
5658 }
5659 
5660 ////////////////////////////////////////////////////////////////////////////////
5661 /// Global function called by a class' static Dictionary() method
5662 /// (see the ClassDef macro).
5663 
5664 TClass *ROOT::CreateClass(const char *cname, Version_t id,
5665  const std::type_info &info, TVirtualIsAProxy *isa,
5666  const char *dfil, const char *ifil,
5667  Int_t dl, Int_t il)
5668 {
5669  // When called via TMapFile (e.g. Update()) make sure that the dictionary
5670  // gets allocated on the heap and not in the mapped file.
5671  TMmallocDescTemp setreset;
5672  return new TClass(cname, id, info, isa, dfil, ifil, dl, il);
5673 }
5674 
5675 ////////////////////////////////////////////////////////////////////////////////
5676 /// Global function called by a class' static Dictionary() method
5677 /// (see the ClassDef macro).
5678 
5679 TClass *ROOT::CreateClass(const char *cname, Version_t id,
5680  const char *dfil, const char *ifil,
5681  Int_t dl, Int_t il)
5682 {
5683  // When called via TMapFile (e.g. Update()) make sure that the dictionary
5684  // gets allocated on the heap and not in the mapped file.
5685  TMmallocDescTemp setreset;
5686  return new TClass(cname, id, dfil, ifil, dl, il);
5687 }
5688 
5689 ////////////////////////////////////////////////////////////////////////////////
5690 /// Static method returning the defConstructor flag passed to TClass::New().
5691 /// New type is either:
5692 /// - TClass::kRealNew - when called via plain new
5693 /// - TClass::kClassNew - when called via TClass::New()
5694 /// - TClass::kDummyNew - when called via TClass::New() but object is a dummy,
5695 /// in which case the object ctor might take short cuts
5696 
5697 TClass::ENewType TClass::IsCallingNew()
5698 {
5699  return TClass__GetCallingNew();
5700 }
5701 
5702 ////////////////////////////////////////////////////////////////////////////////
5703 /// Return true if the shared library of this class is currently in the a
5704 /// process's memory. Return false, after the shared library has been
5705 /// unloaded or if this is an 'emulated' class created from a file's StreamerInfo.
5706 
5707 Bool_t TClass::IsLoaded() const
5708 {
5709  return fState == kHasTClassInit;
5710 }
5711 
5712 ////////////////////////////////////////////////////////////////////////////////
5713 /// Returns true if this class inherits from TObject and if the start of
5714 /// the TObject parts is at the very beginning of the objects.
5715 /// Concretely this means that the following code is proper for this class:
5716 /// ~~~ {.cpp}
5717 /// ThisClass *ptr;
5718 /// void *void_ptr = (void)ptr;
5719 /// TObject *obj = (TObject*)void_ptr;
5720 /// ~~~
5721 /// This code would be wrong if 'ThisClass' did not inherit 'first' from
5722 /// TObject.
5723 
5724 Bool_t TClass::IsStartingWithTObject() const
5725 {
5726  if (fProperty==(-1)) Property();
5727  return TestBit(kStartWithTObject);
5728 }
5729 
5730 ////////////////////////////////////////////////////////////////////////////////
5731 /// Return kTRUE is the class inherits from TObject.
5732 
5733 Bool_t TClass::IsTObject() const
5734 {
5735  if (fProperty==(-1)) Property();
5736  return TestBit(kIsTObject);
5737 }
5738 
5739 ////////////////////////////////////////////////////////////////////////////////
5740 /// Return kTRUE is the class is Foreign (the class does not have a Streamer method).
5741 
5742 Bool_t TClass::IsForeign() const
5743 {
5744  if (fProperty==(-1)) Property();
5745  return TestBit(kIsForeign);
5746 }
5747 
5748 ////////////////////////////////////////////////////////////////////////////////
5749 /// Do the initialization that can only be done after the CINT dictionary has
5750 /// been fully populated and can not be delayed efficiently.
5751 
5752 void TClass::PostLoadCheck()
5753 {
5754  // In the case of a Foreign class (loaded class without a Streamer function)
5755  // we reset fClassVersion to be -1 so that the current TVirtualStreamerInfo will not
5756  // be confused with a previously loaded streamerInfo.
5757 
5758  if (IsLoaded() && HasInterpreterInfo() && fClassVersion==1 /*&& fStreamerInfo
5759  && fStreamerInfo->At(1)*/ && IsForeign() )
5760  {
5761  SetClassVersion(-1);
5762  }
5763  // Note: We are careful to check the class version first because checking
5764  // for foreign can trigger an AutoParse.
5765  else if (IsLoaded() && HasDataMemberInfo() && fStreamerInfo && ((fClassVersion > 1) || !IsForeign()))
5766  {
5767  R__LOCKGUARD(gInterpreterMutex);
5768 
5769  TVirtualStreamerInfo *info = (TVirtualStreamerInfo*)(fStreamerInfo->At(fClassVersion));
5770  // Here we need to check whether this TVirtualStreamerInfo (which presumably has been
5771  // loaded from a file) is consistent with the definition in the library we just loaded.
5772  // BuildCheck is not appropriate here since it check a streamerinfo against the
5773  // 'current streamerinfo' which, at time point, would be the same as 'info'!
5774  if (info && GetListOfDataMembers() && !GetCollectionProxy()
5775  && (info->GetCheckSum()!=GetCheckSum() && !info->CompareContent(this,0,kFALSE,kFALSE, 0) && !(MatchLegacyCheckSum(info->GetCheckSum()))))
5776  {
5777  Bool_t warn = ! TestBit(kWarned);
5778  if (warn && info->GetOldVersion()<=2) {
5779  // Names of STL base classes was modified in vers==3. Allocators removed
5780  //
5781  TIter nextBC(GetListOfBases());
5782  TBaseClass *bc;
5783  while ((bc=(TBaseClass*)nextBC()))
5784  {if (TClassEdit::IsSTLCont(bc->GetName())) warn = kFALSE;}
5785  }
5786 
5787  if (warn) {
5788  if (info->GetOnFileClassVersion()==1 && fClassVersion>1) {
5789  Warning("PostLoadCheck","\n\
5790  The class %s transitioned from not having a specified class version\n\
5791  to having a specified class version (the current class version is %d).\n\
5792  However too many different non-versioned layouts of the class have\n\
5793  already been loaded so far. To work around this problem you can\n\
5794  load fewer 'old' file in the same ROOT session or load the C++ library\n\
5795  describing the class %s before opening the files or increase the version\n\
5796  number of the class for example ClassDef(%s,%d).\n\
5797  Do not try to write objects with the current class definition,\n\
5798  the files might not be readable.\n",
5799  GetName(), fClassVersion, GetName(), GetName(), fStreamerInfo->GetLast()+1);
5800  } else {
5801  Warning("PostLoadCheck","\n\
5802  The StreamerInfo version %d for the class %s which was read\n\
5803  from a file previously opened has the same version as the active class\n\
5804  but a different checksum. You should update the version to ClassDef(%s,%d).\n\
5805  Do not try to write objects with the current class definition,\n\
5806  the files will not be readable.\n"
5807  , fClassVersion, GetName(), GetName(), fStreamerInfo->GetLast()+1);
5808  }
5809  info->CompareContent(this,0,kTRUE,kTRUE,0);
5810  SetBit(kWarned);
5811  }
5812  }
5813  }
5814 }
5815 
5816 ////////////////////////////////////////////////////////////////////////////////
5817 /// Set TObject::fBits and fStreamerType to cache information about the
5818 /// class. The bits are
5819 /// ~~~ {.cpp}
5820 /// kIsTObject : the class inherits from TObject
5821 /// kStartWithTObject: TObject is the left-most class in the inheritance tree
5822 /// kIsForeign : the class doe not have a Streamer method
5823 /// ~~~
5824 /// The value of fStreamerType are
5825 /// ~~~ {.cpp}
5826 /// kTObject : the class inherits from TObject
5827 /// kForeign : the class does not have a Streamer method
5828 /// kInstrumented: the class does have a Streamer method
5829 /// kExternal: the class has a free standing way of streaming itself
5830 /// kEmulatedStreamer: the class is missing its shared library.
5831 /// ~~~
5832 
5833 Long_t TClass::Property() const
5834 {
5835  // Check if we can return without taking the lock,
5836  // this is valid since fProperty is atomic and set as
5837  // the last operation before return.
5838  if (fProperty!=(-1)) return fProperty;
5839 
5840  R__LOCKGUARD(gInterpreterMutex);
5841 
5842  // Check if another thread set fProperty while we
5843  // were waiting.
5844  if (fProperty!=(-1)) return fProperty;
5845 
5846  // Avoid asking about the class when it is still building
5847  if (TestBit(kLoading)) return fProperty;
5848 
5849  // When called via TMapFile (e.g. Update()) make sure that the dictionary
5850  // gets allocated on the heap and not in the mapped file.
5851  TMmallocDescTemp setreset;
5852 
5853  TClass *kl = const_cast<TClass*>(this);
5854 
5855  kl->fStreamerType = TClass::kDefault;
5856  kl->fStreamerImpl = &TClass::StreamerDefault;
5857 
5858  if (InheritsFrom(TObject::Class())) {
5859  kl->SetBit(kIsTObject);
5860 
5861  // Is it DIRECT inheritance from TObject?
5862  Int_t delta = kl->GetBaseClassOffsetRecurse(TObject::Class());
5863  if (delta==0) kl->SetBit(kStartWithTObject);
5864 
5865  kl->fStreamerType = kTObject;
5866  kl->fStreamerImpl = &TClass::StreamerTObject;
5867  }
5868 
5869  if (HasInterpreterInfo()) {
5870 
5871  // This code used to use ClassInfo_Has|IsValidMethod but since v6
5872  // they return true if the routine is defined in the class or any of
5873  // its parent. We explicitly want to know whether the function is
5874  // defined locally.
5875  if (!const_cast<TClass*>(this)->GetClassMethodWithPrototype("Streamer","TBuffer&",kFALSE)) {
5876 
5877  kl->SetBit(kIsForeign);
5878  kl->fStreamerType = kForeign;
5879  kl->fStreamerImpl = &TClass::StreamerStreamerInfo;
5880 
5881  } else if ( kl->fStreamerType == TClass::kDefault ) {
5882  if (kl->fConvStreamerFunc) {
5883  kl->fStreamerType = kInstrumented;
5884  kl->fStreamerImpl = &TClass::ConvStreamerInstrumented;
5885  } else if (kl->fStreamerFunc) {
5886  kl->fStreamerType = kInstrumented;
5887  kl->fStreamerImpl = &TClass::StreamerInstrumented;
5888  } else {
5889  // We have an automatic streamer using the StreamerInfo .. no need to go through the
5890  // Streamer method function itself.
5891  kl->fStreamerType = kInstrumented;
5892  kl->fStreamerImpl = &TClass::StreamerStreamerInfo;
5893  }
5894  }
5895 
5896  if (fStreamer) {
5897  kl->fStreamerType = kExternal;
5898  kl->fStreamerImpl = &TClass::StreamerExternal;
5899  }
5900 
5901  if (const_cast<TClass *>(this)->GetClassMethodWithPrototype("Hash", "", kTRUE)) {
5902  kl->SetBit(kHasLocalHashMember);
5903  }
5904 
5905  if (GetClassInfo()) {
5906  // In the case where the TClass for one of ROOT's core class
5907  // (eg TClonesArray for map<int,TClonesArray*>) is requested
5908  // during the execution of rootcling, we could end up in a situation
5909  // where we should have the information (since TClonesArray has
5910  // a dictionary as part of libCore) but do not because the user
5911  // only include a forward declaration of TClonesArray and we do not
5912  // forcefully load the header file either (because the autoparsing
5913  // is intentionally disabled).
5914  kl->fClassProperty = gCling->ClassInfo_ClassProperty(fClassInfo);
5915  // Must set this last since other threads may read fProperty
5916  // and think all test bits have been properly set.
5917  kl->fProperty = gCling->ClassInfo_Property(fClassInfo);
5918  }
5919  } else {
5920 
5921  if (fStreamer) {
5922  kl->fStreamerType = kExternal;
5923  kl->fStreamerImpl = &TClass::StreamerExternal;
5924  }
5925 
5926  kl->fStreamerType |= kEmulatedStreamer;
5927  kl->SetStreamerImpl();
5928  // fProperty was *not* set so that it can be forced to be recalculated
5929  // next time.
5930  return 0;
5931  }
5932 
5933  return fProperty;
5934 }
5935 
5936 ////////////////////////////////////////////////////////////////////////////////
5937 /// Internal routine to set calculate the class properties that can only be
5938 /// known at run-time, for example whether the Hash member function and the
5939 /// destructor are consistent.
5940 
5941 void TClass::SetRuntimeProperties()
5942 {
5943  // For now, no need to lock this routines as fRuntimeProperties is
5944  // the only atomic set here and this is done at the end
5945  // and there is no downside if the execution is done twice.
5946 
5947  // Note SetRuntimeProperties is set to const as it is technically
5948  // thread-safe.
5949 
5950  UChar_t properties = static_cast<UChar_t>(ERuntimeProperties::kSet);
5951 
5952  if (ROOT::Internal::TCheckHashRecursiveRemoveConsistency::Check(*this))
5953  properties |= static_cast<UChar_t>(ERuntimeProperties::kConsistentHash);
5954 
5955  const_cast<TClass *>(this)->fRuntimeProperties = properties;
5956 }
5957 
5958 ////////////////////////////////////////////////////////////////////////////////
5959 /// Internal routine to set fStreamerImpl based on the value of
5960 /// fStreamerType.
5961 
5962 void TClass::SetStreamerImpl()
5963 {
5964  switch (fStreamerType) {
5965  case kTObject: fStreamerImpl = &TClass::StreamerTObject; break;
5966  case kForeign: fStreamerImpl = &TClass::StreamerStreamerInfo; break;
5967  case kExternal: fStreamerImpl = &TClass::StreamerExternal; break;
5968  case kInstrumented: {
5969  if (fConvStreamerFunc) fStreamerImpl = &TClass::ConvStreamerInstrumented;
5970  else if (fStreamerFunc) fStreamerImpl = &TClass::StreamerInstrumented;
5971  else fStreamerImpl = &TClass::StreamerStreamerInfo;
5972  break;
5973  }
5974 
5975  case kEmulatedStreamer: // intentional fall through
5976  case kForeign|kEmulatedStreamer: // intentional fall through
5977  case kInstrumented|kEmulatedStreamer: fStreamerImpl = &TClass::StreamerStreamerInfo; break;
5978  case kExternal|kEmulatedStreamer: fStreamerImpl = &TClass::StreamerExternal; break;
5979  case kTObject|kEmulatedStreamer: fStreamerImpl = &TClass::StreamerTObjectEmulated; break;
5980  case TClass::kDefault: fStreamerImpl = &TClass::StreamerDefault; break;
5981  default:
5982  Error("SetStreamerImpl","Unexpected value of fStreamerType: %d",fStreamerType);
5983  }
5984 }
5985 
5986 
5987 ////////////////////////////////////////////////////////////////////////////////
5988 /// Create the collection proxy object (and the streamer object) from
5989 /// using the information in the TCollectionProxyInfo.
5990 
5991 void TClass::SetCollectionProxy(const ROOT::Detail::TCollectionProxyInfo &info)
5992 {
5993  R__LOCKGUARD(gInterpreterMutex);
5994 
5995  delete fCollectionProxy;
5996 
5997  // We can not use GetStreamerInfo() instead of TVirtualStreamerInfo::Factory()
5998  // because GetStreamerInfo call TStreamerInfo::Build which need to have fCollectionProxy
5999  // set correctly.
6000 
6001  TVirtualCollectionProxy *p = TVirtualStreamerInfo::Factory()->GenExplicitProxy(info,this);
6002  fCollectionProxy = p;
6003 
6004  AdoptStreamer(TVirtualStreamerInfo::Factory()->GenExplicitClassStreamer(info,this));
6005 
6006  if (fCollectionProxy && !fSchemaRules) {
6007  // Numeric Collections have implicit conversions:
6008  GetSchemaRules(kTRUE);
6009  }
6010  fCanSplit = -1;
6011 }
6012 
6013 ////////////////////////////////////////////////////////////////////////////////
6014 /// Change (i.e. set) the title of the TNamed.
6015 
6016 void TClass::SetContextMenuTitle(const char *title)
6017 {
6018  fContextMenuTitle = title;
6019 }
6020 
6021 ////////////////////////////////////////////////////////////////////////////////
6022 /// This function installs a global IsA function for this class.
6023 /// The global IsA function will be used if there is no local IsA function (fIsA)
6024 ///
6025 /// A global IsA function has the signature:
6026 ///
6027 /// ~~~ {.cpp}
6028 /// TClass *func( TClass *cl, const void *obj);
6029 /// ~~~
6030 ///
6031 /// 'cl' is a pointer to the TClass object that corresponds to the
6032 /// 'pointer type' used to retrieve the value 'obj'
6033 ///
6034 /// For example with:
6035 /// ~~~ {.cpp}
6036 /// TNamed * m = new TNamed("example","test");
6037 /// TObject* o = m
6038 /// ~~~
6039 /// and
6040 /// the global IsA function would be called with TObject::Class() as
6041 /// the first parameter and the exact numerical value in the pointer
6042 /// 'o'.
6043 ///
6044 /// In other word, inside the global IsA function. it is safe to C-style
6045 /// cast the value of 'obj' into a pointer to the class described by 'cl'.
6046 
6047 void TClass::SetGlobalIsA(IsAGlobalFunc_t func)
6048 {
6049  fGlobalIsA = func;
6050 }
6051 
6052 ////////////////////////////////////////////////////////////////////////////////
6053 /// Call this method to indicate that the shared library containing this
6054 /// class's code has been removed (unloaded) from the process's memory
6055 
6056 void TClass::SetUnloaded()
6057 {
6058  if (TestBit(kUnloaded) && !TestBit(kUnloading)) {
6059  // Don't redo the work.
6060  return;
6061  }
6062  SetBit(kUnloading);
6063 
6064  //R__ASSERT(fState == kLoaded);
6065  if (fState != kLoaded) {
6066  Fatal("SetUnloaded","The TClass for %s is being unloaded when in state %d\n",
6067  GetName(),(int)fState);
6068  }
6069 
6070  InsertTClassInRegistryRAII insertRAII(fState, fName, fNoInfoOrEmuOrFwdDeclNameRegistry);
6071 
6072  // Make sure SetClassInfo, re-calculated the state.
6073  fState = kForwardDeclared;
6074 
6075  delete fIsA; fIsA = 0;
6076  // Disable the autoloader while calling SetClassInfo, to prevent
6077  // the library from being reloaded!
6078  {
6079  TInterpreter::SuspendAutoloadingRAII autoloadOff(gInterpreter);
6080  TInterpreter::SuspendAutoParsing autoParseRaii(gCling);
6081  gInterpreter->SetClassInfo(this,kTRUE);
6082  }
6083  fDeclFileName = 0;
6084  fDeclFileLine = 0;
6085  fImplFileName = 0;
6086  fImplFileLine = 0;
6087  fTypeInfo = 0;
6088 
6089  if (fMethod.load()) {
6090  (*fMethod).Unload();
6091  }
6092  if (fData) {
6093  fData->Unload();
6094  }
6095  if (fEnums.load()) {
6096  (*fEnums).Unload();
6097  }
6098 
6099  if (fState <= kForwardDeclared && fStreamerInfo->GetEntries() != 0) {
6100  fState = kEmulated;
6101  }
6102 
6103  ResetBit(kUnloading);
6104  SetBit(kUnloaded);
6105 }
6106 
6107 ////////////////////////////////////////////////////////////////////////////////
6108 /// Info is a string describing the names and types of attributes
6109 /// written by the class Streamer function.
6110 /// If info is an empty string (when called by TObject::StreamerInfo)
6111 /// the default Streamer info string is build. This corresponds to
6112 /// the case of an automatically generated Streamer.
6113 /// In case of user defined Streamer function, it is the user responsibility
6114 /// to implement a StreamerInfo function (override TObject::StreamerInfo).
6115 /// The user must call IsA()->SetStreamerInfo(info) from this function.
6116 
6117 TVirtualStreamerInfo *TClass::SetStreamerInfo(Int_t /*version*/, const char * /*info*/)
6118 {
6119  // info is specified, nothing to do, except that we should verify
6120  // that it contains a valid descriptor.
6121 
6122 /*
6123  TDataMember *dm;
6124  Int_t nch = strlen(info);
6125  Bool_t update = kTRUE;
6126  if (nch != 0) {
6127  //decode strings like "TObject;TAttLine;fA;fB;Int_t i,j,k;"
6128  char *save, *temp, *blank, *colon, *comma;
6129  save = new char[10000];
6130  temp = save;
6131  strlcpy(temp,info,10000);
6132  //remove heading and trailing blanks
6133  while (*temp == ' ') temp++;
6134  while (save[nch-1] == ' ') {nch--; save[nch] = 0;}
6135  if (nch == 0) {delete [] save; return;}
6136  if (save[nch-1] != ';') {save[nch] = ';'; save[nch+1] = 0;}
6137  //remove blanks around , or ;
6138  while ((blank = strstr(temp,"; "))) strcpy(blank+1,blank+2);
6139  while ((blank = strstr(temp," ;"))) strcpy(blank, blank+1);
6140  while ((blank = strstr(temp,", "))) strcpy(blank+1,blank+2);
6141  while ((blank = strstr(temp," ,"))) strcpy(blank, blank+1);
6142  while ((blank = strstr(temp," "))) strcpy(blank, blank+1);
6143  //loop on tokens separated by ;
6144  char *final = new char[1000];
6145  char token[100];
6146  while ((colon=strchr(temp,';'))) {
6147  *colon = 0;
6148  strlcpy(token,temp,100);
6149  blank = strchr(token,' ');
6150  if (blank) {
6151  *blank = 0;
6152  if (!gROOT->GetType(token)) {
6153  Error("SetStreamerInfo","Illegal type: %s in %s",token,info);
6154  return;
6155  }
6156  while (blank) {
6157  strlcat(final,token,1000);
6158  strlcat(final," ",1000);
6159  comma = strchr(blank+1,','); if (comma) *comma=0;
6160  strlcat(final,blank+1,1000);
6161  strlcat(final,";",1000);
6162  blank = comma;
6163  }
6164 
6165  } else {
6166  if (TClass::GetClass(token,update)) {
6167  //a class name
6168  strlcat(final,token,1000); strlcat(final,";",1000);
6169  } else {
6170  //a data member name
6171  dm = (TDataMember*)GetListOfDataMembers()->FindObject(token);
6172  if (dm) {
6173  strlcat(final,dm->GetFullTypeName(),1000);
6174  strlcat(final," ",1000);
6175  strlcat(final,token,1000); strlcat(final,";",1000);
6176  } else {
6177  Error("SetStreamerInfo","Illegal name: %s in %s",token,info);
6178  return;
6179  }
6180  }
6181  update = kFALSE;
6182  }
6183  temp = colon+1;
6184  if (*temp == 0) break;
6185  }
6186  //// fStreamerInfo = final;
6187  delete [] final;
6188  delete [] save;
6189  return;
6190  }
6191 
6192  //info is empty. Let's build the default Streamer descriptor
6193 
6194  char *temp = new char[10000];
6195  temp[0] = 0;
6196  char local[100];
6197 
6198  //add list of base classes
6199  TIter nextb(GetListOfBases());
6200  TBaseClass *base;
6201  while ((base = (TBaseClass*) nextb())) {
6202  snprintf(local,100,"%s;",base->GetName());
6203  strlcat(temp,local,10000);
6204  }
6205 
6206  //add list of data members and types
6207  TIter nextd(GetListOfDataMembers());
6208  while ((dm = (TDataMember *) nextd())) {
6209  if (dm->IsEnum()) continue;
6210  if (!dm->IsPersistent()) continue;
6211  Long_t property = dm->Property();
6212  if (property & kIsStatic) continue;
6213  TClass *acl = TClass::GetClass(dm->GetTypeName(),update);
6214  update = kFALSE;
6215  if (acl) {
6216  if (acl->GetClassVersion() == 0) continue;
6217  }
6218 
6219  // dm->GetArrayIndex() returns an empty string if it does not
6220  // applies
6221  const char * index = dm->GetArrayIndex();
6222  if (strlen(index)==0)
6223  snprintf(local,100,"%s %s;",dm->GetFullTypeName(),dm->GetName());
6224  else
6225  snprintf(local,100,"%s %s[%s];",dm->GetFullTypeName(),dm->GetName(),index);
6226  strlcat(temp,local,10000);
6227  }
6228  //fStreamerInfo = temp;
6229  delete [] temp;
6230 */
6231  return 0;
6232 }
6233 
6234 ////////////////////////////////////////////////////////////////////////////////
6235 /// Return true if the checksum passed as argument is one of the checksum
6236 /// value produced by the older checksum calculation algorithm.
6237 
6238 Bool_t TClass::MatchLegacyCheckSum(UInt_t checksum) const
6239 {
6240  for(UInt_t i = 1; i < kLatestCheckSum; ++i) {
6241  if ( checksum == GetCheckSum( (ECheckSum) i ) ) return kTRUE;
6242  }
6243  return kFALSE;
6244 }
6245 
6246 ////////////////////////////////////////////////////////////////////////////////
6247 /// Call GetCheckSum with validity check.
6248 
6249 UInt_t TClass::GetCheckSum(ECheckSum code) const
6250 {
6251  bool isvalid;
6252  return GetCheckSum(code,isvalid);
6253 }
6254 
6255 ////////////////////////////////////////////////////////////////////////////////
6256 /// Return GetCheckSum(kCurrentCheckSum,isvalid);
6257 
6258 UInt_t TClass::GetCheckSum(Bool_t &isvalid) const
6259 {
6260  return GetCheckSum(kCurrentCheckSum,isvalid);
6261 }
6262 
6263 ////////////////////////////////////////////////////////////////////////////////
6264 /// Compute and/or return the class check sum.
6265 ///
6266 /// isvalid is set to false, if the function is unable to calculate the
6267 /// checksum.
6268 ///
6269 /// The class ckecksum is used by the automatic schema evolution algorithm
6270 /// to uniquely identify a class version.
6271 /// The check sum is built from the names/types of base classes and
6272 /// data members.
6273 /// Original algorithm from Victor Perevovchikov (perev@bnl.gov).
6274 ///
6275 /// The valid range of code is determined by ECheckSum.
6276 ///
6277 /// - kNoEnum: data members of type enum are not counted in the checksum
6278 /// - kNoRange: return the checksum of data members and base classes, not including the ranges and array size found in comments.
6279 /// - kWithTypeDef: use the sugared type name in the calculation.
6280 ///
6281 /// This is needed for backward compatibility.
6282 ///
6283 /// WARNING: this function must be kept in sync with TStreamerInfo::GetCheckSum.
6284 /// They are both used to handle backward compatibility and should both return the same values.
6285 /// TStreamerInfo uses the information in TStreamerElement while TClass uses the information
6286 /// from TClass::GetListOfBases and TClass::GetListOfDataMembers.
6287 
6288 UInt_t TClass::GetCheckSum(ECheckSum code, Bool_t &isvalid) const
6289 {
6290  // fCheckSum is an atomic variable. Also once it has
6291  // transition from a zero Value it never changes. If two
6292  // thread reach past this if statement and calculated the
6293  // 'kLastestCheckSum', they will by definition obtain the
6294  // same value, so technically we could simply have:
6295  // if (fCheckSum && code == kCurrentCheckSum) return fCheckSum;
6296  // However save a little bit of barrier time by calling load()
6297  // only once.
6298 
6299  isvalid = kTRUE;
6300 
6301  UInt_t currentChecksum = fCheckSum.load();
6302  if (currentChecksum && code == kCurrentCheckSum) return currentChecksum;
6303 
6304  R__LOCKGUARD(gInterpreterMutex);
6305 
6306  // kCurrentCheckSum (0) is the default parameter value and should be kept
6307  // for backward compatibility, too be able to use the inequality checks,
6308  // we need to set the code to the largest value.
6309  if (code == kCurrentCheckSum) code = kLatestCheckSum;
6310 
6311  UInt_t id = 0;
6312 
6313  int il;
6314  TString name = GetName();
6315  TString type;
6316  il = name.Length();
6317  for (int i=0; i<il; i++) id = id*3+name[i];
6318 
6319  // Here we skip he base classes in case this is a pair or STL collection,
6320  // otherwise, on some STL implementations, it can happen that pair has
6321  // base classes which are an internal implementation detail.
6322  TList *tlb = ((TClass*)this)->GetListOfBases();
6323  if (tlb && !GetCollectionProxy() && strncmp(GetName(), "pair<", 5)) {
6324  // Loop over bases if not a proxied collection or a pair
6325 
6326  TIter nextBase(tlb);
6327 
6328  TBaseClass *tbc=0;
6329  while((tbc=(TBaseClass*)nextBase())) {
6330  name = tbc->GetName();
6331  Bool_t isSTL = TClassEdit::IsSTLCont(name);
6332  if (isSTL)
6333  name = TClassEdit::ShortType( name, TClassEdit::kDropStlDefault );
6334  il = name.Length();
6335  for (int i=0; i<il; i++) id = id*3+name[i];
6336  if (code > kNoBaseCheckSum && !isSTL) {
6337  if (tbc->GetClassPointer() == 0) {
6338  Error("GetCheckSum","Calculating the checksum for (%s) requires the base class (%s) meta information to be available!",
6339  GetName(),tbc->GetName());
6340  isvalid = kFALSE;
6341  return 0;
6342  } else
6343  id = id*3 + tbc->GetClassPointer()->GetCheckSum();
6344  }
6345  }/*EndBaseLoop*/
6346  }
6347  TList *tlm = ((TClass*)this)->GetListOfDataMembers();
6348  if (tlm) { // Loop over members
6349  TIter nextMemb(tlm);
6350  TDataMember *tdm=0;
6351  Long_t prop = 0;
6352  while((tdm=(TDataMember*)nextMemb())) {
6353  if (!tdm->IsPersistent()) continue;
6354  // combine properties
6355  prop = (tdm->Property());
6356  TDataType* tdt = tdm->GetDataType();
6357  if (tdt) prop |= tdt->Property();
6358 
6359  if ( prop&kIsStatic) continue;
6360  name = tdm->GetName(); il = name.Length();
6361  if ( (code > kNoEnum) && code != kReflex && code != kReflexNoComment && prop&kIsEnum)
6362  id = id*3 + 1;
6363 
6364  int i;
6365  for (i=0; i<il; i++) id = id*3+name[i];
6366 
6367  if (code > kWithTypeDef || code == kReflexNoComment) {
6368  type = tdm->GetTrueTypeName();
6369  // GetTrueTypeName uses GetFullyQualifiedName which already drops
6370  // the default template parameter, so we no longer need to do this.
6371  //if (TClassEdit::IsSTLCont(type))
6372  // type = TClassEdit::ShortType( type, TClassEdit::kDropStlDefault );
6373  if (code == kReflex || code == kReflexNoComment) {
6374  if (prop&kIsEnum) {
6375  type = "int";
6376  } else {
6377  type.ReplaceAll("ULong64_t","unsigned long long");
6378  type.ReplaceAll("Long64_t","long long");
6379  type.ReplaceAll("<signed char","<char");
6380  type.ReplaceAll(",signed char",",char");
6381  if (type=="signed char") type = "char";
6382  }
6383  }
6384  } else {
6385  type = tdm->GetFullTypeName();
6386  // GetFullTypeName uses GetFullyQualifiedName which already drops
6387  // the default template parameter, so we no longer need to do this.
6388  //if (TClassEdit::IsSTLCont(type))
6389  // type = TClassEdit::ShortType( type, TClassEdit::kDropStlDefault );
6390  }
6391 
6392  il = type.Length();
6393  for (i=0; i<il; i++) id = id*3+type[i];
6394 
6395  int dim = tdm->GetArrayDim();
6396  if (prop&kIsArray) {
6397  for (int ii=0;ii<dim;ii++) id = id*3+tdm->GetMaxIndex(ii);
6398  }
6399  if (code > kNoRange) {
6400  const char *left;
6401  if (code > TClass::kNoRangeCheck)
6402  left = TVirtualStreamerInfo::GetElementCounterStart(tdm->GetTitle());
6403  else
6404  left = strstr(tdm->GetTitle(),"[");
6405  if (left) {
6406  const char *right = strstr(left,"]");
6407  if (right) {
6408  ++left;
6409  while (left != right) {
6410  id = id*3 + *left;
6411  ++left;
6412  }
6413  }
6414  }
6415  }
6416  }/*EndMembLoop*/
6417  }
6418  // This should be moved to Initialization time however the last time
6419  // we tried this cause problem, in particular in the end-of-process operation.
6420  if (code==kLatestCheckSum) fCheckSum = id;
6421  return id;
6422 }
6423 
6424 ////////////////////////////////////////////////////////////////////////////////
6425 /// Adopt the Reference proxy pointer to indicate that this class
6426 /// represents a reference.
6427 /// When a new proxy is adopted, the old one is deleted.
6428 
6429 void TClass::AdoptReferenceProxy(TVirtualRefProxy* proxy)
6430 {
6431  R__LOCKGUARD(gInterpreterMutex);
6432 
6433  if ( fRefProxy ) {
6434  fRefProxy->Release();
6435  }
6436  fRefProxy = proxy;
6437  if ( fRefProxy ) {
6438  fRefProxy->SetClass(this);
6439  }
6440  fCanSplit = -1;
6441 }
6442 
6443 ////////////////////////////////////////////////////////////////////////////////
6444 /// Adopt the TMemberStreamer pointer to by p and use it to Stream non basic
6445 /// member name.
6446 
6447 void TClass::AdoptMemberStreamer(const char *name, TMemberStreamer *p)
6448 {
6449  if (!fRealData) return;
6450 
6451  R__LOCKGUARD(gInterpreterMutex);
6452 
6453  TIter next(fRealData);
6454  TRealData *rd;
6455  while ((rd = (TRealData*)next())) {
6456  if (strcmp(rd->GetName(),name) == 0) {
6457  // If there is a TStreamerElement that took a pointer to the
6458  // streamer we should inform it!
6459  rd->AdoptStreamer(p);
6460  break;
6461  }
6462  }
6463 
6464 // NOTE: This alternative was proposed but not is not used for now,
6465 // One of the major difference with the code above is that the code below
6466 // did not require the RealData to have been built
6467 // if (!fData) return;
6468 // const char *n = name;
6469 // while (*n=='*') n++;
6470 // TString ts(n);
6471 // int i = ts.Index("[");
6472 // if (i>=0) ts.Remove(i,999);
6473 // TDataMember *dm = (TDataMember*)fData->FindObject(ts.Data());
6474 // if (!dm) {
6475 // Warning("SetStreamer","Can not find member %s::%s",GetName(),name);
6476 // return;
6477 // }
6478 // dm->SetStreamer(p);
6479  return;
6480 }
6481 
6482 ////////////////////////////////////////////////////////////////////////////////
6483 /// Install a new member streamer (p will be copied).
6484 
6485 void TClass::SetMemberStreamer(const char *name, MemberStreamerFunc_t p)
6486 {
6487  AdoptMemberStreamer(name,new TMemberStreamer(p));
6488 }
6489 
6490 ////////////////////////////////////////////////////////////////////////////////
6491 /// Function called by the Streamer functions to deserialize information
6492 /// from buffer b into object at p.
6493 /// This function assumes that the class version and the byte count information
6494 /// have been read.
6495 /// - version is the version number of the class
6496 /// - start is the starting position in the buffer b
6497 /// - count is the number of bytes for this object in the buffer
6498 
6499 Int_t TClass::ReadBuffer(TBuffer &b, void *pointer, Int_t version, UInt_t start, UInt_t count)
6500 {
6501  return b.ReadClassBuffer(this,pointer,version,start,count);
6502 }
6503 
6504 ////////////////////////////////////////////////////////////////////////////////
6505 /// Function called by the Streamer functions to deserialize information
6506 /// from buffer b into object at p.
6507 
6508 Int_t TClass::ReadBuffer(TBuffer &b, void *pointer)
6509 {
6510  return b.ReadClassBuffer(this,pointer);
6511 }
6512 
6513 ////////////////////////////////////////////////////////////////////////////////
6514 /// Function called by the Streamer functions to serialize object at p
6515 /// to buffer b. The optional argument info may be specified to give an
6516 /// alternative StreamerInfo instead of using the default StreamerInfo
6517 /// automatically built from the class definition.
6518 /// For more information, see class TVirtualStreamerInfo.
6519 
6520 Int_t TClass::WriteBuffer(TBuffer &b, void *pointer, const char * /*info*/)
6521 {
6522  b.WriteClassBuffer(this,pointer);
6523  return 0;
6524 }
6525 
6526 ////////////////////////////////////////////////////////////////////////////////
6527 ///There is special streamer for the class
6528 
6529 void TClass::StreamerExternal(const TClass* pThis, void *object, TBuffer &b, const TClass *onfile_class)
6530 {
6531  // case kExternal:
6532  // case kExternal|kEmulatedStreamer:
6533 
6534  TClassStreamer *streamer = gThreadTsd ? pThis->GetStreamer() : pThis->fStreamer;
6535  streamer->Stream(b,object,onfile_class);
6536 }
6537 
6538 ////////////////////////////////////////////////////////////////////////////////
6539 /// Case of TObjects
6540 
6541 void TClass::StreamerTObject(const TClass* pThis, void *object, TBuffer &b, const TClass * /* onfile_class */)
6542 {
6543  // case kTObject:
6544 
6545  if (!pThis->fIsOffsetStreamerSet) {
6546  pThis->CalculateStreamerOffset();
6547  }
6548  TObject *tobj = (TObject*)((Long_t)object + pThis->fOffsetStreamer);
6549  tobj->Streamer(b);
6550 }
6551 
6552 ////////////////////////////////////////////////////////////////////////////////
6553 /// Case of TObjects when fIsOffsetStreamerSet is known to have been set.
6554 
6555 void TClass::StreamerTObjectInitialized(const TClass* pThis, void *object, TBuffer &b, const TClass * /* onfile_class */)
6556 {
6557  TObject *tobj = (TObject*)((Long_t)object + pThis->fOffsetStreamer);
6558  tobj->Streamer(b);
6559 }
6560 
6561 ////////////////////////////////////////////////////////////////////////////////
6562 /// Case of TObjects when we do not have the library defining the class.
6563 
6564 void TClass::StreamerTObjectEmulated(const TClass* pThis, void *object, TBuffer &b, const TClass *onfile_class)
6565 {
6566  // case kTObject|kEmulatedStreamer :
6567  if (b.IsReading()) {
6568  b.ReadClassEmulated(pThis, object, onfile_class);
6569  } else {
6570  b.WriteClassBuffer(pThis, object);
6571  }
6572 }
6573 
6574 ////////////////////////////////////////////////////////////////////////////////
6575 /// Case of instrumented class with a library
6576 
6577 void TClass::StreamerInstrumented(const TClass* pThis, void *object, TBuffer &b, const TClass * /* onfile_class */)
6578 {
6579  // case kInstrumented:
6580  pThis->fStreamerFunc(b,object);
6581 }
6582 
6583 ////////////////////////////////////////////////////////////////////////////////
6584 /// Case of instrumented class with a library
6585 
6586 void TClass::ConvStreamerInstrumented(const TClass* pThis, void *object, TBuffer &b, const TClass *onfile_class)
6587 {
6588  // case kInstrumented:
6589  pThis->fConvStreamerFunc(b,object,onfile_class);
6590 }
6591 
6592 ////////////////////////////////////////////////////////////////////////////////
6593 /// Case of where we should directly use the StreamerInfo.
6594 /// - case kForeign:
6595 /// - case kForeign|kEmulatedStreamer:
6596 /// - case kInstrumented|kEmulatedStreamer:
6597 /// - case kEmulatedStreamer:
6598 
6599 void TClass::StreamerStreamerInfo(const TClass* pThis, void *object, TBuffer &b, const TClass *onfile_class)
6600 {
6601  if (b.IsReading()) {
6602  b.ReadClassBuffer(pThis, object, onfile_class);
6603  //ReadBuffer (b, object);
6604  } else {
6605  //WriteBuffer(b, object);
6606  b.WriteClassBuffer(pThis, object);
6607  }
6608 }
6609 
6610 ////////////////////////////////////////////////////////////////////////////////
6611 /// Default streaming in cases where either we have no way to know what to do
6612 /// or if Property() has not yet been called.
6613 
6614 void TClass::StreamerDefault(const TClass* pThis, void *object, TBuffer &b, const TClass *onfile_class)
6615 {
6616  if (pThis->fProperty==(-1)) {
6617  pThis->Property();
6618  }
6619 
6620  // We could get here because after this thread started StreamerDefault
6621  // *and* before check fProperty, another thread might have call Property
6622  // and this fProperty when we read it, is not -1 and fStreamerImpl is
6623  // supposed to be set properly (no longer pointing to the default).
6624  if (pThis->fStreamerImpl.load() == &TClass::StreamerDefault) {
6625  pThis->Fatal("StreamerDefault", "fStreamerImpl not properly initialized (%d)", pThis->fStreamerType);
6626  } else {
6627  (*pThis->fStreamerImpl)(pThis,object,b,onfile_class);
6628  }
6629 }
6630 
6631 ////////////////////////////////////////////////////////////////////////////////
6632 /// Adopt a TClassStreamer object. Ownership is transfered to this TClass
6633 /// object.
6634 
6635 void TClass::AdoptStreamer(TClassStreamer *str)
6636 {
6637 // // This code can be used to quickly test the STL Emulation layer
6638 // Int_t k = TClassEdit::IsSTLCont(GetName());
6639 // if (k==1||k==-1) { delete str; return; }
6640 
6641  R__LOCKGUARD(gInterpreterMutex);
6642 
6643  if (fStreamer) delete fStreamer;
6644  if (str) {
6645  fStreamerType = kExternal | ( fStreamerType&kEmulatedStreamer );
6646  fStreamer = str;
6647  fStreamerImpl = &TClass::StreamerExternal;
6648  } else if (fStreamer) {
6649  // Case where there was a custom streamer and it is hereby removed,
6650  // we need to reset fStreamerType
6651  fStreamer = str;
6652  fStreamerType = TClass::kDefault;
6653  if (fProperty != -1) {
6654  fProperty = -1;
6655  Property();
6656  }
6657  }
6658 }
6659 
6660 ////////////////////////////////////////////////////////////////////////////////
6661 /// Set a wrapper/accessor function around this class custom streamer.
6662 
6663 void TClass::SetStreamerFunc(ClassStreamerFunc_t strm)
6664 {
6665  R__LOCKGUARD(gInterpreterMutex);
6666  if (fProperty != -1 && !fConvStreamerFunc &&
6667  ( (fStreamerFunc == 0 && strm != 0) || (fStreamerFunc != 0 && strm == 0) ) )
6668  {
6669  fStreamerFunc = strm;
6670 
6671  // Since initialization has already been done, make sure to tweak it
6672  // for the new state.
6673  if (HasInterpreterInfo() && fStreamerType != kTObject && !fStreamer) {
6674  fStreamerType = kInstrumented;
6675  fStreamerImpl = &TClass::StreamerInstrumented;
6676  }
6677  } else {
6678  fStreamerFunc = strm;
6679  }
6680  fCanSplit = -1;
6681 }
6682 
6683 ////////////////////////////////////////////////////////////////////////////////
6684 /// Set a wrapper/accessor function around this class custom conversion streamer.
6685 
6686 void TClass::SetConvStreamerFunc(ClassConvStreamerFunc_t strm)
6687 {
6688  R__LOCKGUARD(gInterpreterMutex);
6689  if (fProperty != -1 &&
6690  ( (fConvStreamerFunc == 0 && strm != 0) || (fConvStreamerFunc != 0 && strm == 0) ) )
6691  {
6692  fConvStreamerFunc = strm;
6693 
6694  // Since initialization has already been done, make sure to tweak it
6695  // for the new state.
6696  if (HasInterpreterInfo() && fStreamerType != kTObject && !fStreamer) {
6697  fStreamerType = kInstrumented;
6698  fStreamerImpl = &TClass::ConvStreamerInstrumented;
6699  }
6700  } else {
6701  fConvStreamerFunc = strm;
6702  }
6703  fCanSplit = -1;
6704 }
6705 
6706 
6707 ////////////////////////////////////////////////////////////////////////////////
6708 /// Install a new wrapper around 'Merge'.
6709 
6710 void TClass::SetMerge(ROOT::MergeFunc_t newMerge)
6711 {
6712  fMerge = newMerge;
6713 }
6714 
6715 ////////////////////////////////////////////////////////////////////////////////
6716 /// Install a new wrapper around 'ResetAfterMerge'.
6717 
6718 void TClass::SetResetAfterMerge(ROOT::ResetAfterMergeFunc_t newReset)
6719 {
6720  fResetAfterMerge = newReset;
6721 }
6722 
6723 ////////////////////////////////////////////////////////////////////////////////
6724 /// Install a new wrapper around 'new'.
6725 
6726 void TClass::SetNew(ROOT::NewFunc_t newFunc)
6727 {
6728  fNew = newFunc;
6729 }
6730 
6731 ////////////////////////////////////////////////////////////////////////////////
6732 /// Install a new wrapper around 'new []'.
6733 
6734 void TClass::SetNewArray(ROOT::NewArrFunc_t newArrayFunc)
6735 {
6736  fNewArray = newArrayFunc;
6737 }
6738 
6739 ////////////////////////////////////////////////////////////////////////////////
6740 /// Install a new wrapper around 'delete'.
6741 
6742 void TClass::SetDelete(ROOT::DelFunc_t deleteFunc)
6743 {
6744  fDelete = deleteFunc;
6745 }
6746 
6747 ////////////////////////////////////////////////////////////////////////////////
6748 /// Install a new wrapper around 'delete []'.
6749 
6750 void TClass::SetDeleteArray(ROOT::DelArrFunc_t deleteArrayFunc)
6751 {
6752  fDeleteArray = deleteArrayFunc;
6753 }
6754 
6755 ////////////////////////////////////////////////////////////////////////////////
6756 /// Install a new wrapper around the destructor.
6757 
6758 void TClass::SetDestructor(ROOT::DesFunc_t destructorFunc)
6759 {
6760  fDestructor = destructorFunc;
6761 }
6762 
6763 ////////////////////////////////////////////////////////////////////////////////
6764 /// Install a new wrapper around the directory auto add function..
6765 /// The function autoAddFunc has the signature void (*)(void *obj, TDirectory dir)
6766 /// and should register 'obj' to the directory if dir is not null
6767 /// and unregister 'obj' from its current directory if dir is null
6768 
6769 void TClass::SetDirectoryAutoAdd(ROOT::DirAutoAdd_t autoAddFunc)
6770 {
6771  fDirAutoAdd = autoAddFunc;
6772 }
6773 
6774 ////////////////////////////////////////////////////////////////////////////////
6775 /// Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum
6776 
6777 TVirtualStreamerInfo *TClass::FindStreamerInfo(UInt_t checksum) const
6778 {
6779  TVirtualStreamerInfo *guess = fLastReadInfo;
6780  if (guess && guess->GetCheckSum() == checksum) {
6781  return guess;
6782  } else {
6783  if (fCheckSum == checksum) return GetStreamerInfo();
6784 
6785  R__LOCKGUARD(gInterpreterMutex);
6786  Int_t ninfos = fStreamerInfo->GetEntriesFast()-1;
6787  for (Int_t i=-1;i<ninfos;++i) {
6788  // TClass::fStreamerInfos has a lower bound not equal to 0,
6789  // so we have to use At and should not use UncheckedAt
6790  TVirtualStreamerInfo *info = (TVirtualStreamerInfo*)fStreamerInfo->UncheckedAt(i);
6791  if (info && info->GetCheckSum() == checksum) {
6792  // R__ASSERT(i==info->GetClassVersion() || (i==-1&&info->GetClassVersion()==1));
6793  info->BuildOld();
6794  if (info->IsCompiled()) fLastReadInfo = info;
6795  return info;
6796  }
6797  }
6798  return 0;
6799  }
6800 }
6801 
6802 ////////////////////////////////////////////////////////////////////////////////
6803 /// Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum
6804 
6805 TVirtualStreamerInfo *TClass::FindStreamerInfo(TObjArray* arr, UInt_t checksum) const
6806 {
6807  R__LOCKGUARD(gInterpreterMutex);
6808  Int_t ninfos = arr->GetEntriesFast()-1;
6809  for (Int_t i=-1;i<ninfos;i++) {
6810  // TClass::fStreamerInfos has a lower bound not equal to 0,
6811  // so we have to use At and should not use UncheckedAt
6812  TVirtualStreamerInfo *info = (TVirtualStreamerInfo*)arr->UncheckedAt(i);
6813  if (!info) continue;
6814  if (info->GetCheckSum() == checksum) {
6815  R__ASSERT(i==info->GetClassVersion() || (i==-1&&info->GetClassVersion()==1));
6816  return info;
6817  }
6818  }
6819  return 0;
6820 }
6821 
6822 ////////////////////////////////////////////////////////////////////////////////
6823 /// Return a Conversion StreamerInfo from the class 'classname' for version number 'version' to this class, if any.
6824 
6825 TVirtualStreamerInfo *TClass::GetConversionStreamerInfo( const char* classname, Int_t version ) const
6826 {
6827  TClass *cl = TClass::GetClass( classname );
6828  if( !cl )
6829  return 0;
6830  return GetConversionStreamerInfo( cl, version );
6831 }
6832 
6833 ////////////////////////////////////////////////////////////////////////////////
6834 /// Return a Conversion StreamerInfo from the class represented by cl for version number 'version' to this class, if any.
6835 
6836 TVirtualStreamerInfo *TClass::GetConversionStreamerInfo( const TClass* cl, Int_t version ) const
6837 {
6838  //----------------------------------------------------------------------------
6839  // Check if the classname was specified correctly
6840  /////////////////////////////////////////////////////////////////////////////
6841 
6842  if( !cl )
6843  return 0;
6844 
6845  if( cl == this )
6846  return GetStreamerInfo( version );
6847 
6848  //----------------------------------------------------------------------------
6849  // Check if we already have it
6850  /////////////////////////////////////////////////////////////////////////////
6851 
6852  TObjArray* arr = 0;
6853  if (fConversionStreamerInfo.load()) {
6854  std::map<std::string, TObjArray*>::iterator it;
6855  R__LOCKGUARD(gInterpreterMutex);
6856 
6857  it = (*fConversionStreamerInfo).find( cl->GetName() );
6858 
6859  if( it != (*fConversionStreamerInfo).end() ) {
6860  arr = it->second;
6861  }
6862 
6863  if( arr && version > -1 && version < arr->GetSize() && arr->At( version ) )
6864  return (TVirtualStreamerInfo*) arr->At( version );
6865  }
6866 
6867  R__LOCKGUARD(gInterpreterMutex);
6868 
6869  //----------------------------------------------------------------------------
6870  // We don't have the streamer info so find it in other class
6871  /////////////////////////////////////////////////////////////////////////////
6872 
6873  const TObjArray *clSI = cl->GetStreamerInfos();
6874  TVirtualStreamerInfo* info = 0;
6875  if( version >= -1 && version < clSI->GetSize() )
6876  info = (TVirtualStreamerInfo*)clSI->At( version );
6877 
6878  if (!info && cl->GetCollectionProxy()) {
6879  info = cl->GetStreamerInfo(); // instantiate the StreamerInfo for STL collections.
6880  }
6881 
6882  if( !info )
6883  return 0;
6884 
6885  //----------------------------------------------------------------------------
6886  // We have the right info so we need to clone it to create new object with
6887  // non artificial streamer elements and we should build it for current class
6888  /////////////////////////////////////////////////////////////////////////////
6889 
6890  info = (TVirtualStreamerInfo*)info->Clone();
6891 
6892  if( !info->BuildFor( this ) ) {
6893  delete info;
6894  return 0;
6895  }
6896 
6897  if (!info->IsCompiled()) {
6898  // Streamer info has not been compiled, but exists.
6899  // Therefore it was read in from a file and we have to do schema evolution?
6900  // Or it didn't have a dictionary before, but does now?
6901  info->BuildOld();
6902  }
6903 
6904  //----------------------------------------------------------------------------
6905  // Cache this streamer info
6906  /////////////////////////////////////////////////////////////////////////////
6907 
6908  if (!arr) {
6909  arr = new TObjArray(version+10, -1);
6910  if (!fConversionStreamerInfo.load()) {
6911  fConversionStreamerInfo = new std::map<std::string, TObjArray*>();
6912  }
6913  (*fConversionStreamerInfo)[cl->GetName()] = arr;
6914  }
6915  arr->AddAtAndExpand( info, info->GetClassVersion() );
6916  return info;
6917 }
6918 
6919 ////////////////////////////////////////////////////////////////////////////////
6920 /// Return a Conversion StreamerInfo from the class 'classname' for the layout represented by 'checksum' to this class, if any.
6921 
6922 TVirtualStreamerInfo *TClass::FindConversionStreamerInfo( const char* classname, UInt_t checksum ) const
6923 {
6924  TClass *cl = TClass::GetClass( classname );
6925  if( !cl )
6926  return 0;
6927  return FindConversionStreamerInfo( cl, checksum );
6928 }
6929 
6930 ////////////////////////////////////////////////////////////////////////////////
6931 /// Return a Conversion StreamerInfo from the class represented by cl for the layout represented by 'checksum' to this class, if any.
6932 
6933 TVirtualStreamerInfo *TClass::FindConversionStreamerInfo( const TClass* cl, UInt_t checksum ) const
6934 {
6935  //---------------------------------------------------------------------------
6936  // Check if the classname was specified correctly
6937  /////////////////////////////////////////////////////////////////////////////
6938 
6939  if( !cl )
6940  return 0;
6941 
6942  if( cl == this )
6943  return FindStreamerInfo( checksum );
6944 
6945  //----------------------------------------------------------------------------
6946  // Check if we already have it
6947  /////////////////////////////////////////////////////////////////////////////
6948 
6949  TObjArray* arr = 0;
6950  TVirtualStreamerInfo* info = 0;
6951  if (fConversionStreamerInfo.load()) {
6952  std::map<std::string, TObjArray*>::iterator it;
6953 
6954  R__LOCKGUARD(gInterpreterMutex);
6955 
6956  it = (*fConversionStreamerInfo).find( cl->GetName() );
6957 
6958  if( it != (*fConversionStreamerInfo).end() ) {
6959  arr = it->second;
6960  }
6961  if (arr) {
6962  info = FindStreamerInfo( arr, checksum );
6963  }
6964  }
6965 
6966  if( info )
6967  return info;
6968 
6969  R__LOCKGUARD(gInterpreterMutex);
6970 
6971  //----------------------------------------------------------------------------
6972  // Get it from the foreign class
6973  /////////////////////////////////////////////////////////////////////////////
6974 
6975  info = cl->FindStreamerInfo( checksum );
6976 
6977  if( !info )
6978  return 0;
6979 
6980  //----------------------------------------------------------------------------
6981  // We have the right info so we need to clone it to create new object with
6982  // non artificial streamer elements and we should build it for current class
6983  /////////////////////////////////////////////////////////////////////////////
6984 
6985  info = (TVirtualStreamerInfo*)info->Clone();
6986  if( !info->BuildFor( this ) ) {
6987  delete info;
6988  return 0;
6989  }
6990 
6991  if (!info->IsCompiled()) {
6992  // Streamer info has not been compiled, but exists.
6993  // Therefore it was read in from a file and we have to do schema evolution?
6994  // Or it didn't have a dictionary before, but does now?
6995  info->BuildOld();
6996  }
6997 
6998  //----------------------------------------------------------------------------
6999  // Cache this streamer info
7000  /////////////////////////////////////////////////////////////////////////////
7001 
7002  if (!arr) {
7003  arr = new TObjArray(16, -2);
7004  if (!fConversionStreamerInfo.load()) {
7005  fConversionStreamerInfo = new std::map<std::string, TObjArray*>();
7006  }
7007  (*fConversionStreamerInfo)[cl->GetName()] = arr;
7008  }
7009  arr->AddAtAndExpand( info, info->GetClassVersion() );
7010 
7011  return info;
7012 }
7013 
7014 ////////////////////////////////////////////////////////////////////////////////
7015 /// Register the StreamerInfo in the given slot, change the State of the
7016 /// TClass as appropriate.
7017 
7018 void TClass::RegisterStreamerInfo(TVirtualStreamerInfo *info)
7019 {
7020  if (info) {
7021  R__LOCKGUARD(gInterpreterMutex);
7022  Int_t slot = info->GetClassVersion();
7023  if (fStreamerInfo->GetSize() > (slot-fStreamerInfo->LowerBound())
7024  && fStreamerInfo->At(slot) != 0
7025  && fStreamerInfo->At(slot) != info) {
7026  Error("RegisterStreamerInfo",
7027  "Register StreamerInfo for %s on non-empty slot (%d).",
7028  GetName(),slot);
7029  }
7030  fStreamerInfo->AddAtAndExpand(info, slot);
7031  if (fState <= kForwardDeclared) {
7032  fState = kEmulated;
7033  if (fCheckSum==0 && slot==fClassVersion) fCheckSum = info->GetCheckSum();
7034  }
7035  }
7036 }
7037 
7038 ////////////////////////////////////////////////////////////////////////////////
7039 /// Remove and delete the StreamerInfo in the given slot.
7040 /// Update the slot accordingly.
7041 
7042 void TClass::RemoveStreamerInfo(Int_t slot)
7043 {
7044  if (fStreamerInfo->GetSize() >= slot) {
7045  R__LOCKGUARD(gInterpreterMutex);
7046  TVirtualStreamerInfo *info = (TVirtualStreamerInfo*)fStreamerInfo->At(slot);
7047  fStreamerInfo->RemoveAt(fClassVersion);
7048  delete info;
7049  if (fState == kEmulated && fStreamerInfo->GetEntries() == 0) {
7050  fState = kForwardDeclared;
7051  }
7052  }
7053 }
7054 
7055 ////////////////////////////////////////////////////////////////////////////////
7056 /// Return true is the Hash/RecursiveRemove setup is consistent, i.e. when all
7057 /// classes in the class hierarchy that overload TObject::Hash do call
7058 /// ROOT::CallRecursiveRemoveIfNeeded in their destructor.
7059 /// i.e. it is safe to call the Hash virtual function during the RecursiveRemove operation.
7060 /// This routines is used for a small subset of the class for which we need
7061 /// the answer before gROOT is properly initialized.
7062 
7063 Bool_t ROOT::Internal::HasConsistentHashMember(const char *cname)
7064 {
7065  // Hand selection of correct classes, those classes should be
7066  // cross-checked in testHashRecursiveRemove.cxx
7067  static const char *handVerified[] = {
7068  "TEnvRec", "TDataType", "TObjArray", "TList", "THashList",
7069  "TClass", "TCling", "TInterpreter", "TMethod", "ROOT::Internal::TCheckHashRecursiveRemoveConsistency",
7070  "TCheckHashRecursiveRemoveConsistency", "TGWindow",
7071  "TDirectory", "TDirectoryFile", "TObject", "TH1",
7072  "TQClass", "TGlobal" };
7073 
7074  if (cname && cname[0]) {
7075  for (auto cursor : handVerified) {
7076  if (strcmp(cname, cursor) == 0)
7077  return true;
7078  }
7079  }
7080  return false;
7081 }
7082 
7083 ////////////////////////////////////////////////////////////////////////////////
7084 /// Return true is the Hash/RecursiveRemove setup is consistent, i.e. when all
7085 /// classes in the class hierarchy that overload TObject::Hash do call
7086 /// ROOT::CallRecursiveRemoveIfNeeded in their destructor.
7087 /// i.e. it is safe to call the Hash virtual function during the RecursiveRemove operation.
7088 
7089 Bool_t ROOT::Internal::HasConsistentHashMember(TClass &clRef)
7090 {
7091  return clRef.HasConsistentHashMember();
7092 }
7093 
7094 ////////////////////////////////////////////////////////////////////////////////
7095 /// Return true if we have access to a constructor useable for I/O. This is
7096 /// typically the default constructor but can also be a constructor specifically
7097 /// marked for I/O (for example a constructor taking a TRootIOCtor* as an
7098 /// argument). In other words, if this routine returns true, TClass::New is
7099 /// guarantee to succeed.
7100 /// To know if the class described by this TClass has a default constructor
7101 /// (public or not), use
7102 /// \code{.cpp}
7103 /// cl->GetProperty() & kClassHasDefaultCtor
7104 /// \code
7105 /// To know if the class described by this TClass has a public default
7106 /// constructor use:
7107 /// \code{.cpp}
7108 /// gInterpreter->ClassInfo_HasDefaultConstructor(aClass->GetClassInfo());
7109 /// \code
7110 
7111 Bool_t TClass::HasDefaultConstructor() const
7112 {
7113 
7114  if (fNew) return kTRUE;
7115 
7116  if (HasInterpreterInfo()) {
7117  R__LOCKGUARD(gInterpreterMutex);
7118  return gCling->ClassInfo_HasDefaultConstructor(GetClassInfo());
7119  }
7120  if (fCollectionProxy) {
7121  return kTRUE;
7122  }
7123  if (fCurrentInfo.load()) {
7124  // Emulated class, we know how to construct them via the TStreamerInfo
7125  return kTRUE;
7126  }
7127  return kFALSE;
7128 }
7129 
7130 ////////////////////////////////////////////////////////////////////////////////
7131 /// Returns true if this class has an definition and/or overload of the
7132 /// member function Hash.
7133 ///
7134 /// For example to test if the class overload TObject::Hash use
7135 /// ~~~ {.cpp}
7136 /// if (cl->IsTObject() && cl->HasLocalHashMember())
7137 /// ~~~
7138 
7139 Bool_t TClass::HasLocalHashMember() const
7140 {
7141  if (fProperty == (-1))
7142  Property();
7143  return TestBit(kHasLocalHashMember);
7144 }
7145 
7146 ////////////////////////////////////////////////////////////////////////////////
7147 /// Return the wrapper around Merge.
7148 
7149 ROOT::MergeFunc_t TClass::GetMerge() const
7150 {
7151  return fMerge;
7152 }
7153 
7154 ////////////////////////////////////////////////////////////////////////////////
7155 /// Return the wrapper around Merge.
7156 
7157 ROOT::ResetAfterMergeFunc_t TClass::GetResetAfterMerge() const
7158 {
7159  return fResetAfterMerge;
7160 }
7161 
7162 ////////////////////////////////////////////////////////////////////////////////
7163 /// Return the wrapper around new ThisClass().
7164 
7165 ROOT::NewFunc_t TClass::GetNew() const
7166 {
7167  return fNew;
7168 }
7169 
7170 ////////////////////////////////////////////////////////////////////////////////
7171 /// Return the wrapper around new ThisClass[].
7172 
7173 ROOT::NewArrFunc_t TClass::GetNewArray() const
7174 {
7175  return fNewArray;
7176 }
7177 
7178 ////////////////////////////////////////////////////////////////////////////////
7179 /// Return the wrapper around delete ThiObject.
7180 
7181 ROOT::DelFunc_t TClass::GetDelete() const
7182 {
7183  return fDelete;
7184 }
7185 
7186 ////////////////////////////////////////////////////////////////////////////////
7187 /// Return the wrapper around delete [] ThiObject.
7188 
7189 ROOT::DelArrFunc_t TClass::GetDeleteArray() const
7190 {
7191  return fDeleteArray;
7192 }
7193 
7194 ////////////////////////////////////////////////////////////////////////////////
7195 /// Return the wrapper around the destructor
7196 
7197 ROOT::DesFunc_t TClass::GetDestructor() const
7198 {
7199  return fDestructor;
7200 }
7201 
7202 ////////////////////////////////////////////////////////////////////////////////
7203 /// Return the wrapper around the directory auto add function.
7204 
7205 ROOT::DirAutoAdd_t TClass::GetDirectoryAutoAdd() const
7206 {
7207  return fDirAutoAdd;
7208 }