00001
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
00012 ProjectionHandler* ProjectionHandler::_instance = 0;
00013
00014
00015
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
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
00048 ProjectionHandler::~ProjectionHandler() {
00049 clear();
00050 }
00051
00052
00053
00054
00055
00056
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
00067 const bool dupOk = _checkDuplicate(parent, proj, name);
00068 if (!dupOk) exit(1);
00069
00070
00071 const Projection* p = _getEquiv(proj);
00072 if (p == 0) {
00073
00074 p = _clone(proj);
00075 }
00076
00077
00078 p = _register(parent, *p, name);
00079
00080
00081 return *p;
00082 }
00083
00084
00085
00086
00087
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
00099 const Projection* ProjectionHandler::_clone(const Projection& proj)
00100 {
00101
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
00108
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
00124
00125
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
00134 _projs.insert(ph);
00135
00136
00137 _namedprojs[&parent][name] = ph;
00138
00139 return ph.get();
00140 }
00141
00142
00143
00144
00145
00146 const Projection* ProjectionHandler::_getEquiv(const Projection& proj) const
00147 {
00148
00149 const std::type_info& newtype = typeid(proj);
00150 getLog() << Log::TRACE << "RTTI type of " << &proj << " is " << newtype.name() << endl;
00151
00152
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
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
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
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
00186 msg << nps.first << 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
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
00250 return toplevel;
00251 } else {
00252
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
00268
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
00282
00283 return *(np->second);
00284 }
00285
00286
00287
00288 }