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 /// Singleton deletion function 00105 static void destroy(); 00106 00107 00108 public: 00109 00110 /// @name Projection registration 00111 //@{ 00112 /// Attach and retrieve a projection as a reference. 00113 const Projection& registerProjection(const ProjectionApplier& parent, 00114 const Projection& proj, 00115 const string& name); 00116 00117 /// Attach and retrieve a projection as a pointer. 00118 const Projection* registerProjection(const ProjectionApplier& parent, 00119 const Projection* proj, 00120 const string& name); 00121 //@} 00122 00123 00124 private: 00125 00126 /// @name Projection registration internal helpers 00127 //@{ 00128 00129 /// Try to get an equivalent projection from the system 00130 /// @returns 0 if no equivalent projection found 00131 const Projection* _getEquiv(const Projection& proj) const; 00132 00133 /// Make a clone of proj, copying across child references from the original 00134 const Projection* _clone(const Projection& proj); 00135 00136 /// Internal function to do the registering 00137 const Projection* _register(const ProjectionApplier& parent, 00138 const Projection& proj, 00139 const string& name); 00140 00141 /// Get a string dump of the current ProjHandler structure 00142 string _getStatus() const; 00143 00144 /// Check that this parent projection doesn't already use this name 00145 bool _checkDuplicate(const ProjectionApplier& parent, 00146 const Projection& proj, 00147 const string& name) const; 00148 00149 //@} 00150 00151 00152 public: 00153 00154 /// @name Projection retrieval. */ 00155 //@{ 00156 00157 /// Retrieve a named projection for the given parent. Returning as a 00158 /// reference is partly to discourage ProjectionApplier classes from storing 00159 /// pointer members to the registered projections, since that can lead to 00160 /// problems and there is no need to do so. 00161 const Projection& getProjection(const ProjectionApplier& parent, 00162 const string& name) const; 00163 00164 /// Get child projections for the given parent. By default this will just 00165 /// return the projections directly contained by the @a parent, but the @a 00166 /// depth argument can be changed to do a deep retrieval, which will recurse 00167 /// through the whole projection chain. In this case, there is no protection 00168 /// against getting stuck in a circular projection dependency loop. 00169 set<const Projection*> getChildProjections(const ProjectionApplier& parent, 00170 ProjDepth depth=SHALLOW) const; 00171 //@} 00172 00173 00174 /// Projection clearing method: deletes all known projections and empties 00175 /// the reference collections. 00176 void clear(); 00177 00178 00179 private: 00180 00181 /// Remove a ProjectionApplier: designed to only be called by ~ProjectionApplier (as a friend) 00182 void removeProjectionApplier(ProjectionApplier& parent); 00183 00184 00185 private: 00186 00187 /// Get a logger. 00188 Log& getLog() const; 00189 00190 00191 // /// Get map of named projections belonging to @a parent. 00192 // /// Throws an exception if @a parent has not got any registered projections. 00193 // const NamedProjs& namedProjs(const ProjectionApplier* parent) const { 00194 // NamedProjsMap::const_iterator nps = _namedprojs.find(parent); 00195 // if (nps == _namedprojs.end()) { 00196 // stringstream ss; 00197 // ss << "No NamedProjs registered for parent " << parent; 00198 // throw Error(ss.str()); 00199 // } 00200 // return *nps; 00201 // } 00202 00203 00204 }; 00205 00206 00207 } 00208 00209 #endif