CMS 3D CMS Logo

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

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