#include "TSchemaRuleSet.h"
#include "TSchemaRule.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TClass.h"
#include "TROOT.h"
#include "Riostream.h"
#include "TVirtualCollectionProxy.h"
#include "TVirtualStreamerInfo.h"
#include "TStreamerElement.h"
#include "TClassEdit.h"
ClassImp(TSchemaRule)
using namespace ROOT;
TSchemaRuleSet::TSchemaRuleSet(): fPersistentRules( 0 ), fRemainingRules( 0 ),
fAllRules( 0 ), fVersion(-3), fCheckSum( 0 )
{
fPersistentRules = new TObjArray();
fRemainingRules = new TObjArray();
fAllRules = new TObjArray();
fAllRules->SetOwner( kTRUE );
}
TSchemaRuleSet::~TSchemaRuleSet()
{
delete fPersistentRules;
delete fRemainingRules;
delete fAllRules;
}
void TSchemaRuleSet::ls(Option_t *) const
{
TROOT::IndentLevel();
std::cout << "TSchemaRuleSet for " << fClassName << ":\n";
TROOT::IncreaseDirLevel();
TObject *object = 0;
TIter next(fPersistentRules);
while ((object = next())) {
object->ls(fClassName);
}
TROOT::DecreaseDirLevel();
}
Bool_t TSchemaRuleSet::AddRules( TSchemaRuleSet* , EConsistencyCheck , TString * )
{
return kFALSE;
}
Bool_t TSchemaRuleSet::AddRule( TSchemaRule* rule, EConsistencyCheck checkConsistency, TString *errmsg )
{
if( (checkConsistency != kNoCheck) && !fClass )
return kFALSE;
if( !rule->IsValid() )
return kFALSE;
if( checkConsistency == kNoCheck ) {
if( rule->GetEmbed() )
fPersistentRules->Add( rule );
else
fRemainingRules->Add( rule );
fAllRules->Add( rule );
return kTRUE;
}
TObject* obj;
if( rule->GetTarget() && !(fClass->TestBit(TClass::kIsEmulation) && (fClass->GetStreamerInfos()==0 || fClass->GetStreamerInfos()->GetEntries()==0)) ) {
TObjArrayIter titer( rule->GetTarget() );
while( (obj = titer.Next()) ) {
TObjString* str = (TObjString*)obj;
if( !fClass->GetDataMember( str->GetString() ) && !fClass->GetBaseClass( str->GetString() ) ) {
if (checkConsistency == kCheckAll) {
if (errmsg) {
errmsg->Form("the target member (%s) is unknown",str->GetString().Data());
}
return kFALSE;
} else {
delete rule;
return kTRUE;
}
}
}
}
const TObjArray* rules = FindRules( rule->GetSourceClass() );
TObjArrayIter it( rules );
TSchemaRule *r;
while( (obj = it.Next()) ) {
r = (TSchemaRule *) obj;
if( rule->Conflicts( r ) ) {
delete rules;
if ( *r == *rule) {
if (errmsg) {
*errmsg = "it conflicts with one of the other rules";
}
delete rule;
return kTRUE;
}
if (errmsg) {
*errmsg = "The existing rule is:\n ";
r->AsString(*errmsg,"s");
*errmsg += "\nand the ignored rule is:\n ";
rule->AsString(*errmsg);
*errmsg += ".\n";
}
return kFALSE;
}
}
delete rules;
if( rule->GetEmbed() )
fPersistentRules->Add( rule );
else
fRemainingRules->Add( rule );
fAllRules->Add( rule );
return kTRUE;
}
void TSchemaRuleSet::AsString(TString &out) const
{
TObjArrayIter it( fAllRules );
TSchemaRule *rule;
while( (rule = (TSchemaRule*)it.Next()) ) {
rule->AsString(out);
out += "\n";
}
}
Bool_t TSchemaRuleSet::HasRuleWithSourceClass( const TString &source ) const
{
TObjArrayIter it( fAllRules );
TObject *obj;
while( (obj = it.Next()) ) {
TSchemaRule* rule = (TSchemaRule*)obj;
if( rule->GetSourceClass() == source )
return kTRUE;
}
if (fClass->GetCollectionProxy()) {
if (fClass->GetCollectionProxy()->GetValueClass() == 0) {
TClass *src = TClass::GetClass(source);
if (src && src->GetCollectionProxy() &&
src->GetCollectionProxy()->HasPointers() == fClass->GetCollectionProxy()->HasPointers()) {
TVirtualCollectionProxy *proxy = src->GetCollectionProxy();
if (proxy->GetValueClass() == 0) {
return kTRUE;
}
}
} else {
TClass *vTargetClass = fClass->GetCollectionProxy()->GetValueClass();
TClass *src = TClass::GetClass(source);
if (vTargetClass->GetSchemaRules()) {
if (src && src->GetCollectionProxy() &&
src->GetCollectionProxy()->HasPointers() == fClass->GetCollectionProxy()->HasPointers()) {
TClass *vSourceClass = src->GetCollectionProxy()->GetValueClass();
if (vSourceClass) {
return vTargetClass->GetSchemaRules()->HasRuleWithSourceClass( vSourceClass->GetName() );
}
}
}
}
} else if (!strncmp(fClass->GetName(),"std::pair<",10) || !strncmp(fClass->GetName(),"pair<",5)) {
if (!strncmp(source,"std::pair<",10) || !strncmp(source,"pair<",5)) {
TClass *src = TClass::GetClass(source);
if (!src) {
Error("HasRuleWithSourceClass","Can not find the TClass for %s when matching with %s\n",source.Data(),fClass->GetName());
return kFALSE;
}
TVirtualStreamerInfo *sourceInfo = src->GetStreamerInfo();
TVirtualStreamerInfo *targetInfo = fClass->GetStreamerInfo();
if (!sourceInfo) {
Error("HasRuleWithSourceClass","Can not find the StreamerInfo for %s when matching with %s\n",source.Data(),fClass->GetName());
return kFALSE;
}
if (!targetInfo) {
Error("HasRuleWithSourceClass","Can not find the StreamerInfo for target class %s\n",fClass->GetName());
return kFALSE;
}
for(int i = 0 ; i<2 ; ++i) {
TStreamerElement *sourceElement = (TStreamerElement*)sourceInfo->GetElements()->At(i);
TStreamerElement *targetElement = (TStreamerElement*)targetInfo->GetElements()->At(i);
if (sourceElement->GetClass()) {
if (!targetElement->GetClass()) {
return kFALSE;
}
if (sourceElement->GetClass() == targetElement->GetClass()) {
continue;
}
TSchemaRuleSet *rules = sourceElement->GetClass()->GetSchemaRules();
if (!rules || !rules->HasRuleWithSourceClass( targetElement->GetClass()->GetName() ) ) {
return kFALSE;
}
} else if (targetElement->GetClass()) {
return kFALSE;
} else {
}
}
ROOT::TSchemaRule *ruleobj = new ROOT::TSchemaRule();
ruleobj->SetSourceClass(source);
ruleobj->SetTargetClass(fClass->GetName());
ruleobj->SetVersion("[1-]");
const_cast<TSchemaRuleSet*>(this)->AddRule(ruleobj);
return kTRUE;
}
}
return kFALSE;
}
const TObjArray* TSchemaRuleSet::FindRules( const TString &source ) const
{
TObject* obj;
TObjArrayIter it( fAllRules );
TObjArray* arr = new TObjArray();
arr->SetOwner( kFALSE );
while( (obj = it.Next()) ) {
TSchemaRule* rule = (TSchemaRule*)obj;
if( rule->GetSourceClass() == source )
arr->Add( rule );
}
#if 0
if (fClass->GetCollectionProxy()) {
if (fClass->GetCollectionProxy()->GetValueClass() == 0
&& (fClass->GetCollectionProxy()->GetCollectionType() == TClassEdit::kVector
|| (fClass->GetCollectionProxy()->GetProperties() & TVirtualCollectionProxy::kIsEmulated))) {
TClass *src = TClass::GetClass(source);
if (src && src->GetCollectionProxy()) {
TVirtualCollectionProxy *proxy = src->GetCollectionProxy();
if (proxy->GetValueClass() == 0) {
}
}
}
}
#endif
return arr;
}
const TSchemaMatch* TSchemaRuleSet::FindRules( const TString &source, Int_t version ) const
{
TObject* obj;
TObjArrayIter it( fAllRules );
TSchemaMatch* arr = new TSchemaMatch();
arr->SetOwner( kFALSE );
while( (obj = it.Next()) ) {
TSchemaRule* rule = (TSchemaRule*)obj;
if( rule->GetSourceClass() == source && rule->TestVersion( version ) )
arr->Add( rule );
}
if( arr->GetEntriesFast() )
return arr;
else {
delete arr;
return 0;
}
}
const TSchemaMatch* TSchemaRuleSet::FindRules( const TString &source, UInt_t checksum ) const
{
TObject* obj;
TObjArrayIter it( fAllRules );
TSchemaMatch* arr = new TSchemaMatch();
arr->SetOwner( kFALSE );
while( (obj = it.Next()) ) {
TSchemaRule* rule = (TSchemaRule*)obj;
if( rule->GetSourceClass() == source && rule->TestChecksum( checksum ) )
arr->Add( rule );
}
if( arr->GetEntriesFast() )
return arr;
else {
delete arr;
return 0;
}
}
const TSchemaMatch* TSchemaRuleSet::FindRules( const TString &source, Int_t version, UInt_t checksum ) const
{
TObject* obj;
TObjArrayIter it( fAllRules );
TSchemaMatch* arr = new TSchemaMatch();
arr->SetOwner( kFALSE );
while( (obj = it.Next()) ) {
TSchemaRule* rule = (TSchemaRule*)obj;
if( rule->GetSourceClass() == source && ( rule->TestVersion( version ) || rule->TestChecksum( checksum ) ) )
arr->Add( rule );
}
if( arr->GetEntriesFast() )
return arr;
else {
delete arr;
return 0;
}
}
TClass* TSchemaRuleSet::GetClass()
{
return fClass;
}
UInt_t TSchemaRuleSet::GetClassCheckSum() const
{
if (fCheckSum == 0 && fClass) {
const_cast<TSchemaRuleSet*>(this)->fCheckSum = fClass->GetCheckSum();
}
return fCheckSum;
}
TString TSchemaRuleSet::GetClassName() const
{
return fClassName;
}
Int_t TSchemaRuleSet::GetClassVersion() const
{
return fVersion;
}
const TObjArray* TSchemaRuleSet::GetRules() const
{
return fAllRules;
}
const TObjArray* TSchemaRuleSet::GetPersistentRules() const
{
return fPersistentRules;
}
void TSchemaRuleSet::RemoveRule( TSchemaRule* rule )
{
fPersistentRules->Remove( rule );
fRemainingRules->Remove( rule );
fAllRules->Remove( rule );
}
void TSchemaRuleSet::RemoveRules( TObjArray* rules )
{
TObject* obj;
TObjArrayIter it( rules );
while( (obj = it.Next()) ) {
fPersistentRules->Remove( obj );
fRemainingRules->Remove( obj );
fAllRules->Remove( obj );
}
}
void TSchemaRuleSet::SetClass( TClass* cls )
{
fClass = cls;
fClassName = cls->GetName();
fVersion = cls->GetClassVersion();
}
const TSchemaRule* TSchemaMatch::GetRuleWithSource( const TString& name ) const
{
for( Int_t i = 0; i < GetEntries(); ++i ) {
TSchemaRule* rule = (ROOT::TSchemaRule*)At(i);
if( rule->HasSource( name ) ) return rule;
}
return 0;
}
const TSchemaRule* TSchemaMatch::GetRuleWithTarget( const TString& name ) const
{
for( Int_t i=0; i<GetEntries(); ++i) {
ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)At(i);
if( rule->HasTarget( name ) ) return rule;
}
return 0;
}
Bool_t TSchemaMatch::HasRuleWithSource( const TString& name, Bool_t needingAlloc ) const
{
for( Int_t i = 0; i < GetEntries(); ++i ) {
TSchemaRule* rule = (ROOT::TSchemaRule*)At(i);
if( rule->HasSource( name ) ) {
if (needingAlloc) {
const TObjArray *targets = rule->GetTarget();
if (targets && (targets->GetEntries() > 1 || targets->GetEntries()==0) ) {
return kTRUE;
}
if (targets && name != targets->UncheckedAt(0)->GetName() ) {
return kTRUE;
}
if (rule->GetReadFunctionPointer() || rule->GetReadRawFunctionPointer()) {
return kTRUE;
}
} else {
return kTRUE;
}
}
}
return kFALSE;
}
Bool_t TSchemaMatch::HasRuleWithTarget( const TString& name, Bool_t willset ) const
{
for( Int_t i=0; i<GetEntries(); ++i) {
ROOT::TSchemaRule *rule = (ROOT::TSchemaRule*)At(i);
if( rule->HasTarget( name ) ) {
if (willset) {
const TObjArray *targets = rule->GetTarget();
if (targets && (targets->GetEntries() > 1 || targets->GetEntries()==0) ) {
return kTRUE;
}
const TObjArray *sources = rule->GetSource();
if (sources && (sources->GetEntries() > 1 || sources->GetEntries()==0) ) {
return kTRUE;
}
if (sources && name != sources->UncheckedAt(0)->GetName() ) {
return kTRUE;
}
if (rule->GetReadFunctionPointer() || rule->GetReadRawFunctionPointer()) {
return kTRUE;
}
} else {
return kTRUE;
}
}
}
return kFALSE;
}
void TSchemaRuleSet::Streamer(TBuffer &R__b)
{
if (R__b.IsReading()) {
R__b.ReadClassBuffer(ROOT::TSchemaRuleSet::Class(),this);
fAllRules->Clear();
fAllRules->AddAll(fPersistentRules);
} else {
GetClassCheckSum();
R__b.WriteClassBuffer(ROOT::TSchemaRuleSet::Class(),this);
}
}