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