Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Migrate R__GenerateTClassForPair to TVirtualStreamerInfo::GenerateInf…
…oForPair
  • Loading branch information
pcanal committed Sep 30, 2020
commit e311a8af1a2e702cb3025729f47b07fb7af76790
8 changes: 8 additions & 0 deletions core/meta/inc/TVirtualStreamerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ class TVirtualStreamerInfo : public TNamed {
static void SetCanDelete(Bool_t opt=kTRUE);
static void SetFactory(TVirtualStreamerInfo *factory);

// \brief Generate the TClass and TStreamerInfo for the requested pair.
// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
// provokes the creation of the corresponding TClass. This relies on the dictionary for
// std::pair<const int, int> to already exist (or the interpreter information being available)
// as it is used as a template.
Comment on lines +185 to +187
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// provokes the creation of the corresponding TClass. This relies on the dictionary for
// std::pair<const int, int> to already exist (or the interpreter information being available)
// as it is used as a template.
// provokes the creation of the corresponding TClass.

Implementation detail; this should be asserted by GenerateInfoForPair, not be part of the doc.

Comment on lines +183 to +187
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// \brief Generate the TClass and TStreamerInfo for the requested pair.
// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
// provokes the creation of the corresponding TClass. This relies on the dictionary for
// std::pair<const int, int> to already exist (or the interpreter information being available)
// as it is used as a template.
// \brief Generate the TClass and TStreamerInfo for the requested pair.
/// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
/// provokes the creation of the corresponding TClass. This relies on the dictionary for
/// std::pair<const int, int> to already exist (or the interpreter information being available)
/// as it is used as a template.

virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname) = 0;
virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname) = 0;

virtual TVirtualCollectionProxy *GenEmulatedProxy(const char* class_name, Bool_t silent) = 0;
virtual TClassStreamer *GenEmulatedClassStreamer(const char* class_name, Bool_t silent) = 0;
virtual TVirtualCollectionProxy *GenExplicitProxy( const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl ) = 0;
Expand Down
1 change: 1 addition & 0 deletions core/metacling/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4380,6 +4380,7 @@ TClass *TCling::GenerateTClass(const char *classname, Bool_t emulation, Bool_t s
if (TClassEdit::IsSTLCont(classname)) {
version = TClass::GetClass("TVirtualStreamerInfo")->GetClassVersion();
}
R__LOCKGUARD(gInterpreterMutex);
TClass *cl = new TClass(classname, version, silent);
if (emulation) {
cl->SetBit(TClass::kIsEmulation);
Expand Down
8 changes: 8 additions & 0 deletions io/io/inc/TStreamerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,14 @@ class TStreamerInfo : public TVirtualStreamerInfo {
public:
virtual void Update(const TClass *oldClass, TClass *newClass);

// \brief Generate the TClass and TStreamerInfo for the requested pair.
// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
// provokes the creation of the corresponding TClass. This relies on the dictionary for
// std::pair<const int, int> to already exist (or the interpreter information being available)
// as it is used as a template.
virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname);
virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname);

virtual TVirtualCollectionProxy *GenEmulatedProxy(const char* class_name, Bool_t silent);
virtual TClassStreamer *GenEmulatedClassStreamer(const char* class_name, Bool_t silent);
virtual TVirtualCollectionProxy *GenExplicitProxy( const ::ROOT::Detail::TCollectionProxyInfo &info, TClass *cl );
Expand Down
101 changes: 1 addition & 100 deletions io/io/src/TEmulatedCollectionProxy.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ the class TEmulatedMapProxy.
// a dictionary (See end of file for implementation
//

static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const char *dmFull, Int_t offset);
TStreamerInfo *R__GenerateTClassForPair(const std::string &f, const std::string &s);

TEmulatedCollectionProxy::TEmulatedCollectionProxy(const TEmulatedCollectionProxy& copy)
Expand Down Expand Up @@ -608,105 +607,7 @@ void TEmulatedCollectionProxy::Streamer(TBuffer &b)
}
}

//
// Utility functions
//
static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const char *dmFull, Int_t offset)
{
// Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.

TString s1( TClassEdit::ShortType(dmFull,0) );
TString dmType( TClassEdit::ShortType(dmFull,1) );
Bool_t dmIsPtr = (s1 != dmType);
const char *dmTitle = "Emulation";

TDataType *dt = gROOT->GetType(dmType);
if (dt && dt->GetType() > 0 ) { // found a basic type
Int_t dsize,dtype;
dtype = dt->GetType();
dsize = dt->Size();
if (dmIsPtr && dtype != kCharStar) {
Error("Pair Emulation Building","%s is not yet supported in pair emulation",
dmFull);
return 0;
} else {
TStreamerElement *el = new TStreamerBasicType(dmName,dmTitle,offset,dtype,dmFull);
el->SetSize(dsize);
return el;
}
} else {

static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
return new TStreamerSTLstring(dmName,dmTitle,offset,dmFull,dmIsPtr);
}
if (TClassEdit::IsSTLCont(dmType)) {
return new TStreamerSTL(dmName,dmTitle,offset,dmFull,dmFull,dmIsPtr);
}
TClass *clm = TClass::GetClass(dmType);
if (!clm) {
// either we have an Emulated enum or a really unknown class!
// let's just claim its an enum :(
Int_t dtype = kInt_t;
return new TStreamerBasicType(dmName,dmTitle,offset,dtype,dmFull);
}
// a pointer to a class
if ( dmIsPtr ) {
if (clm->IsTObject()) {
return new TStreamerObjectPointer(dmName,dmTitle,offset,dmFull);
} else {
return new TStreamerObjectAnyPointer(dmName,dmTitle,offset,dmFull);
}
}
// a class
if (clm->IsTObject()) {
return new TStreamerObject(dmName,dmTitle,offset,dmFull);
} else if(clm == TString::Class() && !dmIsPtr) {
return new TStreamerString(dmName,dmTitle,offset);
} else {
return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull);
}
}
}


TStreamerInfo *R__GenerateTClassForPair(const std::string &fname, const std::string &sname)
{
// Generate a TStreamerInfo for a std::pair<fname,sname>
// This TStreamerInfo is then used as if it was read from a file to generate
// and emulated TClass.

TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
std::string pname = "pair<"+fname+","+sname;
pname += (pname[pname.length()-1]=='>') ? " >" : ">";
i->SetName(pname.c_str());
i->SetClass(0);
i->GetElements()->Delete();
TStreamerElement *fel = R__CreateEmulatedElement("first", fname.c_str(), 0);
Int_t size = 0;
if (fel) {
i->GetElements()->Add( fel );

size = fel->GetSize();
Int_t sp = sizeof(void *);
//align the non-basic data types (required on alpha and IRIX!!)
if (size%sp != 0) size = size - size%sp + sp;
} else {
delete i;
return 0;
}
TStreamerElement *second = R__CreateEmulatedElement("second", sname.c_str(), size);
if (second) {
i->GetElements()->Add( second );
} else {
delete i;
return 0;
}
Int_t oldlevel = gErrorIgnoreLevel;
// Hide the warning about the missing pair dictionary.
gErrorIgnoreLevel = kError;
i->BuildCheck();
gErrorIgnoreLevel = oldlevel;
i->BuildOld();
return i;
return (TStreamerInfo*)TVirtualStreamerInfo::Factory()->GenerateInfoForPair(fname, sname);
}
126 changes: 126 additions & 0 deletions io/io/src/TStreamerInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -5547,3 +5547,129 @@ TStreamerInfo::GenExplicitClassStreamer( const ::ROOT::TCollectionProxyInfo &inf
{
return TCollectionProxyFactory::GenExplicitClassStreamer(info, cl);
}

//
// Utility functions
//
static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const std::string &dmFull, Int_t offset)
{
// Create a TStreamerElement for the type 'dmFull' and whose data member name is 'dmName'.

TString s1( TClassEdit::ShortType(dmFull.c_str(),0) );
TString dmType( TClassEdit::ShortType(dmFull.c_str(),1) );
Bool_t dmIsPtr = (s1 != dmType);
const char *dmTitle = "Emulation";

TDataType *dt = gROOT->GetType(dmType);
if (dt && dt->GetType() > 0 ) { // found a basic type
Int_t dsize,dtype;
dtype = dt->GetType();
dsize = dt->Size();
if (dmIsPtr && dtype != kCharStar) {
Error("Pair Emulation Building","%s is not yet supported in pair emulation",
dmFull.c_str());
return 0;
} else {
TStreamerElement *el = new TStreamerBasicType(dmName,dmTitle,offset,dtype,dmFull.c_str());
el->SetSize(dsize);
return el;
}
} else {

static const char *full_string_name = "basic_string<char,char_traits<char>,allocator<char> >";
if (strcmp(dmType,"string") == 0 || strcmp(dmType,"std::string") == 0 || strcmp(dmType,full_string_name)==0 ) {
return new TStreamerSTLstring(dmName,dmTitle,offset,dmFull.c_str(),dmIsPtr);
}
if (TClassEdit::IsSTLCont(dmType)) {
return new TStreamerSTL(dmName,dmTitle,offset,dmFull.c_str(),dmFull.c_str(),dmIsPtr);
}
TClass *clm = TClass::GetClass(dmType);
if (!clm) {
// either we have an Emulated enum or a really unknown class!
// let's just claim its an enum :(
Int_t dtype = kInt_t;
return new TStreamerBasicType(dmName,dmTitle,offset,dtype,dmFull.c_str());
}
// a pointer to a class
if ( dmIsPtr ) {
if (clm->IsTObject()) {
return new TStreamerObjectPointer(dmName,dmTitle,offset,dmFull.c_str());
} else {
return new TStreamerObjectAnyPointer(dmName,dmTitle,offset,dmFull.c_str());
}
}
// a class
if (clm->IsTObject()) {
return new TStreamerObject(dmName,dmTitle,offset,dmFull.c_str());
} else if(clm == TString::Class() && !dmIsPtr) {
return new TStreamerString(dmName,dmTitle,offset);
} else {
return new TStreamerObjectAny(dmName,dmTitle,offset,dmFull.c_str());
}
}
}

// \brief Generate the TClass and TStreamerInfo for the requested pair.
// This creates a TVirtualStreamerInfo for the pair and trigger the BuildCheck/Old to
// provoke the creation of the corresponding TClass. This relies on the dictionary for
// std::pair<const int, int> to already exist (or the interpreter information being available)
// as it is used as a template.
TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firstname, const std::string &secondname)
{
// Generate a TStreamerInfo for a std::pair<fname,sname>
// This TStreamerInfo is then used as if it was read from a file to generate
// and emulated TClass.

TStreamerInfo *i = (TStreamerInfo*)TClass::GetClass("pair<const int,int>")->GetStreamerInfo()->Clone();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you R__ASSERT on i (or even better, TClass::GetClass("pair<const int,int>")), such that if the bootstrap ever changes we get some reasonable / helpful diagnostics, better than a nullptr this in a virtual function?

std::string pname = "pair<" + firstname + "," + secondname;
pname += (pname[pname.length()-1]=='>') ? " >" : ">";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pname += (pname[pname.length()-1]=='>') ? " >" : ">";
if (pname.back() == '>')
pname += ' ';
pname += '>';

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry - I realize now that this is just moved from R__GenerateTClassForPair - take my comments as irrelevant suggestions: I agree we can keep this code as is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically the existing version is (slightly) faster and, in my humble opinion (aka "for me") is at least as readable.

i->SetName(pname.c_str());
i->SetClass(nullptr);
i->GetElements()->Delete();
TStreamerElement *fel = R__CreateEmulatedElement("first", firstname, 0);
Int_t size = 0;
if (fel) {
i->GetElements()->Add( fel );

size = fel->GetSize();
Int_t sp = sizeof(void *);
//align the non-basic data types (required on alpha and IRIX!!)
if (size%sp != 0) size = size - size%sp + sp;
} else {
delete i;
return 0;
}
TStreamerElement *second = R__CreateEmulatedElement("second", secondname, size);
if (second) {
i->GetElements()->Add( second );
} else {
delete i;
return 0;
}
Int_t oldlevel = gErrorIgnoreLevel;
// Hide the warning about the missing pair dictionary.
gErrorIgnoreLevel = kError;
i->BuildCheck();
gErrorIgnoreLevel = oldlevel;
i->BuildOld();
return i;
}

TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pairclassname)
{
const static int pairlen = strlen("pair<");
if (pairclassname.compare(0, pairlen, "pair<") != 0) {
Error("GenerateInfoForPair", "The class name passed is not a pair: %s", pairclassname.c_str());
return nullptr;
}

std::vector<std::string> inside;
int nested = 0;
int num = TClassEdit::GetSplit(pairclassname.c_str(), inside, nested);
if (num != 4) {
Error("GenerateInfoForPair", "Could not find the pair arguments in %s", pairclassname.c_str());
return nullptr;
}

return GenerateInfoForPair(inside[1], inside[2]);
}