Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TDataMember.cxx
Go to the documentation of this file.
1 // @(#)root/meta:$Id$
2 // Author: Fons Rademakers 04/02/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 TDataMember
13 
14 All ROOT classes may have RTTI (run time type identification) support
15 added. The data is stored in so called DICTIONARY (look at TDictionary).
16 Information about a class is stored in TClass.
17 This information may be obtained via the cling api - see class TCling.
18 TClass has a list of TDataMember objects providing information about all
19 data members of described class.
20 
21 \image html base_classinfo.png
22 
23 TDataMember provides information about name of data member, its type,
24 and comment field string. It also tries to find the TMethodCall objects
25 responsible for getting/setting a value of it, and gives you pointers
26 to these methods. This gives you a unique possibility to access
27 protected and private (!) data members if only methods for doing that
28 are defined.
29 
30 These methods could either be specified in a comment field, or found
31 out automatically by ROOT: here's an example:
32 suppose you have a class definition:
33 ~~~ {.cpp}
34  class MyClass{
35  private:
36  Float_t fX1;
37  ...
38  public:
39  void SetX1(Float_t x) {fX1 = x;};
40  Float_t GetX1() {return fX1;};
41  ...
42  }
43 ~~~
44 Look at the data member name and method names: a data member name has
45 a prefix letter (f) and has a base name X1 . The methods for getting and
46 setting this value have names which consist of string Get/Set and the
47 same base name. This convention of naming data fields and methods which
48 access them allows TDataMember find this methods by itself completely
49 automatically. To make this description complete, one should know,
50 that names that are automatically recognized may be also:
51 for data fields: either fXXX or fIsXXX; and for getter function
52 GetXXX() or IsXXX() [where XXX is base name].
53 
54 As an example of using it let's analyse a few lines which get and set
55 a fEditable field in TCanvas:
56 ~~~ {.cpp}
57  TCanvas *c = new TCanvas("c"); // create a canvas
58  TClass *cl = c->IsA(); // get its class description object.
59 
60  TDataMember *dm = cl->GetDataMember("fEditable"); //This is our data member
61 
62  TMethodCall *getter = dm->GetterMethod(c); //find a method that gets value!
63  Long_t l; // declare a storage for this value;
64 
65  getter->Execute(c,"",l); // Get this Value !!!! It will appear in l !!!
66 
67 
68  TMethodCall *setter = dm->SetterMethod(c);
69  setter->Execute(c,"0",); // Set Value 0 !!!
70 ~~~
71 
72 This trick is widely used in ROOT TContextMenu and dialogs for obtaining
73 current values and put them as initial values in dialog fields.
74 
75 If you don't want to follow the convention of naming used by ROOT
76 you still could benefit from Getter/Setter method support: the solution
77 is to instruct ROOT what the names of these routines are.
78 The way to do it is putting this information in a comment string to a data
79 field in your class declaration:
80 
81 ~~~ {.cpp}
82  class MyClass{
83  Int_t mydata; // *OPTIONS={GetMethod="Get";SetMethod="Set"}
84  ...
85  Int_t Get() const { return mydata;};
86  void Set(Int_t i) {mydata=i;};
87  }
88 ~~~
89 
90 However, this getting/setting functions are not the only feature of
91 this class. The next point is providing lists of possible settings
92 for the concerned data member. The idea is to have a list of possible
93 options for this data member, with strings identifying them. This
94 is used in dialogs with parameters to set - for details see
95 TMethodArg, TRootContextMenu, TContextMenu. This list not only specifies
96 the allowed value, but also provides strings naming the options.
97 Options are managed via TList of TOptionListItem objects. This list
98 is also created automatically: if a data type is an enum type,
99 the list will have items describing every enum value, and named
100 according to enum name. If type is Bool_t, two options "On" and "Off"
101 with values 0 and 1 are created. For other types you need to instruct
102 ROOT about possible options. The way to do it is the same as in case of
103 specifying getter/setter method: a comment string to a data field in
104 Your header file with class definition.
105 The most general format of this string is:
106 ~~~ {.cpp}
107 *OPTIONS={GetMethod="getter";SetMethod="setter";Items=(it1="title1",it2="title2", ... ) }
108 ~~~
109 
110 While parsing this string ROOT firstly looks for command-tokens:
111 GetMethod, SetMethod, Items; They must be preceded by string
112 *OPTIONS= , enclosed by {} and separated by semicolons ";".
113 All command token should have a form TOKEN=VALUE.
114 All tokens are optional.
115 The names of getter and setter method must be enclosed by double-quote
116 marks (") .
117 Specifications of Items is slightly more complicated: you need to
118 put token ITEMS= and then enclose all options in curly brackets "()".
119 You separate options by comas ",".
120 Each option item may have one of the following forms:
121 ~~~ {.cpp}
122  IntegerValue = "Text Label"
123 
124  EnumValue = "Text Label"
125 
126  "TextValue" = Text Label"
127 
128 ~~~
129 
130 One can specify values as Integers or Enums - when data field is an
131 Integer, Float or Enum type; as texts - for char (more precisely:
132 Option_t).
133 
134 As mentioned above - this information are mainly used by contextmenu,
135 but also in Dump() and Inspect() methods and by the THtml class.
136 */
137 
138 #include "TDataMember.h"
139 
140 #include "Strlen.h"
141 #include "TClass.h"
142 #include "TClassEdit.h"
143 #include "TDataType.h"
144 #include "TEnum.h"
145 #include "TEnumConstant.h"
146 #include "TGlobal.h"
147 #include "TInterpreter.h"
148 #include "TIterator.h"
149 #include "TList.h"
150 #include "TListOfDataMembers.h"
151 #include "TMethod.h"
152 #include "TMethodCall.h"
153 #include "TRealData.h"
154 #include "TROOT.h"
155 #include "TVirtualMutex.h"
156 
157 #include <cassert>
158 #include <cctype>
159 #include <stdlib.h>
160 
161 
162 ClassImp(TDataMember);
163 
164 ////////////////////////////////////////////////////////////////////////////////
165 /// Default TDataMember ctor. TDataMembers are constructed in TClass
166 /// via a call to TCling::CreateListOfDataMembers(). It parses the comment
167 /// string, initializes optionlist and getter/setter methods.
168 
169 TDataMember::TDataMember(DataMemberInfo_t *info, TClass *cl) : TDictionary()
170 {
171  fInfo = info;
172  fClass = cl;
173  fDataType = 0;
174  fOptions = 0;
175  fValueSetter = 0;
176  fValueGetter = 0;
177  fOffset = -1;
178  fProperty = -1;
179  fSTLCont = -1;
180  fArrayDim = -1;
181  fArrayMaxIndex=0;
182  if (!fInfo && !fClass) return; // default ctor is called
183 
184  Init(false);
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Routines called by the constructor and Update to reset the member's
189 /// information.
190 /// afterReading is set when initializing after reading through Streamer().
191 
192 void TDataMember::Init(bool afterReading)
193 {
194  const char *t = 0;
195  if (!afterReading) {
196  // Initialize from fInfo
197  if (!fInfo || !gInterpreter->DataMemberInfo_IsValid(fInfo)) return;
198 
199  fFullTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeName(fInfo));
200  fTrueTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeTrueName(fInfo));
201  fTypeName = TClassEdit::GetLong64_Name(gCling->TypeName(fTrueTypeName));
202  SetName(gCling->DataMemberInfo_Name(fInfo));
203  t = gCling->DataMemberInfo_Title(fInfo);
204  SetTitle(t);
205  } else {
206  // We have read the persistent data members.
207  t = GetTitle();
208  }
209  if (t && t[0] != '!') SetBit(kObjIsPersistent);
210  fDataType = 0;
211  if (IsBasic() || IsEnum()) {
212  if (IsBasic()) {
213  const char *name = GetFullTypeName();
214  if (strcmp(name, "unsigned char") != 0 &&
215  strncmp(name, "unsigned short", sizeof ("unsigned short")) != 0 &&
216  strcmp(name, "unsigned int") != 0 &&
217  strncmp(name, "unsigned long", sizeof ("unsigned long")) != 0)
218  // strncmp() also covers "unsigned long long"
219  name = GetTypeName();
220  fDataType = gROOT->GetType(name);
221 
222  if (fDataType==0) {
223  // humm we did not find it ... maybe it's a typedef that has not been loaded yet.
224  // (this can happen if the executable does not have a TApplication object).
225  fDataType = gROOT->GetType(name,kTRUE);
226  }
227  } else {
228  fDataType = gROOT->GetType("Int_t", kTRUE); // In rare instance we are called before Int_t has been added to the list of types in TROOT, the kTRUE insures it is there.
229  }
230  // if (!fDataType)
231  // Error("TDataMember", "basic data type %s not found in list of basic types",
232  // GetTypeName());
233  }
234 
235 
236  if (afterReading) {
237  // Options are streamed; can't build TMethodCall for getters and setters
238  // because we deserialize a TDataMember when we do not have interpreter
239  // data. Thus do an early return.
240  return;
241  }
242 
243 
244  // If option string exist in comment - we'll parse it and create
245  // list of options
246 
247  // Option-list string has a form:
248  // *OPTION={GetMethod="GetXXX";SetMethod="SetXXX";
249  // Items=(0="NULL ITEM","one"="First Item",kRed="Red Item")}
250  //
251  // As one can see it is possible to specify value as either numerical
252  // value , string or enum.
253  // One can also specify implicitly names of Getter/Setter methods.
254 
255  char cmt[2048];
256  char opt[2048];
257  char *opt_ptr = 0;
258  const char *ptr1 = 0;
259  char *ptr2 = 0;
260  char *ptr3 = 0;
261  char *tok = 0;
262  Int_t cnt = 0;
263  Int_t token_cnt;
264  Int_t i;
265 
266  strlcpy(cmt,GetTitle(),2048);
267 
268  if ((opt_ptr=strstr(cmt,"*OPTION={"))) {
269 
270  // If we found it - parsing...
271 
272  //let's cut the part lying between {}
273  char *rest;
274  ptr1 = R__STRTOK_R(opt_ptr, "{}", &rest); // starts tokenizing:extracts "*OPTION={"
275  if (ptr1 == 0) {
276  Fatal("TDataMember","Internal error, found \"*OPTION={\" but not \"{}\" in %s.",GetTitle());
277  return;
278  }
279  ptr1 = R__STRTOK_R(nullptr, "{}", &rest); // And now we have what we need in ptr1!!!
280  if (ptr1 == 0) {
281  Fatal("TDataMember","Internal error, found \"*OPTION={\" but not \"{}\" in %s.",GetTitle());
282  return;
283  }
284 
285  //and save it:
286  strlcpy(opt,ptr1,2048);
287 
288  // Let's extract sub-tokens extracted by ';' sign.
289  // We'll put'em in an array for convenience;
290  // You have to do it in this manner because you cannot use nested tokenizing
291 
292  char *tokens[256]; // a storage for these sub-tokens.
293  token_cnt = 0;
294  cnt = 0;
295 
296  do { //tokenizing loop
297  ptr1 = R__STRTOK_R((char *)(cnt++ ? nullptr : opt), ";", &rest);
298  if (ptr1){
299  Int_t nch = strlen(ptr1)+1;
300  tok=new char[nch];
301  strlcpy(tok,ptr1,nch);
302  tokens[token_cnt]=tok;
303  token_cnt++;
304  }
305  } while (ptr1);
306 
307  // OK! Now let's check whether we have Get/Set methods encode in any string
308  for (i=0;i<token_cnt;i++) {
309  if (strstr(tokens[i],"GetMethod")) {
310  ptr1 = R__STRTOK_R(tokens[i], "\"", &rest); // tokenizing-strip text "GetMethod"
311  if (ptr1 == 0) {
312  Fatal("TDataMember","Internal error, found \"GetMethod\" but not \"\\\"\" in %s.",GetTitle());
313  return;
314  }
315  ptr1 = R__STRTOK_R(nullptr, "\"", &rest); // tokenizing - name is in ptr1!
316  if (ptr1 == 0) {
317  Fatal("TDataMember","Internal error, found \"GetMethod\" but not \"\\\"\" in %s.",GetTitle());
318  return;
319  }
320 
321  if (!afterReading && GetClass()->GetMethod(ptr1,"")) // check whether such method exists
322  // FIXME: wrong in case called derives via multiple inheritance from this class
323  fValueGetter = new TMethodCall(GetClass(),ptr1,"");
324 
325  continue; //next item!
326  }
327 
328  if (strstr(tokens[i],"SetMethod")) {
329  ptr1 = R__STRTOK_R(tokens[i], "\"", &rest);
330  if (ptr1 == 0) {
331  Fatal("TDataMember","Internal error, found \"SetMethod\" but not \"\\\"\" in %s.",GetTitle());
332  return;
333  }
334  ptr1 = R__STRTOK_R(nullptr, "\"", &rest); // name of Setter in ptr1
335  if (ptr1 == 0) {
336  Fatal("TDataMember","Internal error, found \"SetMethod\" but not \"\\\"\" in %s.",GetTitle());
337  return;
338  }
339  if (GetClass()->GetMethod(ptr1,"1"))
340  // FIXME: wrong in case called derives via multiple inheritance from this class
341  fValueSetter = new TMethodCall(GetClass(),ptr1,"1");
342  }
343  }
344 
345  //Now let's parse option strings...
346 
347  Int_t opt_cnt = 0;
348  std::unique_ptr<TList> optionlist{new TList()}; //storage for options strings
349 
350  for (i=0;i<token_cnt;i++) {
351  if (strstr(tokens[i],"Items")) {
352  ptr1 = R__STRTOK_R(tokens[i], "()", &rest);
353  if (ptr1 == 0) {
354  Fatal("TDataMember","Internal error, found \"Items\" but not \"()\" in %s.",GetTitle());
355  return;
356  }
357  ptr1 = R__STRTOK_R(nullptr, "()", &rest);
358  if (ptr1 == 0) {
359  Fatal("TDataMember","Internal error, found \"Items\" but not \"()\" in %s.",GetTitle());
360  return;
361  }
362 
363  char opts[2048]; //and save it!
364  strlcpy(opts,ptr1,2048);
365 
366  //now parse it...
367  //firstly we just store strings like: xxx="Label Name"
368  //We'll store it in TOptionListItem objects, because they're derived
369  //from TObject and thus can be stored in TList.
370  //It's not elegant but works.
371  do {
372  ptr1 = R__STRTOK_R(opt_cnt++ ? nullptr : opts, ",", &rest); // options extraction
373  if (ptr1) {
374  TOptionListItem *it = new TOptionListItem(this,1,0,0,ptr1,"");
375  optionlist->Add(it);
376  }
377  } while(ptr1);
378 
379  }
380  }
381 
382  //having all options extracted and put into list, we finally can parse
383  //them to create a list of options...
384 
385  fOptions = new TList(); //create the list
386 
387  TIter next(optionlist.get()); //we'll iterate through all
388  //strings containing options
389  TOptionListItem *it = 0;
390  TOptionListItem *it1 = 0;
391  while ((it=(TOptionListItem*)next())) {
392 
393  ptr1 = it->fOptName; // We will change the value of OptName ... but it is fine since we delete the object at the end of the loop.
394  Bool_t islabel = (ptr1[0]=='\"'); // value is label or numerical?
395  ptr2 = R__STRTOK_R((char *)ptr1, "=\"", &rest); // extract LeftHandeSide
396  ptr3 = R__STRTOK_R(nullptr, "=\"", &rest); // extract RightHandedSize
397 
398  if (islabel) {
399  it1=new TOptionListItem(this,-9999,0,0,ptr3,ptr2);
400  fOptions->Add(it1);
401  } else {
402 
403  char *strtolResult;
404  Long_t l = std::strtol(ptr1, &strtolResult, 10);
405  bool isnumber = (strtolResult != ptr1);
406 
407  if (!isnumber) {
408  TGlobal *enumval = gROOT->GetGlobal(ptr1, kTRUE);
409  if (enumval) {
410  Int_t *value = (Int_t *)(enumval->GetAddress());
411  // We'll try to find global enum existing in ROOT...
412  l = (Long_t)(*value);
413  } else if (IsEnum()) {
414  TObject *obj = fClass->GetListOfDataMembers(false)->FindObject(ptr1);
415  if (obj)
416  l = ((TEnumConstant *)obj)->GetValue();
417  else
418  l = gInterpreter->Calc(Form("%s;", ptr1));
419  } else {
420  Fatal("TDataMember", "Internal error, couldn't recognize enum/global value %s.", ptr1);
421  }
422  }
423 
424  it1 = new TOptionListItem(this,l,0,0,ptr3,ptr1);
425  fOptions->Add(it1);
426  }
427 
428  optionlist->Remove(it); //delete this option string from list
429  delete it; // and dispose of it.
430 
431  }
432 
433  // Garbage collection
434 
435  //And dispose tokens string...
436  for (i=0;i<token_cnt;i++) if(tokens[i]) delete [] tokens[i];
437 
438  // if option string does not exist but it's an Enum - parse it!!!!
439  } else if (IsEnum()) {
440  fOptions = new TList();
441  if (TEnum* enumDict = TEnum::GetEnum(GetTypeName()) ){
442  TIter iEnumConst(enumDict->GetConstants());
443  while (TEnumConstant* enumConst = (TEnumConstant*)iEnumConst()) {
444  TOptionListItem *it
445  = new TOptionListItem(this, enumConst->GetValue(),0,0,
446  enumConst->GetName(),enumConst->GetName());
447  fOptions->Add(it);
448  }
449  }
450 
451  // and the case od Bool_t : we add items "ON" and "Off"
452  } else if (!strncmp(GetFullTypeName(),"Bool_t",6)){
453 
454  fOptions = new TList();
455  TOptionListItem *it = new TOptionListItem(this,1,0,0,"ON",0);
456  fOptions->Add(it);
457  it = new TOptionListItem(this,0,0,0,"Off",0);
458  fOptions->Add(it);
459 
460  } else fOptions = 0;
461 
462 }
463 
464 ////////////////////////////////////////////////////////////////////////////////
465 /// copy constructor
466 
467 TDataMember::TDataMember(const TDataMember& dm) :
468  TDictionary(dm),
469  fInfo(gCling->DataMemberInfo_FactoryCopy(dm.fInfo)),
470  fClass(dm.fClass),
471  fDataType(dm.fDataType),
472  fOffset(dm.fOffset),
473  fSTLCont(dm.fSTLCont),
474  fProperty(dm.fProperty),
475  fArrayDim(dm.fArrayDim),
476  fArrayMaxIndex( dm.fArrayDim ? new Int_t[dm.fArrayDim] : 0),
477  fArrayIndex(dm.fArrayIndex),
478  fTypeName(dm.fTypeName),
479  fFullTypeName(dm.fFullTypeName),
480  fTrueTypeName(dm.fTrueTypeName),
481  fValueGetter(0),
482  fValueSetter(0),
483  fOptions(dm.fOptions ? (TList*)dm.fOptions->Clone() : 0)
484 {
485  for(Int_t d = 0; d < fArrayDim; ++d)
486  fArrayMaxIndex[d] = dm.fArrayMaxIndex[d];
487 }
488 
489 ////////////////////////////////////////////////////////////////////////////////
490 /// assignment operator
491 
492 TDataMember& TDataMember::operator=(const TDataMember& dm)
493 {
494  if(this!=&dm) {
495  gCling->DataMemberInfo_Delete(fInfo);
496  delete fValueSetter;
497  delete fValueGetter;
498  if (fOptions) {
499  fOptions->Delete();
500  delete fOptions;
501  fOptions = 0;
502  }
503 
504  TDictionary::operator=(dm);
505  fInfo= gCling->DataMemberInfo_FactoryCopy(dm.fInfo);
506  fClass=dm.fClass;
507  fDataType=dm.fDataType;
508  fOffset=dm.fOffset;
509  fSTLCont=dm.fSTLCont;
510  fProperty=dm.fProperty;
511  fArrayDim = dm.fArrayDim;
512  fArrayMaxIndex = dm.fArrayDim ? new Int_t[dm.fArrayDim] : 0;
513  for(Int_t d = 0; d < fArrayDim; ++d)
514  fArrayMaxIndex[d] = dm.fArrayMaxIndex[d];
515  fArrayIndex = dm.fArrayIndex;
516  fTypeName=dm.fTypeName;
517  fFullTypeName=dm.fFullTypeName;
518  fTrueTypeName=dm.fTrueTypeName;
519  fOptions = dm.fOptions ? (TList*)dm.fOptions->Clone() : 0;
520  }
521  return *this;
522 }
523 
524 ////////////////////////////////////////////////////////////////////////////////
525 /// TDataMember dtor deletes adopted CINT DataMemberInfo object.
526 
527 TDataMember::~TDataMember()
528 {
529  delete [] fArrayMaxIndex;
530  gCling->DataMemberInfo_Delete(fInfo);
531  delete fValueSetter;
532  delete fValueGetter;
533  if (fOptions) {
534  fOptions->Delete();
535  delete fOptions;
536  }
537 }
538 
539 ////////////////////////////////////////////////////////////////////////////////
540 /// Return number of array dimensions.
541 
542 Int_t TDataMember::GetArrayDim() const
543 {
544  if (fArrayDim<0 && fInfo) {
545  R__LOCKGUARD(gInterpreterMutex);
546  TDataMember *dm = const_cast<TDataMember*>(this);
547  dm->fArrayDim = gCling->DataMemberInfo_ArrayDim(fInfo);
548  // fArrayMaxIndex should be zero
549  if (dm->fArrayDim) {
550  dm->fArrayMaxIndex = new Int_t[fArrayDim];
551  for(Int_t dim = 0; dim < dm->fArrayDim; ++dim) {
552  dm->fArrayMaxIndex[dim] = gCling->DataMemberInfo_MaxIndex(fInfo,dim);
553  }
554  }
555  }
556  return fArrayDim;
557 }
558 
559 ////////////////////////////////////////////////////////////////////////////////
560 /// If the data member is pointer and has a valid array size in its comments
561 /// GetArrayIndex returns a string pointing to it;
562 /// otherwise it returns an empty string.
563 
564 const char *TDataMember::GetArrayIndex() const
565 {
566  if (!IsaPointer()) return "";
567  if (fArrayIndex.Length()==0 && fInfo) {
568  R__LOCKGUARD(gInterpreterMutex);
569  TDataMember *dm = const_cast<TDataMember*>(this);
570  const char* val = gCling->DataMemberInfo_ValidArrayIndex(fInfo);
571  if (val) dm->fArrayIndex = val;
572  else dm->fArrayIndex.Append((Char_t)0); // Make length non-zero but string still empty.
573  }
574  return fArrayIndex;
575 }
576 
577 ////////////////////////////////////////////////////////////////////////////////
578 
579 TDictionary::DeclId_t TDataMember::GetDeclId() const
580 {
581  if (fInfo) return gInterpreter->GetDeclId(fInfo);
582  else return 0;
583 }
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 /// Return maximum index for array dimension "dim".
587 
588 Int_t TDataMember::GetMaxIndex(Int_t dim) const
589 {
590  if (fArrayDim<0 && fInfo) {
591  return gCling->DataMemberInfo_MaxIndex(fInfo,dim);
592  } else {
593  if (dim < 0 || dim >= fArrayDim) return -1;
594  return fArrayMaxIndex[dim];
595  }
596 }
597 
598 ////////////////////////////////////////////////////////////////////////////////
599 /// Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
600 
601 const char *TDataMember::GetTypeName() const
602 {
603  if (fProperty==(-1)) Property();
604  return fTypeName.Data();
605 }
606 
607 ////////////////////////////////////////////////////////////////////////////////
608 /// Get full type description of data member, e,g.: "class TDirectory*".
609 
610 const char *TDataMember::GetFullTypeName() const
611 {
612  if (fProperty==(-1)) Property();
613 
614  return fFullTypeName.Data();
615 }
616 
617 ////////////////////////////////////////////////////////////////////////////////
618 /// Get full type description of data member, e,g.: "class TDirectory*".
619 
620 const char *TDataMember::GetTrueTypeName() const
621 {
622  return fTrueTypeName.Data();
623 }
624 
625 ////////////////////////////////////////////////////////////////////////////////
626 /// Get offset from "this".
627 
628 Long_t TDataMember::GetOffset() const
629 {
630  if (fOffset>=0) return fOffset;
631 
632  R__LOCKGUARD(gInterpreterMutex);
633  //case of an interpreted or emulated class
634  if (fClass->GetDeclFileLine() < 0) {
635  ((TDataMember*)this)->fOffset = gCling->DataMemberInfo_Offset(fInfo);
636  return fOffset;
637  }
638  //case of a compiled class
639  //Note that the offset cannot be computed in case of an abstract class
640  //for which the list of real data has not yet been computed via
641  //a real daughter class.
642  TString dmbracket;
643  dmbracket.Form("%s[",GetName());
644  fClass->BuildRealData();
645  TIter next(fClass->GetListOfRealData());
646  TRealData *rdm;
647  Int_t offset = 0;
648  while ((rdm = (TRealData*)next())) {
649  char *rdmc = (char*)rdm->GetName();
650  //next statement required in case a class and one of its parent class
651  //have data members with the same name
652  if (this->IsaPointer() && rdmc[0] == '*') rdmc++;
653 
654  if (rdm->GetDataMember() != this) continue;
655  if (strcmp(rdmc,GetName()) == 0) {
656  offset = rdm->GetThisOffset();
657  break;
658  }
659  if (strcmp(rdm->GetName(),GetName()) == 0) {
660  if (rdm->IsObject()) {
661  offset = rdm->GetThisOffset();
662  break;
663  }
664  }
665  if (strstr(rdm->GetName(),dmbracket.Data())) {
666  offset = rdm->GetThisOffset();
667  break;
668  }
669  }
670  ((TDataMember*)this)->fOffset = offset;
671  return fOffset;
672 }
673 
674 ////////////////////////////////////////////////////////////////////////////////
675 /// Get offset from "this" using the information in CINT only.
676 
677 Long_t TDataMember::GetOffsetCint() const
678 {
679  if (fOffset>=0) return fOffset;
680 
681  R__LOCKGUARD(gInterpreterMutex);
682  TDataMember *dm = const_cast<TDataMember*>(this);
683 
684  if (dm->IsValid()) return gCling->DataMemberInfo_Offset(dm->fInfo);
685  else return -1;
686 }
687 
688 ////////////////////////////////////////////////////////////////////////////////
689 /// Get the sizeof the underlying type of the data member
690 /// (i.e. if the member is an array sizeof(member)/length)
691 
692 Int_t TDataMember::GetUnitSize() const
693 {
694  if (IsaPointer()) return sizeof(void*);
695  if (IsEnum() ) return sizeof(Int_t);
696  if (IsBasic() ) return GetDataType()->Size();
697 
698  TClass *cl = TClass::GetClass(GetTypeName());
699  if (!cl) cl = TClass::GetClass(GetTrueTypeName());
700  if ( cl) return cl->Size();
701 
702  Warning("GetUnitSize","Can not determine sizeof(%s)",GetTypeName());
703  return 0;
704 }
705 
706 ////////////////////////////////////////////////////////////////////////////////
707 /// Return true if data member is a basic type, e.g. char, int, long...
708 
709 Bool_t TDataMember::IsBasic() const
710 {
711  if (fProperty == -1) Property();
712  return (fProperty & kIsFundamental) ? kTRUE : kFALSE;
713 }
714 
715 ////////////////////////////////////////////////////////////////////////////////
716 /// Return true if data member is an enum.
717 
718 Bool_t TDataMember::IsEnum() const
719 {
720  if (fProperty == -1) Property();
721  return (fProperty & kIsEnum) ? kTRUE : kFALSE;
722 }
723 
724 ////////////////////////////////////////////////////////////////////////////////
725 /// Return true if data member is a pointer.
726 
727 Bool_t TDataMember::IsaPointer() const
728 {
729  if (fProperty == -1) Property();
730  return (fProperty & kIsPointer) ? kTRUE : kFALSE;
731 }
732 
733 ////////////////////////////////////////////////////////////////////////////////
734 /// The return type is defined in TDictionary (kVector, kList, etc.)
735 
736 int TDataMember::IsSTLContainer()
737 {
738  if (fSTLCont != -1) return fSTLCont;
739  R__LOCKGUARD(gInterpreterMutex);
740  fSTLCont = TClassEdit::UnderlyingIsSTLCont(GetTrueTypeName());
741  return fSTLCont;
742 }
743 
744 ////////////////////////////////////////////////////////////////////////////////
745 /// Return true if this data member object is pointing to a currently
746 /// loaded data member. If a function is unloaded after the TDataMember
747 /// is created, the TDataMember will be set to be invalid.
748 
749 Bool_t TDataMember::IsValid()
750 {
751  if (fOffset >= 0) return kTRUE;
752 
753  // Register the transaction when checking the validity of the object.
754  if (!fInfo && UpdateInterpreterStateMarker()) {
755  DeclId_t newId = gInterpreter->GetDataMember(fClass->GetClassInfo(), fName);
756  if (newId) {
757  DataMemberInfo_t *info
758  = gInterpreter->DataMemberInfo_Factory(newId, fClass->GetClassInfo());
759  Update(info);
760  // We need to make sure that the list of data member is properly
761  // informed and updated.
762  TListOfDataMembers *lst = dynamic_cast<TListOfDataMembers*>(fClass->GetListOfDataMembers());
763  lst->Update(this);
764  }
765  return newId != 0;
766  }
767  return fInfo != 0;
768 }
769 
770 ////////////////////////////////////////////////////////////////////////////////
771 /// Get property description word. For meaning of bits see EProperty.
772 
773 Long_t TDataMember::Property() const
774 {
775  if (fProperty!=(-1)) return fProperty;
776 
777  R__LOCKGUARD(gInterpreterMutex);
778  TDataMember *t = (TDataMember*)this;
779 
780  if (!fInfo || !gCling->DataMemberInfo_IsValid(fInfo)) return 0;
781  int prop = gCling->DataMemberInfo_Property(fInfo);
782  int propt = gCling->DataMemberInfo_TypeProperty(fInfo);
783  t->fProperty = prop|propt;
784 
785  t->fFullTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeName(fInfo));
786  t->fTrueTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeTrueName(fInfo));
787  t->fTypeName = TClassEdit::GetLong64_Name(gCling->TypeName(fTrueTypeName));
788 
789  t->fName = gCling->DataMemberInfo_Name(fInfo);
790  t->fTitle = gCling->DataMemberInfo_Title(fInfo);
791 
792  return fProperty;
793 }
794 
795 ////////////////////////////////////////////////////////////////////////////////
796 /// Returns list of options - list of TOptionListItems
797 
798 TList *TDataMember::GetOptions() const
799 {
800  return fOptions;
801 }
802 
803 ////////////////////////////////////////////////////////////////////////////////
804 /// Return a TMethodCall method responsible for getting the value
805 /// of data member. The cl argument specifies the class of the object
806 /// which will be used to call this method (in case of multiple
807 /// inheritance TMethodCall needs to know this to calculate the proper
808 /// offset).
809 
810 TMethodCall *TDataMember::GetterMethod(TClass *cl)
811 {
812  if (!fValueGetter || cl) {
813 
814  R__LOCKGUARD(gInterpreterMutex);
815 
816  if (!cl) cl = fClass;
817 
818  if (fValueGetter) {
819  TString methodname = fValueGetter->GetMethodName();
820  delete fValueGetter;
821  fValueGetter = new TMethodCall(cl, methodname.Data(), "");
822 
823  } else {
824  // try to guess Getter function:
825  // we strip the fist character of name of data field ('f') and then
826  // try to find the name of Getter by applying "Get", "Is" or "Has"
827  // as a prefix
828 
829  const char *dataname = GetName();
830 
831  TString gettername;
832  gettername.Form( "Get%s", dataname+1);
833  if (GetClass()->GetMethod(gettername, ""))
834  return fValueGetter = new TMethodCall(cl, gettername, "");
835  gettername.Form( "Is%s", dataname+1);
836  if (GetClass()->GetMethod(gettername, ""))
837  return fValueGetter = new TMethodCall(cl, gettername, "");
838  gettername.Form( "Has%s", dataname+1);
839  if (GetClass()->GetMethod(gettername, ""))
840  return fValueGetter = new TMethodCall(cl, gettername, "");
841  }
842  }
843 
844  return fValueGetter;
845 }
846 
847 ////////////////////////////////////////////////////////////////////////////////
848 /// Return a TMethodCall method responsible for setting the value
849 /// of data member. The cl argument specifies the class of the object
850 /// which will be used to call this method (in case of multiple
851 /// inheritance TMethodCall needs to know this to calculate the proper
852 /// offset).
853 
854 TMethodCall *TDataMember::SetterMethod(TClass *cl)
855 {
856  if (!fValueSetter || cl) {
857 
858  R__LOCKGUARD(gInterpreterMutex);
859 
860  if (!cl) cl = fClass;
861 
862  if (fValueSetter) {
863 
864  TString methodname = fValueSetter->GetMethodName();
865  TString params = fValueSetter->GetParams();
866  delete fValueSetter;
867  fValueSetter = new TMethodCall(cl, methodname.Data(), params.Data());
868 
869  } else {
870 
871  // try to guess Setter function:
872  // we strip the fist character of name of data field ('f') and then
873  // try to find the name of Setter by applying "Set" as a prefix
874 
875  const char *dataname = GetName();
876 
877  TString settername;
878  settername.Form( "Set%s", dataname+1);
879  if (strstr(settername, "Is")) settername.Form( "Set%s", dataname+3);
880  if (GetClass()->GetMethod(settername, "1"))
881  fValueSetter = new TMethodCall(cl, settername, "1");
882  if (!fValueSetter)
883  if (GetClass()->GetMethod(settername, "true"))
884  fValueSetter = new TMethodCall(cl, settername, "true");
885  }
886  }
887 
888  return fValueSetter;
889 }
890 
891 ////////////////////////////////////////////////////////////////////////////////
892 /// Update the TFunction to reflect the new info.
893 ///
894 /// This can be used to implement unloading (info == 0) and then reloading
895 /// (info being the 'new' decl address).
896 
897 Bool_t TDataMember::Update(DataMemberInfo_t *info)
898 {
899  R__LOCKGUARD(gInterpreterMutex);
900 
901  if (fInfo) gCling->DataMemberInfo_Delete(fInfo);
902  SafeDelete(fValueSetter);
903  SafeDelete(fValueGetter);
904  if (fOptions) {
905  fOptions->Delete();
906  SafeDelete(fOptions);
907  }
908 
909  if (info == 0) {
910  fOffset = -1;
911  fProperty = -1;
912  fSTLCont = -1;
913  fArrayDim = -1;
914  delete [] fArrayMaxIndex;
915  fArrayMaxIndex=0;
916  fArrayIndex.Clear();
917 
918  fInfo = 0;
919  return kTRUE;
920  } else {
921  fInfo = info;
922  Init(false);
923  return kTRUE;
924  }
925 }
926 
927 
928 ////////////////////////////////////////////////////////////////////////////////
929 /// Stream an object of TDataMember. Forces calculation of all cached
930 /// (and persistent) values.
931 
932 void TDataMember::Streamer(TBuffer& b) {
933  if (b.IsReading()) {
934  b.ReadClassBuffer(Class(), this);
935  Init(true /*reading*/);
936  } else {
937  // Writing.
938  if (fProperty & kIsStatic) {
939  // We have a static member and in this case fOffset contains the
940  // actual address in memory of the data, it will be different everytime,
941  // let's not record it.
942  fOffset = -1;
943  } else {
944  GetOffset();
945  }
946  IsSTLContainer();
947  GetArrayDim();
948  GetArrayIndex();
949  Property(); // also calculates fTypeName and friends
950  b.WriteClassBuffer(Class(), this);
951  }
952 }
953 
954 ////////////////////////////////////////////////////////////////////////////////
955 /// Constructor.
956 
957 TOptionListItem::TOptionListItem(TDataMember *d, Long_t val, Long_t valmask,
958  Long_t tglmask,const char *name, const char *label)
959 {
960  fDataMember = d;
961  fValue = val;
962  fValueMaskBit = valmask;
963  fToggleMaskBit = tglmask;
964  if (name) {
965  fOptName = name;
966  }
967 
968  if (label) {
969  fOptLabel = label;
970  }
971 }