Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 10:45:39

0001 #ifndef CommonTools_Utils_associationMapFilterValues_h
0002 #define CommonTools_Utils_associationMapFilterValues_h
0003 
0004 #include "DataFormats/Common/interface/Ref.h"
0005 #include "DataFormats/Common/interface/RefVector.h"
0006 #include "DataFormats/Common/interface/View.h"
0007 #include "DataFormats/Common/interface/AssociationMapHelpers.h"
0008 
0009 #include "FWCore/Utilities/interface/IndexSet.h"
0010 
0011 namespace associationMapFilterValuesHelpers {
0012   // Common implementation
0013   template <typename T_AssociationMap, typename T_Key, typename T_ValueIndex, typename T_Value, typename T_ValueIndices>
0014   void findInsert(T_AssociationMap& ret,
0015                   const T_Key& key,
0016                   const T_ValueIndex& valueIndex,
0017                   const T_Value& value,
0018                   const T_ValueIndices& value_indices) {
0019     if (value_indices.has(valueIndex)) {
0020       ret.insert(key, value);
0021     }
0022   }
0023 
0024   // By default no implementation, as it turns out to be very specific for the types
0025   template <typename ValueTag>
0026   struct IfFound;
0027 
0028   // Specialize for Ref and RefToBase, implementation is the same
0029   template <typename C, typename T, typename F>
0030   struct IfFound<edm::Ref<C, T, F>> {
0031     template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
0032     static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
0033       findInsert(ret, keyValue.key, keyValue.val.key(), keyValue.val, value_indices);
0034     }
0035   };
0036 
0037   template <typename T>
0038   struct IfFound<edm::RefToBase<T>> {
0039     template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
0040     static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
0041       findInsert(ret, keyValue.key, keyValue.val.key(), keyValue.val, value_indices);
0042     }
0043   };
0044 
0045   // Specialize for RefVector
0046   template <typename C, typename T, typename F>
0047   struct IfFound<edm::RefVector<C, T, F>> {
0048     template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
0049     static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
0050       for (const auto& value : keyValue.val) {
0051         findInsert(ret, keyValue.key, value.key(), value, value_indices);
0052       }
0053     }
0054   };
0055 
0056   // Specialize for vector<pair<Ref, Q>> for OneToManyWithQuality
0057   template <typename C, typename T, typename F, typename Q>
0058   struct IfFound<std::vector<std::pair<edm::Ref<C, T, F>, Q>>> {
0059     template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
0060     static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
0061       for (const auto& value : keyValue.val) {
0062         findInsert(ret, keyValue.key, value.first.key(), value, value_indices);
0063       }
0064     }
0065   };
0066 
0067   // Specialize for vector<pair<RefToBase, Q>> for OneToManyWithQuality
0068   template <typename T, typename Q>
0069   struct IfFound<std::vector<std::pair<edm::RefToBase<T>, Q>>> {
0070     template <typename T_AssociationMap, typename T_KeyValue, typename T_ValueIndices>
0071     static void insert(T_AssociationMap& ret, const T_KeyValue& keyValue, const T_ValueIndices& value_indices) {
0072       for (const auto& value : keyValue.val) {
0073         findInsert(ret, keyValue.key, value.first.key(), value, value_indices);
0074       }
0075     }
0076   };
0077 
0078   // Default implementation for RefVector or vector<Ref>
0079   template <typename T_RefVector>
0080   struct FillIndices {
0081     template <typename T_Set, typename T_RefProd>
0082     static void fill(T_Set& set, const T_RefVector& valueRefs, const T_RefProd& refProd) {
0083       for (const auto& ref : valueRefs) {
0084         edm::helpers::checkRef(refProd.val, ref);
0085         set.insert(ref.key());
0086       }
0087     }
0088   };
0089 
0090   // Specialize for View
0091   template <typename T>
0092   struct FillIndices<edm::View<T>> {
0093     template <typename T_Set, typename T_RefProd>
0094     static void fill(T_Set& set, const edm::View<T>& valueView, const T_RefProd& refProd) {
0095       for (size_t i = 0; i < valueView.size(); ++i) {
0096         const auto& ref = valueView.refAt(i);
0097         edm::helpers::checkRef(refProd.val, ref);
0098         set.insert(ref.key());
0099       }
0100     }
0101   };
0102 }  // namespace associationMapFilterValuesHelpers
0103 
0104 /**
0105  * Filters entries of AssociationMap by keeping only those
0106  * associations that have a value in a given collection
0107  *
0108  * @param map        AssociationMap to filter
0109  * @param valueRefs  Collection of Refs to values.
0110  *
0111  * @tparam T_AssociationMap  Type of the AssociationMap
0112  * @tparam T_RefVector       Type of the Ref collection.
0113  *
0114  * For AssociationMap<Tag<CKey, CVal>>, the collection of Refs can be
0115  * RefVector<CVal>, vector<Ref<CVal>>, vector<RefToBase<CVal>>, or
0116  * View<T>. More can be supported if needed.
0117  *
0118  * @return A filtered copy of the AssociationMap
0119  *
0120  * Throws if the values of AssociationMap and valueRefs point to
0121  * different collections (similar check as in
0122  * AssociationMap::operator[] for the keys).
0123  */
0124 template <typename T_AssociationMap, typename T_RefVector>
0125 T_AssociationMap associationMapFilterValues(const T_AssociationMap& map, const T_RefVector& valueRefs) {
0126   // If the input map is empty, just return it in order to avoid an
0127   // exception from failing edm::helpers::checkRef() (in this case the
0128   // refProd points to (0,0) that will fail the check).
0129   if (map.empty())
0130     return map;
0131 
0132   T_AssociationMap ret(map.refProd());
0133 
0134   // First copy the keys of values to a set for faster lookup of their existence in the map
0135   edm::IndexSet value_indices;
0136   value_indices.reserve(
0137       valueRefs
0138           .size());  // hopefully a good guess of the last ref index without having to do the gymnastics for genericity
0139   associationMapFilterValuesHelpers::FillIndices<T_RefVector>::fill(value_indices, valueRefs, map.refProd());
0140 
0141   for (const auto& keyValue : map) {
0142     associationMapFilterValuesHelpers::IfFound<typename T_AssociationMap::value_type::value_type>::insert(
0143         ret, keyValue, value_indices);
0144   }
0145 
0146   return ret;
0147 }
0148 
0149 #endif