Skip to content

Commit 49212d7

Browse files
fwyzardmakortel
andcommitted
Specialise Handle and OrphanHandle for WrapperBase
This lets user code produce and consume collections via their wrapper, using their run time type information (e.g. type name, type id, ...) instead of the compile time types. Co-authored-by: Matti Kortelainen <[email protected]>
1 parent 11eaa89 commit 49212d7

File tree

3 files changed

+252
-0
lines changed

3 files changed

+252
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#ifndef FWCore_Framework_interface_WrapperBaseHandle_h
2+
#define FWCore_Framework_interface_WrapperBaseHandle_h
3+
/*
4+
Description: Allows interaction with data in the Event without actually using the C++ class
5+
6+
Usage:
7+
The Handle<WrapperBase> allows one to get data back from the edm::Event as an edm::Wrapper<T>
8+
via a polymorphic pointer of type edm::WrapperBase, instead of as the actual C++ class type.
9+
10+
// make a handle to hold an instance of MyClass
11+
edm::Handle<edm::WrapperBase> handle(typeid(MyClass));
12+
event.getByToken(token, handle);
13+
14+
// handle.product() returns a polymorphic pointer of type edm::WrapperBase to the underlying
15+
// edm::Wrapper<MyClass>
16+
assert(handle.product()->dynamicTypeInfo() == typeid(MyClass));
17+
edm::Wrapper<MyClass> const* wrapper = dynamic_cast<edm::Wrapper<MyClass> const*>(handle.product());
18+
*/
19+
20+
// c++ include files
21+
#include <memory>
22+
#include <string>
23+
24+
// CMSSW include files
25+
#include "DataFormats/Common/interface/Handle.h"
26+
#include "DataFormats/Common/interface/WrapperBase.h"
27+
#include "DataFormats/Provenance/interface/ProductID.h"
28+
#include "FWCore/Framework/interface/Event.h"
29+
#include "FWCore/Utilities/interface/EDMException.h"
30+
#include "FWCore/Utilities/interface/TypeID.h"
31+
32+
// forward declarations
33+
namespace edm {
34+
35+
class Provenance;
36+
37+
template <>
38+
class Handle<WrapperBase> {
39+
public:
40+
explicit Handle(std::type_info const& type) : type_(type), product_(nullptr), prov_(nullptr) {}
41+
42+
explicit Handle(TypeID type) : type_(type), product_(nullptr), prov_(nullptr) {
43+
if (not type_) {
44+
throw Exception(errors::NotFound, "Handle<WrapperBase> given an invalid type.");
45+
}
46+
}
47+
48+
Handle(WrapperBase const* product, Provenance const* prov)
49+
: type_(product->dynamicTypeInfo()), product_(product), prov_(prov) {
50+
assert(product_);
51+
assert(prov_);
52+
}
53+
54+
// Reimplement the interface of HandleBase
55+
56+
void clear() {
57+
product_ = nullptr;
58+
prov_ = nullptr;
59+
whyFailedFactory_ = nullptr;
60+
}
61+
62+
bool isValid() const { return nullptr != product_ and nullptr != prov_; }
63+
64+
bool failedToGet() const { return bool(whyFailedFactory_); }
65+
66+
Provenance const* provenance() const { return prov_; }
67+
68+
ProductID id() const { return prov_->productID(); }
69+
70+
std::shared_ptr<cms::Exception> whyFailed() const {
71+
if (whyFailedFactory_.get()) {
72+
return whyFailedFactory_->make();
73+
}
74+
return std::shared_ptr<cms::Exception>();
75+
}
76+
77+
std::shared_ptr<HandleExceptionFactory const> const& whyFailedFactory() const { return whyFailedFactory_; }
78+
79+
explicit operator bool() const { return isValid(); }
80+
81+
bool operator!() const { return not isValid(); }
82+
83+
// Reimplement the interface of Handle<T>
84+
85+
WrapperBase const* product() const {
86+
if (this->failedToGet()) {
87+
whyFailedFactory_->make()->raise();
88+
}
89+
return product_;
90+
}
91+
92+
WrapperBase const* operator->() const { return this->product(); }
93+
WrapperBase const& operator*() const { return *(this->product()); }
94+
95+
// Additional methods
96+
97+
TypeID const& type() const { return type_; }
98+
99+
void setWhyFailedFactory(std::shared_ptr<HandleExceptionFactory const> const& iWhyFailed) {
100+
whyFailedFactory_ = iWhyFailed;
101+
}
102+
103+
private:
104+
TypeID type_;
105+
WrapperBase const* product_;
106+
Provenance const* prov_;
107+
std::shared_ptr<HandleExceptionFactory const> whyFailedFactory_;
108+
};
109+
110+
// Specialize convert_handle for Handle<WrapperBase>
111+
void convert_handle(BasicHandle&& orig, Handle<WrapperBase>& result);
112+
113+
// Specialize the Event's getByToken method to work with a Handle<WrapperBase>
114+
template <>
115+
bool Event::getByToken<WrapperBase>(EDGetToken token, Handle<WrapperBase>& result) const;
116+
117+
} // namespace edm
118+
119+
#endif // FWCore_Framework_interface_WrapperBaseHandle_h
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#ifndef FWCore_Framework_interface_WrapperBaseOrphanHandle_h
2+
#define FWCore_Framework_interface_WrapperBaseOrphanHandle_h
3+
4+
// c++ include files
5+
#include <memory>
6+
#include <typeinfo>
7+
8+
// CMSSW include files
9+
#include "DataFormats/Common/interface/OrphanHandle.h"
10+
#include "DataFormats/Common/interface/WrapperBase.h"
11+
#include "DataFormats/Provenance/interface/ProductID.h"
12+
#include "FWCore/Framework/interface/Event.h"
13+
#include "FWCore/Utilities/interface/TypeID.h"
14+
15+
// forward declarations
16+
namespace edm {
17+
18+
template <>
19+
class OrphanHandle<WrapperBase> {
20+
public:
21+
OrphanHandle() : product_(nullptr), id_() {}
22+
23+
OrphanHandle(WrapperBase const* prod, ProductID const& id) : product_(prod), id_(id) { assert(product_); }
24+
25+
// Reimplement the interface of OrphanHandleBase
26+
27+
void clear() { product_ = nullptr; }
28+
29+
bool isValid() const { return nullptr != product_; }
30+
31+
ProductID id() const { return id_; }
32+
33+
// Reimplement the interface of OrphanHandle
34+
35+
WrapperBase const* product() const { return product_; }
36+
37+
WrapperBase const* operator->() const { return this->product(); }
38+
WrapperBase const& operator*() const { return *(this->product()); }
39+
40+
private:
41+
WrapperBase const* product_;
42+
ProductID id_;
43+
};
44+
45+
// specialise Event::putImpl for WrapperBase
46+
template <>
47+
inline OrphanHandle<WrapperBase> Event::putImpl(EDPutToken::value_type index, std::unique_ptr<WrapperBase> product) {
48+
// Event::putImpl<PROD> calls detail::do_post_insert_if_available(prod),
49+
// but that requires access to the concrete type of PROD, which is not
50+
// available here. Eventually the call to post_insert() should be moved to
51+
// be part of the Wrapper constructor.
52+
// For now the call to post_insert() is the responsibility of the caller.
53+
54+
assert(index < putProducts().size());
55+
56+
// move the wrapped product into the event
57+
putProducts()[index] = std::move(product);
58+
59+
// construct and return a handle to the product
60+
WrapperBase const* prod = putProducts()[index].get();
61+
ProductID const& prodID = provRecorder_.getProductID(index);
62+
return OrphanHandle<WrapperBase>(prod, prodID);
63+
}
64+
65+
// specialise Event::put for WrapperBase
66+
template <>
67+
inline OrphanHandle<WrapperBase> Event::put(EDPutToken token, std::unique_ptr<WrapperBase> product) {
68+
if (UNLIKELY(product.get() == nullptr)) { // null pointer is illegal
69+
TypeID typeID(typeid(WrapperBase));
70+
principal_get_adapter_detail::throwOnPutOfNullProduct("Event", typeID, provRecorder_.productInstanceLabel(token));
71+
}
72+
std::type_info const& type = product->dynamicTypeInfo();
73+
if (UNLIKELY(token.isUninitialized())) {
74+
principal_get_adapter_detail::throwOnPutOfUninitializedToken("Event", type);
75+
}
76+
TypeID const& expected = provRecorder_.getTypeIDForPutTokenIndex(token.index());
77+
if (UNLIKELY(expected != TypeID{type})) {
78+
principal_get_adapter_detail::throwOnPutOfWrongType(type, expected);
79+
}
80+
81+
return putImpl(token.index(), std::move(product));
82+
}
83+
84+
} // namespace edm
85+
86+
#endif // FWCore_Framework_interface_WrapperBaseOrphanHandle_h
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// CMSSW include files
2+
#include "DataFormats/Common/interface/Handle.h"
3+
#include "DataFormats/Common/interface/WrapperBase.h"
4+
#include "DataFormats/Provenance/interface/Provenance.h"
5+
#include "FWCore/Framework/interface/Event.h"
6+
#include "FWCore/Framework/interface/WrapperBaseHandle.h"
7+
#include "FWCore/Utilities/interface/EDMException.h"
8+
#include "FWCore/Utilities/interface/TypeDemangler.h"
9+
#include "FWCore/Utilities/interface/TypeID.h"
10+
11+
namespace edm {
12+
13+
// Specialize the convert_handle free function for Handle<WrapperBase>
14+
void convert_handle(BasicHandle&& handle, Handle<WrapperBase>& result) {
15+
if (handle.failedToGet()) {
16+
result.setWhyFailedFactory(handle.whyFailedFactory());
17+
return;
18+
}
19+
20+
WrapperBase const* wrapper = handle.wrapper();
21+
if (wrapper == nullptr) {
22+
throw Exception(errors::InvalidReference, "NullPointer") << "edm::BasicHandle has null pointer to Wrapper";
23+
}
24+
25+
if (TypeID(wrapper->dynamicTypeInfo()) != result.type()) {
26+
throw Exception(errors::LogicError) << "WrapperBase asked for " << typeDemangle(result.type().name())
27+
<< " but was given a " << typeDemangle(wrapper->dynamicTypeInfo().name());
28+
}
29+
30+
// Move the handle into result
31+
result = Handle<WrapperBase>(wrapper, handle.provenance());
32+
}
33+
34+
// Specialize the Event::getByToken method for Handle<WrapperBase>
35+
template <>
36+
bool Event::getByToken<WrapperBase>(EDGetToken token, Handle<WrapperBase>& result) const {
37+
result.clear();
38+
BasicHandle bh = provRecorder_.getByToken_(result.type(), PRODUCT_TYPE, token, moduleCallingContext_);
39+
convert_handle(std::move(bh), result); // throws on conversion error
40+
if (UNLIKELY(result.failedToGet())) {
41+
return false;
42+
}
43+
addToGotBranchIDs(*result.provenance());
44+
return true;
45+
}
46+
47+
} // namespace edm

0 commit comments

Comments
 (0)