CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/DataFormats/Common/interface/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 ----------------------------------------------------------------------*/
00027 
00028 #include <algorithm>
00029 #include <vector>
00030 
00031 #include "boost/concept_check.hpp"
00032 #include "boost/iterator/transform_iterator.hpp"
00033 #include "boost/shared_ptr.hpp"
00034 
00035 #include "DataFormats/Common/interface/traits.h"
00036 #include "DataFormats/Common/interface/DetSet.h"
00037 #include "FWCore/Utilities/interface/EDMException.h"
00038 #include "DataFormats/Common/interface/Ref.h"
00039 
00040 namespace edm {
00041 
00042   //------------------------------------------------------------
00043   // Forward declarations
00044   template <class T> class DetSetLazyVector;
00045 
00046   //------------------------------------------------------------
00047   // Helper function, to regularize throwing of exceptions.
00048   //------------------------------------------------------------
00049 
00050   namespace dslvdetail
00051   {
00052     // Throw an edm::Exception with an appropriate message
00053     inline
00054     void _throw_range(det_id_type i)
00055   {
00056       Exception::throwThis(errors::InvalidReference,
00057         "DetSetLazyVector::operator[] called with index not in collection;\nindex value: ", i);
00058   }
00059   }
00060   
00061   namespace dslv {
00062     template< typename T>
00063     class LazyGetter {
00064 public:
00065       virtual ~LazyGetter() {}
00066       virtual void fill(DetSet<T>&) = 0;
00067     };
00068     template<typename T>
00069       struct LazyAdapter : public std::unary_function<const DetSet<T>&, const DetSet<T>&> {
00070         LazyAdapter(boost::shared_ptr<LazyGetter<T> > iGetter): getter_(iGetter) {}
00071         const DetSet<T>& operator()(const DetSet<T>& iUpdate) const {
00072           if(iUpdate.data.empty() && getter_) {
00073             //NOTE: because this is 'updating a cache' we need to cast away the const
00074             DetSet<T>& temp = const_cast< DetSet<T>& >(iUpdate);
00075             getter_->fill(temp);
00076             std::sort(temp.begin(),temp.end());
00077           }
00078           return iUpdate;
00079         }
00080 private:
00081         boost::shared_ptr<LazyGetter<T> > getter_;
00082       };
00083   }
00084   //------------------------------------------------------------
00085   //
00086   namespace refhelper {
00087     template<typename T>
00088     struct FindDetSetForDetSetLazyVector : public std::binary_function<const DetSetLazyVector<T>&, edm::det_id_type, const DetSet<T>*> {
00089       typedef FindDetSetForDetSetLazyVector<T> self;
00090       typename self::result_type operator()(typename self::first_argument_type iContainer,  typename self::second_argument_type iIndex) const {
00091         return &(*(iContainer.find(iIndex)));
00092       }
00093     };
00094   }
00095   
00096   template <class T>
00097   class DetSetLazyVector 
00098   {
00101     BOOST_CLASS_REQUIRE(T, boost, LessThanComparableConcept);
00102   public:
00103 
00104     typedef DetSet<T>           detset;
00105     typedef detset              value_type;
00106     typedef std::vector<value_type> collection_type;
00107 
00108     typedef detset const&  const_reference;
00109 
00110     //iterator returns a DetSet<T> instead of a Ref<...>
00111     typedef boost::transform_iterator< dslv::LazyAdapter<T>, typename collection_type::const_iterator > const_iterator;
00112     typedef typename collection_type::size_type      size_type;
00113 
00116 
00117     // Add the following only if needed.
00118     //template <class InputIterator>
00119     //DetSetLazyVector(InputIterator b, InputIterator e);
00120 
00121     DetSetLazyVector() {}
00122     
00123     DetSetLazyVector(boost::shared_ptr<dslv::LazyGetter<T> > iGetter, const std::vector<det_id_type>& iDets) :
00124     sets_(),
00125     getter_(iGetter) {
00126         sets_.reserve(iDets.size());
00127         det_id_type sanityCheck = 0;
00128         for(std::vector<det_id_type>::const_iterator itDetId = iDets.begin(), itDetIdEnd = iDets.end();
00129             itDetId != itDetIdEnd;
00130             ++itDetId) {
00131           assert(sanityCheck <= *itDetId && "vector of det_id_type was not ordered");
00132           sanityCheck = *itDetId;
00133           sets_.push_back(DetSet<T>(*itDetId));
00134         }
00135       }
00136 
00137     void swap(DetSetLazyVector& other);
00138 
00139     //    DetSetVector& operator=(DetSetVector const& rhs);
00140 
00142     bool empty() const;
00143 
00145     size_type size() const;
00146 
00147     // Do we need a short-hand method to return the number of T
00148     // instances? If so, do we optimize for size (calculate on the
00149     // fly) or speed (keep a current cache)?
00150 
00153     const_iterator find(det_id_type id) const;
00154 
00158     const_reference operator[](det_id_type i) const;
00159 
00161     const_iterator begin() const;
00162 
00164     const_iterator end() const;
00165 
00168     //void post_insert();
00169 
00170   private:
00171     collection_type   sets_;
00172     boost::shared_ptr<dslv::LazyGetter<T> > getter_;
00173   };
00174 
00175   template <class T>
00176   inline
00177   void
00178   DetSetLazyVector<T>::swap(DetSetLazyVector<T>& other) 
00179   {
00180     sets_.swap(other.sets_);
00181     std::swap(getter_,other.getter_);
00182   }
00183 
00184   template <class T>
00185   inline
00186   bool
00187   DetSetLazyVector<T>::empty() const 
00188   {
00189     return sets_.empty();
00190   }
00191 
00192   template <class T>
00193   inline
00194   typename DetSetLazyVector<T>::size_type
00195   DetSetLazyVector<T>::size() const
00196   {
00197     return sets_.size();
00198   }
00199 
00200   template <class T>
00201   inline
00202   typename DetSetLazyVector<T>::const_iterator
00203   DetSetLazyVector<T>::find(det_id_type id) const
00204   {
00205     if(empty()) {
00206       dslv::LazyAdapter<T> adapter(getter_);
00207       return boost::make_transform_iterator(sets_.end(),adapter);
00208     }
00209     //NOTE: using collection_type::const_iterator and NOT const_iterator. We do this to avoid calling the
00210     // dereferencing operation on const_iterator which would cause the 'lazy update' to happen
00211     std::pair<typename collection_type::const_iterator,typename collection_type::const_iterator> p = 
00212     std::equal_range(sets_.begin(), sets_.end(), id);
00213     if (p.first == p.second) {
00214       dslv::LazyAdapter<T> adapter(getter_);
00215       return boost::make_transform_iterator(sets_.end(),adapter);
00216     }
00217     // The range indicated by [p.first, p.second) should be exactly of
00218     // length 1.
00219     assert(std::distance(p.first, p.second) == 1);
00220     dslv::LazyAdapter<T> adapter(getter_);
00221     return boost::make_transform_iterator(p.first,adapter);
00222   }
00223 
00224   template <class T>
00225   inline
00226   typename DetSetLazyVector<T>::const_reference
00227   DetSetLazyVector<T>::operator[](det_id_type i) const 
00228   {
00229     // Find the right DetSet, and return a reference to it.  Throw if
00230     // there is none.
00231     const_iterator it = this->find(i);
00232     if (it == this->end()) dslvdetail::_throw_range(i);
00233     return *it;
00234   }
00235 
00236   template <class T>
00237   inline
00238   typename DetSetLazyVector<T>::const_iterator
00239   DetSetLazyVector<T>::begin() const
00240   {
00241     dslv::LazyAdapter<T> adapter(getter_);
00242     return boost::make_transform_iterator(sets_.begin(),adapter);
00243   }
00244 
00245   template <class T>
00246   inline
00247   typename DetSetLazyVector<T>::const_iterator
00248   DetSetLazyVector<T>::end() const
00249   {
00250     dslv::LazyAdapter<T> adapter(getter_);
00251     return boost::make_transform_iterator(sets_.end(),adapter);
00252   }
00253 
00254   // Free swap function
00255   template <class T>
00256   inline
00257   void
00258   swap(DetSetLazyVector<T>& a, DetSetLazyVector<T>& b) 
00259   {
00260     a.swap(b);
00261   }
00262 
00263 //specialize behavior of edm::Ref to get access to the 'Det'
00264 
00265   namespace refhelper {
00266     template<typename T>
00267     struct FindForDetSetLazyVector : public std::binary_function<const DetSetLazyVector<T>&, std::pair<det_id_type, typename DetSet<T>::collection_type::size_type>, const T*> {
00268       typedef FindForDetSetLazyVector<T> self;
00269       typename self::result_type operator()(typename self::first_argument_type iContainer,  typename self::second_argument_type iIndex) {
00270         return &(*(iContainer.find(iIndex.first)->data.begin()+iIndex.second));
00271       }
00272     };
00273     
00274     template<typename T> 
00275       struct FindTrait<DetSetLazyVector<T>,T> {
00276         typedef FindForDetSetLazyVector<T> value;
00277       };
00278   }
00279   
00280    //helper function to make it easier to create a edm::Ref
00281    
00282    template<class HandleT>
00283    Ref< typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> 
00284    makeRefToDetSetLazyVector(const HandleT& iHandle, 
00285              det_id_type iDetID,
00286              typename HandleT::element_type::value_type::const_iterator itIter) {
00287       typedef typename HandleT::element_type Vec;
00288       typename Vec::value_type::collection_type::size_type index=0;
00289       typename Vec::const_iterator itFound = iHandle->find(iDetID);
00290       index += (itIter- itFound->data.begin());
00291       return    Ref< typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> (iHandle,std::make_pair(iDetID,index));
00292    }
00293    
00294    template<class HandleT>
00295    Ref< typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> 
00296    makeRefToDetSetLazyVector(const HandleT& iHandle, 
00297              det_id_type iDetID,
00298              typename HandleT::element_type::value_type::iterator itIter) {
00299       typedef typename HandleT::element_type Vec;
00300       typename Vec::detset::const_iterator itIter2 = itIter;
00301       return makeRefToDetSetLazyVector(iHandle,iDetID,itIter2);
00302    }
00303 }  
00304 #endif