Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TEnum.cxx
Go to the documentation of this file.
1 // @(#)root/meta:$Id$
2 // Author: Bianca-Cristina Cristescu 10/07/13
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2013, 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 TEnum
13 The TEnum class implements the enum type.
14 */
15 
16 #include <iostream>
17 
18 #include "TEnum.h"
19 #include "TEnumConstant.h"
20 #include "TInterpreter.h"
21 #include "TClass.h"
22 #include "TClassEdit.h"
23 #include "TClassTable.h"
24 #include "TProtoClass.h"
25 #include "TROOT.h"
26 
27 #include "TListOfEnums.h"
28 
29 ClassImp(TEnum);
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 /// Constructor for TEnum class.
33 /// It takes the name of the TEnum type, interpreter info and surrounding class
34 /// the enum it is not globalat namespace scope.
35 /// Constant List is owner if enum not on global scope (thus constants not
36 /// in TROOT::GetListOfGlobals).
37 
38 TEnum::TEnum(const char *name, DeclId_t declid, TClass *cls)
39  : fInfo(nullptr), fClass(cls)
40 {
41  SetName(name);
42  if (cls) {
43  fConstantList.SetOwner(kTRUE);
44  }
45 
46  // Determine fQualName
47  if (0 != strcmp("",GetTitle())){ // It comes from a protoclass
48  fQualName = std::string(GetTitle()) + "::" + GetName();
49  }
50  else if (GetClass()){ // It comes from a class/ns
51  fQualName = std::string(GetClass()->GetName()) + "::" + GetName();
52  }
53  else { // it is in the global scope
54  fQualName = GetName();
55  }
56 
57  Update(declid);
58 }
59 
60 ////////////////////////////////////////////////////////////////////////////////
61 /// Destructor
62 
63 TEnum::~TEnum()
64 {
65  gInterpreter->ClassInfo_Delete(fInfo);
66 }
67 
68 ////////////////////////////////////////////////////////////////////////////////
69 /// Add a EnumConstant to the list of constants of the Enum Type.
70 
71 void TEnum::AddConstant(TEnumConstant *constant)
72 {
73  fConstantList.Add(constant);
74 }
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// Return true if this enum object is pointing to a currently
78 /// loaded enum. If a enum is unloaded after the TEnum
79 /// is created, the TEnum will be set to be invalid.
80 
81 Bool_t TEnum::IsValid()
82 {
83  // Register the transaction when checking the validity of the object.
84  if (!fInfo && UpdateInterpreterStateMarker()) {
85  DeclId_t newId = gInterpreter->GetEnum(fClass, fName);
86  if (newId)
87  Update(newId);
88  return newId != 0;
89  }
90  return fInfo != 0;
91 }
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Get property description word. For meaning of bits see EProperty.
95 
96 Long_t TEnum::Property() const
97 {
98  return kIsEnum | (TestBit(kBitIsScopedEnum) ? kIsScopedEnum : 0);
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 /// Get the unterlying integer type of the enum:
103 /// enum E { kOne }; // ==> int
104 /// enum F: long; // ==> long
105 /// Returns kNumDataTypes if the enum is unknown / invalid.
106 
107 EDataType TEnum::GetUnderlyingType() const
108 {
109  if (fInfo)
110  return gInterpreter->ClassInfo_GetUnderlyingType(fInfo);
111  return kNumDataTypes;
112 }
113 
114 ////////////////////////////////////////////////////////////////////////////////
115 
116 TDictionary::DeclId_t TEnum::GetDeclId() const
117 {
118  if (fInfo)
119  return gInterpreter->GetDeclId(fInfo);
120 
121  return nullptr;
122 }
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 
126 void TEnum::Update(DeclId_t id)
127 {
128  if (fInfo)
129  gInterpreter->ClassInfo_Delete(fInfo);
130  if (!id) {
131  fInfo = nullptr;
132  return;
133  }
134 
135  fInfo = gInterpreter->ClassInfo_Factory(id);
136 
137  if (fInfo)
138  SetBit(kBitIsScopedEnum, gInterpreter->ClassInfo_IsScopedEnum(fInfo));
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 
143 TEnum *TEnum::GetEnum(const std::type_info &ti, ESearchAction sa)
144 {
145  int errorCode = 0;
146  char *demangledEnumName = TClassEdit::DemangleName(ti.name(), errorCode);
147 
148  if (errorCode != 0) {
149  free(demangledEnumName);
150  std::cerr << "ERROR TEnum::GetEnum - A problem occurred while demangling name.\n";
151  return nullptr;
152  }
153 
154  const char *constDemangledEnumName = demangledEnumName;
155  TEnum *en = TEnum::GetEnum(constDemangledEnumName, sa);
156  free(demangledEnumName);
157  return en;
158 
159 }
160 
161 ////////////////////////////////////////////////////////////////////////////////
162 /// Static function to retrieve enumerator from the ROOT's typesystem.
163 /// It has no side effect, except when the load flag is true. In this case,
164 /// the load of the library containing the scope of the enumerator is attempted.
165 /// There are two top level code paths: the enumerator is scoped or isn't.
166 /// If it is not, a lookup in the list of global enums is performed.
167 /// If it is, two lookups are carried out for its scope: one in the list of
168 /// classes and one in the list of protoclasses. If a scope with the desired name
169 /// is found, the enum is searched. If the scope is not found, and the load flag is
170 /// true, the aforementioned two steps are performed again after an autoload attempt
171 /// with the name of the scope as key is tried out.
172 /// If the interpreter lookup flag is false, the ListOfEnums objects are not treated
173 /// as such, but rather as THashList objects. This prevents any flow of information
174 /// from the interpreter into the ROOT's typesystem: a snapshot of the typesystem
175 /// status is taken.
176 
177 TEnum *TEnum::GetEnum(const char *enumName, ESearchAction sa)
178 {
179  // Potential optimisation: reduce number of branches using partial specialisation of
180  // helper functions.
181 
182  TEnum *theEnum = nullptr;
183 
184  // Wrap some gymnastic around the enum finding. The special treatment of the
185  // ListOfEnums objects is located in this routine.
186  auto findEnumInList = [](const TCollection * l, const char * enName, ESearchAction sa_local) {
187  TObject *obj;
188  if (sa_local & kInterpLookup) {
189  obj = l->FindObject(enName);
190  } else {
191  auto enumTable = dynamic_cast<const TListOfEnums *>(l);
192  obj = enumTable->GetObject(enName);
193  }
194  return static_cast<TEnum *>(obj);
195  };
196 
197  // Helper routine to look fo the scope::enum in the typesystem.
198  // If autoload and interpreter lookup is allowed, TClass::GetClass is called.
199  // If not, the list of classes and the list of protoclasses is inspected.
200  auto searchEnum = [&theEnum, findEnumInList](const char * scopeName, const char * enName, ESearchAction sa_local) {
201  // Check if the scope is a class
202  if (sa_local == (kALoadAndInterpLookup)) {
203  auto scope = TClass::GetClass(scopeName, true);
204  TEnum *en = nullptr;
205  if (scope) en = findEnumInList(scope->GetListOfEnums(kFALSE), enName, sa_local);
206  return en;
207  }
208 
209  // Lock need for gROOT->GetListOfClasses() and the later update/modification to
210  // the autoparsing state.
211  R__LOCKGUARD(gInterpreterMutex);
212  if (auto tClassScope = static_cast<TClass *>(gROOT->GetListOfClasses()->FindObject(scopeName))) {
213  // If this is a class, load only if the user allowed interpreter lookup
214  // If this is a namespace and the user did not allow for interpreter lookup, load but before disable
215  // autoparsing if enabled.
216  bool canLoadEnums (sa_local & kInterpLookup);
217  const bool scopeIsNamespace (tClassScope->Property() & kIsNamespace);
218 
219  const bool autoParseSuspended = gInterpreter->IsAutoParsingSuspended();
220  const bool suspendAutoParse = autoParseSuspended || scopeIsNamespace;
221 
222  TInterpreter::SuspendAutoParsing autoParseRaii(gInterpreter, suspendAutoParse);
223 
224  if (scopeIsNamespace && !autoParseSuspended){
225  canLoadEnums=true;
226  }
227 
228  auto listOfEnums = tClassScope->GetListOfEnums(canLoadEnums);
229 
230  // Previous incarnation of the code re-enabled the auto parsing,
231  // before executing findEnumInList
232  theEnum = findEnumInList(listOfEnums, enName, sa_local);
233  }
234  // Check if the scope is still a protoclass
235  else if (auto tProtoClassscope = static_cast<TProtoClass *>((gClassTable->GetProtoNorm(scopeName)))) {
236  auto listOfEnums = tProtoClassscope->GetListOfEnums();
237  if (listOfEnums) theEnum = findEnumInList(listOfEnums, enName, sa_local);
238  }
239  return theEnum;
240  };
241 
242  const char *lastPos = TClassEdit::GetUnqualifiedName(enumName);
243 
244  if (strchr(lastPos,'<')) {
245  // The unqualified name has template syntax, it can't possibly be an
246  // enum.
247  return nullptr;
248  }
249 
250  if (lastPos != enumName) {
251  // We have a scope
252  // All of this C gymnastic is to avoid allocations on the heap (see TClingLookupHelper__ExistingTypeCheck)
253  const auto enName = lastPos;
254  const auto scopeNameSize = ((Long64_t)lastPos - (Long64_t)enumName) / sizeof(decltype(*lastPos)) - 2;
255 #ifdef R__WIN32
256  char *scopeName = new char[scopeNameSize + 1];
257 #else
258  char scopeName[scopeNameSize + 1]; // on the stack, +1 for the terminating character '\0'
259 #endif
260  strncpy(scopeName, enumName, scopeNameSize);
261  scopeName[scopeNameSize] = '\0';
262  // Three levels of search
263  theEnum = searchEnum(scopeName, enName, kNone);
264  if (!theEnum && (sa & kAutoload)) {
265  const auto libsLoaded = gInterpreter->AutoLoad(scopeName);
266  // It could be an enum in a scope which is not selected
267  if (libsLoaded == 0){
268  gInterpreter->AutoLoad(enumName);
269  }
270  theEnum = searchEnum(scopeName, enName, kAutoload);
271  }
272  if (!theEnum && (sa & kALoadAndInterpLookup)) {
273  if (gDebug > 0) {
274  printf("TEnum::GetEnum: Header Parsing - The enumerator %s is not known to the typesystem: an interpreter lookup will be performed. This can imply parsing of headers. This can be avoided selecting the numerator in the linkdef/selection file.\n", enumName);
275  }
276  theEnum = searchEnum(scopeName, enName, kALoadAndInterpLookup);
277  }
278 #ifdef R__WIN32
279  delete [] scopeName;
280 #endif
281  } else {
282  // We don't have any scope: this is a global enum
283  theEnum = findEnumInList(gROOT->GetListOfEnums(), enumName, kNone);
284  if (!theEnum && (sa & kAutoload)) {
285  gInterpreter->AutoLoad(enumName);
286  theEnum = findEnumInList(gROOT->GetListOfEnums(), enumName, kAutoload);
287  }
288  if (!theEnum && (sa & kALoadAndInterpLookup)) {
289  if (gDebug > 0) {
290  printf("TEnum::GetEnum: Header Parsing - The enumerator %s is not known to the typesystem: an interpreter lookup will be performed. This can imply parsing of headers. This can be avoided selecting the numerator in the linkdef/selection file.\n", enumName);
291  }
292  theEnum = findEnumInList(gROOT->GetListOfEnums(), enumName, kALoadAndInterpLookup);
293  }
294  }
295 
296  return theEnum;
297 }