FillIndices

FillIndices

IfFound

IfFound

IfFound

IfFound

IfFound

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
#ifndef CommonTools_Utils_associationMapFilterValues_h
#define CommonTools_Utils_associationMapFilterValues_h

#include "DataFormats/Common/interface/Ref.h"
#include "DataFormats/Common/interface/RefVector.h"
#include "DataFormats/Common/interface/View.h"
#include "DataFormats/Common/interface/AssociationMapHelpers.h"

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

namespace associationMapFilterValuesHelpers {
  // Common implementation
  template <typename T_AssociationMap, typename T_Key, typename T_ValueIndex, typename T_Value, typename T_ValueIndices>
  void findInsert(T_AssociationMap& ret,
                  const T_Key& key,
                  const T_ValueIndex& valueIndex,
                  const T_Value& value,
                  const T_ValueIndices& value_indices) {
    if (value_indices.has(valueIndex)) {
      ret.insert(key, value);
    }
  }

  // By default no implementation, as it turns out to be very specific for the types
  template <typename ValueTag>
  struct IfFound;

  // Specialize for Ref and RefToBase, implementation is the same
  template <typename C, typename T, typename F>
  struct IfFound<edm::Ref<C, T, F>> {
    template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
    static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
      findInsert(ret, keyValue.key, keyValue.val.key(), keyValue.val, value_indices);
    }
  };

  template <typename T>
  struct IfFound<edm::RefToBase<T>> {
    template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
    static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
      findInsert(ret, keyValue.key, keyValue.val.key(), keyValue.val, value_indices);
    }
  };

  // Specialize for RefVector
  template <typename C, typename T, typename F>
  struct IfFound<edm::RefVector<C, T, F>> {
    template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
    static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
      for (const auto& value : keyValue.val) {
        findInsert(ret, keyValue.key, value.key(), value, value_indices);
      }
    }
  };

  // Specialize for vector<pair<Ref, Q>> for OneToManyWithQuality
  template <typename C, typename T, typename F, typename Q>
  struct IfFound<std::vector<std::pair<edm::Ref<C, T, F>, Q>>> {
    template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
    static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
      for (const auto& value : keyValue.val) {
        findInsert(ret, keyValue.key, value.first.key(), value, value_indices);
      }
    }
  };

  // Specialize for vector<pair<RefToBase, Q>> for OneToManyWithQuality
  template <typename T, typename Q>
  struct IfFound<std::vector<std::pair<edm::RefToBase<T>, Q>>> {
    template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
    static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
      for (const auto& value : keyValue.val) {
        findInsert(ret, keyValue.key, value.first.key(), value, value_indices);
      }
    }
  };

  // Default implementation for RefVector or vector<Ref>
  template <typename T_RefVector>
  struct FillIndices {
    template <typename T_Set, typename T_RefProd>
    static void fill(T_Set& set, const T_RefVector& valueRefs, const T_RefProd& refProd) {
      for (const auto& ref : valueRefs) {
        edm::helpers::checkRef(refProd.val, ref);
        set.insert(ref.key());
      }
    }
  };

  // Specialize for View
  template <typename T>
  struct FillIndices<edm::View<T>> {
    template <typename T_Set, typename T_RefProd>
    static void fill(T_Set& set, const edm::View<T>& valueView, const T_RefProd& refProd) {
      for (size_t i = 0; i < valueView.size(); ++i) {
        const auto& ref = valueView.refAt(i);
        edm::helpers::checkRef(refProd.val, ref);
        set.insert(ref.key());
      }
    }
  };
}  // namespace associationMapFilterValuesHelpers

/**
 * Filters entries of AssociationMap by keeping only those
 * associations that have a value in a given collection
 *
 * @param map        AssociationMap to filter
 * @param valueRefs  Collection of Refs to values.
 *
 * @tparam T_AssociationMap  Type of the AssociationMap
 * @tparam T_RefVector       Type of the Ref collection.
 *
 * For AssociationMap<Tag<CKey, CVal>>, the collection of Refs can be
 * RefVector<CVal>, vector<Ref<CVal>>, vector<RefToBase<CVal>>, or
 * View<T>. More can be supported if needed.
 *
 * @return A filtered copy of the AssociationMap
 *
 * Throws if the values of AssociationMap and valueRefs point to
 * different collections (similar check as in
 * AssociationMap::operator[] for the keys).
 */
template <typename T_AssociationMap, typename T_RefVector>
T_AssociationMap associationMapFilterValues(const T_AssociationMap& map, const T_RefVector& valueRefs) {
  // If the input map is empty, just return it in order to avoid an
  // exception from failing edm::helpers::checkRef() (in this case the
  // refProd points to (0,0) that will fail the check).
  if (map.empty())
    return map;

  T_AssociationMap ret(map.refProd());

  // First copy the keys of values to a set for faster lookup of their existence in the map
  edm::IndexSet value_indices;
  value_indices.reserve(
      valueRefs
          .size());  // hopefully a good guess of the last ref index without having to do the gymnastics for genericity
  associationMapFilterValuesHelpers::FillIndices<T_RefVector>::fill(value_indices, valueRefs, map.refProd());

  for (const auto& keyValue : map) {
    associationMapFilterValuesHelpers::IfFound<typename T_AssociationMap::value_type::value_type>::insert(
        ret, keyValue, value_indices);
  }

  return ret;
}

#endif