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 } Generated on Tue Dec 13 2016 16:32:40 for The Rivet MC analysis system by ![]() |