/* ======================================================================== *\ ! ! * ! * This file is part of MARS, the MAGIC Analysis and Reconstruction ! * Software. It is distributed to you in the hope that it can be a useful ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. ! * It is distributed WITHOUT ANY WARRANTY. ! * ! * Permission to use, copy, modify and distribute this software and its ! * documentation for any purpose is hereby granted without fee, ! * provided that the above copyright notice appear in all copies and ! * that both that copyright notice and this permission notice appear ! * in supporting documentation. It is provided "as is" without express ! * or implied warranty. ! * ! ! ! Author(s): Thomas Bretz 12/2000 ! ! Copyright: MAGIC Software Development, 2000-2002 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // // MParList // // // // This class contains a list of different parameter containers. // // // // A parameter container is an object which is derived from // // MParContainer. // // // // Normally a parameter container is used for data exchange between two // // tasks at runtime. // // // // You can add every parameter container (Named object) to the // // instance and access it from somewhere else via its Name. // // // ///////////////////////////////////////////////////////////////////////////// #include "MParList.h" #include // ofstream, SavePrimitive #include #include #include #include "MLog.h" #include "MLogManip.h" #include "MIter.h" ClassImp(MParList); using namespace std; static const TString gsDefName = "MParList"; static const TString gsDefTitle = "A list of Parameter Containers"; // -------------------------------------------------------------------------- // // default constructor // creates an empty list // MParList::MParList(const char *name, const char *title) { fName = name ? name : gsDefName.Data(); fTitle = title ? title : gsDefTitle.Data(); // // This sets a flag that the list is the owner, which means // that the destructor of the list deletes all it's objects // fContainer = new TOrdCollection; fAutodelete = new TOrdCollection; gROOT->GetListOfCleanups()->Add(fContainer); gROOT->GetListOfCleanups()->Add(fAutodelete); fContainer->SetBit(kMustCleanup); fAutodelete->SetBit(kMustCleanup); } // -------------------------------------------------------------------------- // // Copy constructor. It copies all entries of the parameter list, but it // takes care of, that the automatically created entries are only deleted // once. (doesn't copy the list which holds the automatically created // entries) // MParList::MParList(MParList &ts) { fContainer->AddAll(ts.fContainer); } // -------------------------------------------------------------------------- // // If the 'IsOwner' bit is set (via SetOwner()) all containers are deleted // by the destructor // MParList::~MParList() { // // Case: // 1) MParList is owner of the containers: // All container are stored in fContainer, and become deleted by // 'delete fContainer'. Some of these containers, which were // created automatically are stored in fAutodelete, too. To prevent // double deletion this containers are not deleted by the destructor // of fAutodelete. // 2) MParList is not owner of the containers: // The containers which were Added by AddToList are not touched. // Only the containers which were created automatically are also // automatically deleted. // IsOwner() ? fContainer->SetOwner() : fAutodelete->SetOwner(); TIter Next(fContainer); TObject *o; while ((o=Next())) if (o->TestBit(kCanDelete)) delete fContainer->Remove(o); // FIXME? If fContainer is owner do we have to remove the object // from fAutodelete due to the acces when checking for a // garbage collection? delete fContainer; delete fAutodelete; } // -------------------------------------------------------------------------- // // If the 'IsOwner' bit is set (via SetOwner()) all containers are deleted // by the destructor // void MParList::SetOwner(Bool_t enable) { enable ? SetBit(kIsOwner) : ResetBit(kIsOwner); } // -------------------------------------------------------------------------- // // Set the logging streamer of the parameter list and all contained // parameter containers // void MParList::SetLogStream(MLog *log) { fContainer->ForEach(MParContainer, SetLogStream)(log); MParContainer::SetLogStream(log); } void MParList::SetDisplay(MStatusDisplay *d) { fContainer->ForEach(MParContainer, SetDisplay)(d); MParContainer::SetDisplay(d); } // -------------------------------------------------------------------------- // // Add a single container to the list. // // If 'where' is given, the object will be added after this. // Bool_t MParList::AddToList(MParContainer *cont, MParContainer *where) { // // check if the object (you want to add) exists // if (!cont) return kFALSE; // // Get Name of new container // const char *name = cont->GetName(); // // Check if the new container is already existing in the list // const TObject *objn = fContainer->FindObject(name); const TObject *objt = fContainer->FindObject(cont); if (objn || objt) { // // If the container is already in the list ignore it. // if (objt || objn==cont) { *fLog << warn << dbginf << "Warning: Container '" << cont->GetName() << ", 0x" << (void*)cont; *fLog << "' already existing in '" << GetName() << "'... ignoring." << endl; return kTRUE; } // // Otherwise add it to the list, but print a warning message // *fLog << warn << dbginf << "Warning: Container with the same name '" << cont->GetName(); *fLog << "' already existing in '" << GetName() << "'." << endl; *fLog << "You may not be able to get a pointer to container task by name." << endl; } // // check if you want to add the new parameter container somewhere // special (in that case you specify "where") // if (where) { if (!fContainer->FindObject(where)) { *fLog << dbginf << "Error: Cannot find parameter container after which the new one should be added!" << endl; return kFALSE; } } *fLog << inf << "Adding " << name << " to " << GetName() << "... " << flush; cont->SetBit(kMustCleanup); fContainer->Add(cont); *fLog << "Done." << endl; return kTRUE; } // -------------------------------------------------------------------------- // // Add all entries of the TObjArray to the list. // void MParList::AddToList(TObjArray *list) { // // check if the object (you want to add) exists // if (!list) return; MIter Next(list); MParContainer *cont = NULL; while ((cont=Next())) { cont->SetBit(kMustCleanup); AddToList(cont); } } // -------------------------------------------------------------------------- // // Find an object with the same name in the list and replace it with // the new one. If the kIsOwner flag is set and the object was not // created automatically, the object is deleted. // Bool_t MParList::Replace(MParContainer *cont) { // // check if the object (you want to add) exists // if (!cont) return kFALSE; TObject *obj = FindObject(cont->GetName()); if (!obj) { *fLog << warn << "No object with the same name '"; *fLog << cont->GetName() << "' in list... adding." << endl; return AddToList(cont); } fContainer->Remove(obj); if (IsOwner() && !fAutodelete->FindObject(obj)) delete obj; *fLog << inf << "MParContainer '" << cont->GetName() << "' found and replaced..." << endl; return AddToList(cont); } // -------------------------------------------------------------------------- // // Find an object with the same name in the list and remove it. // If the kIsOwner flag is set and the object was not created // automatically, the object is deleted. // void MParList::Remove(MParContainer *cont) { // // check if the object (you want to add) exists // if (!cont) return; TObject *obj = fContainer->Remove(cont); if (!obj) { *fLog << warn << "Object not found in list..." << endl; return; } *fLog << inf << "MParContainer '" << cont->GetName() << "' removed..." << endl; if (IsOwner() && !fAutodelete->FindObject(obj)) delete obj; } // -------------------------------------------------------------------------- // // Find an object in the list. // 'name' is the name of the object you are searching for. // TObject *MParList::FindObject(const char *name) const { return fContainer->FindObject(name); } // -------------------------------------------------------------------------- // // check if the object is in the list or not // TObject *MParList::FindObject(const TObject *obj) const { return fContainer->FindObject(obj); } // -------------------------------------------------------------------------- // // Find an object in the list and check for the correct inheritance. // 'name' is the name of the object you are searching for. // // In words: Find object name and check whether it inherits from classname // TObject *MParList::FindObject(const char *name, const char *classname) const { TObject *obj = fContainer->FindObject(name); if (!obj) return NULL; if (obj->InheritsFrom(classname)) return obj; *fLog << dbginf << warn << "Found object '" << name << "' doesn't "; *fLog << "inherit from " << "'" << classname << "'" << endl; return NULL; } // -------------------------------------------------------------------------- // // check if the object is in the list or not and check for the correct // inheritance // TObject *MParList::FindObject(const TObject *obj, const char *classname) const { TObject *nobj = fContainer->FindObject(obj); if (!nobj) return NULL; if (nobj->InheritsFrom(classname)) return nobj; *fLog << dbginf << warn << "Found object '" << nobj->GetName() << "' "; *fLog << "doesn't inherit from " << "'" << classname << "'" << endl; return NULL; } // -------------------------------------------------------------------------- // // returns the ClassName without anything which is behind that last ';' in // string. // TString MParList::GetClassName(const char *classname) { TString cname(classname); const char *semicolon = strrchr(cname, ';'); if (semicolon) cname.Remove(semicolon-cname); return cname; } // -------------------------------------------------------------------------- // // returns the ObjectName. It is created from a class and object name. // If no object name is given the objectname is the same than the // class name. Leading dots are removed from the object name // TString MParList::GetObjectName(const char *classname, const char *objname) { TString cname(classname); const char *semicolon = strrchr(cname, ';'); TString oname(objname ? objname : classname); if (semicolon) { // // Remove leading dots from objectname (eg. "MMcTrig;5.") // Int_t sz = oname.Sizeof()-2; while (sz>=0 && oname[sz]=='.') oname.Remove(sz--); } return oname; } // -------------------------------------------------------------------------- // // Find an object in the list. // 'name' is the name of the object you are searching for. // If the object doesn't exist we try to create one from the // dictionary. If this isn't possible NULL is returned. // // An object which was created automatically is deleted automatically in // the destructor of the parameter list, too. This means, that if an // object should survive (eg. Histograms) you MUST create it by yourself // and add it to the parameter list. // // By default (you don't specify an object name) the object name is // the same as the classname // // If the classname (default classname) is of the structure // "Name;something" - containing a semicolon - evarything which is // after the last appearance of a semicolon is stripped to get the // Name of the Class. Normally this is used to number your objects. // "Name;1", "Name;2", ... If a semicolon is detected leading dots // are stripped from the object-name (eg. "name;5.") // // In words: Create object of type classname and set its name to objname. // If an object with objname already exists return it. // MParContainer *MParList::FindCreateObj(const char *classname, const char *objname) { // // If now object name (name of the object to identify it in the // List) is given use it's classname as the objectname // // // Check if the classname is a 'numbered' name (like: "MTime;2") // if so strip the number from the classname. // // Becareful: We check for the last occurance of a ';' only and we // also don't check if a number follows or something else. // // Rem: I use a TString to make the code more readyble and to get // the new object deleted automatically // TString cname = GetClassName(classname); TString oname = GetObjectName(classname, objname); // // Try to find a object with this object name which is already // in the List. If we can find one we are done. // MParContainer *pcont = (MParContainer*)FindObject(oname); if (pcont) { if (pcont->InheritsFrom(cname)) return pcont; *fLog << err << "Warning: Object '" << oname << "' found in list doesn't inherit from " << cname << "." << endl; return NULL; } // // if object is not existing in the list try to create one // *fLog << inf << "Object '" << oname << "' [" << cname << "] not yet in " << GetName() << "... creating." << endl; // // try to get class from root environment // TClass *cls = gROOT->GetClass(cname); Int_t rc = 0; if (!cls) rc =1; else { if (!cls->Property()) rc = 5; if (!cls->Size()) rc = 4; if (!cls->IsLoaded()) rc = 3; if (!cls->HasDefaultConstructor()) rc = 2; } if (rc) { *fLog << err << dbginf << "Cannot create new instance of class '" << cname << "': "; switch (rc) { case 1: *fLog << "gROOT->GetClass() returned NULL." << endl; return NULL; case 2: *fLog << "no default constructor." << endl; return NULL; case 3: *fLog << "not loaded." << endl; return NULL; case 4: *fLog << "zero size." << endl; return NULL; case 5: *fLog << "no property." << endl; return NULL; } } // // create the parameter container of the the given class type // pcont = (MParContainer*)cls->New(); if (!pcont) { *fLog << " - Class has no default constructor." << endl; *fLog << " - An abstract member functions of a base class is not overwritten." << endl; return NULL; } // // Set the name of the container // pcont->SetName(oname); // // Now add the object to the parameter list // AddToList(pcont); // // The object was automatically created. This makes sure, that such an // object is deleted together with the list // fAutodelete->Add(pcont); // // Find an object in the list. // 'name' is the name of the object you are searching for. // return pcont; } // -------------------------------------------------------------------------- // // print some information about the current status of MParList // void MParList::Print(Option_t *t) const { *fLog << all << underline << GetDescriptor() << ":" << endl; MParContainer *obj = NULL; MIter Next(fContainer); while ((obj=Next())) { *fLog << " " << obj->GetDescriptor(); if (fAutodelete->FindObject(obj)) *fLog << " "; *fLog << endl; } *fLog << endl; } // -------------------------------------------------------------------------- // // Sets the flags off all containers in the list (and the list // itself) to unchanged // void MParList::SetReadyToSave(Bool_t flag) { fContainer->ForEach(MParContainer, SetReadyToSave)(flag); MParContainer::SetReadyToSave(flag); } // -------------------------------------------------------------------------- // // Reset all containers in the list // void MParList::Reset() { fContainer->ForEach(MParContainer, Reset)(); } // -------------------------------------------------------------------------- // // This finds numbered objects. The objects are returned in a copy of a // TObjArray. // // If from only is given (or to=0) object are assumed numbered // from 1 to from. // TObjArray MParList::FindObjectList(const char *name, UInt_t first, const UInt_t last) const { TObjArray list; if (first>0 && last0 && last0 && lastGetClass(cname); if (!cls) { // // if class is not existing in the root environment // gLog << dbginf << "Class '" << cname << "' not existing in dictionary." << endl; return list; } const UInt_t len = strlen(cname); char *auxname = new char[len+7]; strcpy(auxname, cname); // // If only 'from' is specified the number of entries are ment // if (first==0 && last!=0) first = 1; for (UInt_t i=first; i<=last; i++) { if (first!=0 || last!=0) sprintf(auxname+len, ";%d", i); // // create the parameter container of the the given class type // MParContainer *pcont = (MParContainer*)cls->New(); if (!pcont) { gLog << err << dbginf << "Cannot create new instance of class '" << cname << "' (Maybe no def. constructor)" << endl; return list; } // // Set the name of the container // pcont->SetName(auxname); // // Add new object to the return list // list.AddLast(pcont); } delete auxname; return list; } void MParList::SavePrimitive(ofstream &out, Option_t *o) { Bool_t saved = IsSavedAsPrimitive(); MParContainer::SavePrimitive(out); MIter Next(fContainer); MParContainer *cont = NULL; while ((cont=Next())) { // // Because it was automatically created don't store its primitive // I guess it will be automatically created again // if (fAutodelete->FindObject(cont) || cont->IsSavedAsPrimitive()) continue; cont->SavePrimitive(out, ""); out << " " << GetUniqueName() << "."; out << (cont->InheritsFrom("MTaskList") && saved ? "Replace" : "AddToList"); out << "(&" << cont->GetUniqueName() << ");" << endl << endl; } } // -------------------------------------------------------------------------- // // Implementation of SavePrimitive. Used to write the call to a constructor // to a macro. In the original root implementation it is used to write // gui elements to a macro-file. // void MParList::StreamPrimitive(ofstream &out) const { out << " MParList " << GetUniqueName(); if (fName!=gsDefName || fTitle!=gsDefTitle) { out << "(\"" << fName << "\""; if (fTitle!=gsDefTitle) out << ", \"" << fTitle << "\""; out <<")"; } out << ";" << endl << endl; } // -------------------------------------------------------------------------- // // Adds one TNamed object per object in the list. The TNamed object must // be deleted by the user. // void MParList::GetNames(TObjArray &arr) const { MParContainer::GetNames(arr); fContainer->ForEach(MParContainer, GetNames)(arr); } // -------------------------------------------------------------------------- // // Sets name and title of each object in the list from the objects in // the array. // void MParList::SetNames(TObjArray &arr) { MParContainer::SetNames(arr); fContainer->ForEach(MParContainer, SetNames)(arr); } // -------------------------------------------------------------------------- // // Read the contents/setup of a parameter container/task from a TEnv // instance (steering card/setup file). // The key to search for in the file should be of the syntax: // prefix.vname // While vname is a name which is specific for a single setup date // (variable) of this container and prefix is something like: // evtloopname.name // While name is the name of the containers/tasks in the parlist/tasklist // // eg. Job4.MImgCleanStd.CleaningLevel1: 3.0 // Job4.MImgCleanStd.CleaningLevel2: 2.5 // // If this cannot be found the next step is to search for // MImgCleanStd.CleaningLevel1: 3.0 // And if this doesn't exist, too, we search for: // CleaningLevel1: 3.0 // // Warning: The programmer is responsible for the names to be unique in // all Mars classes. // Bool_t MParList::ReadEnv(const TEnv &env, TString prefix, Bool_t print) { if (print) *fLog << all << "MParList::ReadEnv: " << prefix << " (" << (int)print << ")" << endl; MParContainer *cont = NULL; MIter Next(fContainer); while ((cont=Next())) { if (cont->InheritsFrom("MTaskList")) { if (cont->ReadEnv(env, prefix, print)==kERROR) return kERROR; continue; } // Check For: Job4.ContainerName.Varname if (print) *fLog << all << "Testing: " << prefix+cont->GetName() << endl; Bool_t rc = cont->ReadEnv(env, prefix+cont->GetName(), print); if (rc==kERROR) return kERROR; if (rc==kTRUE) continue; // Check For: Job4.MClassName.Varname if (print) *fLog << all << "Testing: " << prefix+cont->ClassName() << endl; rc = cont->ReadEnv(env, prefix+cont->ClassName(), print); if (rc==kERROR) return kERROR; if (rc==kTRUE) continue; // Check For: ContainerName.Varname if (print) *fLog << all << "Testing: " << cont->GetName() << endl; rc = cont->ReadEnv(env, cont->GetName(), print); if (rc==kERROR) return kERROR; if (rc==kTRUE) continue; // Check For: MClassName.Varname if (print) *fLog << all << "Testing: " << cont->ClassName() << endl; rc = cont->ReadEnv(env, cont->ClassName(), print); if (rc==kERROR) return kERROR; if (rc==kTRUE) continue; } return kTRUE; } // -------------------------------------------------------------------------- // // Write the contents/setup of a parameter container/task to a TEnv // instance (steering card/setup file). // The key to search for in the file should be of the syntax: // prefix.vname // While vname is a name which is specific for a single setup date // (variable) of this container and prefix is something like: // evtloopname.name // While name is the name of the containers/tasks in the parlist/tasklist // // eg. Job4.MImgCleanStd.CleaningLevel1: 3.0 // Job4.MImgCleanStd.CleaningLevel2: 2.5 // // If this cannot be found the next step is to search for // MImgCleanStd.CleaningLevel1: 3.0 // And if this doesn't exist, too, we search for: // CleaningLevel1: 3.0 // // Warning: The programmer is responsible for the names to be unique in // all Mars classes. // Bool_t MParList::WriteEnv(TEnv &env, TString prefix, Bool_t print) const { MParContainer *cont = NULL; MIter Next(fContainer); while ((cont=Next())) if (!cont->WriteEnv(env, prefix, print)) return kFALSE; return kTRUE; }