CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch13/src/DataFormats/Common/interface/DetSetVector.h

Go to the documentation of this file.
00001 #ifndef DataFormats_Common_DetSetVector_h
00002 #define DataFormats_Common_DetSetVector_h
00003 
00004 /*----------------------------------------------------------------------
00005 
00006 DetSetVector: 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 Since CMSSW 2_0_0_pre4, it is possible to skip the automatic sorting
00027 when creating a DetSetVector<T> from an already sorted vector<DetSet<T>>.
00028 If the DSV is not modified afterwards, it will no longer be sorted when
00029 it is inserted in the event.
00030 ONE NOTE OF CAUTION: it is not sufficient to to say that the vector is 
00031 sorted already.  In addition the sorting must have been done with the same
00032 criteria and obey the rules of "strict weak ordering" as will be used to
00033 find things in the collection.  Not insuring this leads to undefined
00034 behavior (usually a core dump).
00035 
00036 ----------------------------------------------------------------------*/
00037 
00038 #include <algorithm>
00039 #include <iterator>
00040 #include <vector>
00041 
00042 #include "boost/concept_check.hpp"
00043 #include "boost/mpl/if.hpp"
00044 #include "boost/bind.hpp"
00045 
00046 
00047 #include "DataFormats/Common/interface/DetSet.h"
00048 #include "DataFormats/Common/interface/FillView.h"
00049 #include "DataFormats/Common/interface/Ref.h"
00050 #include "DataFormats/Common/interface/traits.h"
00051 
00052 #include "FWCore/Utilities/interface/EDMException.h"
00053 
00054 #include "DataFormats/Common/interface/BoolCache.h"
00055 
00056 namespace edm {
00057   class ProductID;
00058 
00059   //------------------------------------------------------------
00060   // Forward declarations
00061   template <class T> class DetSetVector;
00062 
00063   //------------------------------------------------------------
00064   // Helper function, to regularize throwing of exceptions.
00065   //------------------------------------------------------------
00066 
00067   namespace detail {
00068     // Throw an edm::Exception with an appropriate message
00069     inline
00070     void _throw_range(det_id_type i) {
00071       Exception::throwThis(errors::InvalidReference,
00072         "DetSetVector::operator[] called with index not in collection;\nindex value: ", i);
00073     }
00074   }
00075 
00076   //------------------------------------------------------------
00077   //
00078 
00079   // If DetSetVector<T> is instantiated with a class T which inherits
00080   // from DoNotSortUponInsertion, the resulting class inherits from
00081   // DoNotSortUponInsertion. In the normal case, DetSetVector<T>
00082   // inherits from Other.  (This is necessary to assure that
00083   // DetSetVector<T> is not sorted upon insertion into the Event when
00084   // T is defined to inherit from DoNotSortUponInsertion).
00085 
00086   template <class T>
00087   class DetSetVector : 
00088     public boost::mpl::if_c<boost::is_base_of<edm::DoNotSortUponInsertion, T>::value,
00089                             edm::DoNotSortUponInsertion,
00090                             Other>::type
00091   {
00094     BOOST_CLASS_REQUIRE(T, boost, LessThanComparableConcept);
00095   public:
00096 
00097     typedef DetSet<T>           detset;
00098     typedef detset              value_type;
00099     typedef std::vector<detset> collection_type;
00100 
00101     typedef detset&        reference;
00102     typedef detset const&  const_reference;
00103 
00104     typedef typename collection_type::iterator       iterator;
00105     typedef typename collection_type::const_iterator const_iterator;
00106     typedef typename collection_type::size_type      size_type;
00107 
00110 
00112     DetSetVector();
00113 
00125     explicit DetSetVector(std::vector<DetSet<T> > & input, bool alreadySorted=false);
00126 
00127 
00128     void swap(DetSetVector& other);
00129 
00130     DetSetVector& operator= (DetSetVector const& other);
00131 
00133     // What should happen if there is already a DetSet with this
00134     // DetId? Right now, it is up to the user *not* to do this. If you
00135     // are unsure whether or not your DetId is already in the
00136     // DetSetVector, then use 'find_or_insert(id)' instead.
00137     void insert(detset const& s);
00138 
00142     reference find_or_insert(det_id_type id);
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     iterator       find(det_id_type id);
00157     const_iterator find(det_id_type id) const;
00158 
00162     reference       operator[](det_id_type  i);
00163     const_reference operator[](det_id_type i) const;
00164 
00166     iterator       begin();
00167     const_iterator begin() const;
00168 
00170     iterator       end();
00171     const_iterator end() const;
00172 
00175     void getIds(std::vector<det_id_type> & result) const;
00176 
00179     void post_insert();
00180 
00181     void fillView(ProductID const& id,
00182                   std::vector<void const*>& pointers,
00183                   helper_vector& helpers) const;
00184 
00185   private:
00186     collection_type   _sets;
00187     edm::BoolCache    _alreadySorted; 
00188 
00190     void _sort();
00191 
00192   };
00193 
00194   template <class T>
00195   inline
00196   DetSetVector<T>::DetSetVector() :
00197     _sets()
00198   { }
00199 
00200   template <class T>
00201   inline
00202   DetSetVector<T>::DetSetVector(std::vector<DetSet<T> > & input, bool alreadySorted) :
00203     _sets(), _alreadySorted(alreadySorted)
00204   {
00205     _sets.swap(input);
00206     if (!alreadySorted) _sort();
00207   }
00208 
00209   template <class T>
00210   inline
00211   void
00212   DetSetVector<T>::swap(DetSetVector<T>& other) {
00213     _sets.swap(other._sets);
00214     bool tmp = _alreadySorted; _alreadySorted = other._alreadySorted; other._alreadySorted = tmp;
00215   }
00216 
00217   template <class T>
00218   inline
00219   DetSetVector<T>&
00220   DetSetVector<T>::operator= (DetSetVector<T> const& other)
00221   {
00222     DetSetVector<T> temp(other);
00223     swap(temp);
00224     return *this;
00225   }
00226 
00227   template <class T>
00228   inline
00229   void
00230   DetSetVector<T>::insert(detset const& t) {
00231     _alreadySorted = false; // we don't know if the DetSet we're adding is already sorted
00232     // Implementation provided by the Performance Task Force.
00233     _sets.insert(std::lower_bound(_sets.begin(),
00234                                   _sets.end(),
00235                                   t),
00236                  t);
00237 #if 0
00238     // It seems we have to sort on each insertion, because we may
00239     // perform lookups during construction.
00240     _sets.push_back(t);
00241 
00242     _sort();
00243 #endif
00244   }
00245 
00246   template <class T>
00247   inline
00248   typename DetSetVector<T>::reference
00249   DetSetVector<T>::find_or_insert(det_id_type id) {
00250     // NOTE: we don't have to clear _alreadySorted: the new DS is empty, 
00251     //       and gets inserted in the correct place
00252     std::pair<iterator,iterator> p =
00253       std::equal_range(_sets.begin(), _sets.end(), id);
00254 
00255     // If the range isn't empty, we already have the right thing;
00256     // return a reference to it...
00257     if (p.first != p.second) return *p.first;
00258 
00259     // Insert the right thing, in the right place, and return a
00260     // reference to the newly inserted thing.
00261     return *(_sets.insert(p.first, detset(id)));
00262   }
00263 
00264   template <class T>
00265   inline
00266   bool
00267   DetSetVector<T>::empty() const {
00268     return _sets.empty();
00269   }
00270 
00271   template <class T>
00272   inline
00273   typename DetSetVector<T>::size_type
00274   DetSetVector<T>::size() const {
00275     return _sets.size();
00276   }
00277 
00278   template <class T>
00279   inline
00280   typename DetSetVector<T>::iterator
00281   DetSetVector<T>::find(det_id_type id) {
00282     _alreadySorted = false; // it's non const 
00283     std::pair<iterator,iterator> p =
00284       std::equal_range(_sets.begin(), _sets.end(), id);
00285     if (p.first == p.second) return _sets.end();
00286 
00287     // The range indicated by [p.first, p.second) should be exactly of
00288     // length 1. It seems likely we don't want to take the time hit of
00289     // checking this, but here is the appropriate test... We can turn
00290     // it on if we need the debugging aid.
00291     #if 0
00292     assert(std::distance(p.first, p.second) == 1);
00293     #endif
00294 
00295     return p.first;
00296   }
00297 
00298   template <class T>
00299   inline
00300   typename DetSetVector<T>::const_iterator
00301   DetSetVector<T>::find(det_id_type id) const {
00302     std::pair<const_iterator,const_iterator> p =
00303       std::equal_range(_sets.begin(), _sets.end(), id);
00304     if (p.first == p.second) return _sets.end();
00305     // The range indicated by [p.first, p.second) should be exactly of
00306     // length 1.
00307     assert(std::distance(p.first, p.second) == 1);
00308     return p.first;
00309   }
00310 
00311   template <class T>
00312   inline
00313   typename DetSetVector<T>::reference
00314   DetSetVector<T>::operator[](det_id_type i) {
00315     _alreadySorted = false; // it's non const 
00316     // Find the right DetSet, and return a reference to it.  Throw if
00317     // there is none.
00318     iterator it = this->find(i);
00319     if (it == this->end()) detail::_throw_range(i);
00320     return *it;
00321   }
00322 
00323   template <class T>
00324   inline
00325   typename DetSetVector<T>::const_reference
00326   DetSetVector<T>::operator[](det_id_type i) const {
00327     // Find the right DetSet, and return a reference to it.  Throw if
00328     // there is none.
00329     const_iterator it = this->find(i);
00330     if (it == this->end()) detail::_throw_range(i);
00331     return *it;
00332   }
00333 
00334   template <class T>
00335   inline
00336   typename DetSetVector<T>::iterator
00337   DetSetVector<T>::begin() {
00338     _alreadySorted = false; // it's non const 
00339     return _sets.begin();
00340   }
00341 
00342   template <class T>
00343   inline
00344   typename DetSetVector<T>::const_iterator
00345   DetSetVector<T>::begin() const {
00346     return _sets.begin();
00347   }
00348 
00349   template <class T>
00350   inline
00351   typename DetSetVector<T>::iterator
00352   DetSetVector<T>::end() {
00353     _alreadySorted = false; // it's non const 
00354     return _sets.end();
00355   }
00356 
00357   template <class T>
00358   inline
00359   typename DetSetVector<T>::const_iterator
00360   DetSetVector<T>::end() const {
00361     return _sets.end();
00362   }
00363 
00364 
00365   template <class T>
00366   inline
00367   void
00368   DetSetVector<T>::getIds(std::vector<det_id_type> & result) const
00369   {
00370     std::transform(this->begin(), this->end(),
00371                    std::back_inserter(result),
00372                    boost::bind(&DetSet<T>::id,_1));
00373   }
00374 
00375   template <class T>
00376   inline
00377   void
00378   DetSetVector<T>::post_insert() {
00379     if (_alreadySorted) return; 
00380     typename collection_type::iterator i = _sets.begin();
00381     typename collection_type::iterator e = _sets.end();
00382     // For each DetSet...
00383     for (; i != e; ++i) {
00384       // sort the Detset pointed to by
00385       std::sort(i->data.begin(), i->data.end());
00386     }
00387   }
00388 
00389   template <class T>
00390   inline
00391   void
00392   DetSetVector<T>::_sort() {
00393     std::sort(_sets.begin(), _sets.end());
00394   }
00395 
00396   template<class T>
00397   void DetSetVector<T>::fillView(ProductID const& id,
00398                                  std::vector<void const*>& pointers,
00399                                  helper_vector& helpers) const
00400   {
00401     detail::reallyFillView(*this, id, pointers, helpers);
00402   }
00403 
00404   //----------------------------------------------------------------------
00405   //
00406   // Free function template to support creation of Views.
00407 
00408   template <class T>
00409   inline
00410   void
00411   fillView(DetSetVector<T> const& obj,
00412            ProductID const& id,
00413            std::vector<void const*>& pointers,
00414            helper_vector& helpers)
00415   {
00416     obj.fillView(id, pointers, helpers);
00417   }
00418 
00419   template <class T>
00420   struct has_fillView<edm::DetSetVector<T> >
00421   {
00422     static bool const value = true;
00423   };
00424 
00425 
00426   // Free swap function
00427   template <class T>
00428   inline
00429   void
00430   swap(DetSetVector<T>& a, DetSetVector<T>& b) 
00431   {
00432     a.swap(b);
00433   }
00434 
00435 }
00436 
00437 
00438 //specialize behavior of edm::Ref to get access to the 'Det'
00439 namespace edm {
00440 
00441   namespace refhelper {
00442     template<typename T>
00443     class FindForDetSetVector : public std::binary_function<const DetSetVector<T>&, std::pair<det_id_type, typename DetSet<T>::collection_type::size_type>, const T*> {
00444     public:
00445       typedef FindForDetSetVector<T> self;
00446       typename self::result_type operator()(typename self::first_argument_type iContainer, typename self::second_argument_type iIndex) {
00447         return &(*(iContainer.find(iIndex.first)->data.begin()+iIndex.second));
00448       }
00449     };
00450 
00451     template<typename T>
00452       struct FindTrait<DetSetVector<T>,T> {
00453         typedef FindForDetSetVector<T> value;
00454       };
00455   }
00456 
00457    //helper function to make it easier to create a edm::Ref
00458 
00459   template<class HandleT>
00460   Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>
00461   makeRefTo(const HandleT& iHandle,
00462              det_id_type iDetID,
00463              typename HandleT::element_type::value_type::const_iterator itIter) {
00464     typedef typename HandleT::element_type Vec;
00465     typename Vec::value_type::collection_type::size_type index=0;
00466     typename Vec::const_iterator itFound = iHandle->find(iDetID);
00467     if(itFound == iHandle->end()) {
00468       Exception::throwThis(errors::InvalidReference,
00469         "an edm::Ref to an edm::DetSetVector was given a DetId, ", iDetID, ", that is not in the DetSetVector");
00470     }
00471     index += (itIter- itFound->data.begin());
00472     if(index >= itFound->data.size()) {
00473       Exception::throwThis(errors::InvalidReference,
00474         "an edm::Ref to a edm::DetSetVector is being made with an interator that is not part of the edm::DetSet itself");
00475     }
00476     return Ref<typename HandleT::element_type,
00477                typename HandleT::element_type::value_type::value_type>
00478               (iHandle,std::make_pair(iDetID,index));
00479   }
00480 
00481   template<class HandleT>
00482   Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>
00483   makeRefToDetSetVector(const HandleT& iHandle,
00484              det_id_type iDetID,
00485              typename HandleT::element_type::value_type::iterator itIter) {
00486     typedef typename HandleT::element_type Vec;
00487     typename Vec::detset::const_iterator itIter2 = itIter;
00488     return makeRefTo(iHandle,iDetID,itIter2);
00489   }
00490 }
00491 #endif