Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TListOfEnums.cxx
Go to the documentation of this file.
1 // @(#)root/cont
2 // Author: Bianca-Cristina Cristescu February 2014
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 TListOfEnums
13 A collection of TEnum objects designed for fast access given a
14 DeclId_t and for keep track of TEnum that were described
15 unloaded enum.
16 */
17 
18 #include <forward_list>
19 
20 #include "TListOfEnums.h"
21 #include "TClass.h"
22 #include "TExMap.h"
23 #include "TEnum.h"
24 #include "TGlobal.h"
25 #include "TInterpreter.h"
26 #include "TVirtualMutex.h"
27 
28 const unsigned int listSize=3;
29 
30 ClassImp(TListOfEnums);
31 
32 ////////////////////////////////////////////////////////////////////////////////
33 /// Constructor.
34 
35 TListOfEnums::TListOfEnums(TClass *cl /*=0*/) :
36  THashList(listSize), fClass(cl), fIds(0), fUnloaded(0), fIsLoaded(kFALSE), fLastLoadMarker(0)
37 {
38  fIds = new TExMap(listSize);
39  fUnloaded = new THashList(listSize);
40 }
41 
42 ////////////////////////////////////////////////////////////////////////////////
43 /// Destructor.
44 
45 TListOfEnums::~TListOfEnums()
46 {
47  THashList::Delete();
48  delete fIds;
49  fUnloaded->Delete();
50  delete fUnloaded;
51 }
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 /// Add pair<id, object> to the map of functions and their ids.
55 
56 void TListOfEnums::MapObject(TObject *obj)
57 {
58  TEnum *e = dynamic_cast<TEnum *>(obj);
59  if (e && e->GetDeclId()) {
60  fIds->Add((Long64_t)e->GetDeclId(), (Long64_t)e);
61  }
62 }
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// Add object at the beginning of the list.
66 
67 void TListOfEnums::AddFirst(TObject *obj)
68 {
69  THashList::AddFirst(obj);
70  MapObject(obj);
71 }
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 /// Add object at the beginning of the list and also store option.
75 /// Storing an option is useful when one wants to change the behaviour
76 /// of an object a little without having to create a complete new
77 /// copy of the object. This feature is used, for example, by the Draw()
78 /// method. It allows the same object to be drawn in different ways.
79 
80 void TListOfEnums::AddFirst(TObject *obj, Option_t *opt)
81 {
82  THashList::AddFirst(obj, opt);
83  MapObject(obj);
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Add object at the end of the list.
88 
89 void TListOfEnums::AddLast(TObject *obj)
90 {
91  THashList::AddLast(obj);
92  MapObject(obj);
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 /// Add object at the end of the list and also store option.
97 /// Storing an option is useful when one wants to change the behaviour
98 /// of an object a little without having to create a complete new
99 /// copy of the object. This feature is used, for example, by the Draw()
100 /// method. It allows the same object to be drawn in different ways.
101 
102 void TListOfEnums::AddLast(TObject *obj, Option_t *opt)
103 {
104  THashList::AddLast(obj, opt);
105  MapObject(obj);
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// Insert object at location idx in the list.
110 
111 void TListOfEnums::AddAt(TObject *obj, Int_t idx)
112 {
113  THashList::AddAt(obj, idx);
114  MapObject(obj);
115 }
116 
117 ////////////////////////////////////////////////////////////////////////////////
118 /// Insert object after object after in the list.
119 
120 void TListOfEnums::AddAfter(const TObject *after, TObject *obj)
121 {
122  THashList::AddAfter(after, obj);
123  MapObject(obj);
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Insert object after object after in the list.
128 
129 void TListOfEnums::AddAfter(TObjLink *after, TObject *obj)
130 {
131  THashList::AddAfter(after, obj);
132  MapObject(obj);
133 }
134 
135 ////////////////////////////////////////////////////////////////////////////////
136 /// Insert object before object before in the list.
137 
138 void TListOfEnums::AddBefore(const TObject *before, TObject *obj)
139 {
140  THashList::AddBefore(before, obj);
141  MapObject(obj);
142 }
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// Insert object before object before in the list.
146 
147 void TListOfEnums::AddBefore(TObjLink *before, TObject *obj)
148 {
149  THashList::AddBefore(before, obj);
150  MapObject(obj);
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 /// Remove all objects from the list. Does not delete the objects unless
155 /// the THashList is the owner (set via SetOwner()).
156 
157 void TListOfEnums::Clear(Option_t *option)
158 {
159  fUnloaded->Clear(option);
160  fIds->Clear();
161  THashList::Clear(option);
162  fIsLoaded = kFALSE;
163 }
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 /// Delete all TDataMember object files.
167 
168 void TListOfEnums::Delete(Option_t *option /* ="" */)
169 {
170  fUnloaded->Delete(option);
171  THashList::Delete(option);
172  fIsLoaded = kFALSE;
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
176 /// Return the TEnum corresponding to the Decl 'id' or NULL if it does not
177 /// exist.
178 
179 TEnum *TListOfEnums::Find(DeclId_t id) const
180 {
181  if (!id) return 0;
182 
183  return (TEnum *)fIds->GetValue((Long64_t)id);
184 }
185 
186 ////////////////////////////////////////////////////////////////////////////////
187 /// Return (after creating it if necessary) the TEnum
188 /// describing the enum corresponding to the Decl 'id'.
189 
190 TEnum *TListOfEnums::Get(DeclId_t id, const char *name)
191 {
192  if (!id) return 0;
193 
194  TEnum *e = Find(id);
195  if (e) return e;
196 
197  // If this declID is not found as key, we look for the enum by name.
198  // Indeed it could have been generated by protoclasses.
199 #if defined(R__MUST_REVISIT)
200 # if R__MUST_REVISIT(6,4)
201  "This special case can be removed once PCMs are available."
202 # endif
203 #endif
204  e = static_cast<TEnum*>(THashList::FindObject(name));
205  if (e) {
206  // In this case, we update the declId, update its constants and add the enum to the ids map and return.
207  // At this point it is like it came from the interpreter.
208  if (0 == e->GetDeclId()){
209  e->Update(id);
210  fIds->Add((Long64_t)id, (Long64_t)e);
211  gInterpreter->UpdateEnumConstants(e, fClass);
212  }
213  return e;
214  }
215 
216  if (fClass) {
217  if (!fClass->HasInterpreterInfoInMemory()) {
218  // The interpreter does not know about this class yet (or a problem
219  // occurred that prevented the proper updating of fClassInfo).
220  // So this decl can not possibly be part of this class.
221  // [In addition calling GetClassInfo would trigger a late parsing
222  // of the header which we want to avoid].
223  return 0;
224  }
225  if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(), id)) return 0;
226  } else {
227  if (!gInterpreter->ClassInfo_Contains(0, id)) return 0;
228  }
229 
230  R__LOCKGUARD(gInterpreterMutex);
231 
232  // Let's see if this is a reload ...
233  // can we check for reloads for enums?
234  e = (TEnum *)fUnloaded->FindObject(name);
235  if (e) {
236  e->Update(id);
237  gInterpreter->UpdateEnumConstants(e, fClass);
238  } else {
239  e = gInterpreter->CreateEnum((void *)id, fClass);
240  }
241  // Calling 'just' THahList::Add would turn around and call
242  // TListOfEnums::AddLast which should *also* do the fIds->Add.
243  THashList::AddLast(e);
244  fIds->Add((Long64_t)id, (Long64_t)e);
245 
246  return e;
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 /// Return an object from the list of enums *if and only if* is has already
251 /// been loaded in the list. This is an internal routine.
252 
253 TEnum *TListOfEnums::GetObject(const char *name) const
254 {
255  return (TEnum*)THashList::FindObject(name);
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 /// Remove a pair<id, object> from the map of functions and their ids.
260 
261 void TListOfEnums::UnmapObject(TObject *obj)
262 {
263  TEnum *e = dynamic_cast<TEnum *>(obj);
264  if (e) {
265  fIds->Remove((Long64_t)e->GetDeclId());
266  }
267 }
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Remove object from this collection and recursively remove the object
271 /// from all other objects (and collections).
272 /// This function overrides TCollection::RecursiveRemove that calls
273 /// the Remove function. THashList::Remove cannot be called because
274 /// it uses the hash value of the hash table. This hash value
275 /// is not available anymore when RecursiveRemove is called from
276 /// the TObject destructor.
277 
278 void TListOfEnums::RecursiveRemove(TObject *obj)
279 {
280  if (!obj) return;
281 
282  THashList::RecursiveRemove(obj);
283  fUnloaded->RecursiveRemove(obj);
284  UnmapObject(obj);
285 }
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 /// Remove object from the list.
289 
290 TObject *TListOfEnums::Remove(TObject *obj)
291 {
292  Bool_t found;
293 
294  found = THashList::Remove(obj);
295  if (!found) {
296  found = fUnloaded->Remove(obj);
297  }
298  UnmapObject(obj);
299  if (found) return obj;
300  else return 0;
301 }
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 /// Remove object via its objlink from the list.
305 
306 TObject *TListOfEnums::Remove(TObjLink *lnk)
307 {
308  if (!lnk) return 0;
309 
310  TObject *obj = lnk->GetObject();
311 
312  THashList::Remove(lnk);
313  fUnloaded->Remove(obj);
314  UnmapObject(obj);
315  return obj;
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 /// Load all the DataMembers known to the interpreter for the scope 'fClass'
320 /// into this collection.
321 
322 void TListOfEnums::Load()
323 {
324  if (fClass && fClass->Property() & (kIsClass | kIsStruct | kIsUnion)) {
325  // Class and union are not extendable, if we already
326  // loaded all the data member there is no need to recheck
327  if (fIsLoaded) return;
328  }
329 
330  // This will provoke the parsing of the headers if need be.
331  if (fClass && fClass->GetClassInfo() == 0) return;
332 
333  R__LOCKGUARD(gInterpreterMutex);
334 
335  ULong64_t currentTransaction = gInterpreter->GetInterpreterStateMarker();
336  if (currentTransaction == fLastLoadMarker) {
337  return;
338  }
339  fLastLoadMarker = currentTransaction;
340 
341  // In the case of namespace, even if we have loaded before we need to
342  // load again in case there was new data member added.
343 
344  // Mark the list as loaded to avoid an infinite recursion in the case
345  // where we have a data member that is a variable size array. In that
346  // case TDataMember::Init needs to get/load the list to find the data
347  // member used as the array size.
348  fIsLoaded = kTRUE;
349 
350  // Respawn the unloaded enums if they come from protoclasses, i.e. they
351  // have a 0 declId.
352 #if defined(R__MUST_REVISIT)
353 # if R__MUST_REVISIT(6,4)
354  "This special case can be removed once PCMs are available."
355 # endif
356 #endif
357 
358  std::forward_list<TEnum*> respownedEnums;
359  for (auto enumAsObj : *fUnloaded){
360  TEnum* en = static_cast<TEnum*>(enumAsObj);
361  if (0 == en->GetDeclId()){
362  THashList::AddLast(en);
363  respownedEnums.push_front(en);
364  }
365  }
366 
367  for (auto en : respownedEnums)
368  fUnloaded->Remove(en);
369 
370  // We cannot clear the whole unloaded list. It is too much.
371 // fUnloaded->Clear();
372 
373  gInterpreter->LoadEnums(*this);
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Mark 'all func' as being unloaded.
378 /// After the unload, the data member can no longer be found directly,
379 /// until the decl can be found again in the interpreter (in which
380 /// the func object will be reused.
381 
382 void TListOfEnums::Unload()
383 {
384  TObjLink *lnk = FirstLink();
385  while (lnk) {
386  TEnum *data = (TEnum *)lnk->GetObject();
387 
388  if (data->GetDeclId())
389  fIds->Remove((Long64_t)data->GetDeclId());
390  fUnloaded->Add(data);
391 
392  lnk = lnk->Next();
393  }
394 
395  THashList::Clear();
396  fIsLoaded = kFALSE;
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Mark enum 'e' as being unloaded.
401 /// After the unload, the data member can no longer be found directly,
402 /// until the decl can be found again in the interpreter (in which
403 /// the func object will be reused.
404 
405 void TListOfEnums::Unload(TEnum *e)
406 {
407  if (THashList::Remove(e)) {
408  // We contains the object, let remove it from the other internal
409  // list and move it to the list of unloaded objects.
410  if (e->GetDeclId())
411  fIds->Remove((Long64_t)e->GetDeclId());
412  fUnloaded->Add(e);
413  }
414 }