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
|