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
|
#include "DataFormats/Common/interface/RefCore.h"
#include "DataFormats/Common/interface/WrapperBase.h"
#include "DataFormats/Common/interface/EDProductGetter.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include "FWCore/Utilities/interface/TypeID.h"
#include <cassert>
static void throwInvalidRefFromNullOrInvalidRef(const edm::TypeID& id) {
throw edm::Exception(edm::errors::InvalidReference, "BadRefCore")
<< "RefCore: Request to resolve a null or invalid reference to a product of type '" << id
<< "' has been detected.\n"
<< "Please modify the calling code to test validity before dereferencing.\n";
}
static void throwInvalidRefFromNoCache(const edm::TypeID& id, edm::ProductID const& prodID) {
throw edm::Exception(edm::errors::InvalidReference, "BadRefCore")
<< "RefCore: A request to resolve a reference to a product of type '" << id << "' with ProductID '" << prodID
<< "' cannot be satisfied.\n"
<< "The reference has neither a valid product pointer nor an EDProductGetter.\n"
<< "The calling code must be modified to establish a functioning EDProducterGetter\n"
<< "for the context in which this call is mode\n";
}
namespace edm {
RefCore::RefCore(ProductID const& theId, void const* prodPtr, EDProductGetter const* prodGetter, bool transient)
: cachePtr_(prodPtr), processIndex_(theId.processIndex()), productIndex_(theId.productIndex()) {
if (transient) {
setTransient();
}
if (prodPtr == nullptr && prodGetter != nullptr) {
setCacheIsProductGetter(prodGetter);
}
}
RefCore::RefCore(RefCore const& iOther) : processIndex_(iOther.processIndex_), productIndex_(iOther.productIndex_) {
cachePtr_.store(iOther.cachePtr_.load(std::memory_order_relaxed), std::memory_order_relaxed);
}
RefCore& RefCore::operator=(RefCore const& iOther) {
cachePtr_.store(iOther.cachePtr_.load(std::memory_order_relaxed), std::memory_order_relaxed);
processIndex_ = iOther.processIndex_;
productIndex_ = iOther.productIndex_;
return *this;
}
WrapperBase const* RefCore::getProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const {
// The following invariant would be nice to establish in all
// constructors, but we can not be sure that the context in which
// EDProductGetter::instance() is called will be one where a
// non-null pointer is returned. The biggest question in the
// various times at which Root makes RefCore instances, and how
// old ones might be recycled.
//
// If our ProductID is non-null, we must have a way to get at the
// product (unless it has been dropped). This means either we
// already have the pointer to the product, or we have a valid
// EDProductGetter to use.
//
// assert(!id_.isValid() || productGetter() || prodPtr_);
ProductID tId = id();
assert(!isTransient());
if (!tId.isValid()) {
throwInvalidRefFromNullOrInvalidRef(TypeID(type));
}
//if (productPtr() == 0 && productGetter() == 0) {
if (cachePtrIsInvalid()) {
throwInvalidRefFromNoCache(TypeID(type), tId);
}
WrapperBase const* product = prodGetter->getIt(tId);
if (product == nullptr) {
productNotFoundException(type);
}
if (!(type == product->dynamicTypeInfo())) {
wrongTypeException(type, product->dynamicTypeInfo());
}
return product;
}
WrapperBase const* RefCore::tryToGetProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const {
ProductID tId = id();
assert(!isTransient());
if (!tId.isValid()) {
throwInvalidRefFromNullOrInvalidRef(TypeID(type));
}
if (cachePtrIsInvalid()) {
throwInvalidRefFromNoCache(TypeID(type), tId);
}
WrapperBase const* product = prodGetter->getIt(tId);
if (product != nullptr && !(type == product->dynamicTypeInfo())) {
wrongTypeException(type, product->dynamicTypeInfo());
}
return product;
}
std::tuple<WrapperBase const*, unsigned int> RefCore::getThinnedProductPtr(std::type_info const& type,
unsigned int key,
EDProductGetter const* prodGetter) const {
ProductID tId = id();
std::optional product = prodGetter->getThinnedProduct(tId, key);
if (not product.has_value()) {
productNotFoundException(type);
}
WrapperBase const* wrapper = std::get<WrapperBase const*>(*product);
if (!(type == wrapper->dynamicTypeInfo())) {
wrongTypeException(type, wrapper->dynamicTypeInfo());
}
return *product;
}
bool RefCore::isThinnedAvailable(unsigned int key, EDProductGetter const* prodGetter) const {
ProductID tId = id();
if (!tId.isValid() || prodGetter == nullptr) {
//another thread may have changed it
return nullptr != productPtr();
}
std::optional product = prodGetter->getThinnedProduct(tId, key);
return product.has_value();
}
void RefCore::productNotFoundException(std::type_info const& type) const {
throw edm::Exception(errors::ProductNotFound)
<< "RefCore: A request to resolve a reference to a product of type '" << TypeID(type) << "' with ProductID '"
<< id() << "'"
<< "\ncan not be satisfied because the product cannot be found."
<< "\nProbably the branch containing the product is not stored in the input file.\n";
}
void RefCore::wrongTypeException(std::type_info const& expectedType, std::type_info const& actualType) const {
throw edm::Exception(errors::InvalidReference, "WrongType")
<< "RefCore: A request to convert a contained product of type '" << TypeID(actualType) << "'\n"
<< " to type '" << TypeID(expectedType) << "'"
<< "\nfor ProductID '" << id() << "' can not be satisfied\n";
}
void RefCore::nullPointerForTransientException(std::type_info const& type) const {
throw edm::Exception(errors::InvalidReference)
<< "RefCore: A request to resolve a transient reference to a product of type: " << TypeID(type)
<< "\ncan not be satisfied because the pointer to the product is null.\n";
}
bool RefCore::isAvailable() const {
ProductID tId = id();
//If another thread changes the cache, it will change a non-null productGetter
// into a null productGeter but productPtr will be non-null
// Therefore reading productGetter() first is the safe order
auto prodGetter = productGetter();
auto prodPtr = productPtr();
return prodPtr != nullptr || (tId.isValid() && prodGetter != nullptr && prodGetter->getIt(tId) != nullptr);
}
void RefCore::setProductGetter(EDProductGetter const* prodGetter) const { setCacheIsProductGetter(prodGetter); }
void RefCore::setId(ProductID const& iId) {
unsigned short head = processIndex_ & (refcoreimpl::kTransientBit | refcoreimpl::kCacheIsProductPtrBit);
processIndex_ = iId.processIndex();
processIndex_ |= head;
productIndex_ = iId.productIndex();
}
void RefCore::pushBackItem(RefCore const& productToBeInserted, bool checkPointer) {
if (productToBeInserted.isNull() && !productToBeInserted.isTransient()) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackItem: Ref or Ptr has invalid (zero) product ID, so it cannot be added to RefVector "
"(PtrVector). "
<< "id should be (" << id() << ")\n";
}
if (isNonnull()) {
if (isTransient() != productToBeInserted.isTransient()) {
if (productToBeInserted.isTransient()) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackItem: Transient Ref or Ptr cannot be added to persistable RefVector (PtrVector). "
<< "id should be (" << id() << ")\n";
} else {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackItem: Persistable Ref or Ptr cannot be added to transient RefVector (PtrVector). "
<< "id is (" << productToBeInserted.id() << ")\n";
}
}
if (!productToBeInserted.isTransient() && id() != productToBeInserted.id()) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackItem: Ref or Ptr is inconsistent with RefVector (PtrVector)"
<< "id = (" << productToBeInserted.id() << ") should be (" << id() << ")\n";
}
if (productToBeInserted.isTransient() && checkPointer && productToBeInserted.isNonnull() &&
productToBeInserted != *this) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackItem: Ref points into different collection than the RefVector.\n";
}
} else {
if (productToBeInserted.isTransient()) {
setTransient();
}
if (productToBeInserted.isNonnull()) {
setId(productToBeInserted.id());
}
}
//Since productPtr and productGetter actually share the same pointer internally,
// we want to be sure that if the productPtr is set we use that one and only if
// it isn't set do we set the productGetter if available
if (productPtr() == nullptr && productToBeInserted.productPtr() != nullptr) {
setProductPtr(productToBeInserted.productPtr());
} else {
auto getter = productToBeInserted.productGetter();
if (cachePtrIsInvalid() && getter != nullptr) {
setProductGetter(getter);
}
}
}
void RefCore::pushBackRefItem(RefCore const& productToBeInserted) {
if (productToBeInserted.isNull() && !productToBeInserted.isTransient()) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackRefItem: Ref has invalid (zero) product ID, so it cannot be added to RefVector."
<< "id should be (" << id() << ")\n";
}
if (isNonnull() || isTransient()) {
if (isTransient() != productToBeInserted.isTransient()) {
if (productToBeInserted.isTransient()) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackRefItem: Transient Ref cannot be added to persistable RefVector. "
<< "id should be (" << id() << ")\n";
} else {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackRefItem: Persistable Ref cannot be added to transient RefVector. "
<< "id is (" << productToBeInserted.id() << ")\n";
}
}
if (!productToBeInserted.isTransient() && id() != productToBeInserted.id()) {
throw edm::Exception(errors::InvalidReference, "Inconsistency")
<< "RefCore::pushBackRefItem: Ref is inconsistent with RefVector"
<< "id = (" << productToBeInserted.id() << ") should be (" << id() << ")\n";
}
} else {
if (productToBeInserted.isTransient()) {
setTransient();
}
if (productToBeInserted.isNonnull()) {
setId(productToBeInserted.id());
}
}
auto prodGetter = productToBeInserted.productGetter();
if (productGetter() == nullptr && prodGetter != nullptr) {
setProductGetter(prodGetter);
}
}
} // namespace edm
|