ProjectionHandler.cc
Go to the documentation of this file.
00001 // -*- C++ -*- 00002 #include "Rivet/Config/RivetCommon.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 } Generated on Thu Mar 10 2016 08:29:52 for The Rivet MC analysis system by ![]() |