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