Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-04-30 22:24:07

0001 // -*- C++ -*-
0002 //
0003 // Package:     FWCore/Framework
0004 // Class  :     EDConsumerBase
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author:  Chris Jones
0010 //         Created:  Tue, 02 Apr 2013 21:36:06 GMT
0011 //
0012 
0013 // system include files
0014 #include <algorithm>
0015 #include <cstring>
0016 #include <set>
0017 #include <string_view>
0018 
0019 // user include files
0020 #include "DataFormats/Provenance/interface/BranchType.h"
0021 #include "FWCore/Framework/interface/EDConsumerBase.h"
0022 #include "FWCore/Framework/interface/ConsumesCollector.h"
0023 #include "FWCore/Framework/interface/ESRecordsToProductResolverIndices.h"
0024 #include "FWCore/Framework/interface/ComponentDescription.h"
0025 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0026 #include "FWCore/ServiceRegistry/interface/ModuleConsumesInfo.h"
0027 #include "FWCore/Utilities/interface/Likely.h"
0028 #include "FWCore/Utilities/interface/Exception.h"
0029 #include "DataFormats/Provenance/interface/ProductResolverIndexHelper.h"
0030 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0031 
0032 using namespace edm;
0033 
0034 namespace {
0035   std::vector<char> makeEmptyTokenLabels() { return std::vector<char>{'\0'}; }
0036 }  // namespace
0037 
0038 EDConsumerBase::EDConsumerBase()
0039     : m_tokenLabels{makeEmptyTokenLabels()},
0040       esDataThatCanBeDeletedEarly_(std::make_unique<ESDataThatCanBeDeletedEarly>()),
0041       frozen_(false),
0042       containsCurrentProcessAlias_(false) {}
0043 
0044 EDConsumerBase::~EDConsumerBase() noexcept(false) {}
0045 
0046 //
0047 // member functions
0048 //
0049 ConsumesCollector EDConsumerBase::consumesCollector() {
0050   ConsumesCollector c{this};
0051   return c;
0052 }
0053 
0054 static const edm::InputTag kWasEmpty("@EmptyLabel@");
0055 
0056 edm::InputTag const& EDConsumerBase::checkIfEmpty(edm::InputTag const& iTag) {
0057   if (iTag.label().empty()) {
0058     return kWasEmpty;
0059   }
0060   return iTag;
0061 }
0062 
0063 unsigned int EDConsumerBase::recordConsumes(BranchType iBranch,
0064                                             TypeToGet const& iType,
0065                                             edm::InputTag const& iTag,
0066                                             bool iAlwaysGets) {
0067   if (frozen_) {
0068     throwConsumesCallAfterFrozen(iType, iTag);
0069   }
0070 
0071   unsigned int index = m_tokenInfo.size();
0072 
0073   bool skipCurrentProcess = iTag.willSkipCurrentProcess();
0074 
0075   const size_t labelSize = iTag.label().size();
0076   const size_t productInstanceSize = iTag.instance().size();
0077   unsigned int labelStart = m_tokenLabels.size();
0078   unsigned short delta1 = labelSize + 1;
0079   unsigned short delta2 = labelSize + 2 + productInstanceSize;
0080   m_tokenInfo.emplace_back(TokenLookupInfo{iType.type(), ProductResolverIndexInvalid, skipCurrentProcess, iBranch},
0081                            iAlwaysGets,
0082                            LabelPlacement{labelStart, delta1, delta2},
0083                            iType.kind());
0084 
0085   const size_t additionalSize = skipCurrentProcess ? labelSize + productInstanceSize + 3
0086                                                    : labelSize + productInstanceSize + iTag.process().size() + 3;
0087 
0088   m_tokenLabels.reserve(m_tokenLabels.size() + additionalSize);
0089   {
0090     const std::string& m = iTag.label();
0091     m_tokenLabels.insert(m_tokenLabels.end(), m.begin(), m.end());
0092     m_tokenLabels.push_back('\0');
0093   }
0094   {
0095     const std::string& m = iTag.instance();
0096     m_tokenLabels.insert(m_tokenLabels.end(), m.begin(), m.end());
0097     m_tokenLabels.push_back('\0');
0098   }
0099   {
0100     const std::string& m = iTag.process();
0101     if (m == InputTag::kCurrentProcess) {
0102       containsCurrentProcessAlias_ = true;
0103     }
0104     if (!skipCurrentProcess) {
0105       m_tokenLabels.insert(m_tokenLabels.end(), m.begin(), m.end());
0106       m_tokenLabels.push_back('\0');
0107     } else {
0108       m_tokenLabels.push_back('\0');
0109     }
0110   }
0111   return index;
0112 }
0113 
0114 void EDConsumerBase::extendUpdateLookup(BranchType, ProductResolverIndexHelper const&) {}
0115 
0116 void EDConsumerBase::updateLookup(BranchType iBranchType,
0117                                   ProductResolverIndexHelper const& iHelper,
0118                                   bool iPrefetchMayGet) {
0119   frozen_ = true;
0120   assert(!containsCurrentProcessAlias_);
0121   extendUpdateLookup(iBranchType, iHelper);
0122   {
0123     auto itKind = m_tokenInfo.begin<kKind>();
0124     auto itLabels = m_tokenInfo.begin<kLabels>();
0125     for (auto itInfo = m_tokenInfo.begin<kLookupInfo>(), itEnd = m_tokenInfo.end<kLookupInfo>(); itInfo != itEnd;
0126          ++itInfo, ++itKind, ++itLabels) {
0127       if (itInfo->m_branchType == iBranchType) {
0128         const unsigned int labelStart = itLabels->m_startOfModuleLabel;
0129         const char* moduleLabel = &(m_tokenLabels[labelStart]);
0130         itInfo->m_index = ProductResolverIndexAndSkipBit(iHelper.index(*itKind,
0131                                                                        itInfo->m_type,
0132                                                                        moduleLabel,
0133                                                                        moduleLabel + itLabels->m_deltaToProductInstance,
0134                                                                        moduleLabel + itLabels->m_deltaToProcessName),
0135                                                          itInfo->m_index.skipCurrentProcess());
0136       }
0137     }
0138   }
0139 
0140   m_tokenInfo.shrink_to_fit();
0141 
0142   itemsToGet(iBranchType, itemsToGetFromBranch_[iBranchType]);
0143   if (iPrefetchMayGet) {
0144     itemsMayGet(iBranchType, itemsToGetFromBranch_[iBranchType]);
0145   }
0146 }
0147 
0148 void EDConsumerBase::updateLookup(eventsetup::ESRecordsToProductResolverIndices const& iPI) {
0149   // temporarily unfreeze to allow late EventSetup consumes registration
0150   frozen_ = false;
0151   registerLateConsumes(iPI);
0152   frozen_ = true;
0153 
0154   unsigned int index = 0;
0155   for (auto it = esTokenLookupInfoContainer().begin<kESLookupInfo>();
0156        it != esTokenLookupInfoContainer().end<kESLookupInfo>();
0157        ++it, ++index) {
0158     auto indexInRecord = iPI.indexInRecord(it->m_record, it->m_key);
0159     if (indexInRecord != ESResolverIndex::noResolverConfigured()) {
0160       const char* componentName = &(m_tokenLabels[it->m_startOfComponentName]);
0161       if (*componentName) {
0162         auto component = iPI.component(it->m_record, it->m_key);
0163         if (component->label_.empty()) {
0164           if (component->type_ != componentName) {
0165             indexInRecord = ESResolverIndex::moduleLabelDoesNotMatch();
0166           }
0167         } else if (component->label_ != componentName) {
0168           indexInRecord = ESResolverIndex::moduleLabelDoesNotMatch();
0169         }
0170       }
0171     }
0172     esDataThatCanBeDeletedEarly_->esTokenLookupInfoContainer_.get<kESResolverIndex>(index) = indexInRecord;
0173 
0174     int negIndex = -1 * (index + 1);
0175     for (auto& items : esItemsToGetFromTransition_) {
0176       for (auto& itemIndex : items) {
0177         if (itemIndex.value() == negIndex) {
0178           itemIndex = indexInRecord;
0179           ESResolverIndexContainer::size_type transitionIndex = &items - &esItemsToGetFromTransition_.front();
0180           std::vector<ESResolverIndex>::size_type indexToItemInTransition = &itemIndex - &items.front();
0181           esRecordsToGetFromTransition_[transitionIndex][indexToItemInTransition] = iPI.recordIndexFor(it->m_record);
0182           esDataThatCanBeDeletedEarly_->consumesIndexConverter_.emplace_back(transitionIndex, indexToItemInTransition);
0183           negIndex = 1;
0184           break;
0185         }
0186       }
0187       if (negIndex > 0) {
0188         break;
0189       }
0190     }
0191   }
0192 }
0193 
0194 void EDConsumerBase::releaseMemoryPostLookupSignal() { esDataThatCanBeDeletedEarly_.reset(); }
0195 
0196 std::tuple<ESTokenIndex, char const*> EDConsumerBase::recordESConsumes(
0197     Transition iTrans,
0198     eventsetup::EventSetupRecordKey const& iRecord,
0199     eventsetup::heterocontainer::HCTypeTag const& iDataType,
0200     edm::ESInputTag const& iTag) {
0201   if (frozen_) {
0202     throwESConsumesCallAfterFrozen(iRecord, iDataType, iTag);
0203   }
0204 
0205   //m_tokenLabels first entry is a null. Since most ES data requests have
0206   // empty labels we will assume we can reuse the first entry
0207   unsigned int startOfComponentName = 0;
0208   if (not iTag.module().empty()) {
0209     startOfComponentName = m_tokenLabels.size();
0210 
0211     m_tokenLabels.reserve(m_tokenLabels.size() + iTag.module().size() + 1);
0212     {
0213       const std::string& m = iTag.module();
0214       m_tokenLabels.insert(m_tokenLabels.end(), m.begin(), m.end());
0215       m_tokenLabels.push_back('\0');
0216     }
0217   }
0218 
0219   auto index = static_cast<ESResolverIndex::Value_t>(esTokenLookupInfoContainer().size());
0220   esDataThatCanBeDeletedEarly_->esTokenLookupInfoContainer_.emplace_back(
0221       ESTokenLookupInfo{iRecord, eventsetup::DataKey{iDataType, iTag.data().c_str()}, startOfComponentName},
0222       ESResolverIndex{-1});
0223   if (iTrans >= edm::Transition::NumberOfEventSetupTransitions) {
0224     throwESConsumesInProcessBlock();
0225   }
0226   auto indexForToken = esItemsToGetFromTransition_[static_cast<unsigned int>(iTrans)].size();
0227   esItemsToGetFromTransition_[static_cast<unsigned int>(iTrans)].emplace_back(-1 * (index + 1));
0228   esRecordsToGetFromTransition_[static_cast<unsigned int>(iTrans)].emplace_back();
0229   return {ESTokenIndex{static_cast<ESTokenIndex::Value_t>(indexForToken)},
0230           esTokenLookupInfoContainer().get<kESLookupInfo>(index).m_key.name().value()};
0231 }
0232 
0233 //
0234 // const member functions
0235 //
0236 ProductResolverIndexAndSkipBit EDConsumerBase::indexFrom(EDGetToken iToken,
0237                                                          BranchType iBranch,
0238                                                          TypeID const& iType) const {
0239   if (UNLIKELY(iToken.index() >= m_tokenInfo.size())) {
0240     throwBadToken(iType, iToken);
0241   }
0242   const auto& info = m_tokenInfo.get<kLookupInfo>(iToken.index());
0243   if (LIKELY(iBranch == info.m_branchType)) {
0244     if (LIKELY(iType == info.m_type)) {
0245       return info.m_index;
0246     } else {
0247       throwTypeMismatch(iType, iToken);
0248     }
0249   } else {
0250     throwBranchMismatch(iBranch, iToken);
0251   }
0252   return ProductResolverIndexAndSkipBit(edm::ProductResolverIndexInvalid, false);
0253 }
0254 
0255 ProductResolverIndexAndSkipBit EDConsumerBase::uncheckedIndexFrom(EDGetToken iToken) const {
0256   return m_tokenInfo.get<kLookupInfo>(iToken.index()).m_index;
0257 }
0258 
0259 void EDConsumerBase::itemsToGet(BranchType iBranch, std::vector<ProductResolverIndexAndSkipBit>& oIndices) const {
0260   //how many are we adding?
0261   unsigned int count = 0;
0262   {
0263     auto itAlwaysGet = m_tokenInfo.begin<kAlwaysGets>();
0264     for (auto it = m_tokenInfo.begin<kLookupInfo>(), itEnd = m_tokenInfo.end<kLookupInfo>(); it != itEnd;
0265          ++it, ++itAlwaysGet) {
0266       if (iBranch == it->m_branchType) {
0267         if (it->m_index.productResolverIndex() != ProductResolverIndexInvalid) {
0268           if (*itAlwaysGet) {
0269             ++count;
0270           }
0271         }
0272       }
0273     }
0274   }
0275   oIndices.reserve(oIndices.size() + count);
0276   {
0277     auto itAlwaysGet = m_tokenInfo.begin<kAlwaysGets>();
0278     for (auto it = m_tokenInfo.begin<kLookupInfo>(), itEnd = m_tokenInfo.end<kLookupInfo>(); it != itEnd;
0279          ++it, ++itAlwaysGet) {
0280       if (iBranch == it->m_branchType) {
0281         if (it->m_index.productResolverIndex() != ProductResolverIndexInvalid) {
0282           if (*itAlwaysGet) {
0283             oIndices.push_back(it->m_index);
0284           }
0285         }
0286       }
0287     }
0288   }
0289 }
0290 
0291 void EDConsumerBase::itemsMayGet(BranchType iBranch, std::vector<ProductResolverIndexAndSkipBit>& oIndices) const {
0292   //how many are we adding?
0293   unsigned int count = 0;
0294   {
0295     auto itAlwaysGet = m_tokenInfo.begin<kAlwaysGets>();
0296     for (auto it = m_tokenInfo.begin<kLookupInfo>(), itEnd = m_tokenInfo.end<kLookupInfo>(); it != itEnd;
0297          ++it, ++itAlwaysGet) {
0298       if (iBranch == it->m_branchType) {
0299         if (it->m_index.productResolverIndex() != ProductResolverIndexInvalid) {
0300           if (not *itAlwaysGet) {
0301             ++count;
0302           }
0303         }
0304       }
0305     }
0306   }
0307   oIndices.reserve(oIndices.size() + count);
0308   {
0309     auto itAlwaysGet = m_tokenInfo.begin<kAlwaysGets>();
0310     for (auto it = m_tokenInfo.begin<kLookupInfo>(), itEnd = m_tokenInfo.end<kLookupInfo>(); it != itEnd;
0311          ++it, ++itAlwaysGet) {
0312       if (iBranch == it->m_branchType) {
0313         if (it->m_index.productResolverIndex() != ProductResolverIndexInvalid) {
0314           if (not *itAlwaysGet) {
0315             oIndices.push_back(it->m_index);
0316           }
0317         }
0318       }
0319     }
0320   }
0321 }
0322 
0323 void EDConsumerBase::labelsForToken(EDGetToken iToken, Labels& oLabels) const {
0324   unsigned int index = iToken.index();
0325   auto labels = m_tokenInfo.get<kLabels>(index);
0326   unsigned int start = labels.m_startOfModuleLabel;
0327   oLabels.module = &(m_tokenLabels[start]);
0328   oLabels.productInstance = oLabels.module + labels.m_deltaToProductInstance;
0329   oLabels.process = oLabels.module + labels.m_deltaToProcessName;
0330 }
0331 
0332 bool EDConsumerBase::registeredToConsume(ProductResolverIndex iIndex,
0333                                          bool skipCurrentProcess,
0334                                          BranchType iBranch) const {
0335   for (auto it = m_tokenInfo.begin<kLookupInfo>(), itEnd = m_tokenInfo.end<kLookupInfo>(); it != itEnd; ++it) {
0336     if (it->m_index.productResolverIndex() == iIndex and it->m_index.skipCurrentProcess() == skipCurrentProcess and
0337         it->m_branchType == iBranch) {
0338       return true;
0339     }
0340   }
0341   return false;
0342 }
0343 
0344 void EDConsumerBase::throwTypeMismatch(edm::TypeID const& iType, EDGetToken iToken) const {
0345   throw cms::Exception("TypeMismatch") << "A get using a EDGetToken used the C++ type '" << iType.className()
0346                                        << "' but the consumes call was for type '"
0347                                        << m_tokenInfo.get<kLookupInfo>(iToken.index()).m_type.className()
0348                                        << "'.\n Please modify either the consumes or get call so the types match.";
0349 }
0350 void EDConsumerBase::throwBranchMismatch(BranchType iBranch, EDGetToken iToken) const {
0351   throw cms::Exception("BranchTypeMismatch")
0352       << "A get using a EDGetToken was done in " << BranchTypeToString(iBranch) << " but the consumes call was for "
0353       << BranchTypeToString(m_tokenInfo.get<kLookupInfo>(iToken.index()).m_branchType)
0354       << ".\n Please modify the consumes call to use the correct branch type.";
0355 }
0356 
0357 void EDConsumerBase::throwBadToken(edm::TypeID const& iType, EDGetToken iToken) const {
0358   if (iToken.isUninitialized()) {
0359     throw cms::Exception("BadToken") << "A get using a EDGetToken with the C++ type '" << iType.className()
0360                                      << "' was made using an uninitialized token.\n Please check that the variable is "
0361                                         "being initialized from a 'consumes' call.";
0362   }
0363   throw cms::Exception("BadToken")
0364       << "A get using a EDGetToken with the C++ type '" << iType.className() << "' was made using a token with a value "
0365       << iToken.index()
0366       << " which is beyond the range used by this module.\n Please check that the variable is being initialized from a "
0367          "'consumes' call from this module.\n You can not share EDGetToken values between modules.";
0368 }
0369 
0370 void EDConsumerBase::throwConsumesCallAfterFrozen(TypeToGet const& typeToGet, InputTag const& inputTag) const {
0371   throw cms::Exception("LogicError") << "A module declared it consumes a product after its constructor.\n"
0372                                      << "This must be done in the contructor\n"
0373                                      << "The product type was: " << typeToGet.type() << "\n"
0374                                      << "and " << inputTag << "\n";
0375 }
0376 
0377 void EDConsumerBase::throwESConsumesCallAfterFrozen(eventsetup::EventSetupRecordKey const& iRecord,
0378                                                     eventsetup::heterocontainer::HCTypeTag const& iDataType,
0379                                                     edm::ESInputTag const& iTag) const {
0380   throw cms::Exception("LogicError") << "A module declared it consumes an EventSetup product after its constructor.\n"
0381                                      << "This must be done in the contructor\n"
0382                                      << "The product type was: " << iDataType.name() << " in record "
0383                                      << iRecord.type().name() << "\n"
0384                                      << "and ESInputTag was " << iTag << "\n";
0385 }
0386 
0387 void EDConsumerBase::throwESConsumesInProcessBlock() const {
0388   throw cms::Exception("LogicError")
0389       << "A module declared it consumes an EventSetup product during a ProcessBlock transition.\n"
0390       << "EventSetup products can only be consumed in Event, Lumi, or Run transitions.\n";
0391 }
0392 
0393 void EDConsumerBase::doSelectInputProcessBlocks(ProductRegistry const&, ProcessBlockHelperBase const&) {}
0394 
0395 void EDConsumerBase::convertCurrentProcessAlias(std::string const& processName) {
0396   frozen_ = true;
0397 
0398   if (containsCurrentProcessAlias_) {
0399     containsCurrentProcessAlias_ = false;
0400 
0401     auto newTokenLabels = makeEmptyTokenLabels();
0402 
0403     // first calculate the size of the new vector and reserve memory for it
0404     std::vector<char>::size_type newSize = newTokenLabels.size();
0405     std::string newProcessName;
0406     for (auto iter = m_tokenInfo.begin<kLabels>(), itEnd = m_tokenInfo.end<kLabels>(); iter != itEnd; ++iter) {
0407       newProcessName = &m_tokenLabels[iter->m_startOfModuleLabel + iter->m_deltaToProcessName];
0408       if (newProcessName == InputTag::kCurrentProcess) {
0409         newProcessName = processName;
0410       }
0411       newSize += (iter->m_deltaToProcessName + newProcessName.size() + 1);
0412     }
0413     newTokenLabels.reserve(newSize);
0414 
0415     unsigned int newStartOfModuleLabel = newTokenLabels.size();
0416     for (auto iter = m_tokenInfo.begin<kLabels>(), itEnd = m_tokenInfo.end<kLabels>(); iter != itEnd; ++iter) {
0417       unsigned int startOfModuleLabel = iter->m_startOfModuleLabel;
0418       unsigned short deltaToProcessName = iter->m_deltaToProcessName;
0419 
0420       iter->m_startOfModuleLabel = newStartOfModuleLabel;
0421 
0422       newProcessName = &m_tokenLabels[startOfModuleLabel + deltaToProcessName];
0423       if (newProcessName == InputTag::kCurrentProcess) {
0424         newProcessName = processName;
0425       }
0426 
0427       newStartOfModuleLabel += (deltaToProcessName + newProcessName.size() + 1);
0428 
0429       // Copy in both the module label and instance, they are the same
0430       newTokenLabels.insert(newTokenLabels.end(),
0431                             m_tokenLabels.begin() + startOfModuleLabel,
0432                             m_tokenLabels.begin() + (startOfModuleLabel + deltaToProcessName));
0433 
0434       newTokenLabels.insert(newTokenLabels.end(), newProcessName.begin(), newProcessName.end());
0435       newTokenLabels.push_back('\0');
0436     }
0437     m_tokenLabels = std::move(newTokenLabels);
0438   }
0439 }
0440 
0441 std::vector<ModuleConsumesInfo> EDConsumerBase::moduleConsumesInfos() const {
0442   std::vector<ModuleConsumesInfo> result;
0443   result.reserve(m_tokenInfo.size());
0444   consumedProducts([&](ModuleConsumesInfo const& info) {
0445     assert(not info.label().empty());
0446     result.push_back(info);
0447   });
0448   return result;
0449 }
0450 
0451 std::vector<ModuleConsumesMinimalESInfo> EDConsumerBase::moduleConsumesMinimalESInfos() const {
0452   std::vector<ModuleConsumesMinimalESInfo> result;
0453   result.reserve(esTokenLookupInfoContainer().size());
0454   consumedESProducts([&](ModuleConsumesMinimalESInfo&& minInfo) mutable { result.emplace_back(std::move(minInfo)); });
0455   return result;
0456 }