CompareRefDetSet

DetSetRefVector

FindDetSetForDetSetVector

FindForDetSetRefVector

FindTrait

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
#ifndef DataFormats_Common_DetSetRefVector_h
#define DataFormats_Common_DetSetRefVector_h

/*----------------------------------------------------------------------
  
DetSeReftVector: A collection of homogeneous objects that can be used for
an EDProduct. DetSetVector is *not* designed for use as a base class
(it has no virtual functions).

DetSetVector<T> contains a vector<DetSet<T> >, sorted on DetId, and
provides fast (O(log n)) lookups, but only O(n) insertion.

It provides an interface such that EdmRef2 can directly reference, and
provide access to, individual T objects.

The collection appears to the user as if it were a sequence of
DetSet<T>; e.g., operator[] returns a DetSet<T>&. However, the
argument to operator[] specifies the (DetId) identifier of the vector
to be returned, *not* the ordinal number of the T to be returned.

			  ------------------
   It is critical that users DO NOT MODIFY the id data member of a
   DetSet object in a DetSetVector.
			  ------------------

----------------------------------------------------------------------*/

#include <algorithm>
#include <vector>

#include "boost/concept_check.hpp"
#include "boost/iterator/indirect_iterator.hpp"

#include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
#include "DataFormats/Common/interface/traits.h"
#include "DataFormats/Common/interface/DetSet.h"
#include "FWCore/Utilities/interface/EDMException.h"

#include "DataFormats/Common/interface/Ref.h"
#include "DataFormats/Common/interface/DetSetVector.h"
#include "DataFormats/Common/interface/Handle.h"
#include "DataFormats/Common/interface/OrphanHandle.h"
#include "DataFormats/Common/interface/TestHandle.h"

namespace edm {

  //------------------------------------------------------------
  // Forward declarations
  template <typename T, typename C>
  class DetSetRefVector;

  //------------------------------------------------------------
  // Helper function, to regularize throwing of exceptions.
  //------------------------------------------------------------

  namespace dsrvdetail {
    // Throw an edm::Exception with an appropriate message
    inline void _throw_range(det_id_type i) {
      Exception::throwThis(errors::InvalidReference,
                           "DetSetRefVector::operator[] called with index not in collection;\nindex value: ",
                           i);
    }
  }  // namespace dsrvdetail

  //------------------------------------------------------------
  //
  namespace refhelper {
    template <typename T, typename C>
    struct FindDetSetForDetSetVector {
      using result_type = DetSet<T> const*;
      using first_argument_type = C const&;
      using second_argument_type = edm::det_id_type const;

      result_type operator()(first_argument_type iContainer, second_argument_type iIndex) const {
        return &(*(iContainer.find(iIndex)));
      }
    };
  }  // namespace refhelper

  //allow comparison of edm::Ref<...> to the det_it_type.  This allows searching without dereferencing the edm::Ref
  template <typename T, typename C = DetSetVector<T> >
  struct CompareRefDetSet {
    typedef Ref<C, DetSet<T>, refhelper::FindDetSetForDetSetVector<T, C> > ref_type;
    bool operator()(const ref_type& iRef, det_id_type iId) { return iRef.key() < iId; }
    bool operator()(det_id_type iId, const ref_type& iRef) { return iId < iRef.key(); }
  };

  template <typename T, typename C = DetSetVector<T> >
  class DetSetRefVector {
    /// DetSetVector requires that T objects can be compared with
    /// operator<.
    BOOST_CLASS_REQUIRE(T, boost, LessThanComparableConcept);

  public:
    typedef DetSet<T> detset;
    typedef detset value_type;
    typedef Ref<C, DetSet<T>, refhelper::FindDetSetForDetSetVector<T, C> > ref_type;
    typedef std::vector<ref_type> collection_type;

    typedef detset const& const_reference;

    //iterator returns a DetSet<T> instead of a Ref<...>
    typedef boost::indirect_iterator<typename collection_type::const_iterator> const_iterator;
    typedef typename collection_type::size_type size_type;

    /// Compiler-generated default c'tor, copy c'tor, d'tor and
    /// assignment are correct.

    // Add the following only if needed.
    //template <class InputIterator>
    //DetSetRefVector(InputIterator b, InputIterator e);

    DetSetRefVector() {}

    DetSetRefVector(const Handle<C>& iHandle, const std::vector<det_id_type>& iDets) : sets_() {
      sets_.reserve(iDets.size());
      det_id_type sanityCheck = 0;
      for (std::vector<det_id_type>::const_iterator itDetId = iDets.begin(), itDetIdEnd = iDets.end();
           itDetId != itDetIdEnd;
           ++itDetId) {
        assert(sanityCheck <= *itDetId && "vector of det_id_type was not ordered");
        sanityCheck = *itDetId;
        //the last 'false' says to not get the data right now
        sets_.push_back(ref_type(iHandle, *itDetId, false));
      }
    }

    DetSetRefVector(const OrphanHandle<C>& iHandle, const std::vector<det_id_type>& iDets) : sets_() {
      sets_.reserve(iDets.size());
      det_id_type sanityCheck = 0;
      for (std::vector<det_id_type>::const_iterator itDetId = iDets.begin(), itDetIdEnd = iDets.end();
           itDetId != itDetIdEnd;
           ++itDetId) {
        assert(sanityCheck <= *itDetId && "vector of det_id_type was not ordered");
        sanityCheck = *itDetId;
        //the last 'false' says to not get the data right now
        sets_.push_back(ref_type(iHandle, *itDetId, false));
      }
    }

    DetSetRefVector(const TestHandle<C>& iHandle, const std::vector<det_id_type>& iDets) : sets_() {
      sets_.reserve(iDets.size());
      det_id_type sanityCheck = 0;
      for (std::vector<det_id_type>::const_iterator itDetId = iDets.begin(), itDetIdEnd = iDets.end();
           itDetId != itDetIdEnd;
           ++itDetId) {
        assert(sanityCheck <= *itDetId && "vector of det_id_type was not ordered");
        sanityCheck = *itDetId;
        //the last 'false' says to not get the data right now
        sets_.push_back(ref_type(iHandle, *itDetId, false));
      }
    }

    void swap(DetSetRefVector& other);

    DetSetRefVector& operator=(DetSetRefVector const& rhs);

    /// Return true if we contain no DetSets.
    bool empty() const;

    /// Return the number of contained DetSets
    size_type size() const;

    // Do we need a short-hand method to return the number of T
    // instances? If so, do we optimize for size (calculate on the
    // fly) or speed (keep a current cache)?

    /// Return an iterator to the DetSet with the given id, or end()
    /// if there is no such DetSet.
    const_iterator find(det_id_type id) const;

    /// Return a reference to the DetSet with the given detector
    /// ID. If there is no such DetSet, we throw an edm::Exception.
    /// **DO NOT MODIFY THE id DATA MEMBER OF THE REFERENCED DetSet!**
    const_reference operator[](det_id_type i) const;

    /// Return an iterator to the first DetSet.
    const_iterator begin() const;

    /// Return the off-the-end iterator.
    const_iterator end() const;

    /// This function will be called by the edm::Event after the
    /// DetSetVector has been inserted into the Event.
    //void post_insert();

    //Needed for ROOT storage
    CMS_CLASS_VERSION(10)

  private:
    collection_type sets_;
  };

  template <typename T, typename C>
  inline void DetSetRefVector<T, C>::swap(DetSetRefVector<T, C>& other) {
    sets_.swap(other.sets_);
  }

  template <typename T, typename C>
  inline DetSetRefVector<T, C>& DetSetRefVector<T, C>::operator=(DetSetRefVector<T, C> const& rhs) {
    DetSetRefVector<T, C> temp(rhs);
    this->swap(temp);
    return *this;
  }

  template <typename T, typename C>
  inline bool DetSetRefVector<T, C>::empty() const {
    return sets_.empty();
  }

  template <typename T, typename C>
  inline typename DetSetRefVector<T, C>::size_type DetSetRefVector<T, C>::size() const {
    return sets_.size();
  }

  template <typename T, typename C>
  inline typename DetSetRefVector<T, C>::const_iterator DetSetRefVector<T, C>::find(det_id_type id) const {
    if (empty()) {
      return sets_.end();
    }
    std::pair<typename collection_type::const_iterator, typename collection_type::const_iterator> p =
        std::equal_range(sets_.begin(), sets_.end(), id, CompareRefDetSet<T, C>());
    if (p.first == p.second)
      return sets_.end();
    // The range indicated by [p.first, p.second) should be exactly of
    // length 1.
    assert(std::distance(p.first, p.second) == 1);
    return p.first;
  }

  template <typename T, typename C>
  inline typename DetSetRefVector<T, C>::const_reference DetSetRefVector<T, C>::operator[](det_id_type i) const {
    // Find the right DetSet, and return a reference to it.  Throw if
    // there is none.
    const_iterator it = this->find(i);
    if (it == this->end())
      dsrvdetail::_throw_range(i);
    return *it;
  }

  template <typename T, typename C>
  inline typename DetSetRefVector<T, C>::const_iterator DetSetRefVector<T, C>::begin() const {
    return sets_.begin();
  }

  template <typename T, typename C>
  inline typename DetSetRefVector<T, C>::const_iterator DetSetRefVector<T, C>::end() const {
    return sets_.end();
  }

  // Free swap function
  template <typename T, typename C>
  inline void swap(DetSetRefVector<T, C>& a, DetSetRefVector<T, C>& b) {
    a.swap(b);
  }

  //specialize behavior of edm::Ref to get access to the 'Det'

  namespace refhelper {
    template <typename T, typename C>
    struct FindForDetSetRefVector {
      using result_type = T const*;
      using first_argument_type = DetSetRefVector<T, C> const&;
      using second_argument_type = std::pair<det_id_type, typename DetSet<T>::collection_type::size_type>;

      result_type operator()(first_argument_type iContainer, second_argument_type iIndex) {
        return &(*(iContainer.find(iIndex.first)->data.begin() + iIndex.second));
      }
    };

    template <typename T, typename C>
    struct FindTrait<DetSetRefVector<T, C>, T> {
      typedef FindForDetSetRefVector<T, C> value;
    };
  }  // namespace refhelper

  //helper function to make it easier to create a edm::Ref

  template <class HandleT>
  Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> makeRefToDetSetRefVector(
      const HandleT& iHandle, det_id_type iDetID, typename HandleT::element_type::value_type::const_iterator itIter) {
    typedef typename HandleT::element_type Vec;
    typename Vec::value_type::collection_type::size_type index = 0;
    typename Vec::const_iterator itFound = iHandle->find(iDetID);
    index += (itIter - itFound->data.begin());
    return Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>(
        iHandle, std::make_pair(iDetID, index));
  }

  template <class HandleT>
  Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> makeRefToDetSetRefVector(
      const HandleT& iHandle, det_id_type iDetID, typename HandleT::element_type::value_type::iterator itIter) {
    typedef typename HandleT::element_type Vec;
    typename Vec::detset::const_iterator itIter2 = itIter;
    return makeRefToDetSetRefVector(iHandle, iDetID, itIter2);
  }
}  // namespace edm
#endif