00001 // -*- C++ -*- 00002 #ifndef RIVET_ProjectionHandler_HH 00003 #define RIVET_ProjectionHandler_HH 00004 00005 #include "Rivet/Rivet.hh" 00006 #include "Rivet/RivetBoost.hh" 00007 #include "Rivet/Tools/Logging.fhh" 00008 #include "Rivet/ProjectionApplier.fhh" 00009 #include "Rivet/Projection.fhh" 00010 00011 namespace Rivet { 00012 00013 00014 /// Typedef for Projection (smart) pointer 00015 typedef shared_ptr<const Projection> ProjHandle; 00016 00017 // Forward declaration. 00018 class ProjectionApplier; 00019 00020 /// @brief The projection handler is a central repository for projections to be used 00021 /// in a Rivet analysis run. 00022 /// 00023 /// Without centralised projections, it can be hard to know which of an 00024 /// equivalent set of projections will be run on a particular event. In turn, 00025 /// this may mean that certain projections in the chain can go out of scope 00026 /// unexpectedly. There were originally also the issues that projections may 00027 /// need to be held as member pointers to an abstract base class, since 00028 /// post-construction setup is needed; that projections contained pointers to 00029 /// their own dependency chain, which could go out of scope; and that 00030 /// projection members could be modified after being applied to an event 00031 /// which, due to the caching model, would have unpredictable consequences. 00032 /// 00033 /// By centralising all the projections, these issues are eliminated, as well 00034 /// as allowing analysis classes to contain fewer data members (since 00035 /// projections are now better accessed by name than by storing a data member 00036 /// reference or pointer). 00037 /// 00038 /// The core of the ProjectionHandler design is that it is a singleton class, 00039 /// essentially a wrapper around a map of @c Projection*, indexed by a hash of 00040 /// the registering object and its local name for the registered projection. 00041 /// 00042 class ProjectionHandler { 00043 public: 00044 00045 /// ProjectionApplier's destructor needs to trigger cleaning up the proj handler repo 00046 friend class ProjectionApplier; 00047 00048 /// Typedef for a vector of Projection pointers. 00049 typedef set<ProjHandle> ProjHandles; 00050 00051 /// @brief Typedef for the structure used to contain named projections for a 00052 /// particular containing Analysis or Projection. 00053 typedef map<const string, ProjHandle> NamedProjs; 00054 00055 /// Enum to specify depth of projection search. 00056 enum ProjDepth { SHALLOW, DEEP }; 00057 00058 00059 private: 00060 00061 /// Structure used to map a containing Analysis or Projection to its set of 00062 /// contained projections. 00063 typedef map<const ProjectionApplier*, NamedProjs> NamedProjsMap; 00064 00065 /// Core data member, associating a given containing class (via a 00066 /// ProjectionApplier pointer) to its contained projections. 00067 NamedProjsMap _namedprojs; 00068 00069 /// Cache of {@link Projection}s for reverse lookup, to speed up registering 00070 /// new projections as @c _namedprojs gets large. 00071 ProjHandles _projs; 00072 00073 00074 private: 00075 00076 /// Private destructor means no inheritance from this class. 00077 ~ProjectionHandler(); 00078 00079 /// The assignment operator is hidden. 00080 ProjectionHandler& operator=(const ProjectionHandler&); 00081 00082 /// The copy constructor is hidden. 00083 ProjectionHandler(const ProjectionHandler&); 00084 00085 00086 private: 00087 00088 /// @name Construction. */ 00089 //@{ 00090 /// The standard constructor. 00091 ProjectionHandler() { } 00092 //@} 00093 00094 /// Singleton instance 00095 /// @todo Threading? 00096 static ProjectionHandler* _instance; 00097 00098 00099 public: 00100 00101 /// Singleton creation function 00102 static ProjectionHandler* create(); 00103 00104 00105 public: 00106 00107 /// @name Projection registration 00108 //@{ 00109 /// Attach and retrieve a projection as a reference. 00110 const Projection& registerProjection(const ProjectionApplier& parent, 00111 const Projection& proj, 00112 const string& name); 00113 00114 /// Attach and retrieve a projection as a pointer. 00115 const Projection* registerProjection(const ProjectionApplier& parent, 00116 const Projection* proj, 00117 const string& name); 00118 //@} 00119 00120 00121 private: 00122 00123 /// @name Projection registration internal helpers 00124 //@{ 00125 00126 /// Try to get an equivalent projection from the system 00127 /// @returns 0 if no equivalent projection found 00128 const Projection* _getEquiv(const Projection& proj) const; 00129 00130 /// Make a clone of proj, copying across child references from the original 00131 const Projection* _clone(const ProjectionApplier& parent, 00132 const Projection& proj); 00133 00134 /// Internal function to do the registering 00135 const Projection* _register(const ProjectionApplier& parent, 00136 const Projection& proj, 00137 const string& name); 00138 00139 /// Get a string dump of the current ProjHandler structure 00140 string _getStatus() const; 00141 00142 /// Check that this parent projection doesn't already use this name 00143 bool _checkDuplicate(const ProjectionApplier& parent, 00144 const Projection& proj, 00145 const string& name) const; 00146 00147 //@} 00148 00149 00150 public: 00151 00152 /// @name Projection retrieval. */ 00153 //@{ 00154 00155 /// Retrieve a named projection for the given parent. Returning as a 00156 /// reference is partly to discourage ProjectionApplier classes from storing 00157 /// pointer members to the registered projections, since that can lead to 00158 /// problems and there is no need to do so. 00159 const Projection& getProjection(const ProjectionApplier& parent, 00160 const string& name) const; 00161 00162 /// Get child projections for the given parent. By default this will just 00163 /// return the projections directly contained by the @a parent, but the @a 00164 /// depth argument can be changed to do a deep retrieval, which will recurse 00165 /// through the whole projection chain. In this case, there is no protection 00166 /// against getting stuck in a circular projection dependency loop. 00167 set<const Projection*> getChildProjections(const ProjectionApplier& parent, 00168 ProjDepth depth=SHALLOW) const; 00169 //@} 00170 00171 00172 /// Projection clearing method: deletes all known projections and empties 00173 /// the reference collections. 00174 void clear(); 00175 00176 00177 private: 00178 00179 /// Remove a ProjectionApplier: designed to only be called by ~ProjectionApplier (as a friend) 00180 void removeProjectionApplier(ProjectionApplier& parent); 00181 00182 00183 private: 00184 00185 /// Get a logger. 00186 Log& getLog() const; 00187 00188 00189 // /// Get map of named projections belonging to @a parent. 00190 // /// Throws an exception if @a parent has not got any registered projections. 00191 // const NamedProjs& namedProjs(const ProjectionApplier* parent) const { 00192 // NamedProjsMap::const_iterator nps = _namedprojs.find(parent); 00193 // if (nps == _namedprojs.end()) { 00194 // stringstream ss; 00195 // ss << "No NamedProjs registered for parent " << parent; 00196 // throw Error(ss.str()); 00197 // } 00198 // return *nps; 00199 // } 00200 00201 00202 }; 00203 00204 00205 } 00206 00207 #endif