Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:03:55

0001 #include "DataFormats/Common/interface/RefCore.h"
0002 #include "DataFormats/Common/interface/WrapperBase.h"
0003 #include "DataFormats/Common/interface/EDProductGetter.h"
0004 #include "FWCore/Utilities/interface/EDMException.h"
0005 #include "FWCore/Utilities/interface/TypeID.h"
0006 #include <cassert>
0007 
0008 static void throwInvalidRefFromNullOrInvalidRef(const edm::TypeID& id) {
0009   throw edm::Exception(edm::errors::InvalidReference, "BadRefCore")
0010       << "RefCore: Request to resolve a null or invalid reference to a product of type '" << id
0011       << "' has been detected.\n"
0012       << "Please modify the calling code to test validity before dereferencing.\n";
0013 }
0014 
0015 static void throwInvalidRefFromNoCache(const edm::TypeID& id, edm::ProductID const& prodID) {
0016   throw edm::Exception(edm::errors::InvalidReference, "BadRefCore")
0017       << "RefCore: A request to resolve a reference to a product of type '" << id << "' with ProductID '" << prodID
0018       << "' cannot be satisfied.\n"
0019       << "The reference has neither a valid product pointer nor an EDProductGetter.\n"
0020       << "The calling code must be modified to establish a functioning EDProducterGetter\n"
0021       << "for the context in which this call is mode\n";
0022 }
0023 
0024 namespace edm {
0025 
0026   RefCore::RefCore(ProductID const& theId, void const* prodPtr, EDProductGetter const* prodGetter, bool transient)
0027       : cachePtr_(prodPtr), processIndex_(theId.processIndex()), productIndex_(theId.productIndex()) {
0028     if (transient) {
0029       setTransient();
0030     }
0031     if (prodPtr == nullptr && prodGetter != nullptr) {
0032       setCacheIsProductGetter(prodGetter);
0033     }
0034   }
0035 
0036   RefCore::RefCore(RefCore const& iOther) : processIndex_(iOther.processIndex_), productIndex_(iOther.productIndex_) {
0037     cachePtr_.store(iOther.cachePtr_.load(std::memory_order_relaxed), std::memory_order_relaxed);
0038   }
0039 
0040   RefCore& RefCore::operator=(RefCore const& iOther) {
0041     cachePtr_.store(iOther.cachePtr_.load(std::memory_order_relaxed), std::memory_order_relaxed);
0042     processIndex_ = iOther.processIndex_;
0043     productIndex_ = iOther.productIndex_;
0044     return *this;
0045   }
0046 
0047   WrapperBase const* RefCore::getProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const {
0048     // The following invariant would be nice to establish in all
0049     // constructors, but we can not be sure that the context in which
0050     // EDProductGetter::instance() is called will be one where a
0051     // non-null pointer is returned. The biggest question in the
0052     // various times at which Root makes RefCore instances, and how
0053     // old ones might be recycled.
0054     //
0055     // If our ProductID is non-null, we must have a way to get at the
0056     // product (unless it has been dropped). This means either we
0057     // already have the pointer to the product, or we have a valid
0058     // EDProductGetter to use.
0059     //
0060     //     assert(!id_.isValid() || productGetter() || prodPtr_);
0061 
0062     ProductID tId = id();
0063     assert(!isTransient());
0064     if (!tId.isValid()) {
0065       throwInvalidRefFromNullOrInvalidRef(TypeID(type));
0066     }
0067 
0068     //if (productPtr() == 0 && productGetter() == 0) {
0069     if (cachePtrIsInvalid()) {
0070       throwInvalidRefFromNoCache(TypeID(type), tId);
0071     }
0072     WrapperBase const* product = prodGetter->getIt(tId);
0073     if (product == nullptr) {
0074       productNotFoundException(type);
0075     }
0076     if (!(type == product->dynamicTypeInfo())) {
0077       wrongTypeException(type, product->dynamicTypeInfo());
0078     }
0079     return product;
0080   }
0081 
0082   WrapperBase const* RefCore::tryToGetProductPtr(std::type_info const& type, EDProductGetter const* prodGetter) const {
0083     ProductID tId = id();
0084     assert(!isTransient());
0085     if (!tId.isValid()) {
0086       throwInvalidRefFromNullOrInvalidRef(TypeID(type));
0087     }
0088 
0089     if (cachePtrIsInvalid()) {
0090       throwInvalidRefFromNoCache(TypeID(type), tId);
0091     }
0092     WrapperBase const* product = prodGetter->getIt(tId);
0093     if (product != nullptr && !(type == product->dynamicTypeInfo())) {
0094       wrongTypeException(type, product->dynamicTypeInfo());
0095     }
0096     return product;
0097   }
0098 
0099   std::tuple<WrapperBase const*, unsigned int> RefCore::getThinnedProductPtr(std::type_info const& type,
0100                                                                              unsigned int key,
0101                                                                              EDProductGetter const* prodGetter) const {
0102     ProductID tId = id();
0103     std::optional product = prodGetter->getThinnedProduct(tId, key);
0104 
0105     if (not product.has_value()) {
0106       productNotFoundException(type);
0107     }
0108     WrapperBase const* wrapper = std::get<WrapperBase const*>(*product);
0109     if (!(type == wrapper->dynamicTypeInfo())) {
0110       wrongTypeException(type, wrapper->dynamicTypeInfo());
0111     }
0112     return *product;
0113   }
0114 
0115   bool RefCore::isThinnedAvailable(unsigned int key, EDProductGetter const* prodGetter) const {
0116     ProductID tId = id();
0117     if (!tId.isValid() || prodGetter == nullptr) {
0118       //another thread may have changed it
0119       return nullptr != productPtr();
0120     }
0121     std::optional product = prodGetter->getThinnedProduct(tId, key);
0122     return product.has_value();
0123   }
0124 
0125   void RefCore::productNotFoundException(std::type_info const& type) const {
0126     throw edm::Exception(errors::ProductNotFound)
0127         << "RefCore: A request to resolve a reference to a product of type '" << TypeID(type) << "' with ProductID '"
0128         << id() << "'"
0129         << "\ncan not be satisfied because the product cannot be found."
0130         << "\nProbably the branch containing the product is not stored in the input file.\n";
0131   }
0132 
0133   void RefCore::wrongTypeException(std::type_info const& expectedType, std::type_info const& actualType) const {
0134     throw edm::Exception(errors::InvalidReference, "WrongType")
0135         << "RefCore: A request to convert a contained product of type '" << TypeID(actualType) << "'\n"
0136         << " to type '" << TypeID(expectedType) << "'"
0137         << "\nfor ProductID '" << id() << "' can not be satisfied\n";
0138   }
0139 
0140   void RefCore::nullPointerForTransientException(std::type_info const& type) const {
0141     throw edm::Exception(errors::InvalidReference)
0142         << "RefCore: A request to resolve a transient reference to a product of type: " << TypeID(type)
0143         << "\ncan not be satisfied because the pointer to the product is null.\n";
0144   }
0145 
0146   bool RefCore::isAvailable() const {
0147     ProductID tId = id();
0148     //If another thread changes the cache, it will change a non-null productGetter
0149     // into a null productGeter but productPtr will be non-null
0150     // Therefore reading productGetter() first is the safe order
0151     auto prodGetter = productGetter();
0152     auto prodPtr = productPtr();
0153     return prodPtr != nullptr || (tId.isValid() && prodGetter != nullptr && prodGetter->getIt(tId) != nullptr);
0154   }
0155 
0156   void RefCore::setProductGetter(EDProductGetter const* prodGetter) const { setCacheIsProductGetter(prodGetter); }
0157 
0158   void RefCore::setId(ProductID const& iId) {
0159     unsigned short head = processIndex_ & (refcoreimpl::kTransientBit | refcoreimpl::kCacheIsProductPtrBit);
0160     processIndex_ = iId.processIndex();
0161     processIndex_ |= head;
0162     productIndex_ = iId.productIndex();
0163   }
0164 
0165   void RefCore::pushBackItem(RefCore const& productToBeInserted, bool checkPointer) {
0166     if (productToBeInserted.isNull() && !productToBeInserted.isTransient()) {
0167       throw edm::Exception(errors::InvalidReference, "Inconsistency")
0168           << "RefCore::pushBackItem: Ref or Ptr has invalid (zero) product ID, so it cannot be added to RefVector "
0169              "(PtrVector). "
0170           << "id should be (" << id() << ")\n";
0171     }
0172     if (isNonnull()) {
0173       if (isTransient() != productToBeInserted.isTransient()) {
0174         if (productToBeInserted.isTransient()) {
0175           throw edm::Exception(errors::InvalidReference, "Inconsistency")
0176               << "RefCore::pushBackItem: Transient Ref or Ptr cannot be added to persistable RefVector (PtrVector). "
0177               << "id should be (" << id() << ")\n";
0178         } else {
0179           throw edm::Exception(errors::InvalidReference, "Inconsistency")
0180               << "RefCore::pushBackItem: Persistable Ref or Ptr cannot be added to transient RefVector (PtrVector). "
0181               << "id is (" << productToBeInserted.id() << ")\n";
0182         }
0183       }
0184       if (!productToBeInserted.isTransient() && id() != productToBeInserted.id()) {
0185         throw edm::Exception(errors::InvalidReference, "Inconsistency")
0186             << "RefCore::pushBackItem: Ref or Ptr is inconsistent with RefVector (PtrVector)"
0187             << "id = (" << productToBeInserted.id() << ") should be (" << id() << ")\n";
0188       }
0189       if (productToBeInserted.isTransient() && checkPointer && productToBeInserted.isNonnull() &&
0190           productToBeInserted != *this) {
0191         throw edm::Exception(errors::InvalidReference, "Inconsistency")
0192             << "RefCore::pushBackItem: Ref points into different collection than the RefVector.\n";
0193       }
0194     } else {
0195       if (productToBeInserted.isTransient()) {
0196         setTransient();
0197       }
0198       if (productToBeInserted.isNonnull()) {
0199         setId(productToBeInserted.id());
0200       }
0201     }
0202     //Since productPtr and productGetter actually share the same pointer internally,
0203     // we want to be sure that if the productPtr is set we use that one and only if
0204     // it isn't set do we set the productGetter if available
0205     if (productPtr() == nullptr && productToBeInserted.productPtr() != nullptr) {
0206       setProductPtr(productToBeInserted.productPtr());
0207     } else {
0208       auto getter = productToBeInserted.productGetter();
0209       if (cachePtrIsInvalid() && getter != nullptr) {
0210         setProductGetter(getter);
0211       }
0212     }
0213   }
0214 
0215   void RefCore::pushBackRefItem(RefCore const& productToBeInserted) {
0216     if (productToBeInserted.isNull() && !productToBeInserted.isTransient()) {
0217       throw edm::Exception(errors::InvalidReference, "Inconsistency")
0218           << "RefCore::pushBackRefItem: Ref has invalid (zero) product ID, so it cannot be added to RefVector."
0219           << "id should be (" << id() << ")\n";
0220     }
0221     if (isNonnull() || isTransient()) {
0222       if (isTransient() != productToBeInserted.isTransient()) {
0223         if (productToBeInserted.isTransient()) {
0224           throw edm::Exception(errors::InvalidReference, "Inconsistency")
0225               << "RefCore::pushBackRefItem: Transient Ref cannot be added to persistable RefVector. "
0226               << "id should be (" << id() << ")\n";
0227         } else {
0228           throw edm::Exception(errors::InvalidReference, "Inconsistency")
0229               << "RefCore::pushBackRefItem: Persistable Ref cannot be added to transient RefVector. "
0230               << "id is (" << productToBeInserted.id() << ")\n";
0231         }
0232       }
0233       if (!productToBeInserted.isTransient() && id() != productToBeInserted.id()) {
0234         throw edm::Exception(errors::InvalidReference, "Inconsistency")
0235             << "RefCore::pushBackRefItem: Ref is inconsistent with RefVector"
0236             << "id = (" << productToBeInserted.id() << ") should be (" << id() << ")\n";
0237       }
0238     } else {
0239       if (productToBeInserted.isTransient()) {
0240         setTransient();
0241       }
0242       if (productToBeInserted.isNonnull()) {
0243         setId(productToBeInserted.id());
0244       }
0245     }
0246     auto prodGetter = productToBeInserted.productGetter();
0247     if (productGetter() == nullptr && prodGetter != nullptr) {
0248       setProductGetter(prodGetter);
0249     }
0250   }
0251 }  // namespace edm