DetSetVector

FindForDetSetVector

FindTrait

has_fillView

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 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
#ifndef DataFormats_Common_DetSetVector_h
#define DataFormats_Common_DetSetVector_h

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

DetSetVector: 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.
			  ------------------

Since CMSSW 2_0_0_pre4, it is possible to skip the automatic sorting
when creating a DetSetVector<T> from an already sorted vector<DetSet<T>>.
If the DSV is not modified afterwards, it will no longer be sorted when
it is inserted in the event.
ONE NOTE OF CAUTION: it is not sufficient to to say that the vector is 
sorted already.  In addition the sorting must have been done with the same
criteria and obey the rules of "strict weak ordering" as will be used to
find things in the collection.  Not insuring this leads to undefined
behavior (usually a core dump).

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

#include <algorithm>
#include <iterator>
#include <vector>

#include <type_traits>
#include "boost/concept_check.hpp"

#include "DataFormats/Common/interface/CMS_CLASS_VERSION.h"
#include "DataFormats/Common/interface/DetSet.h"
#include "DataFormats/Common/interface/FillView.h"
#include "DataFormats/Common/interface/Ref.h"
#include "DataFormats/Common/interface/traits.h"

#include "FWCore/Utilities/interface/EDMException.h"

#include "DataFormats/Common/interface/BoolCache.h"

namespace edm {
  class ProductID;

  //------------------------------------------------------------
  // Forward declarations
  template <class T>
  class DetSetVector;

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

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

  //------------------------------------------------------------
  //

  // If DetSetVector<T> is instantiated with a class T which inherits
  // from DoNotSortUponInsertion, the resulting class inherits from
  // DoNotSortUponInsertion. In the normal case, DetSetVector<T>
  // inherits from Other.  (This is necessary to assure that
  // DetSetVector<T> is not sorted upon insertion into the Event when
  // T is defined to inherit from DoNotSortUponInsertion).

  template <class T>
  class DetSetVector : public std::conditional_t<std::is_base_of<edm::DoNotSortUponInsertion, T>::value,
                                                 edm::DoNotSortUponInsertion,
                                                 Other> {
    /// 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 std::vector<detset> collection_type;

    typedef detset& reference;
    typedef detset const& const_reference;

    typedef typename collection_type::iterator iterator;
    typedef typename collection_type::const_iterator const_iterator;
    typedef typename collection_type::size_type size_type;

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

    /// Create an empty DetSetVector
    DetSetVector();

    /// Create a DetSetVector by copying swapping in the given vector,
    /// and then sorting the contents.
    /// N.B.: Swapping in the vector *destructively modifies the input*.
    /// Using swap here allows us to avoid copying the data.
    /// N.B. 2: if you set alreadySorted to true, data *must* be sorted,
    /// (the vector<DetSet<T>> must be ordered by detid, and each DetSet
    /// must be ordered according to the natural "strict weak ordering" of Ts.
    /// You *must not* modify the contents after this DSV after creation,
    /// or you might get an undefined behavior / a core dump.
    /// (there are some checks to assure alreadySorted is resetted if you try
    /// to modify the DSV, but you should not count on them)
    explicit DetSetVector(std::vector<DetSet<T> >& input, bool alreadySorted = false);

    void swap(DetSetVector& other);

    ///  Insert the given DetSet.
    // What should happen if there is already a DetSet with this
    // DetId? Right now, it is up to the user *not* to do this. If you
    // are unsure whether or not your DetId is already in the
    // DetSetVector, then use 'find_or_insert(id)' instead.
    void insert(detset const& s);

    /// Find the DetSet with the given DetId, and return a reference
    /// to it. If there is none, create one with the right DetId, and
    /// an empty vector, and return a reference to the new one.
    reference find_or_insert(det_id_type id);

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

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

    // reserve...
    void reserve(size_t s) { _sets.reserve(s); }

    // 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.
    iterator find(det_id_type id);
    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!**
    reference operator[](det_id_type i);
    const_reference operator[](det_id_type i) const;

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

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

    /// Push all the id for each DetSet stored in this DetSetVector
    /// into the given vector 'result'.
    void getIds(std::vector<det_id_type>& result) const;

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

    void fillView(ProductID const& id, std::vector<void const*>& pointers, FillViewHelperVector& helpers) const;

    //Used by ROOT storage
    CMS_CLASS_VERSION(10)

  private:
    collection_type _sets;
    edm::BoolCache _alreadySorted;

    /// Sort the DetSet in order of increasing DetId.
    void _sort();
  };

  template <class T>
  inline DetSetVector<T>::DetSetVector() : _sets() {}

  template <class T>
  inline DetSetVector<T>::DetSetVector(std::vector<DetSet<T> >& input, bool alreadySorted)
      : _sets(), _alreadySorted(alreadySorted) {
    _sets.swap(input);
    if (!alreadySorted)
      _sort();
  }

  template <class T>
  inline void DetSetVector<T>::swap(DetSetVector<T>& other) {
    _sets.swap(other._sets);
    bool tmp = _alreadySorted;
    _alreadySorted = other._alreadySorted;
    other._alreadySorted = tmp;
  }

  template <class T>
  inline void DetSetVector<T>::insert(detset const& t) {
    _alreadySorted = false;  // we don't know if the DetSet we're adding is already sorted
    // Implementation provided by the Performance Task Force.
    _sets.insert(std::lower_bound(_sets.begin(), _sets.end(), t), t);
#if 0
    // It seems we have to sort on each insertion, because we may
    // perform lookups during construction.
    _sets.push_back(t);

    _sort();
#endif
  }

  template <class T>
  inline typename DetSetVector<T>::reference DetSetVector<T>::find_or_insert(det_id_type id) {
    // NOTE: we don't have to clear _alreadySorted: the new DS is empty,
    //       and gets inserted in the correct place
    std::pair<iterator, iterator> p = std::equal_range(_sets.begin(), _sets.end(), id);

    // If the range isn't empty, we already have the right thing;
    // return a reference to it...
    if (p.first != p.second)
      return *p.first;

      // Insert the right thing, in the right place, and return a
      // reference to the newly inserted thing.
#if defined(__GXX_EXPERIMENTAL_CXX0X__)
    return *(_sets.emplace(p.first, id));
#else
    return *(_sets.insert(p.first, detset(id)));
#endif
  }

  template <class T>
  inline bool DetSetVector<T>::empty() const {
    return _sets.empty();
  }

  template <class T>
  inline typename DetSetVector<T>::size_type DetSetVector<T>::size() const {
    return _sets.size();
  }

  template <class T>
  inline typename DetSetVector<T>::iterator DetSetVector<T>::find(det_id_type id) {
    _alreadySorted = false;  // it's non const
    std::pair<iterator, iterator> p = std::equal_range(_sets.begin(), _sets.end(), id);
    if (p.first == p.second)
      return _sets.end();

// The range indicated by [p.first, p.second) should be exactly of
// length 1. It seems likely we don't want to take the time hit of
// checking this, but here is the appropriate test... We can turn
// it on if we need the debugging aid.
#if 0
    assert(std::distance(p.first, p.second) == 1);
#endif

    return p.first;
  }

  template <class T>
  inline typename DetSetVector<T>::const_iterator DetSetVector<T>::find(det_id_type id) const {
    std::pair<const_iterator, const_iterator> p = std::equal_range(_sets.begin(), _sets.end(), id);
    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 <class T>
  inline typename DetSetVector<T>::reference DetSetVector<T>::operator[](det_id_type i) {
    _alreadySorted = false;  // it's non const
    // Find the right DetSet, and return a reference to it.  Throw if
    // there is none.
    iterator it = this->find(i);
    if (it == this->end())
      detail::_throw_range(i);
    return *it;
  }

  template <class T>
  inline typename DetSetVector<T>::const_reference DetSetVector<T>::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())
      detail::_throw_range(i);
    return *it;
  }

  template <class T>
  inline typename DetSetVector<T>::iterator DetSetVector<T>::begin() {
    _alreadySorted = false;  // it's non const
    return _sets.begin();
  }

  template <class T>
  inline typename DetSetVector<T>::const_iterator DetSetVector<T>::begin() const {
    return _sets.begin();
  }

  template <class T>
  inline typename DetSetVector<T>::iterator DetSetVector<T>::end() {
    _alreadySorted = false;  // it's non const
    return _sets.end();
  }

  template <class T>
  inline typename DetSetVector<T>::const_iterator DetSetVector<T>::end() const {
    return _sets.end();
  }

  template <class T>
  inline void DetSetVector<T>::getIds(std::vector<det_id_type>& result) const {
    std::transform(
        this->begin(), this->end(), std::back_inserter(result), std::bind(&DetSet<T>::id, std::placeholders::_1));
  }

  template <class T>
  inline void DetSetVector<T>::post_insert() {
    _sets.shrink_to_fit();
    if (_alreadySorted)
      return;
    typename collection_type::iterator i = _sets.begin();
    typename collection_type::iterator e = _sets.end();
    // For each DetSet...
    for (; i != e; ++i) {
      i->data.shrink_to_fit();
      // sort the Detset pointed to by
      std::sort(i->data.begin(), i->data.end());
    }
  }

  template <class T>
  inline void DetSetVector<T>::_sort() {
    std::sort(_sets.begin(), _sets.end());
  }

  template <class T>
  void DetSetVector<T>::fillView(ProductID const& id,
                                 std::vector<void const*>& pointers,
                                 FillViewHelperVector& helpers) const {
    detail::reallyFillView(*this, id, pointers, helpers);
  }

  //----------------------------------------------------------------------
  //
  // Free function template to support creation of Views.

  template <class T>
  inline void fillView(DetSetVector<T> const& obj,
                       ProductID const& id,
                       std::vector<void const*>& pointers,
                       FillViewHelperVector& helpers) {
    obj.fillView(id, pointers, helpers);
  }

  template <class T>
  struct has_fillView<edm::DetSetVector<T> > {
    static bool const value = true;
  };

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

}  // namespace edm

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

  namespace refhelper {
    template <typename T>
    class FindForDetSetVector {
    public:
      using first_argument_type = const DetSetVector<T>&;
      using second_argument_type = std::pair<det_id_type, typename DetSet<T>::collection_type::size_type>;
      using result_type = const T*;

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

    template <typename T>
    struct FindTrait<DetSetVector<T>, T> {
      typedef FindForDetSetVector<T> value;
    };
  }  // namespace refhelper

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

  template <class HandleT>
  inline Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type> makeRefTo(
      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);
    if (itFound == iHandle->end()) {
      Exception::throwThis(errors::InvalidReference,
                           "an edm::Ref to an edm::DetSetVector was given a DetId, ",
                           iDetID,
                           ", that is not in the DetSetVector");
    }
    index += (itIter - itFound->data.begin());
    if (index >= itFound->data.size()) {
      Exception::throwThis(errors::InvalidReference,
                           "an edm::Ref to a edm::DetSetVector is being made with an interator that is not part of the "
                           "edm::DetSet itself");
    }
    return Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>(
        iHandle, std::make_pair(iDetID, index));
  }

  template <class HandleT>
  inline Ref<typename HandleT::element_type, typename HandleT::element_type::value_type::value_type>
  makeRefToDetSetVector(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 makeRefTo(iHandle, iDetID, itIter2);
  }
}  // namespace edm
#endif