diff --git a/DataFormats/FWLite/interface/ChainEvent.h b/DataFormats/FWLite/interface/ChainEvent.h index 2cb66644d5d3a..74a2e20e474a3 100644 --- a/DataFormats/FWLite/interface/ChainEvent.h +++ b/DataFormats/FWLite/interface/ChainEvent.h @@ -64,7 +64,10 @@ namespace fwlite { // ---------- const member functions --------------------- std::string const getBranchNameFor(std::type_info const&, char const*, char const*, char const*) const override; - + template + edm::EDGetTokenT consumes(edm::InputTag const& iTag) const { + return event_->consumes(iTag); + } using fwlite::EventBase::getByLabel; // This function should only be called by fwlite::Handle<> @@ -124,6 +127,8 @@ namespace fwlite { fwlite::Run const& getRun(); private: + bool getByTokenImp(edm::EDGetToken, edm::WrapperBase const*&) const override; + friend class MultiChainEvent; ChainEvent(Event const&); // stop default diff --git a/DataFormats/FWLite/interface/DataGetterHelper.h b/DataFormats/FWLite/interface/DataGetterHelper.h index 43cc32ba9ae85..e461a47c4bac0 100644 --- a/DataFormats/FWLite/interface/DataGetterHelper.h +++ b/DataFormats/FWLite/interface/DataGetterHelper.h @@ -60,15 +60,17 @@ namespace fwlite { std::shared_ptr getter = std::shared_ptr(), bool useCache = false, std::function baFunc = [](TBranch const&) {}); - virtual ~DataGetterHelper(); + ~DataGetterHelper(); // ---------- const member functions --------------------- - virtual std::string const getBranchNameFor(std::type_info const&, char const*, char const*, char const*) const; + std::string const getBranchNameFor(std::type_info const&, char const*, char const*, char const*) const; + std::optional getBranchIDFor(std::type_info const&, char const*, char const*, char const*) const; // This function should only be called by fwlite::Handle<> - virtual bool getByLabel(std::type_info const&, char const*, char const*, char const*, void*, Long_t) const; + bool getByLabel(std::type_info const&, char const*, char const*, char const*, void*, Long_t) const; edm::WrapperBase const* getByProductID(edm::ProductID const& pid, Long_t eventEntry) const; + edm::WrapperBase const* getByBranchID(edm::BranchID const& bid, Long_t eventEntry) const; std::optional> getThinnedProduct(edm::ProductID const& pid, unsigned int key, Long_t eventEntry) const; @@ -98,7 +100,6 @@ namespace fwlite { internal::Data& getBranchDataFor(std::type_info const&, char const*, char const*, char const*) const; void getBranchData(edm::EDProductGetter const*, Long64_t, internal::Data&) const; bool getByBranchDescription(edm::BranchDescription const&, Long_t eventEntry, KeyToDataMap::iterator&) const; - edm::WrapperBase const* getByBranchID(edm::BranchID const& bid, Long_t eventEntry) const; edm::WrapperBase const* wrapperBasePtr(edm::ObjectWithDict const&) const; edm::ThinnedAssociation const* getThinnedAssociation(edm::BranchID const& branchID, Long_t eventEntry) const; diff --git a/DataFormats/FWLite/interface/Event.h b/DataFormats/FWLite/interface/Event.h index f3bcf81ec6af3..efbda24c222e0 100644 --- a/DataFormats/FWLite/interface/Event.h +++ b/DataFormats/FWLite/interface/Event.h @@ -84,8 +84,14 @@ namespace fwlite { class HistoryGetterBase; class DataGetterHelper; class RunFactory; + class ChainEvent; + class MultiChainEvent; + class Event : public EventBase { public: + friend class ChainEvent; + friend class MultiChainEvent; + // NOTE: Does NOT take ownership so iFile must remain around // at least as long as Event. // useCache and baFunc (branch-access-function) are passed to @@ -127,6 +133,15 @@ namespace fwlite { char const* iProductInstanceLabel, char const* iProcessName) const override; + template + edm::EDGetTokenT consumes(edm::InputTag const& iTag) const { + auto bid = + dataHelper_.getBranchIDFor(typeid(T), iTag.label().c_str(), iTag.instance().c_str(), iTag.process().c_str()); + if (bid) { + return this->makeTokenUsing(bid.value().id()); + } + return {}; + } using fwlite::EventBase::getByLabel; /// This function should only be called by fwlite::Handle<> bool getByLabel(std::type_info const&, char const*, char const*, char const*, void*) const override; @@ -190,6 +205,7 @@ namespace fwlite { static void throwProductNotFoundException(std::type_info const&, char const*, char const*, char const*); private: + bool getByTokenImp(edm::EDGetToken, edm::WrapperBase const*&) const override; friend class internal::ProductGetter; friend class ChainEvent; friend class EventHistoryGetter; diff --git a/DataFormats/FWLite/interface/EventBase.h b/DataFormats/FWLite/interface/EventBase.h index 16ea744f2faa0..c1f8b4b7f19e3 100644 --- a/DataFormats/FWLite/interface/EventBase.h +++ b/DataFormats/FWLite/interface/EventBase.h @@ -56,8 +56,17 @@ namespace fwlite { virtual Long64_t fileIndex() const { return -1; } virtual Long64_t secondaryFileIndex() const { return -1; } + protected: + template + static edm::EDGetTokenT makeTokenUsing(unsigned int iIndex) { + return edm::EDGetTokenT(iIndex); + } + private: + virtual bool getByTokenImp(edm::EDGetToken, edm::WrapperBase const*&) const = 0; edm::BasicHandle getByLabelImpl(std::type_info const&, std::type_info const&, const edm::InputTag&) const override; + edm::BasicHandle getByTokenImpl(std::type_info const&, edm::EDGetToken) const override; + edm::BasicHandle getImpl(std::type_info const&, edm::ProductID const&) const override; }; } // namespace fwlite diff --git a/DataFormats/FWLite/interface/MultiChainEvent.h b/DataFormats/FWLite/interface/MultiChainEvent.h index 3ada21fbc519e..18b4051cef8c1 100644 --- a/DataFormats/FWLite/interface/MultiChainEvent.h +++ b/DataFormats/FWLite/interface/MultiChainEvent.h @@ -74,6 +74,14 @@ namespace fwlite { // ---------- const member functions --------------------- std::string const getBranchNameFor(std::type_info const&, char const*, char const*, char const*) const override; + template + edm::EDGetTokenT consumes(edm::InputTag const& iTag) const { + auto t = event1_->consumes(iTag); + if (t) { + return t; + } + return event2_->consumes(iTag); + } using fwlite::EventBase::getByLabel; @@ -133,6 +141,8 @@ namespace fwlite { edm::ProductID const& thinned) const; private: + bool getByTokenImp(edm::EDGetToken, edm::WrapperBase const*&) const override; + MultiChainEvent(Event const&); // stop default const MultiChainEvent& operator=(Event const&); // stop default diff --git a/DataFormats/FWLite/src/ChainEvent.cc b/DataFormats/FWLite/src/ChainEvent.cc index 386ac24cfc04e..2e316d027146b 100644 --- a/DataFormats/FWLite/src/ChainEvent.cc +++ b/DataFormats/FWLite/src/ChainEvent.cc @@ -217,6 +217,10 @@ namespace fwlite { return event_->getByLabel(iType, iModule, iInstance, iProcess, iValue); } + bool ChainEvent::getByTokenImp(edm::EDGetToken iToken, edm::WrapperBase const*& iValue) const { + return event_->getByTokenImp(iToken, iValue); + } + edm::WrapperBase const* ChainEvent::getByProductID(edm::ProductID const& iID) const { return event_->getByProductID(iID); } diff --git a/DataFormats/FWLite/src/DataGetterHelper.cc b/DataFormats/FWLite/src/DataGetterHelper.cc index f012664b453f9..d1feea1cb7b94 100644 --- a/DataFormats/FWLite/src/DataGetterHelper.cc +++ b/DataFormats/FWLite/src/DataGetterHelper.cc @@ -147,6 +147,37 @@ namespace fwlite { iData.lastProduct_ = eventEntry; } + std::optional DataGetterHelper::getBranchIDFor(std::type_info const& iInfo, + char const* iModuleLabel, + char const* iProductInstanceLabel, + char const* iProcessLabel) const { + auto branchFor = [this](edm::TypeID const& iInfo, + char const* iModuleLabel, + char const* iProductInstanceLabel, + char const* iProcessLabel) -> std::optional { + for (auto const& bd : branchMap_->getBranchDescriptions()) { + if (bd.unwrappedTypeID() == iInfo and bd.moduleLabel() == iModuleLabel and + bd.productInstanceName() == iProductInstanceLabel and bd.processName() == iProcessLabel) { + return bd.branchID(); + } + } + return std::nullopt; + }; + if (nullptr == iProcessLabel || strlen(iProcessLabel) == 0) { + //have to search in reverse order since newest are on the bottom + const edm::ProcessHistory& h = DataGetterHelper::history(); + edm::TypeID typeID(iInfo); + for (edm::ProcessHistory::const_reverse_iterator iproc = h.rbegin(), eproc = h.rend(); iproc != eproc; ++iproc) { + auto v = branchFor(typeID, iModuleLabel, iProductInstanceLabel, iproc->processName().c_str()); + if (v) { + return v; + } + } + return std::nullopt; + } + return branchFor(edm::TypeID(iInfo), iModuleLabel, iProductInstanceLabel, iProcessLabel); + } + internal::Data& DataGetterHelper::getBranchDataFor(std::type_info const& iInfo, char const* iModuleLabel, char const* iProductInstanceLabel, diff --git a/DataFormats/FWLite/src/Event.cc b/DataFormats/FWLite/src/Event.cc index a859fbf0b61d7..d7c792a5c64ae 100644 --- a/DataFormats/FWLite/src/Event.cc +++ b/DataFormats/FWLite/src/Event.cc @@ -297,6 +297,15 @@ namespace fwlite { return dataHelper_.getByLabel(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel, oData, eventIndex); } + bool Event::getByTokenImp(edm::EDGetToken iToken, edm::WrapperBase const*& oData) const { + if (atEnd()) { + throw cms::Exception("OffEnd") << "You have requested data past the last event"; + } + Long_t eventIndex = branchMap_.getEventEntry(); + oData = dataHelper_.getByBranchID(edm::BranchID(iToken.index()), eventIndex); + return oData != nullptr; + } + edm::EventAuxiliary const& Event::eventAuxiliary() const { Long_t eventIndex = branchMap_.getEventEntry(); updateAux(eventIndex); diff --git a/DataFormats/FWLite/src/EventBase.cc b/DataFormats/FWLite/src/EventBase.cc index 50ae5e6d9a4a7..13851a27949ce 100644 --- a/DataFormats/FWLite/src/EventBase.cc +++ b/DataFormats/FWLite/src/EventBase.cc @@ -64,6 +64,26 @@ namespace fwlite { return value; } + edm::BasicHandle EventBase::getByTokenImpl(std::type_info const& iProdInfo, edm::EDGetToken iToken) const { + edm::WrapperBase const* prod = nullptr; + getByTokenImp(iToken, prod); + if (prod == nullptr || !prod->isPresent()) { + edm::TypeID productType(iProdInfo); + + edm::BasicHandle failed(edm::makeHandleExceptionFactory([=]() -> std::shared_ptr { + std::shared_ptr whyFailed(std::make_shared(edm::errors::ProductNotFound)); + *whyFailed << "getByToken: Found zero products matching all criteria\n" + << "Looking for type: " << productType << "\n" + << "The data is registered in the file but is not available for this event\n"; + return whyFailed; + })); + return failed; + } + + edm::BasicHandle value(prod, &s_prov); + return value; + } + edm::BasicHandle EventBase::getImpl(std::type_info const& iProductInfo, const edm::ProductID& pid) const { edm::WrapperBase const* prod = getByProductID(pid); if (prod == nullptr || !prod->isPresent()) { diff --git a/DataFormats/FWLite/src/MultiChainEvent.cc b/DataFormats/FWLite/src/MultiChainEvent.cc index 93fa4be102bdb..29d89aeae7e44 100644 --- a/DataFormats/FWLite/src/MultiChainEvent.cc +++ b/DataFormats/FWLite/src/MultiChainEvent.cc @@ -315,6 +315,17 @@ namespace fwlite { return true; } + bool MultiChainEvent::getByTokenImp(edm::EDGetToken iToken, edm::WrapperBase const*& iValue) const { + bool ret1 = event1_->getByTokenImp(iToken, iValue); + if (!ret1) { + (const_cast(this))->toSec(event1_->id()); + bool ret2 = event2_->getByTokenImp(iToken, iValue); + if (!ret2) + return false; + } + return true; + } + edm::WrapperBase const* MultiChainEvent::getByProductID(edm::ProductID const& iID) const { // First try the first file edm::WrapperBase const* edp = event1_->getByProductID(iID); diff --git a/DataFormats/FWLite/test/event_looping_consumes_cint.C b/DataFormats/FWLite/test/event_looping_consumes_cint.C new file mode 100644 index 0000000000000..890c3db0ed96f --- /dev/null +++ b/DataFormats/FWLite/test/event_looping_consumes_cint.C @@ -0,0 +1,47 @@ +#include +#include +using namespace std; + +#if defined(__CINT__) && !defined(__MAKECINT__) +class loadFWLite { +public: + loadFWLite() { + gSystem->Load("libFWCoreFWLite"); + FWLiteEnabler::enable(); + } +}; + +static loadFWLite lfw; +#endif + +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/FWLite/interface/Event.h" +#include "FWCore/Utilities/interface/InputTag.h" + +#if !defined(__CINT__) && !defined(__MAKECINT__) +#include "DataFormats/TestObjects/interface/ThingCollection.h" +#endif + +void event_looping_consumes_cint() { + TFile f("good_a.root"); + fwlite::Event e(&f); + + auto token = e.consumes>(edm::InputTag("Thing")); + + int i = 0; + int returnValue = 0; + for (; e.isValid(); ++e, ++i) { + edm::Handle> pThing; + e.getByToken(token, pThing); + + for (int i = 0; i != pThing->size(); ++i) { + cout << pThing->at(i).a << " "; + } + cout << endl; + } + if (i == 0) { + cout << "First loop failed!" << endl; + returnValue = 1; + } + exit(returnValue); +} diff --git a/DataFormats/FWLite/test/run_all_t.sh b/DataFormats/FWLite/test/run_all_t.sh index 0663d8238397b..334cb37510b75 100755 --- a/DataFormats/FWLite/test/run_all_t.sh +++ b/DataFormats/FWLite/test/run_all_t.sh @@ -6,6 +6,7 @@ function die { echo $1: status $2 ; exit $2; } ${LOCAL_TEST_DIR}/RefTest_a.sh || die 'Failed to create file' $? root -b -n -q ${LOCAL_TEST_DIR}/event_looping_cint.C || die 'Failed in event_looping_cint.C' $? +root -b -n -q ${LOCAL_TEST_DIR}/event_looping_consumes_cint.C || die 'Failed in event_looping_cint.C' $? root -b -n -q ${LOCAL_TEST_DIR}/chainevent_looping_cint.C || die 'Failed in chainevent_looping_cint.C' $? python3 ${LOCAL_TEST_DIR}/chainEvent_python.py || die 'Failed in chainEvent_python.py' $? #root -b -n -q ${LOCAL_TEST_DIR}/autoload_with_std.C || die 'Failed in autoload_with_std.C' $? diff --git a/FWCore/Common/interface/EventBase.h b/FWCore/Common/interface/EventBase.h index 754fc2b460b0b..e0600279486a3 100644 --- a/FWCore/Common/interface/EventBase.h +++ b/FWCore/Common/interface/EventBase.h @@ -31,6 +31,7 @@ #include "DataFormats/Common/interface/Handle.h" #include "FWCore/Common/interface/TriggerResultsByName.h" #include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/Utilities/interface/EDGetToken.h" // system include files #include @@ -52,6 +53,9 @@ namespace edm { template bool getByLabel(InputTag const&, Handle&) const; + template + bool getByToken(edm::EDGetTokenT const& token, edm::Handle& result) const; + template bool get(ProductID const&, Handle&) const; @@ -84,6 +88,7 @@ namespace edm { virtual BasicHandle getByLabelImpl(std::type_info const& iWrapperType, std::type_info const& iProductType, InputTag const& iTag) const = 0; + virtual BasicHandle getByTokenImpl(std::type_info const& iProductType, EDGetToken) const = 0; virtual BasicHandle getImpl(std::type_info const& iProductType, ProductID const& iTag) const = 0; // ---------- member data -------------------------------- }; @@ -99,6 +104,17 @@ namespace edm { return true; } + template + bool EventBase::getByToken(edm::EDGetTokenT const& token, edm::Handle& result) const { + result.clear(); + edm::BasicHandle bh = this->getByTokenImpl(typeid(T), token); + result = edm::convert_handle(std::move(bh)); + if (result.failedToGet()) { + return false; + } + return true; + } + template bool EventBase::get(ProductID const& pid, Handle& result) const { result.clear(); diff --git a/FWCore/Framework/interface/Event.h b/FWCore/Framework/interface/Event.h index acb3401d95307..a4648a50472db 100644 --- a/FWCore/Framework/interface/Event.h +++ b/FWCore/Framework/interface/Event.h @@ -279,6 +279,7 @@ namespace edm { BasicHandle getByLabelImpl(std::type_info const& iWrapperType, std::type_info const& iProductType, InputTag const& iTag) const override; + BasicHandle getByTokenImpl(std::type_info const& iProductType, EDGetToken iToken) const override; //override used by EventBase class BasicHandle getImpl(std::type_info const& iProductType, ProductID const& pid) const override; diff --git a/FWCore/Framework/src/Event.cc b/FWCore/Framework/src/Event.cc index 00974f938aba6..702d1175e745c 100644 --- a/FWCore/Framework/src/Event.cc +++ b/FWCore/Framework/src/Event.cc @@ -264,6 +264,14 @@ namespace edm { return h; } + BasicHandle Event::getByTokenImpl(std::type_info const& iProductType, EDGetToken iToken) const { + BasicHandle h = provRecorder_.getByToken_(TypeID(iProductType), PRODUCT_TYPE, iToken, moduleCallingContext_); + if (h.isValid()) { + addToGotBranchIDs(*(h.provenance())); + } + return h; + } + BasicHandle Event::getImpl(std::type_info const&, ProductID const& pid) const { BasicHandle h = this->getByProductID_(pid); if (h.isValid()) { diff --git a/FWCore/Framework/test/Event_t.cpp b/FWCore/Framework/test/Event_t.cpp index e24b057b1aaa5..4376b051aae27 100644 --- a/FWCore/Framework/test/Event_t.cpp +++ b/FWCore/Framework/test/Event_t.cpp @@ -499,6 +499,16 @@ void testEvent::getByTokenFromEmpty() { CPPUNIT_ASSERT(!nonesuch.isValid()); CPPUNIT_ASSERT(nonesuch.failedToGet()); CPPUNIT_ASSERT_THROW(*nonesuch, cms::Exception); + + { + edm::EventBase const* eb = currentEvent_.get(); + Handle nonesuch; + CPPUNIT_ASSERT(!nonesuch.isValid()); + CPPUNIT_ASSERT(!eb->getByToken(consumer.m_tokens[0], nonesuch)); + CPPUNIT_ASSERT(!nonesuch.isValid()); + CPPUNIT_ASSERT(nonesuch.failedToGet()); + CPPUNIT_ASSERT_THROW(*nonesuch, cms::Exception); + } } void testEvent::getHandleFromEmpty() { @@ -765,6 +775,7 @@ void testEvent::getByToken() { consumer.updateLookup(InEvent, principal_->productLookup(), false); currentEvent_->setConsumer(&consumer); + edm::EventBase const* eb = currentEvent_.get(); const auto modMultiToken = consumer.m_tokens[0]; const auto modMultiInt1Token = consumer.m_tokens[1]; @@ -778,9 +789,13 @@ void testEvent::getByToken() { handle_t h; CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiToken, h)); CPPUNIT_ASSERT(h->value == 3); + CPPUNIT_ASSERT(eb->getByToken(modMultiToken, h)); + CPPUNIT_ASSERT(h->value == 3); CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiInt1Token, h)); CPPUNIT_ASSERT(h->value == 200); + CPPUNIT_ASSERT(eb->getByToken(modMultiInt1Token, h)); + CPPUNIT_ASSERT(h->value == 200); CPPUNIT_ASSERT(!currentEvent_->getByToken(modMultinomatchToken, h)); CPPUNIT_ASSERT(!h.isValid()); @@ -788,21 +803,33 @@ void testEvent::getByToken() { CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiInt1Token, h)); CPPUNIT_ASSERT(h->value == 200); + CPPUNIT_ASSERT(eb->getByToken(modMultiInt1Token, h)); + CPPUNIT_ASSERT(h->value == 200); CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiInt1EarlyToken, h)); CPPUNIT_ASSERT(h->value == 1); + CPPUNIT_ASSERT(eb->getByToken(modMultiInt1EarlyToken, h)); + CPPUNIT_ASSERT(h->value == 1); CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiInt1LateToken, h)); CPPUNIT_ASSERT(h->value == 100); + CPPUNIT_ASSERT(eb->getByToken(modMultiInt1LateToken, h)); + CPPUNIT_ASSERT(h->value == 100); CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiInt1CurrentToken, h)); CPPUNIT_ASSERT(h->value == 200); + CPPUNIT_ASSERT(eb->getByToken(modMultiInt1CurrentToken, h)); + CPPUNIT_ASSERT(h->value == 200); CPPUNIT_ASSERT(currentEvent_->getByToken(modMultiInt2EarlyToken, h)); CPPUNIT_ASSERT(h->value == 2); + CPPUNIT_ASSERT(eb->getByToken(modMultiInt2EarlyToken, h)); + CPPUNIT_ASSERT(h->value == 2); CPPUNIT_ASSERT(currentEvent_->getByToken(modOneToken, h)); CPPUNIT_ASSERT(h->value == 4); + CPPUNIT_ASSERT(eb->getByToken(modOneToken, h)); + CPPUNIT_ASSERT(h->value == 4); } void testEvent::getHandle() { diff --git a/FWCore/Utilities/interface/EDGetToken.h b/FWCore/Utilities/interface/EDGetToken.h index 49a0fced1bf66..2c660eb78a5c2 100644 --- a/FWCore/Utilities/interface/EDGetToken.h +++ b/FWCore/Utilities/interface/EDGetToken.h @@ -27,6 +27,10 @@ The templated form, EDGetTokenT, is the same as EDGetToken except when used t // user include files // forward declarations +namespace fwlite { + class EventBase; +} + namespace edm { class EDConsumerBase; template @@ -66,6 +70,7 @@ namespace edm { class EDGetTokenT { friend class EDConsumerBase; friend class EDGetToken; + friend class ::fwlite::EventBase; public: constexpr EDGetTokenT() : m_value{s_uninitializedValue} {}