rivet is hosted by Hepforge, IPPP Durham
ProjectionHandler.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 #include "Rivet/Rivet.hh"
00003 #include "Rivet/Tools/Logging.hh"
00004 #include "Rivet/ProjectionHandler.hh"
00005 #include "Rivet/Cmp.hh"
00006 #include <algorithm>
00007 
00008 namespace Rivet {
00009 
00010 
00011   // Initialize instance pointer to null.
00012   ProjectionHandler* ProjectionHandler::_instance = 0;
00013 
00014   ProjectionHandler& ProjectionHandler::getInstance() {
00015     if (!_instance) {
00016       _instance = new ProjectionHandler();
00017       Log::getLog("Rivet.ProjectionHandler")
00018         << Log::TRACE << "Created new ProjectionHandler at " << _instance << endl;
00019     }
00020     return *_instance;
00021   }
00022 
00023 
00024 
00025   // Get a logger.
00026   Log& ProjectionHandler::getLog() const {
00027     return Log::getLog("Rivet.ProjectionHandler");
00028   }
00029 
00030 
00031   void ProjectionHandler::clear() {
00032     _projs.clear();
00033     _namedprojs.clear();
00034   }
00035 
00036 
00037   // Delete contained pointers.
00038   ProjectionHandler::~ProjectionHandler() {
00039     clear();
00040   }
00041 
00042 
00043 
00044   // Take a Projection, compare it to the others on record, and return (by
00045   // reference) an equivalent Projection which is guaranteed to be the
00046   // (persistent) version that will be applied to an event.
00047   const Projection& ProjectionHandler::registerProjection(const ProjectionApplier& parent,
00048                                                           const Projection& proj,
00049                                                           const string& name)
00050   {
00051     getLog() << Log::TRACE << "Trying to register"
00052              << " projection " << &proj  << " (" << proj.name() << ")"
00053              << " for parent " << &parent << " (" << parent.name() << ")"
00054              << " with name '" << name << "'" << endl;
00055 
00056     // Check for duplicate use of "name" on "parent"
00057     const bool dupOk = _checkDuplicate(parent, proj, name);
00058     if (!dupOk) {
00059       cerr << "Duplicate name '" << name << "' in parent '" << parent.name() << "'." << endl;
00060       exit(1);
00061     }
00062 
00063     // Choose which version of the projection to register with this parent and name
00064     const Projection* p = _getEquiv(proj);
00065     if (p == 0) { // a null pointer is a non-match
00066       // If there is no equivalent projection, clone proj and use the clone for registering
00067       p = _clone(proj);
00068     }
00069 
00070     // Do the registering
00071     p = _register(parent, *p, name);
00072 
00073     // Return registered proj
00074     return *p;
00075   }
00076 
00077 
00078 
00079 
00080   // Attach and retrieve a projection as a pointer.
00081   const Projection* ProjectionHandler::registerProjection(const ProjectionApplier& parent,
00082                                                           const Projection* proj,
00083                                                           const string& name) {
00084     if (proj == 0) return 0;
00085     const Projection& p = registerProjection(parent, *proj, name);
00086     return &p;
00087   }
00088 
00089 
00090 
00091   // Clone neatly
00092   const Projection* ProjectionHandler::_clone(const Projection& proj)
00093   {
00094     // Clone a new copy of the passed projection on the heap
00095     getLog() << Log::TRACE << "Cloning projection " << proj.name() << " from " << &proj << endl;
00096     const Projection* newproj = proj.clone();
00097     getLog() << Log::TRACE << "Cloned projection " << proj.name() << " at " << newproj << endl;
00098     getLog() << Log::TRACE << "Clone types " << typeid(proj).name() << " -> " << typeid(newproj).name() << endl;
00099 
00100     // Copy all the child ProjHandles when cloning, since otherwise links to "stack parents"
00101     // will be generated by their children, without any connection to the cloned parent
00102     if (&proj != newproj) {
00103       NamedProjsMap::const_iterator nps = _namedprojs.find(&proj);
00104       if (nps != _namedprojs.end()) {
00105         getLog() << Log::TRACE << "Cloning registered projections list: "
00106                  << &proj << " -> " << newproj << endl;
00107         _namedprojs[newproj] = nps->second;
00108       }
00109     }
00110 
00111     return newproj;
00112   }
00113 
00114 
00115 
00116   // Take a Projection, compare it to the others on record, and
00117   // return (by reference) an equivalent Projection which is guaranteed to be
00118   // the version that will be applied to an event.
00119   const Projection* ProjectionHandler::_register(const ProjectionApplier& parent,
00120                                                  const Projection& proj,
00121                                                  const string& name)
00122   {
00123     ProjHandle ph(&proj);
00124     getLog() << Log::TRACE << "Registering new projection at " << ph << endl;
00125 
00126     // Add the passed Projection to _projs
00127     _projs.insert(ph);
00128 
00129     // Add the ProjApplier* => name location to the associative container
00130     _namedprojs[&parent][name] = ph;
00131 
00132     return ph.get();
00133   }
00134 
00135 
00136 
00137 
00138   // Try to find a equivalent projection in the system
00139   const Projection* ProjectionHandler::_getEquiv(const Projection& proj) const
00140   {
00141     // Get class type using RTTI
00142     const std::type_info& newtype = typeid(proj);
00143     getLog() << Log::TRACE << "RTTI type of " << &proj << " is " << newtype.name() << endl;
00144 
00145     // Compare to ALL projections via _projs collection
00146     getLog() << Log::TRACE << "Comparing " << &proj
00147              << " with " << _projs.size()
00148              << " registered projection" << (_projs.size() == 1 ? "" : "s") <<  endl;
00149     foreach (const ProjHandle& ph, _projs) {
00150       // Make sure the concrete types match, using RTTI.
00151       const std::type_info& regtype = typeid(*ph);
00152       getLog() << Log::TRACE << "RTTI type comparison with " << ph << ": "
00153                << newtype.name() << " vs. " << regtype.name() << endl;
00154       if (newtype != regtype) continue;
00155       getLog() << Log::TRACE << "RTTI type matches with " << ph << endl;
00156 
00157       // Test for semantic match
00158       if (pcmp(*ph, proj) != EQUIVALENT) {
00159         getLog() << Log::TRACE << "Projections at "
00160                  << &proj << " and " << ph << " are not equivalent" << endl;
00161       } else {
00162         getLog() << Log::TRACE << "MATCH! Projections at "
00163                  << &proj << " and " << ph << " are equivalent" << endl;
00164         return ph.get();
00165       }
00166     }
00167 
00168     // If no match, just return a null pointer
00169     return 0;
00170   }
00171 
00172 
00173 
00174   string ProjectionHandler::_getStatus() const {
00175     ostringstream msg;
00176     msg << "Current projection hierarchy:" << endl;
00177     foreach (const NamedProjsMap::value_type& nps, _namedprojs) {
00178       //const string parentname = nps.first->name();
00179       msg << nps.first << endl; //"(" << parentname << ")" << endl;
00180       foreach (const NamedProjs::value_type& np, nps.second) {
00181         msg << "  " << np.second << " (" << np.second->name()
00182             << ", locally called '" << np.first << "')" << endl;
00183       }
00184       msg << endl;
00185     }
00186     return msg.str();
00187   }
00188 
00189 
00190 
00191   // Check that the same parent hasn't already used this name for something else
00192   bool ProjectionHandler::_checkDuplicate(const ProjectionApplier& parent,
00193                                           const Projection& proj,
00194                                           const string& name) const
00195   {
00196     NamedProjsMap::const_iterator ipnps = _namedprojs.find(&parent);
00197     if (ipnps != _namedprojs.end()) {
00198       const NamedProjs pnps = ipnps->second;
00199       const NamedProjs::const_iterator ipph = pnps.find(name);
00200       if (ipph != pnps.end()) {
00201         const ProjHandle pph = ipph->second;
00202         getLog() << Log::ERROR << "Projection clash! "
00203                  << parent.name() << " (" << &parent << ") "
00204                  << "is trying to overwrite its registered '" << name << "' "
00205                  << "projection (" << pph << "="
00206                  << pph->name() << ") with a non-equivalent projection "
00207                  << "(" << &proj << "=" << proj.name() << ")" << endl;
00208         getLog() << Log::ERROR << _getStatus();
00209         return false;
00210       }
00211     }
00212     return true;
00213   }
00214 
00215 
00216 
00217 
00218   void ProjectionHandler::removeProjectionApplier(ProjectionApplier& parent) {
00219     NamedProjsMap::iterator npi = _namedprojs.find(&parent);
00220     if (npi != _namedprojs.end()) _namedprojs.erase(npi);
00221     //
00222     const Projection* parentprojptr = dynamic_cast<Projection*>(&parent);
00223     if (parentprojptr) {
00224       ProjHandle parentph(parentprojptr);
00225       ProjHandles::iterator pi = find(_projs.begin(), _projs.end(), parentph);
00226       if (pi != _projs.end()) _projs.erase(pi);
00227     }
00228   }
00229 
00230 
00231 
00232 
00233   set<const Projection*> ProjectionHandler::getChildProjections(const ProjectionApplier& parent,
00234                                                                 ProjDepth depth) const
00235   {
00236     set<const Projection*> toplevel;
00237     NamedProjs nps = _namedprojs.find(&parent)->second;
00238     foreach (NamedProjs::value_type& np, nps) {
00239       toplevel.insert(np.second.get());
00240     }
00241     if (depth == SHALLOW) {
00242       // Only return the projections directly contained within the top level
00243       return toplevel;
00244     } else {
00245       // Return recursively built projection list
00246       set<const Projection*> alllevels = toplevel;
00247       foreach (const Projection* p, toplevel) {
00248         set<const Projection*> allsublevels = getChildProjections(*p, DEEP);
00249         alllevels.insert(allsublevels.begin(), allsublevels.end());
00250       }
00251       return alllevels;
00252     }
00253   }
00254 
00255 
00256 
00257 
00258   const Projection& ProjectionHandler::getProjection(const ProjectionApplier& parent,
00259                                                      const string& name) const {
00260     //getLog() << Log::TRACE << "Searching for child projection '"
00261     //         << name << "' of " << &parent << endl;
00262     NamedProjsMap::const_iterator nps = _namedprojs.find(&parent);
00263     if (nps == _namedprojs.end()) {
00264       ostringstream msg;
00265       msg << "No projections registered for parent " << &parent;
00266       throw Error(msg.str());
00267     }
00268     NamedProjs::const_iterator np = nps->second.find(name);
00269     if (np == nps->second.end()) {
00270       ostringstream msg;
00271       msg << "No projection '" << name << "' found for parent " << &parent;
00272       throw Error(msg.str());
00273     }
00274     // If it's registered with the projection handler, we must be able to safely
00275     // dereference the Projection pointer to a reference...
00276     return *(np->second);
00277   }
00278 
00279 
00280 
00281 }