/*
<img align=center src="gif/classinfo.gif">
*/
//End_Html
/*
class MyClass{
private:
Float_t fX1;
...
public:
void SetX1(Float_t x) {fX1 = x;};
Float_t GetX1() {return fX1;};
...
}
*/
//</pre>
//End_Html
/*
TCanvas *c = new TCanvas("c"); // create a canvas
TClass *cl = c->IsA(); // get its class description object.
TDataMember *dm = cl->GetDataMember("fEditable"); //This is our data member
TMethodCall *getter = dm->GetterMethod(c); //find a method that gets value!
Long_t l; // declare a storage for this value;
getter->Execute(c,"",l); // Get this Value !!!! It will appear in l !!!
TMethodCall *setter = dm->SetterMethod(c);
setter->Execute(c,"0",); // Set Value 0 !!!
*/
//</pre>
//End_Html
/*
class MyClass{
Int_t mydata; // <em> *OPTIONS={GetMethod="Get";SetMethod="Set"} </em>
...
Int_t Get() const { return mydata;};
void Set(Int_t i) {mydata=i;};
}
*/
//</pre>
//End_Html
/*
<em>*OPTIONS={GetMethod="</em>getter<em>";SetMethod="</em>setter<em>";Items=(</em>it1<em>="</em>title1<em>",</em>it2<em>="</em>title2<em>", ... ) } </em>
*/
//</pre>
//End_Html
/*
IntegerValue<em> = "</em>Text Label<em>"</em>
EnumValue <em> = "</em>Text Label<em>"</em>
<em>"</em>TextValue<em>" = </em>Text Label<em>"</em>
*/
//</pre>
//End_Html
#include "TDataMember.h"
#include "Strlen.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TDataType.h"
#include "TEnum.h"
#include "TEnumConstant.h"
#include "TGlobal.h"
#include "TInterpreter.h"
#include "TIterator.h"
#include "TList.h"
#include "TListOfDataMembers.h"
#include "TMethod.h"
#include "TMethodCall.h"
#include "TRealData.h"
#include "TROOT.h"
#include "TVirtualMutex.h"
#include <stdlib.h>
ClassImp(TDataMember)
TDataMember::TDataMember(DataMemberInfo_t *info, TClass *cl) : TDictionary()
{
fInfo = info;
fClass = cl;
fDataType = 0;
fOptions = 0;
fValueSetter = 0;
fValueGetter = 0;
fOffset = -1;
fProperty = -1;
fSTLCont = -1;
fArrayDim = -1;
fArrayMaxIndex=0;
if (!fInfo && !fClass) return;
Init(false);
}
void TDataMember::Init(bool afterReading)
{
const char *t = 0;
if (!afterReading) {
if (!fInfo || !gInterpreter->DataMemberInfo_IsValid(fInfo)) return;
fFullTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeName(fInfo));
fTrueTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeTrueName(fInfo));
fTypeName = TClassEdit::GetLong64_Name(gCling->TypeName(fTrueTypeName));
SetName(gCling->DataMemberInfo_Name(fInfo));
t = gCling->DataMemberInfo_Title(fInfo);
SetTitle(t);
} else {
t = GetTitle();
}
if (t && t[0] != '!') SetBit(kObjIsPersistent);
fDataType = 0;
if (IsBasic() || IsEnum()) {
if (IsBasic()) {
const char *name = GetFullTypeName();
if (strcmp(name, "unsigned char") != 0 &&
strncmp(name, "unsigned short", sizeof ("unsigned short")) != 0 &&
strcmp(name, "unsigned int") != 0 &&
strncmp(name, "unsigned long", sizeof ("unsigned long")) != 0)
name = GetTypeName();
fDataType = gROOT->GetType(name);
if (fDataType==0) {
fDataType = gROOT->GetType(name,kTRUE);
}
} else {
fDataType = gROOT->GetType("Int_t", kTRUE);
}
}
if (afterReading) {
return;
}
char cmt[2048];
char opt[2048];
char *opt_ptr = 0;
const char *ptr1 = 0;
char *ptr2 = 0;
char *ptr3 = 0;
char *tok = 0;
Int_t cnt = 0;
Int_t token_cnt;
Int_t i;
strlcpy(cmt,GetTitle(),2048);
if ((opt_ptr=strstr(cmt,"*OPTION={"))) {
ptr1 = strtok(opt_ptr ,"{}");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"*OPTION={\" but not \"{}\" in %s.",GetTitle());
return;
}
ptr1 = strtok((char*)0,"{}");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"*OPTION={\" but not \"{}\" in %s.",GetTitle());
return;
}
strlcpy(opt,ptr1,2048);
char *tokens[256];
token_cnt = 0;
cnt = 0;
do {
ptr1=strtok((char*) (cnt++ ? 0:opt),";");
if (ptr1){
Int_t nch = strlen(ptr1)+1;
tok=new char[nch];
strlcpy(tok,ptr1,nch);
tokens[token_cnt]=tok;
token_cnt++;
}
} while (ptr1);
for (i=0;i<token_cnt;i++) {
if (strstr(tokens[i],"GetMethod")) {
ptr1 = strtok(tokens[i],"\"");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"GetMethod\" but not \"\\\"\" in %s.",GetTitle());
return;
}
ptr1 = strtok(0,"\"");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"GetMethod\" but not \"\\\"\" in %s.",GetTitle());
return;
}
if (!afterReading && GetClass()->GetMethod(ptr1,""))
fValueGetter = new TMethodCall(GetClass(),ptr1,"");
continue;
}
if (strstr(tokens[i],"SetMethod")) {
ptr1 = strtok(tokens[i],"\"");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"SetMethod\" but not \"\\\"\" in %s.",GetTitle());
return;
}
ptr1 = strtok((char*)0,"\"");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"SetMethod\" but not \"\\\"\" in %s.",GetTitle());
return;
}
if (GetClass()->GetMethod(ptr1,"1"))
fValueSetter = new TMethodCall(GetClass(),ptr1,"1");
}
}
Int_t opt_cnt = 0;
TList *optionlist = new TList();
for (i=0;i<token_cnt;i++) {
if (strstr(tokens[i],"Items")) {
ptr1 = strtok(tokens[i],"()");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"Items\" but not \"()\" in %s.",GetTitle());
return;
}
ptr1 = strtok((char*)0,"()");
if (ptr1 == 0) {
Fatal("TDataMember","Internal error, found \"Items\" but not \"()\" in %s.",GetTitle());
return;
}
char opts[2048];
strlcpy(opts,ptr1,2048);
do {
ptr1 = strtok(opt_cnt++ ? (char*)0:opts,",");
if (ptr1) {
TOptionListItem *it = new TOptionListItem(this,1,0,0,ptr1,"");
optionlist->Add(it);
}
} while(ptr1);
}
}
fOptions = new TList();
TIter next(optionlist);
TOptionListItem *it = 0;
TOptionListItem *it1 = 0;
while ((it=(TOptionListItem*)next())) {
ptr1 = it->fOptName;
Bool_t islabel = (ptr1[0]=='\"'); // value is label or numerical?
ptr2 = strtok((char*)ptr1,"=\"");
ptr3 = strtok(0,"=\"");
if (islabel) {
it1=new TOptionListItem(this,-9999,0,0,ptr3,ptr2);
fOptions->Add(it1);
} else {
Long_t l=0;
Int_t *value;
TGlobal *enumval = gROOT->GetGlobal(ptr1,kTRUE);
if (enumval){
value = (Int_t*)(enumval->GetAddress());
l = (Long_t)(*value);
} else if (IsEnum()) {
TObject *obj = fClass->GetListOfDataMembers(false)->FindObject(ptr1);
if (obj)
l = ((TEnumConstant*)obj)->GetValue();
else
l = gInterpreter->Calc(Form("%s;",ptr1));
} else
l = atol(ptr1);
it1 = new TOptionListItem(this,l,0,0,ptr3,ptr1);
fOptions->Add(it1);
}
optionlist->Remove(it);
delete it;
}
delete optionlist;
for (i=0;i<token_cnt;i++) if(tokens[i]) delete [] tokens[i];
} else if (IsEnum()) {
fOptions = new TList();
if (TEnum* enumDict = TEnum::GetEnum(GetTypeName()) ){
TIter iEnumConst(enumDict->GetConstants());
while (TEnumConstant* enumConst = (TEnumConstant*)iEnumConst()) {
TOptionListItem *it
= new TOptionListItem(this, enumConst->GetValue(),0,0,
enumConst->GetName(),enumConst->GetName());
fOptions->Add(it);
}
}
} else if (!strncmp(GetFullTypeName(),"Bool_t",6)){
fOptions = new TList();
TOptionListItem *it = new TOptionListItem(this,1,0,0,"ON",0);
fOptions->Add(it);
it = new TOptionListItem(this,0,0,0,"Off",0);
fOptions->Add(it);
} else fOptions = 0;
}
TDataMember::TDataMember(const TDataMember& dm) :
TDictionary(dm),
fInfo(gCling->DataMemberInfo_FactoryCopy(dm.fInfo)),
fClass(dm.fClass),
fDataType(dm.fDataType),
fOffset(dm.fOffset),
fSTLCont(dm.fSTLCont),
fProperty(dm.fProperty),
fArrayDim(dm.fArrayDim),
fArrayMaxIndex( dm.fArrayDim ? new Int_t[dm.fArrayDim] : 0),
fArrayIndex(dm.fArrayIndex),
fTypeName(dm.fTypeName),
fFullTypeName(dm.fFullTypeName),
fTrueTypeName(dm.fTrueTypeName),
fValueGetter(0),
fValueSetter(0),
fOptions(dm.fOptions ? (TList*)dm.fOptions->Clone() : 0)
{
for(Int_t d = 0; d < fArrayDim; ++d)
fArrayMaxIndex[d] = dm.fArrayMaxIndex[d];
}
TDataMember& TDataMember::operator=(const TDataMember& dm)
{
if(this!=&dm) {
gCling->DataMemberInfo_Delete(fInfo);
delete fValueSetter;
delete fValueGetter;
if (fOptions) {
fOptions->Delete();
delete fOptions;
fOptions = 0;
}
TDictionary::operator=(dm);
fInfo= gCling->DataMemberInfo_FactoryCopy(dm.fInfo);
fClass=dm.fClass;
fDataType=dm.fDataType;
fOffset=dm.fOffset;
fSTLCont=dm.fSTLCont;
fProperty=dm.fProperty;
fArrayDim = dm.fArrayDim;
fArrayMaxIndex = dm.fArrayDim ? new Int_t[dm.fArrayDim] : 0;
for(Int_t d = 0; d < fArrayDim; ++d)
fArrayMaxIndex[d] = dm.fArrayMaxIndex[d];
fArrayIndex = dm.fArrayIndex;
fTypeName=dm.fTypeName;
fFullTypeName=dm.fFullTypeName;
fTrueTypeName=dm.fTrueTypeName;
fOptions = dm.fOptions ? (TList*)dm.fOptions->Clone() : 0;
}
return *this;
}
TDataMember::~TDataMember()
{
delete [] fArrayMaxIndex;
gCling->DataMemberInfo_Delete(fInfo);
delete fValueSetter;
delete fValueGetter;
if (fOptions) {
fOptions->Delete();
delete fOptions;
}
}
Int_t TDataMember::GetArrayDim() const
{
if (fArrayDim<0 && fInfo) {
R__LOCKGUARD(gInterpreterMutex);
TDataMember *dm = const_cast<TDataMember*>(this);
dm->fArrayDim = gCling->DataMemberInfo_ArrayDim(fInfo);
if (dm->fArrayDim) {
dm->fArrayMaxIndex = new Int_t[fArrayDim];
for(Int_t dim = 0; dim < fArrayDim; ++dim) {
dm->fArrayMaxIndex[dim] = gCling->DataMemberInfo_MaxIndex(fInfo,dim);
}
}
}
return fArrayDim;
}
const char *TDataMember::GetArrayIndex() const
{
if (!IsaPointer()) return "";
if (fArrayIndex.Length()==0 && fInfo) {
R__LOCKGUARD(gInterpreterMutex);
TDataMember *dm = const_cast<TDataMember*>(this);
const char* val = gCling->DataMemberInfo_ValidArrayIndex(fInfo);
if (val) dm->fArrayIndex = val;
else dm->fArrayIndex.Append((Char_t)0);
}
return fArrayIndex;
}
TDictionary::DeclId_t TDataMember::GetDeclId() const
{
if (fInfo) return gInterpreter->GetDeclId(fInfo);
else return 0;
}
Int_t TDataMember::GetMaxIndex(Int_t dim) const
{
if (fArrayDim<0 && fInfo) {
return gCling->DataMemberInfo_MaxIndex(fInfo,dim);
} else {
if (dim < 0 || dim >= fArrayDim) return -1;
return fArrayMaxIndex[dim];
}
}
const char *TDataMember::GetTypeName() const
{
if (fProperty==(-1)) Property();
return fTypeName.Data();
}
const char *TDataMember::GetFullTypeName() const
{
if (fProperty==(-1)) Property();
return fFullTypeName.Data();
}
const char *TDataMember::GetTrueTypeName() const
{
return fTrueTypeName.Data();
}
Long_t TDataMember::GetOffset() const
{
if (fOffset>=0) return fOffset;
R__LOCKGUARD(gInterpreterMutex);
if (fClass->GetDeclFileLine() < 0) {
((TDataMember*)this)->fOffset = gCling->DataMemberInfo_Offset(fInfo);
return fOffset;
}
TString dmbracket;
dmbracket.Form("%s[",GetName());
fClass->BuildRealData();
TIter next(fClass->GetListOfRealData());
TRealData *rdm;
Int_t offset = 0;
while ((rdm = (TRealData*)next())) {
char *rdmc = (char*)rdm->GetName();
if (this->IsaPointer() && rdmc[0] == '*') rdmc++;
if (rdm->GetDataMember() != this) continue;
if (strcmp(rdmc,GetName()) == 0) {
offset = rdm->GetThisOffset();
break;
}
if (strcmp(rdm->GetName(),GetName()) == 0) {
if (rdm->IsObject()) {
offset = rdm->GetThisOffset();
break;
}
}
if (strstr(rdm->GetName(),dmbracket.Data())) {
offset = rdm->GetThisOffset();
break;
}
}
((TDataMember*)this)->fOffset = offset;
return fOffset;
}
Long_t TDataMember::GetOffsetCint() const
{
if (fOffset>=0) return fOffset;
R__LOCKGUARD(gInterpreterMutex);
TDataMember *dm = const_cast<TDataMember*>(this);
if (dm->IsValid()) return gCling->DataMemberInfo_Offset(dm->fInfo);
else return -1;
}
Int_t TDataMember::GetUnitSize() const
{
if (IsaPointer()) return sizeof(void*);
if (IsEnum() ) return sizeof(Int_t);
if (IsBasic() ) return GetDataType()->Size();
TClass *cl = TClass::GetClass(GetTypeName());
if (!cl) cl = TClass::GetClass(GetTrueTypeName());
if ( cl) return cl->Size();
Warning("GetUnitSize","Can not determine sizeof(%s)",GetTypeName());
return 0;
}
Bool_t TDataMember::IsBasic() const
{
if (fProperty == -1) Property();
return (fProperty & kIsFundamental) ? kTRUE : kFALSE;
}
Bool_t TDataMember::IsEnum() const
{
if (fProperty == -1) Property();
return (fProperty & kIsEnum) ? kTRUE : kFALSE;
}
Bool_t TDataMember::IsaPointer() const
{
if (fProperty == -1) Property();
return (fProperty & kIsPointer) ? kTRUE : kFALSE;
}
int TDataMember::IsSTLContainer()
{
if (fSTLCont != -1) return fSTLCont;
R__LOCKGUARD(gInterpreterMutex);
fSTLCont = TClassEdit::UnderlyingIsSTLCont(GetTrueTypeName());
return fSTLCont;
}
Bool_t TDataMember::IsValid()
{
if (fOffset >= 0) return kTRUE;
if (!fInfo && UpdateInterpreterStateMarker()) {
DeclId_t newId = gInterpreter->GetDataMember(fClass->GetClassInfo(), fName);
if (newId) {
DataMemberInfo_t *info
= gInterpreter->DataMemberInfo_Factory(newId, fClass->GetClassInfo());
Update(info);
TListOfDataMembers *lst = dynamic_cast<TListOfDataMembers*>(fClass->GetListOfDataMembers());
lst->Update(this);
}
return newId != 0;
}
return fInfo != 0;
}
Long_t TDataMember::Property() const
{
if (fProperty!=(-1)) return fProperty;
R__LOCKGUARD(gInterpreterMutex);
TDataMember *t = (TDataMember*)this;
if (!fInfo || !gCling->DataMemberInfo_IsValid(fInfo)) return 0;
int prop = gCling->DataMemberInfo_Property(fInfo);
int propt = gCling->DataMemberInfo_TypeProperty(fInfo);
t->fProperty = prop|propt;
t->fFullTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeName(fInfo));
t->fTrueTypeName = TClassEdit::GetLong64_Name(gCling->DataMemberInfo_TypeTrueName(fInfo));
t->fTypeName = TClassEdit::GetLong64_Name(gCling->TypeName(fTrueTypeName));
t->fName = gCling->DataMemberInfo_Name(fInfo);
t->fTitle = gCling->DataMemberInfo_Title(fInfo);
return fProperty;
}
TList *TDataMember::GetOptions() const
{
return fOptions;
}
TMethodCall *TDataMember::GetterMethod(TClass *cl)
{
if (!fValueGetter || cl) {
R__LOCKGUARD(gInterpreterMutex);
if (!cl) cl = fClass;
if (fValueGetter) {
TString methodname = fValueGetter->GetMethodName();
delete fValueGetter;
fValueGetter = new TMethodCall(cl, methodname.Data(), "");
} else {
const char *dataname = GetName();
TString gettername;
gettername.Form( "Get%s", dataname+1);
if (GetClass()->GetMethod(gettername, ""))
return fValueGetter = new TMethodCall(cl, gettername, "");
gettername.Form( "Is%s", dataname+1);
if (GetClass()->GetMethod(gettername, ""))
return fValueGetter = new TMethodCall(cl, gettername, "");
gettername.Form( "Has%s", dataname+1);
if (GetClass()->GetMethod(gettername, ""))
return fValueGetter = new TMethodCall(cl, gettername, "");
}
}
return fValueGetter;
}
TMethodCall *TDataMember::SetterMethod(TClass *cl)
{
if (!fValueSetter || cl) {
R__LOCKGUARD(gInterpreterMutex);
if (!cl) cl = fClass;
if (fValueSetter) {
TString methodname = fValueSetter->GetMethodName();
TString params = fValueSetter->GetParams();
delete fValueSetter;
fValueSetter = new TMethodCall(cl, methodname.Data(), params.Data());
} else {
const char *dataname = GetName();
TString settername;
settername.Form( "Set%s", dataname+1);
if (strstr(settername, "Is")) settername.Form( "Set%s", dataname+3);
if (GetClass()->GetMethod(settername, "1"))
fValueSetter = new TMethodCall(cl, settername, "1");
if (!fValueSetter)
if (GetClass()->GetMethod(settername, "true"))
fValueSetter = new TMethodCall(cl, settername, "true");
}
}
return fValueSetter;
}
Bool_t TDataMember::Update(DataMemberInfo_t *info)
{
R__LOCKGUARD(gInterpreterMutex);
if (fInfo) gCling->DataMemberInfo_Delete(fInfo);
SafeDelete(fValueSetter);
SafeDelete(fValueGetter);
if (fOptions) {
fOptions->Delete();
SafeDelete(fOptions);
}
if (info == 0) {
fOffset = -1;
fProperty = -1;
fSTLCont = -1;
fArrayDim = -1;
delete [] fArrayMaxIndex;
fArrayMaxIndex=0;
fArrayIndex.Clear();
fInfo = 0;
return kTRUE;
} else {
fInfo = info;
Init(false);
return kTRUE;
}
}
void TDataMember::Streamer(TBuffer& b) {
if (b.IsReading()) {
b.ReadClassBuffer(Class(), this);
Init(true );
} else {
if (fProperty & kIsStatic) {
fOffset = -1;
} else {
GetOffset();
}
IsSTLContainer();
GetArrayDim();
GetArrayIndex();
Property();
b.WriteClassBuffer(Class(), this);
}
}
TOptionListItem::TOptionListItem(TDataMember *d, Long_t val, Long_t valmask,
Long_t tglmask,const char *name, const char *label)
{
fDataMember = d;
fValue = val;
fValueMaskBit = valmask;
fToggleMaskBit = tglmask;
if (name) {
fOptName = name;
}
if(label) {
fOptLabel = fOptLabel;
}
}