Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-12 23:29:41

0001 #ifndef DataFormats_Common_DetSetVector_h
0002 #define DataFormats_Common_DetSetVector_h
0003 
0004 /*----------------------------------------------------------------------
0005 
0006 DetSetVector: A collection of homogeneous objects that can be used for
0007 an EDProduct. DetSetVector is *not* designed for use as a base class
0008 (it has no virtual functions).
0009 
0010 DetSetVector<T> contains a vector<DetSet<T> >, sorted on DetId, and
0011 provides fast (O(log n)) lookups, but only O(n) insertion.
0012 
0013 It provides an interface such that EdmRef2 can directly reference, and
0014 provide access to, individual T objects.
0015 
0016 The collection appears to the user as if it were a sequence of
0017 DetSet<T>; e.g., operator[] returns a DetSet<T>&. However, the
0018 argument to operator[] specifies the (DetId) identifier of the vector
0019 to be returned, *not* the ordinal number of the T to be returned.
0020 
0021               ------------------
0022    It is critical that users DO NOT MODIFY the id data member of a
0023    DetSet object in a DetSetVector.
0024               ------------------
0025 
0026 Since CMSSW 2_0_0_pre4, it is possible to skip the automatic sorting
0027 when creating a DetSetVector<T> from an already sorted vector<DetSet<T>>.
0028 If the DSV is not modified afterwards, it will no longer be sorted when
0029 it is inserted in the event.
0030 ONE NOTE OF CAUTION: it is not sufficient to to say that the vector is 
0031 sorted already.  In addition the sorting must have been done with the same
0032 criteria and obey the rules of "strict weak ordering" as will be used to
0033 find things in the collection.  Not insuring this leads to undefined
0034 behavior (usually a core dump).
0035 
0036 ----------------------------------------------------------------------*/
0037 
0038 #include <algorithm>
0039 #include <iterator>
0040 #include <numeric>
0041 #include <type_traits>
0042 #include <vector>
0043 
0044 #include <boost/concept_check.hpp>
0045 
0046 #include "DataFormats/Common/interface/BoolCache.h"
0047 #include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
0048 #include "DataFormats/Common/interface/DetSet.h"
0049 #include "DataFormats/Common/interface/FillView.h"
0050 #include "DataFormats/Common/interface/Ref.h"
0051 #include "DataFormats/Common/interface/traits.h"
0052 #include "FWCore/Utilities/interface/EDMException.h"
0053 
0054 namespace edm {
0055 
0056   namespace detail {
0057 
0058     // from https://devblogs.microsoft.com/oldnewthing/20170104-00/?p=95115
0059 
0060     template <typename Iter1, typename Iter2>
0061     void apply_permutation(Iter1 first, Iter1 last, Iter2 indices) {
0062       using T = std::iterator_traits<Iter1>::value_type;
0063       using Diff = std::iterator_traits<Iter2>::value_type;
0064       Diff length = last - first;
0065       for (Diff i = 0; i < length; i++) {
0066         Diff current = i;
0067         if (i != indices[current]) {
0068           T t{std::move(first[i])};
0069           while (i != indices[current]) {
0070             Diff next = indices[current];
0071             first[current] = std::move(first[next]);
0072             indices[current] = current;
0073             current = next;
0074           }
0075           first[current] = std::move(t);
0076           indices[current] = current;
0077         }
0078       }
0079     }
0080 
0081     // from https://devblogs.microsoft.com/oldnewthing/20170106-00/?p=95135
0082 
0083     template <typename Iter, typename UnaryOperation, typename Compare>
0084     void sort_by_key(Iter first, Iter last, UnaryOperation op, Compare comp) {
0085       using Diff = std::iterator_traits<Iter>::difference_type;
0086       using T = std::iterator_traits<Iter>::value_type;
0087       using Key = decltype(op(std::declval<T>()));
0088       Diff length = std::distance(first, last);
0089       std::vector<Key> keys;
0090       keys.reserve(length);
0091       std::transform(first, last, std::back_inserter(keys), [&](T& t) { return op(t); });
0092       std::vector<Diff> indices(length);
0093       std::iota(indices.begin(), indices.end(), static_cast<Diff>(0));
0094       std::sort(indices.begin(), indices.end(), [&](Diff a, Diff b) { return comp(keys[a], keys[b]); });
0095       apply_permutation(first, last, indices.begin());
0096     }
0097 
0098     template <typename Iter, typename UnaryOperation>
0099     void sort_by_key(Iter first, Iter last, UnaryOperation op) {
0100       sort_by_key(first, last, op, std::less<>());
0101     }
0102 
0103   }  // namespace detail
0104 
0105   class ProductID;
0106 
0107   //------------------------------------------------------------
0108   // Forward declarations
0109   template <class T>
0110   class DetSetVector;
0111 
0112   //------------------------------------------------------------
0113   // Helper function, to regularize throwing of exceptions.
0114   //------------------------------------------------------------
0115 
0116   namespace detail {
0117     // Throw an edm::Exception with an appropriate message
0118     inline void _throw_range(det_id_type i) {
0119       Exception::throwThis(
0120           errors::InvalidReference, "DetSetVector::operator[] called with index not in collection;\nindex value: ", i);
0121     }
0122   }  // namespace detail
0123 
0124   //------------------------------------------------------------
0125   //
0126 
0127   // If DetSetVector<T> is instantiated with a class T which inherits
0128   // from DoNotSortUponInsertion, the resulting class inherits from
0129   // DoNotSortUponInsertion. In the normal case, DetSetVector<T>
0130   // inherits from Other.  (This is necessary to assure that
0131   // DetSetVector<T> is not sorted upon insertion into the Event when
0132   // T is defined to inherit from DoNotSortUponInsertion).
0133 
0134   template <class T>
0135   class DetSetVector : public std::conditional_t<std::is_base_of<edm::DoNotSortUponInsertion, T>::value,
0136                                                  edm::DoNotSortUponInsertion,
0137                                                  Other> {
0138     /// DetSetVector requires that T objects can be compared with
0139     /// operator<.
0140     BOOST_CLASS_REQUIRE(T, boost, LessThanComparableConcept);
0141 
0142   public:
0143     typedef DetSet<T> detset;
0144     typedef detset value_type;
0145     typedef std::vector<detset> collection_type;
0146 
0147     typedef detset& reference;
0148     typedef detset const& const_reference;
0149 
0150     typedef typename collection_type::iterator iterator;
0151     typedef typename collection_type::const_iterator const_iterator;
0152     typedef typename collection_type::size_type size_type;
0153 
0154     /// Compiler-generated copy c'tor, d'tor and
0155     /// assignment are correct.
0156 
0157     /// Create an empty DetSetVector
0158     DetSetVector();
0159 
0160     /// Create a DetSetVector by copying swapping in the given vector,
0161     /// and then sorting the contents.
0162     /// N.B.: Swapping in the vector *destructively modifies the input*.
0163     /// Using swap here allows us to avoid copying the data.
0164     /// N.B. 2: if you set alreadySorted to true, data *must* be sorted,
0165     /// (the vector<DetSet<T>> must be ordered by detid, and each DetSet
0166     /// must be ordered according to the natural "strict weak ordering" of Ts.
0167     /// You *must not* modify the contents after this DSV after creation,
0168     /// or you might get an undefined behavior / a core dump.
0169     /// (there are some checks to assure alreadySorted is resetted if you try
0170     /// to modify the DSV, but you should not count on them)
0171     explicit DetSetVector(std::vector<DetSet<T> >& input, bool alreadySorted = false);
0172 
0173     void swap(DetSetVector& other);
0174 
0175     ///  Insert the given DetSet.
0176     // What should happen if there is already a DetSet with this
0177     // DetId? Right now, it is up to the user *not* to do this. If you
0178     // are unsure whether or not your DetId is already in the
0179     // DetSetVector, then use 'find_or_insert(id)' instead.
0180     void insert(detset const& s);
0181 
0182     /// Find the DetSet with the given DetId, and return a reference
0183     /// to it. If there is none, create one with the right DetId, and
0184     /// an empty vector, and return a reference to the new one.
0185     reference find_or_insert(det_id_type id);
0186 
0187     /// Return true if we contain no DetSets.
0188     bool empty() const;
0189 
0190     /// Return the number of contained DetSets
0191     size_type size() const;
0192 
0193     // reserve...
0194     void reserve(size_t s) { _sets.reserve(s); }
0195 
0196     // Do we need a short-hand method to return the number of T
0197     // instances? If so, do we optimize for size (calculate on the
0198     // fly) or speed (keep a current cache)?
0199 
0200     /// Return an iterator to the DetSet with the given id, or end()
0201     /// if there is no such DetSet.
0202     iterator find(det_id_type id);
0203     const_iterator find(det_id_type id) const;
0204 
0205     /// Return a reference to the DetSet with the given detector
0206     /// ID. If there is no such DetSet, we throw an edm::Exception.
0207     /// **DO NOT MODIFY THE id DATA MEMBER OF THE REFERENCED DetSet!**
0208     reference operator[](det_id_type i);
0209     const_reference operator[](det_id_type i) const;
0210 
0211     /// Return an iterator to the first DetSet.
0212     iterator begin();
0213     const_iterator begin() const;
0214 
0215     /// Return the off-the-end iterator.
0216     iterator end();
0217     const_iterator end() const;
0218 
0219     /// Push all the id for each DetSet stored in this DetSetVector
0220     /// into the given vector 'result'.
0221     void getIds(std::vector<det_id_type>& result) const;
0222 
0223     /// This function will be called by the edm::Event after the
0224     /// DetSetVector has been inserted into the Event.
0225     void post_insert();
0226 
0227     void fillView(ProductID const& id, std::vector<void const*>& pointers, FillViewHelperVector& helpers) const;
0228 
0229     //Used by ROOT storage
0230     CMS_CLASS_VERSION(10)
0231 
0232   private:
0233     collection_type _sets;
0234     edm::BoolCache _alreadySorted;
0235 
0236     /// Sort the DetSet in order of increasing DetId.
0237     void _sort();
0238   };
0239 
0240   template <class T>
0241   inline DetSetVector<T>::DetSetVector() : _sets() {}
0242 
0243   template <class T>
0244   inline DetSetVector<T>::DetSetVector(std::vector<DetSet<T> >& input, bool alreadySorted)
0245       : _sets(), _alreadySorted(alreadySorted) {
0246     _sets.swap(input);
0247     if (!alreadySorted)
0248       _sort();
0249   }
0250 
0251   template <class T>
0252   inline void DetSetVector<T>::swap(DetSetVector<T>& other) {
0253     _sets.swap(other._sets);
0254     bool tmp = _alreadySorted;
0255     _alreadySorted = other._alreadySorted;
0256     other._alreadySorted = tmp;
0257   }
0258 
0259   template <class T>
0260   inline void DetSetVector<T>::insert(detset const& t) {
0261     _alreadySorted = false;  // we don't know if the DetSet we're adding is already sorted
0262     // Implementation provided by the Performance Task Force.
0263     _sets.insert(std::lower_bound(_sets.begin(), _sets.end(), t), t);
0264 #if 0
0265     // It seems we have to sort on each insertion, because we may
0266     // perform lookups during construction.
0267     _sets.push_back(t);
0268 
0269     _sort();
0270 #endif
0271   }
0272 
0273   template <class T>
0274   inline typename DetSetVector<T>::reference DetSetVector<T>::find_or_insert(det_id_type id) {
0275     // NOTE: we don't have to clear _alreadySorted: the new DS is empty,
0276     //       and gets inserted in the correct place
0277     std::pair<iterator, iterator> p = std::equal_range(_sets.begin(), _sets.end(), id);
0278 
0279     // If the range isn't empty, we already have the right thing;
0280     // return a reference to it...
0281     if (p.first != p.second)
0282       return *p.first;
0283 
0284       // Insert the right thing, in the right place, and return a
0285       // reference to the newly inserted thing.
0286 #if defined(__GXX_EXPERIMENTAL_CXX0X__)
0287     return *(_sets.emplace(p.first, id));
0288 #else
0289     return *(_sets.insert(p.first, detset(id)));
0290 #endif
0291   }
0292 
0293   template <class T>
0294   inline bool DetSetVector<T>::empty() const {
0295     return _sets.empty();
0296   }
0297 
0298   template <class T>
0299   inline typename DetSetVector<T>::size_type DetSetVector<T>::size() const {
0300     return _sets.size();
0301   }
0302 
0303   template <class T>
0304   inline typename DetSetVector<T>::iterator DetSetVector<T>::find(det_id_type id) {
0305     _alreadySorted = false;  // it's non const
0306     std::pair<iterator, iterator> p = std::equal_range(_sets.begin(), _sets.end(), id);
0307     if (p.first == p.second)
0308       return _sets.end();
0309 
0310 // The range indicated by [p.first, p.second) should be exactly of
0311 // length 1. It seems likely we don't want to take the time hit of
0312 // checking this, but here is the appropriate test... We can turn
0313 // it on if we need the debugging aid.
0314 #if 0
0315     assert(std::distance(p.first, p.second) == 1);
0316 #endif
0317 
0318     return p.first;
0319   }
0320 
0321   template <class T>
0322   inline typename DetSetVector<T>::const_iterator DetSetVector<T>::find(det_id_type id) const {
0323     std::pair<const_iterator, const_iterator> p = std::equal_range(_sets.begin(), _sets.end(), id);
0324     if (p.first == p.second)
0325       return _sets.end();
0326     // The range indicated by [p.first, p.second) should be exactly of
0327     // length 1.
0328     assert(std::distance(p.first, p.second) == 1);
0329     return p.first;
0330   }
0331 
0332   template <class T>
0333   inline typename DetSetVector<T>::reference DetSetVector<T>::operator[](det_id_type i) {
0334     _alreadySorted = false;  // it's non const
0335     // Find the right DetSet, and return a reference to it.  Throw if
0336     // there is none.
0337     iterator it = this->find(i);
0338     if (it == this->end())
0339       detail::_throw_range(i);
0340     return *it;
0341   }
0342 
0343   template <class T>
0344   inline typename DetSetVector<T>::const_reference DetSetVector<T>::operator[](det_id_type i) const {
0345     // Find the right DetSet, and return a reference to it.  Throw if
0346     // there is none.
0347     const_iterator it = this->find(i);
0348     if (it == this->end())
0349       detail::_throw_range(i);
0350     return *it;
0351   }
0352 
0353   template <class T>
0354   inline typename DetSetVector<T>::iterator DetSetVector<T>::begin() {
0355     _alreadySorted = false;  // it's non const
0356     return _sets.begin();
0357   }
0358 
0359   template <class T>
0360   inline typename DetSetVector<T>::const_iterator DetSetVector<T>::begin() const {
0361     return _sets.begin();
0362   }
0363 
0364   template <class T>
0365   inline typename DetSetVector<T>::iterator DetSetVector<T>::end() {
0366     _alreadySorted = false;  // it's non const
0367     return _sets.end();
0368   }
0369 
0370   template <class T>
0371   inline typename DetSetVector<T>::const_iterator DetSetVector<T>::end() const {
0372     return _sets.end();
0373   }
0374 
0375   template <class T>
0376   inline void DetSetVector<T>::getIds(std::vector<det_id_type>& result) const {
0377     std::transform(
0378         this->begin(), this->end(), std::back_inserter(result), std::bind(&DetSet<T>::id, std::placeholders::_1));
0379   }
0380 
0381   template <class T>
0382   inline void DetSetVector<T>::post_insert() {
0383     _sets.shrink_to_fit();
0384     if (_alreadySorted)
0385       return;
0386     typename collection_type::iterator i = _sets.begin();
0387     typename collection_type::iterator e = _sets.end();
0388     // For each DetSet...
0389     for (; i != e; ++i) {
0390       i->data.shrink_to_fit();
0391       // sort the Detset pointed to by
0392       if constexpr (requires(const T& t) { t.sort_key(); }) {
0393         edm::detail::sort_by_key(i->data.begin(), i->data.end(), [](const T& t) { return t.sort_key(); });
0394       } else {
0395         std::sort(i->data.begin(), i->data.end());
0396       }
0397     }
0398   }
0399 
0400   template <class T>
0401   inline void DetSetVector<T>::_sort() {
0402     std::sort(_sets.begin(), _sets.end());
0403   }
0404 
0405   template <class T>
0406   void DetSetVector<T>::fillView(ProductID const& id,
0407                                  std::vector<void const*>& pointers,
0408                                  FillViewHelperVector& helpers) const {
0409     detail::reallyFillView(*this, id, pointers, helpers);
0410   }
0411 
0412   //----------------------------------------------------------------------
0413   //
0414   // Free function template to support creation of Views.
0415 
0416   template <class T>
0417   inline void fillView(DetSetVector<T> const& obj,
0418                        ProductID const& id,
0419                        std::vector<void const*>& pointers,
0420                        FillViewHelperVector& helpers) {
0421     obj.fillView(id, pointers, helpers);
0422   }
0423 
0424   template <class T>
0425   struct has_fillView<edm::DetSetVector<T> > {
0426     static bool const value = true;
0427   };
0428 
0429   // Free swap function
0430   template <class T>
0431   inline void swap(DetSetVector<T>& a, DetSetVector<T>& b) {
0432     a.swap(b);
0433   }
0434 
0435 }  // namespace edm
0436 
0437 //specialize behavior of edm::Ref to get access to the 'Det'
0438 namespace edm {
0439 
0440   namespace refhelper {
0441     template <typename T>
0442     class FindForDetSetVector {
0443     public:
0444       using first_argument_type = const DetSetVector<T>&;
0445       using second_argument_type = std::pair<det_id_type, typename DetSet<T>::collection_type::size_type>;
0446       using result_type = const T*;
0447 
0448       result_type operator()(first_argument_type iContainer, second_argument_type iIndex) {
0449         return &(*(iContainer.find(iIndex.first)->data.begin() + iIndex.second));
0450       }
0451     };
0452 
0453     template <typename T>
0454     struct FindTrait<DetSetVector<T>, T> {
0455       typedef FindForDetSetVector<T> value;
0456     };
0457   }  // namespace refhelper
0458 
0459   //helper function to make it easier to create a edm::Ref
0460 
0461   template <class HandleT>
0462   inline Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> makeRefTo(
0463       const HandleT& iHandle, det_id_type iDetID, typename HandleT::element_type::value_type::const_iterator itIter) {
0464     typedef typename HandleT::element_type Vec;
0465     typename Vec::value_type::collection_type::size_type index = 0;
0466     typename Vec::const_iterator itFound = iHandle->find(iDetID);
0467     if (itFound == iHandle->end()) {
0468       Exception::throwThis(errors::InvalidReference,
0469                            "an edm::Ref to an edm::DetSetVector was given a DetId, ",
0470                            iDetID,
0471                            ", that is not in the DetSetVector");
0472     }
0473     index += (itIter - itFound->data.begin());
0474     if (index >= itFound->data.size()) {
0475       Exception::throwThis(errors::InvalidReference,
0476                            "an edm::Ref to a edm::DetSetVector is being made with an interator that is not part of the "
0477                            "edm::DetSet itself");
0478     }
0479     return Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>(
0480         iHandle, std::make_pair(iDetID, index));
0481   }
0482 
0483   template <class HandleT>
0484   inline Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>
0485   makeRefToDetSetVector(const HandleT& iHandle,
0486                         det_id_type iDetID,
0487                         typename HandleT::element_type::value_type::iterator itIter) {
0488     typedef typename HandleT::element_type Vec;
0489     typename Vec::detset::const_iterator itIter2 = itIter;
0490     return makeRefTo(iHandle, iDetID, itIter2);
0491   }
0492 }  // namespace edm
0493 #endif