CMS 3D CMS Logo

DetSetLazyVector.h

Go to the documentation of this file.
00001 #ifndef DataFormats_Common_DetSetLazyVector_h
00002 #define DataFormats_Common_DetSetLazyVector_h
00003 
00004 /*----------------------------------------------------------------------
00005   
00006 DetSetLazyVector: A collection of homogeneous objects that can be used for
00007 an EDProduct. DetSetVector is *not* designed for use as a base class
00008 (it has no virtual functions).
00009 
00010 DetSetVector<T> contains a vector<DetSet<T> >, sorted on DetId, and
00011 provides fast (O(log n)) lookups, but only O(n) insertion.
00012 
00013 It provides an interface such that EdmRef2 can directly reference, and
00014 provide access to, individual T objects.
00015 
00016 The collection appears to the user as if it were a sequence of
00017 DetSet<T>; e.g., operator[] returns a DetSet<T>&. However, the
00018 argument to operator[] specifies the (DetId) identifier of the vector
00019 to be returned, *not* the ordinal number of the T to be returned.
00020 
00021                           ------------------
00022    It is critical that users DO NOT MODIFY the id data member of a
00023    DetSet object in a DetSetVector.
00024                           ------------------
00025 
00026 $Id: DetSetLazyVector.h,v 1.10 2008/03/31 21:12:11 wmtan Exp $
00027 
00028 ----------------------------------------------------------------------*/
00029 
00030 #include <algorithm>
00031 #include <vector>
00032 
00033 #include "boost/concept_check.hpp"
00034 #include "boost/iterator/transform_iterator.hpp"
00035 #include "boost/shared_ptr.hpp"
00036 
00037 #include "DataFormats/Common/interface/traits.h"
00038 #include "DataFormats/Common/interface/DetSet.h"
00039 #include "FWCore/Utilities/interface/EDMException.h"
00040 #include "DataFormats/Common/interface/Ref.h"
00041 
00042 namespace edm {
00043 
00044   //------------------------------------------------------------
00045   // Forward declarations
00046   template <class T> class DetSetLazyVector;
00047 
00048   //------------------------------------------------------------
00049   // Helper function, to regularize throwing of exceptions.
00050   //------------------------------------------------------------
00051 
00052   namespace dslvdetail
00053   {
00054     // Throw an edm::Exception with an appropriate message
00055     inline
00056     void _throw_range(det_id_type i)
00057   {
00058       throw edm::Exception(errors::InvalidReference)
00059       << "DetSetLazyVector::operator[] called with index not in collection;\n"
00060       << "index value: " << i;
00061   }
00062   }
00063   
00064   namespace dslv {
00065     template< typename T>
00066     class LazyGetter {
00067 public:
00068       virtual ~LazyGetter() {}
00069       virtual void fill(DetSet<T>&) = 0;
00070     };
00071     template<typename T>
00072       struct LazyAdapter : public std::unary_function<const DetSet<T>&, const DetSet<T>&> {
00073         LazyAdapter(boost::shared_ptr<LazyGetter<T> > iGetter): getter_(iGetter) {}
00074         const DetSet<T>& operator()(const DetSet<T>& iUpdate) const {
00075           if(iUpdate.data.empty() && getter_) {
00076             //NOTE: because this is 'updating a cache' we need to cast away the const
00077             DetSet<T>& temp = const_cast< DetSet<T>& >(iUpdate);
00078             getter_->fill(temp);
00079             std::sort(temp.begin(),temp.end());
00080           }
00081           return iUpdate;
00082         }
00083 private:
00084         boost::shared_ptr<LazyGetter<T> > getter_;
00085       };
00086   }
00087   //------------------------------------------------------------
00088   //
00089   namespace refhelper {
00090     template<typename T>
00091     struct FindDetSetForDetSetLazyVector : public std::binary_function<const DetSetLazyVector<T>&, edm::det_id_type, const DetSet<T>*> {
00092       typedef FindDetSetForDetSetLazyVector<T> self;
00093       typename self::result_type operator()(typename self::first_argument_type iContainer,  typename self::second_argument_type iIndex) const {
00094         return &(*(iContainer.find(iIndex)));
00095       }
00096     };
00097   }
00098   
00099   template <class T>
00100   class DetSetLazyVector 
00101   {
00104     BOOST_CLASS_REQUIRE(T, boost, LessThanComparableConcept);
00105   public:
00106 
00107     typedef DetSet<T>           detset;
00108     typedef detset              value_type;
00109     typedef std::vector<value_type> collection_type;
00110 
00111     typedef detset const&  const_reference;
00112 
00113     //iterator returns a DetSet<T> instead of a Ref<...>
00114     typedef boost::transform_iterator< dslv::LazyAdapter<T>, typename collection_type::const_iterator > const_iterator;
00115     typedef typename collection_type::size_type      size_type;
00116 
00119 
00120     // Add the following only if needed.
00121     //template <class InputIterator>
00122     //DetSetLazyVector(InputIterator b, InputIterator e);
00123 
00124     DetSetLazyVector() {}
00125     
00126     DetSetLazyVector(boost::shared_ptr<dslv::LazyGetter<T> > iGetter, const std::vector<det_id_type>& iDets) :
00127     sets_(),
00128     getter_(iGetter) {
00129         sets_.reserve(iDets.size());
00130         det_id_type sanityCheck = 0;
00131         for(std::vector<det_id_type>::const_iterator itDetId = iDets.begin(), itDetIdEnd = iDets.end();
00132             itDetId != itDetIdEnd;
00133             ++itDetId) {
00134           assert(sanityCheck <= *itDetId && "vector of det_id_type was not ordered");
00135           sanityCheck = *itDetId;
00136           sets_.push_back(DetSet<T>(*itDetId));
00137         }
00138       }
00139 
00140     void swap(DetSetLazyVector& other);
00141 
00142     //    DetSetVector& operator=(DetSetVector const& rhs);
00143 
00145     bool empty() const;
00146 
00148     size_type size() const;
00149 
00150     // Do we need a short-hand method to return the number of T
00151     // instances? If so, do we optimize for size (calculate on the
00152     // fly) or speed (keep a current cache)?
00153 
00156     const_iterator find(det_id_type id) const;
00157 
00161     const_reference operator[](det_id_type i) const;
00162 
00164     const_iterator begin() const;
00165 
00167     const_iterator end() const;
00168 
00171     //void post_insert();
00172 
00173   private:
00174     collection_type   sets_;
00175     boost::shared_ptr<dslv::LazyGetter<T> > getter_;
00176   };
00177 
00178   template <class T>
00179   inline
00180   void
00181   DetSetLazyVector<T>::swap(DetSetLazyVector<T>& other) 
00182   {
00183     sets_.swap(other.sets_);
00184     std::swap(getter_,other.getter_);
00185   }
00186 
00187   template <class T>
00188   inline
00189   bool
00190   DetSetLazyVector<T>::empty() const 
00191   {
00192     return sets_.empty();
00193   }
00194 
00195   template <class T>
00196   inline
00197   typename DetSetLazyVector<T>::size_type
00198   DetSetLazyVector<T>::size() const
00199   {
00200     return sets_.size();
00201   }
00202 
00203   template <class T>
00204   inline
00205   typename DetSetLazyVector<T>::const_iterator
00206   DetSetLazyVector<T>::find(det_id_type id) const
00207   {
00208     if(empty()) {
00209       dslv::LazyAdapter<T> adapter(getter_);
00210       return boost::make_transform_iterator(sets_.end(),adapter);
00211     }
00212     //NOTE: using collection_type::const_iterator and NOT const_iterator. We do this to avoid calling the
00213     // dereferencing operation on const_iterator which would cause the 'lazy update' to happen
00214     std::pair<typename collection_type::const_iterator,typename collection_type::const_iterator> p = 
00215     std::equal_range(sets_.begin(), sets_.end(), id);
00216     if (p.first == p.second) {
00217       dslv::LazyAdapter<T> adapter(getter_);
00218       return boost::make_transform_iterator(sets_.end(),adapter);
00219     }
00220     // The range indicated by [p.first, p.second) should be exactly of
00221     // length 1.
00222     assert(std::distance(p.first, p.second) == 1);
00223     dslv::LazyAdapter<T> adapter(getter_);
00224     return boost::make_transform_iterator(p.first,adapter);
00225   }
00226 
00227   template <class T>
00228   inline
00229   typename DetSetLazyVector<T>::const_reference
00230   DetSetLazyVector<T>::operator[](det_id_type i) const 
00231   {
00232     // Find the right DetSet, and return a reference to it.  Throw if
00233     // there is none.
00234     const_iterator it = this->find(i);
00235     if (it == this->end()) dslvdetail::_throw_range(i);
00236     return *it;
00237   }
00238 
00239   template <class T>
00240   inline
00241   typename DetSetLazyVector<T>::const_iterator
00242   DetSetLazyVector<T>::begin() const
00243   {
00244     dslv::LazyAdapter<T> adapter(getter_);
00245     return boost::make_transform_iterator(sets_.begin(),adapter);
00246   }
00247 
00248   template <class T>
00249   inline
00250   typename DetSetLazyVector<T>::const_iterator
00251   DetSetLazyVector<T>::end() const
00252   {
00253     dslv::LazyAdapter<T> adapter(getter_);
00254     return boost::make_transform_iterator(sets_.end(),adapter);
00255   }
00256 
00257   // Free swap function
00258   template <class T>
00259   inline
00260   void
00261   swap(DetSetLazyVector<T>& a, DetSetLazyVector<T>& b) 
00262   {
00263     a.swap(b);
00264   }
00265 
00266 //specialize behavior of edm::Ref to get access to the 'Det'
00267 
00268   namespace refhelper {
00269     template<typename T>
00270     struct FindForDetSetLazyVector : public std::binary_function<const DetSetLazyVector<T>&, std::pair<det_id_type, typename DetSet<T>::collection_type::size_type>, const T*> {
00271       typedef FindForDetSetLazyVector<T> self;
00272       typename self::result_type operator()(typename self::first_argument_type iContainer,  typename self::second_argument_type iIndex) {
00273         return &(*(iContainer.find(iIndex.first)->data.begin()+iIndex.second));
00274       }
00275     };
00276     
00277     template<typename T> 
00278       struct FindTrait<DetSetLazyVector<T>,T> {
00279         typedef FindForDetSetLazyVector<T> value;
00280       };
00281   }
00282   
00283    //helper function to make it easier to create a edm::Ref
00284    
00285    template<class HandleT>
00286    Ref< typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> 
00287    makeRefToDetSetLazyVector(const HandleT& iHandle, 
00288              det_id_type iDetID,
00289              typename HandleT::element_type::value_type::const_iterator itIter) {
00290       typedef typename HandleT::element_type Vec;
00291       typename Vec::value_type::collection_type::size_type index=0;
00292       typename Vec::const_iterator itFound = iHandle->find(iDetID);
00293       index += (itIter- itFound->data.begin());
00294       return    Ref< typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> (iHandle,std::make_pair(iDetID,index));
00295    }
00296    
00297    template<class HandleT>
00298    Ref< typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> 
00299    makeRefToDetSetLazyVector(const HandleT& iHandle, 
00300              det_id_type iDetID,
00301              typename HandleT::element_type::value_type::iterator itIter) {
00302       typedef typename HandleT::element_type Vec;
00303       typename Vec::detset::const_iterator itIter2 = itIter;
00304       return makeRefToDetSetLazyVector(iHandle,iDetID,itIter2);
00305    }
00306 }  
00307 #endif

Generated on Tue Jun 9 17:28:44 2009 for CMSSW by  doxygen 1.5.4