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