Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TListOfDataMembers.cxx
Go to the documentation of this file.
1 // @(#)root/cont
2 // Author: Philippe Canal Aug 2013
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 TListOfDataMembers
13 A collection of TDataMember objects designed for fast access given a
14 DeclId_t and for keep track of TDataMember that were described
15 unloaded data member.
16 */
17 
18 #include "TListOfDataMembers.h"
19 #include "TBuffer.h"
20 #include "TClass.h"
21 #include "TClassRef.h"
22 #include "TExMap.h"
23 #include "TDataMember.h"
24 #include "TGlobal.h"
25 #include "TInterpreter.h"
26 #include "TVirtualMutex.h"
27 #include "TError.h"
28 #include "TClassEdit.h"
29 
30 #include <sstream>
31 
32 const unsigned int idsSize=19;
33 
34 ClassImp(TListOfDataMembers);
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Constructor.
38 
39 TListOfDataMembers::TListOfDataMembers(TClass *cl /*=0*/) :
40  fClass(cl),fIds(0),fUnloaded(0),fIsLoaded(kFALSE), fLastLoadMarker(0)
41 {
42 }
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 /// Destructor.
46 
47 TListOfDataMembers::~TListOfDataMembers()
48 {
49  THashList::Delete();
50  delete fIds;
51  if (fUnloaded) fUnloaded->Delete();
52  delete fUnloaded;
53 }
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 /// Add a pair<id, object> to the map of data members and their ids.
57 
58 void TListOfDataMembers::MapObject(TObject* obj)
59 {
60  if (!fIds) fIds = new TExMap(idsSize);
61 
62  if (fClass) {
63  TDataMember *d = dynamic_cast<TDataMember*>(obj);
64  if (d) {
65  fIds->Add((Long64_t)d->GetDeclId(),(Long64_t)d);
66  }
67  } else {
68  TGlobal *g = dynamic_cast<TGlobal*>(obj);
69  if (g && g->GetDeclId()) {
70  fIds->Add((Long64_t)g->GetDeclId(),(Long64_t)g);
71  }
72  }
73 }
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 /// Add object at the beginning of the list.
77 
78 void TListOfDataMembers::AddFirst(TObject *obj)
79 {
80  THashList::AddFirst(obj);
81  MapObject(obj);
82 }
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 /// Add object at the beginning of the list and also store option.
86 /// Storing an option is useful when one wants to change the behaviour
87 /// of an object a little without having to create a complete new
88 /// copy of the object. This feature is used, for example, by the Draw()
89 /// method. It allows the same object to be drawn in different ways.
90 
91 void TListOfDataMembers::AddFirst(TObject *obj, Option_t *opt)
92 {
93  THashList::AddFirst(obj,opt);
94  MapObject(obj);
95 }
96 
97 ////////////////////////////////////////////////////////////////////////////////
98 /// Add object at the end of the list.
99 
100 void TListOfDataMembers::AddLast(TObject *obj)
101 {
102  THashList::AddLast(obj);
103  MapObject(obj);
104 }
105 
106 ////////////////////////////////////////////////////////////////////////////////
107 /// Add object at the end of the list and also store option.
108 /// Storing an option is useful when one wants to change the behaviour
109 /// of an object a little without having to create a complete new
110 /// copy of the object. This feature is used, for example, by the Draw()
111 /// method. It allows the same object to be drawn in different ways.
112 
113 void TListOfDataMembers::AddLast(TObject *obj, Option_t *opt)
114 {
115  THashList::AddLast(obj, opt);
116  MapObject(obj);
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// Insert object at location idx in the list.
121 
122 void TListOfDataMembers::AddAt(TObject *obj, Int_t idx)
123 {
124  THashList::AddAt(obj, idx);
125  MapObject(obj);
126 }
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Insert object after object after in the list.
130 
131 void TListOfDataMembers::AddAfter(const TObject *after, TObject *obj)
132 {
133  THashList::AddAfter(after, obj);
134  MapObject(obj);
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Insert object after object after in the list.
139 
140 void TListOfDataMembers::AddAfter(TObjLink *after, TObject *obj)
141 {
142  THashList::AddAfter(after, obj);
143  MapObject(obj);
144 }
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 /// Insert object before object before in the list.
148 
149 void TListOfDataMembers::AddBefore(const TObject *before, TObject *obj)
150 {
151  THashList::AddBefore(before, obj);
152  MapObject(obj);
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Insert object before object before in the list.
157 
158 void TListOfDataMembers::AddBefore(TObjLink *before, TObject *obj)
159 {
160  THashList::AddBefore(before, obj);
161  MapObject(obj);
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Remove all objects from the list. Does not delete the objects unless
166 /// the THashList is the owner (set via SetOwner()).
167 
168 void TListOfDataMembers::Clear(Option_t *option)
169 {
170  if (fUnloaded) fUnloaded->Clear(option);
171  if (fIds) fIds->Clear();
172  THashList::Clear(option);
173  fIsLoaded = kFALSE;
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Delete all TDataMember object files.
178 
179 void TListOfDataMembers::Delete(Option_t *option /* ="" */)
180 {
181  if (fUnloaded) fUnloaded->Delete(option);
182  THashList::Delete(option);
183  fIsLoaded = kFALSE;
184 }
185 
186 ////////////////////////////////////////////////////////////////////////////////
187 /// Specialize FindObject to do search for the
188 /// a data member just by name or create it if its not already in the list
189 
190 TObject *TListOfDataMembers::FindObject(const char *name) const
191 {
192  TObject *result = THashList::FindObject(name);
193  if (!result) {
194  if (IsLoaded() && fClass && fClass->Property() & (kIsClass|kIsStruct|kIsUnion)) {
195  // We already have all the information, no need to search more
196  return 0;
197  }
198 
199  R__LOCKGUARD(gInterpreterMutex);
200 
201  TInterpreter::DeclId_t decl;
202  if (fClass) decl = gInterpreter->GetDataMember(fClass->GetClassInfo(),name);
203  else decl = gInterpreter->GetDataMember(0,name);
204  if (decl) result = const_cast<TListOfDataMembers*>(this)->Get(decl);
205  }
206  return result;
207 }
208 
209 ////////////////////////////////////////////////////////////////////////////////
210 /// Return (after creating it if necessary) the TDataMember
211 /// describing the data member corresponding to the Decl 'id'.
212 
213 TDictionary *TListOfDataMembers::Find(DeclId_t id) const
214 {
215  if (!id) return 0;
216 
217  return fIds ? (TDataMember*)fIds->GetValue((Long64_t)id) : 0;
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 /// Return (after creating it if necessary) the TDataMember
222 /// describing the data member corresponding to the Decl 'id'.
223 
224 TDictionary *TListOfDataMembers::Get(DeclId_t id)
225 {
226  if (!id) return 0;
227 
228  TDictionary *dm = Find(id);
229  if (dm) return dm;
230 
231  if (fClass) {
232  if (!fClass->HasInterpreterInfoInMemory()) {
233  // The interpreter does not know about this class yet (or a problem
234  // occurred that prevented the proper updating of fClassInfo).
235  // So this decl can not possibly be part of this class.
236  // [In addition calling GetClassInfo would trigger a late parsing
237  // of the header which we want to avoid].
238  return 0;
239  }
240  if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
241  } else {
242  if (!gInterpreter->ClassInfo_Contains(0,id)) return 0;
243  }
244 
245  R__LOCKGUARD(gInterpreterMutex);
246 
247  DataMemberInfo_t *info = gInterpreter->DataMemberInfo_Factory(id,fClass ? fClass->GetClassInfo() : 0);
248 
249  // Let's see if this is a reload ...
250  const char *name = gInterpreter->DataMemberInfo_Name(info);
251 
252  TDictionary *update = fUnloaded ? (TDictionary *)fUnloaded->FindObject(name) : 0;
253  if (update) {
254  if (fClass) {
255  ((TDataMember*)update)->Update(info);
256  } else {
257  ((TGlobal*)update)->Update(info);
258  }
259  dm = update;
260  }
261  if (!dm) {
262  if (fClass) dm = new TDataMember(info, fClass);
263  else dm = new TGlobal(info);
264  }
265  // Calling 'just' THahList::Add would turn around and call
266  // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
267  THashList::AddLast(dm);
268  if (!fIds) fIds = new TExMap(idsSize);
269  fIds->Add((Long64_t)id,(Long64_t)dm);
270 
271  return dm;
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Return (after creating it if necessary) the TDataMember
276 /// describing the data member corresponding to the Decl 'id'.
277 /// The skipChecks flag controls the consistency checks performed inspecting
278 /// the AST. In some cases, we explicitly alter the datamembers in the
279 /// typesystem with respect to the AST and therefore we must not enforce
280 /// consistency.
281 
282 TDictionary *TListOfDataMembers::Get(DataMemberInfo_t *info, bool skipChecks)
283 {
284  if (!info) return 0;
285 
286  TDictionary::DeclId_t id = gInterpreter->GetDeclId(info);
287  R__ASSERT( id != 0 && "DeclId should not be null");
288  TDictionary *dm = fIds ? (TDataMember*)fIds->GetValue((Long64_t)id) : 0;
289  if (!dm) {
290  if (fClass) {
291  if (!fClass->HasInterpreterInfoInMemory()) {
292  // The interpreter does not know about this class yet (or a problem
293  // occurred that prevented the proper updating of fClassInfo).
294  // So this decl can not possibly be part of this class.
295  // [In addition calling GetClassInfo would trigger a late parsing
296  // of the header which we want to avoid].
297  return 0;
298  }
299  if (!skipChecks && !gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
300  } else {
301  if (!skipChecks && !gInterpreter->ClassInfo_Contains(0,id)) return 0;
302  }
303 
304  R__LOCKGUARD(gInterpreterMutex);
305 
306  DataMemberInfo_t *dm_info = gInterpreter->DataMemberInfo_FactoryCopy(info);
307 
308  // Let's see if this is a reload ...
309  const char *name = gInterpreter->DataMemberInfo_Name(info);
310  TDataMember *update = fUnloaded ? (TDataMember *)fUnloaded->FindObject(name) : 0;
311  if (update) {
312  update->Update(dm_info);
313  dm = update;
314  }
315  if (!dm) {
316  if (fClass) dm = new TDataMember(dm_info, fClass);
317  else dm = new TGlobal(dm_info);
318  }
319  // Calling 'just' THahList::Add would turn around and call
320  // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
321  THashList::AddLast(dm);
322  if (!fIds) fIds = new TExMap(idsSize);
323  fIds->Add((Long64_t)id,(Long64_t)dm);
324  }
325  return dm;
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 /// Remove a pair<id, object> from the map of data members and their ids.
330 
331 void TListOfDataMembers::UnmapObject(TObject* obj)
332 {
333  if (!fIds) return;
334  if (fClass) {
335  TDataMember *d = dynamic_cast<TDataMember*>(obj);
336  if (d) {
337  if (d->GetDeclId()) {
338  fIds->Remove((Long64_t)d->GetDeclId());
339  }
340  d->Update(0);
341  }
342  } else {
343  TGlobal *g = dynamic_cast<TGlobal*>(obj);
344  if (g) {
345  if (g->GetDeclId()) {
346  fIds->Remove((Long64_t)g->GetDeclId());
347  }
348  g->Update(0);
349  }
350  }
351 }
352 
353 ////////////////////////////////////////////////////////////////////////////////
354 /// Remove object from this collection and recursively remove the object
355 /// from all other objects (and collections).
356 /// This function overrides TCollection::RecursiveRemove that calls
357 /// the Remove function. THashList::Remove cannot be called because
358 /// it uses the hash value of the hash table. This hash value
359 /// is not available anymore when RecursiveRemove is called from
360 /// the TObject destructor.
361 
362 void TListOfDataMembers::RecursiveRemove(TObject *obj)
363 {
364  if (!obj) return;
365 
366  THashList::RecursiveRemove(obj);
367  if (fUnloaded) fUnloaded->RecursiveRemove(obj);
368  UnmapObject(obj);
369 
370 }
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 /// Remove object from the list.
374 
375 TObject* TListOfDataMembers::Remove(TObject *obj)
376 {
377  Bool_t found;
378 
379  found = THashList::Remove(obj);
380  if (!found && fUnloaded) {
381  found = fUnloaded->Remove(obj);
382  }
383  UnmapObject(obj);
384  if (found) return obj;
385  else return 0;
386 }
387 
388 ////////////////////////////////////////////////////////////////////////////////
389 /// Remove object via its objlink from the list.
390 
391 TObject* TListOfDataMembers::Remove(TObjLink *lnk)
392 {
393  if (!lnk) return 0;
394 
395  TObject *obj = lnk->GetObject();
396 
397  THashList::Remove(lnk);
398  if (fUnloaded) fUnloaded->Remove(obj);
399 
400  UnmapObject(obj);
401  return obj;
402 }
403 
404 ////////////////////////////////////////////////////////////////////////////////
405 /// Load all the DataMembers known to the interpreter for the scope 'fClass'
406 /// into this collection.
407 
408 void TListOfDataMembers::Load()
409 {
410  if (fClass && fClass->Property() & (kIsClass|kIsStruct|kIsUnion)) {
411  // Class and union are not extendable, if we already
412  // loaded all the data member there is no need to recheck
413  if (fIsLoaded) return;
414  }
415 
416  // This will provoke the parsing of the headers if need be.
417  if (fClass && fClass->GetClassInfo() == 0) return;
418 
419  R__LOCKGUARD(gInterpreterMutex);
420 
421  ULong64_t currentTransaction = gInterpreter->GetInterpreterStateMarker();
422  if (currentTransaction == fLastLoadMarker) {
423  return;
424  }
425  fLastLoadMarker = currentTransaction;
426 
427  // In the case of namespace, even if we have loaded before we need to
428  // load again in case there was new data member added.
429 
430  // Mark the list as loaded to avoid an infinite recursion in the case
431  // where we have a data member that is a variable size array. In that
432  // case TDataMember::Init needs to get/load the list to find the data
433  // member used as the array size.
434  fIsLoaded = kTRUE;
435 
436  ClassInfo_t *info;
437  if (fClass) info = fClass->GetClassInfo();
438  else info = gInterpreter->ClassInfo_Factory();
439 
440  // Treat the complex<float>, complex<double> in a special way, i.e. replacing
441  // the datamembers with the ones of _root_std_complex<T>
442  bool skipChecks = false;
443  if (fClass) {
444  auto complexType = TClassEdit::GetComplexType(fClass->GetName());
445  switch(complexType) {
446  case TClassEdit::EComplexType::kNone:
447  {
448  break;
449  }
450  case TClassEdit::EComplexType::kFloat:
451  {
452  skipChecks = true;
453  info = TClass::GetClass("_root_std_complex<float>")->GetClassInfo();
454  break;
455  }
456  case TClassEdit::EComplexType::kDouble:
457  {
458  skipChecks = true;
459  info = TClass::GetClass("_root_std_complex<double>")->GetClassInfo();
460  break;
461  }
462  case TClassEdit::EComplexType::kInt:
463  {
464  skipChecks = true;
465  info = TClass::GetClass("_root_std_complex<int>")->GetClassInfo();
466  break;
467  }
468  case TClassEdit::EComplexType::kLong:
469  {
470  skipChecks = true;
471  info = TClass::GetClass("_root_std_complex<long>")->GetClassInfo();
472  break;
473  }
474  }
475  }
476 
477  // Now we follow the ordinary pattern
478  DataMemberInfo_t *t = gInterpreter->DataMemberInfo_Factory(info);
479  while (gInterpreter->DataMemberInfo_Next(t)) {
480  if (gInterpreter->DataMemberInfo_IsValid(t)) {
481  // Get will check if there is already there or create a new one
482  // (or re-use a previously unloaded version).
483  Get(t,skipChecks);
484  }
485  }
486  gInterpreter->DataMemberInfo_Delete(t);
487  if (!fClass) gInterpreter->ClassInfo_Delete(info);
488 }
489 
490 ////////////////////////////////////////////////////////////////////////////////
491 /// Stream an object of class TListOfDataMembers.
492 
493 void TListOfDataMembers::Streamer(TBuffer &R__b)
494 {
495  if (R__b.IsReading()) {
496  R__b.ReadClassBuffer(TListOfDataMembers::Class(),this);
497  fIsLoaded = kTRUE;
498  } else {
499  R__b.WriteClassBuffer(TListOfDataMembers::Class(),this);
500  }
501 }
502 
503 ////////////////////////////////////////////////////////////////////////////////
504 /// Move the member or data member to the expect set of list.
505 
506 void TListOfDataMembers::Update(TDictionary *member) {
507  if (fClass) {
508  TDataMember *d = dynamic_cast<TDataMember*>(member);
509  if (d) {
510  if (d->GetDeclId()) {
511  if (!fIds) fIds = new TExMap(idsSize);
512  fIds->Add((Long64_t)d->GetDeclId(),(Long64_t)d);
513  }
514  TDictionary *update = fUnloaded ? (TDictionary *)fUnloaded->FindObject(d->GetName()) : 0;
515  if (update) fUnloaded->Remove(update);
516 
517  if (! THashList::FindObject(d) ) {
518  // Calling 'just' THahList::Add would turn around and call
519  // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
520  THashList::AddLast(d);
521  }
522  }
523  } else {
524  TGlobal *g = dynamic_cast<TGlobal*>(member);
525  if (g) {
526  if (g->GetDeclId()) {
527  if (!fIds) fIds = new TExMap(idsSize);
528  fIds->Add((Long64_t)g->GetDeclId(),(Long64_t)g);
529 
530  TDictionary *update = fUnloaded ? (TDictionary *)fUnloaded->FindObject(g->GetName()) : 0;
531  if (update) fUnloaded->Remove(update);
532 
533  if (! THashList::FindObject(g) ) {
534  // Calling 'just' THahList::Add would turn around and call
535  // TListOfDataMembers::AddLast which should *also* do the fIds->Add.
536  THashList::AddLast(g);
537  }
538  }
539  }
540  }
541 
542 
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Mark 'all func' as being unloaded.
547 /// After the unload, the data member can no longer be found directly,
548 /// until the decl can be found again in the interpreter (in which
549 /// the func object will be reused.
550 
551 void TListOfDataMembers::Unload()
552 {
553  TObjLink *lnk = FirstLink();
554  while (lnk) {
555  TDictionary *data = (TDictionary *)lnk->GetObject();
556  UnmapObject(data);
557  if (!fUnloaded) fUnloaded = new THashList;
558  fUnloaded->Add(data);
559 
560  lnk = lnk->Next();
561  }
562 
563  THashList::Clear();
564  fIsLoaded = kFALSE;
565 }
566 
567 ////////////////////////////////////////////////////////////////////////////////
568 /// Mark 'func' as being unloaded.
569 /// After the unload, the data member can no longer be found directly,
570 /// until the decl can be found again in the interpreter (in which
571 /// the func object will be reused.
572 
573 void TListOfDataMembers::Unload(TDictionary *mem)
574 {
575  if (THashList::Remove(mem)) {
576  // We contains the object, let remove it from the other internal
577  // list and move it to the list of unloaded objects.
578 
579  UnmapObject(mem);
580  if (!fUnloaded) fUnloaded = new THashList;
581  fUnloaded->Add(mem);
582  }
583 }