File indexing completed on 2024-04-06 12:03:51
0001 #ifndef DataFormats_Common_getThinned_implementation_h
0002 #define DataFormats_Common_getThinned_implementation_h
0003
0004 #include <algorithm>
0005 #include <cassert>
0006 #include <functional>
0007 #include <optional>
0008 #include <tuple>
0009 #include <variant>
0010 #include <limits>
0011
0012 #include "DataFormats/Common/interface/ThinnedAssociation.h"
0013 #include "DataFormats/Provenance/interface/BranchID.h"
0014 #include "DataFormats/Provenance/interface/ProductID.h"
0015 #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h"
0016 #include "FWCore/Utilities/interface/EDMException.h"
0017
0018 namespace edm {
0019 class WrapperBase;
0020
0021 namespace detail {
0022 constexpr unsigned int kThinningDoNotLookForThisIndex = std::numeric_limits<unsigned int>::max();
0023
0024 class ThinnedOrSlimmedProduct {
0025 public:
0026 ThinnedOrSlimmedProduct() = default;
0027 explicit ThinnedOrSlimmedProduct(WrapperBase const* thinned, unsigned int key)
0028 : thinnedProduct_{thinned}, thinnedKey_{key} {}
0029 explicit ThinnedOrSlimmedProduct(ThinnedAssociation const* slimmed, unsigned int key)
0030 : slimmedAssociation_{slimmed}, thinnedKey_{key} {}
0031
0032 bool hasThinned() const { return thinnedProduct_ != nullptr; }
0033 bool hasSlimmed() const { return slimmedAssociation_ != nullptr; }
0034
0035 std::tuple<WrapperBase const*, unsigned int> thinnedProduct() const {
0036 return std::tuple(thinnedProduct_, thinnedKey_);
0037 }
0038
0039 std::tuple<ThinnedAssociation const*, unsigned int> slimmedAssociation() const {
0040 return std::tuple(slimmedAssociation_, thinnedKey_);
0041 }
0042
0043 private:
0044 WrapperBase const* thinnedProduct_ = nullptr;
0045 ThinnedAssociation const* slimmedAssociation_ = nullptr;
0046 unsigned int thinnedKey_ = 0;
0047 };
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 template <typename F1, typename F2, typename F3>
0068 ThinnedOrSlimmedProduct getThinnedProductOnSlimmingDepth(ProductID const& pid,
0069 unsigned int key,
0070 ThinnedAssociationsHelper const& thinnedAssociationsHelper,
0071 F1 pidToBid,
0072 F2 getThinnedAssociation,
0073 F3 getByProductID) {
0074 BranchID parent = pidToBid(pid);
0075
0076 auto associatedBranches = thinnedAssociationsHelper.parentBegin(parent);
0077 auto const iEnd = thinnedAssociationsHelper.parentEnd(parent);
0078
0079 if (associatedBranches == iEnd) {
0080 return ThinnedOrSlimmedProduct();
0081 }
0082 bool const slimmedAllowed = (associatedBranches + 1 == iEnd);
0083 if (slimmedAllowed and associatedBranches->isSlimmed()) {
0084
0085 ThinnedAssociation const* slimmedAssociation = getThinnedAssociation(associatedBranches->association());
0086 if (slimmedAssociation == nullptr or
0087 associatedBranches->parent() != pidToBid(slimmedAssociation->parentCollectionID())) {
0088 return ThinnedOrSlimmedProduct();
0089 }
0090
0091
0092 auto slimmedIndex = slimmedAssociation->getThinnedIndex(key);
0093 if (slimmedIndex.has_value()) {
0094 return ThinnedOrSlimmedProduct(slimmedAssociation, *slimmedIndex);
0095 } else {
0096 return ThinnedOrSlimmedProduct();
0097 }
0098 }
0099
0100
0101 for (; associatedBranches != iEnd; ++associatedBranches) {
0102 if (associatedBranches->isSlimmed()) {
0103 continue;
0104 }
0105
0106 ThinnedAssociation const* thinnedAssociation = getThinnedAssociation(associatedBranches->association());
0107 if (thinnedAssociation == nullptr)
0108 continue;
0109
0110 if (associatedBranches->parent() != pidToBid(thinnedAssociation->parentCollectionID())) {
0111 continue;
0112 }
0113
0114
0115 auto thinnedIndex = thinnedAssociation->getThinnedIndex(key);
0116 if (not thinnedIndex.has_value()) {
0117 continue;
0118 }
0119
0120
0121 ProductID const& thinnedCollectionPID = thinnedAssociation->thinnedCollectionID();
0122 WrapperBase const* thinnedCollection = getByProductID(thinnedCollectionPID);
0123 if (thinnedCollection != nullptr) {
0124 return ThinnedOrSlimmedProduct(thinnedCollection, *thinnedIndex);
0125 }
0126
0127
0128
0129 auto thinnedOrSlimmed = getThinnedProductOnSlimmingDepth(thinnedCollectionPID,
0130 *thinnedIndex,
0131 thinnedAssociationsHelper,
0132 pidToBid,
0133 getThinnedAssociation,
0134 getByProductID);
0135 if (thinnedOrSlimmed.hasThinned() or (slimmedAllowed and thinnedOrSlimmed.hasSlimmed())) {
0136 return thinnedOrSlimmed;
0137 }
0138 }
0139
0140 return ThinnedOrSlimmedProduct();
0141 }
0142
0143 inline auto makeThinnedIndexes(std::vector<unsigned int> const& keys,
0144 std::vector<WrapperBase const*> const& foundContainers,
0145 ThinnedAssociation const* thinnedAssociation) {
0146 unsigned const nKeys = keys.size();
0147 std::vector<unsigned int> thinnedIndexes(nKeys, kThinningDoNotLookForThisIndex);
0148 bool hasAny = false;
0149 for (unsigned k = 0; k < nKeys; ++k) {
0150
0151 if (foundContainers[k] != nullptr) {
0152 continue;
0153 }
0154
0155 if (keys[k] == kThinningDoNotLookForThisIndex) {
0156 continue;
0157 }
0158
0159 if (auto thinnedIndex = thinnedAssociation->getThinnedIndex(keys[k]); thinnedIndex.has_value()) {
0160 thinnedIndexes[k] = *thinnedIndex;
0161 hasAny = true;
0162 }
0163 }
0164 return std::tuple(std::move(thinnedIndexes), hasAny);
0165 }
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 template <typename F1, typename F2, typename F3>
0188 std::optional<std::tuple<ThinnedAssociation const*, std::vector<unsigned int>>> getThinnedProductsOnSlimmingDepth(
0189 ProductID const& pid,
0190 ThinnedAssociationsHelper const& thinnedAssociationsHelper,
0191 F1 pidToBid,
0192 F2 getThinnedAssociation,
0193 F3 getByProductID,
0194 std::vector<WrapperBase const*>& foundContainers,
0195 std::vector<unsigned int>& keys) {
0196 BranchID parent = pidToBid(pid);
0197
0198 auto associatedBranches = thinnedAssociationsHelper.parentBegin(parent);
0199 auto const iEnd = thinnedAssociationsHelper.parentEnd(parent);
0200
0201 if (associatedBranches == iEnd) {
0202 return std::nullopt;
0203 }
0204 bool const slimmedAllowed = associatedBranches + 1 == iEnd;
0205 if (slimmedAllowed and associatedBranches->isSlimmed()) {
0206
0207 ThinnedAssociation const* slimmedAssociation = getThinnedAssociation(associatedBranches->association());
0208 if (slimmedAssociation == nullptr or
0209 associatedBranches->parent() != pidToBid(slimmedAssociation->parentCollectionID())) {
0210 return std::nullopt;
0211 }
0212
0213 auto [slimmedIndexes, hasAny] = makeThinnedIndexes(keys, foundContainers, slimmedAssociation);
0214
0215 if (hasAny) {
0216 return std::tuple(slimmedAssociation, std::move(slimmedIndexes));
0217 } else {
0218 return std::nullopt;
0219 }
0220 }
0221
0222
0223 for (; associatedBranches != iEnd; ++associatedBranches) {
0224 if (associatedBranches->isSlimmed()) {
0225 continue;
0226 }
0227
0228 ThinnedAssociation const* thinnedAssociation = getThinnedAssociation(associatedBranches->association());
0229 if (thinnedAssociation == nullptr)
0230 continue;
0231
0232 if (associatedBranches->parent() != pidToBid(thinnedAssociation->parentCollectionID())) {
0233 continue;
0234 }
0235
0236 auto [thinnedIndexes, hasAny] = makeThinnedIndexes(keys, foundContainers, thinnedAssociation);
0237 if (!hasAny) {
0238 continue;
0239 }
0240
0241
0242 ProductID thinnedCollectionPID = thinnedAssociation->thinnedCollectionID();
0243 WrapperBase const* thinnedCollection = getByProductID(thinnedCollectionPID);
0244 unsigned const nKeys = keys.size();
0245 if (thinnedCollection == nullptr) {
0246
0247
0248 auto slimmed = getThinnedProductsOnSlimmingDepth(thinnedCollectionPID,
0249 thinnedAssociationsHelper,
0250 pidToBid,
0251 getThinnedAssociation,
0252 getByProductID,
0253 foundContainers,
0254 thinnedIndexes);
0255 if (slimmedAllowed and slimmed.has_value()) {
0256 return slimmed;
0257 }
0258 for (unsigned k = 0; k < nKeys; ++k) {
0259 if (foundContainers[k] == nullptr)
0260 continue;
0261 if (thinnedIndexes[k] == kThinningDoNotLookForThisIndex)
0262 continue;
0263 keys[k] = thinnedIndexes[k];
0264 }
0265 } else {
0266 for (unsigned k = 0; k < nKeys; ++k) {
0267 if (thinnedIndexes[k] == kThinningDoNotLookForThisIndex)
0268 continue;
0269 keys[k] = thinnedIndexes[k];
0270 foundContainers[k] = thinnedCollection;
0271 }
0272 }
0273 }
0274 return std::nullopt;
0275 }
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 template <typename F1, typename F2, typename F3>
0288 std::optional<std::tuple<WrapperBase const*, unsigned int>> getThinnedProduct(
0289 ProductID const& pid,
0290 unsigned int key,
0291 ThinnedAssociationsHelper const& thinnedAssociationsHelper,
0292 F1 pidToBid,
0293 F2 getThinnedAssociation,
0294 F3 getByProductID) {
0295 auto thinnedOrSlimmed = getThinnedProductOnSlimmingDepth(
0296 pid, key, thinnedAssociationsHelper, pidToBid, getThinnedAssociation, getByProductID);
0297
0298 if (thinnedOrSlimmed.hasThinned()) {
0299 return thinnedOrSlimmed.thinnedProduct();
0300 } else if (thinnedOrSlimmed.hasSlimmed()) {
0301 auto [slimmedAssociation, slimmedIndex] = thinnedOrSlimmed.slimmedAssociation();
0302 ProductID const& slimmedCollectionPID = slimmedAssociation->thinnedCollectionID();
0303 WrapperBase const* slimmedCollection = getByProductID(slimmedCollectionPID);
0304 if (slimmedCollection == nullptr) {
0305
0306
0307 return getThinnedProduct(slimmedCollectionPID,
0308 slimmedIndex,
0309 thinnedAssociationsHelper,
0310 pidToBid,
0311 getThinnedAssociation,
0312 getByProductID);
0313 }
0314 return std::tuple(slimmedCollection, slimmedIndex);
0315 }
0316 return std::nullopt;
0317 }
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334 template <typename F1, typename F2, typename F3>
0335 void getThinnedProducts(ProductID const& pid,
0336 ThinnedAssociationsHelper const& thinnedAssociationsHelper,
0337 F1 pidToBid,
0338 F2 getThinnedAssociation,
0339 F3 getByProductID,
0340 std::vector<WrapperBase const*>& foundContainers,
0341 std::vector<unsigned int>& keys) {
0342 auto slimmed = getThinnedProductsOnSlimmingDepth(
0343 pid, thinnedAssociationsHelper, pidToBid, getThinnedAssociation, getByProductID, foundContainers, keys);
0344 if (slimmed.has_value()) {
0345
0346 auto [slimmedAssociation, slimmedIndexes] = std::move(*slimmed);
0347 ProductID const& slimmedCollectionPID = slimmedAssociation->thinnedCollectionID();
0348 WrapperBase const* slimmedCollection = getByProductID(slimmedCollectionPID);
0349 unsigned const nKeys = keys.size();
0350 if (slimmedCollection == nullptr) {
0351 getThinnedProducts(slimmedCollectionPID,
0352 thinnedAssociationsHelper,
0353 pidToBid,
0354 getThinnedAssociation,
0355 getByProductID,
0356 foundContainers,
0357 slimmedIndexes);
0358 for (unsigned k = 0; k < nKeys; ++k) {
0359 if (foundContainers[k] == nullptr)
0360 continue;
0361 if (slimmedIndexes[k] == kThinningDoNotLookForThisIndex)
0362 continue;
0363 keys[k] = slimmedIndexes[k];
0364 }
0365 } else {
0366 for (unsigned k = 0; k < nKeys; ++k) {
0367 if (slimmedIndexes[k] == kThinningDoNotLookForThisIndex)
0368 continue;
0369 keys[k] = slimmedIndexes[k];
0370 foundContainers[k] = slimmedCollection;
0371 }
0372 }
0373 }
0374 }
0375
0376 using GetThinnedKeyFromExceptionFactory = std::function<edm::Exception()>;
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394 template <typename F>
0395 std::variant<unsigned int, GetThinnedKeyFromExceptionFactory, std::monostate> getThinnedKeyFrom_implementation(
0396 ProductID const& parentID,
0397 BranchID const& parent,
0398 unsigned int key,
0399 ProductID const& thinnedID,
0400 BranchID thinned,
0401 ThinnedAssociationsHelper const& thinnedAssociationsHelper,
0402 F&& getThinnedAssociation) {
0403
0404
0405
0406
0407 if (auto iParent = thinnedAssociationsHelper.parentBegin(parent);
0408 iParent == thinnedAssociationsHelper.parentEnd(parent) or iParent->parent() != parent) {
0409 return [parentID]() {
0410 return Exception(errors::InvalidReference)
0411 << "Parent collection with ProductID " << parentID << " has not been thinned";
0412 };
0413 }
0414
0415 bool foundParent = false;
0416 std::vector<ThinnedAssociation const*> thinnedAssociationParentage;
0417 while (not foundParent) {
0418
0419 auto branchesToThinned = std::find_if(
0420 thinnedAssociationsHelper.begin(), thinnedAssociationsHelper.end(), [&thinned](auto& associatedBranches) {
0421 return associatedBranches.thinned() == thinned;
0422 });
0423 if (branchesToThinned == thinnedAssociationsHelper.end()) {
0424 return [parentID, thinnedID, thinnedIsThinned = not thinnedAssociationParentage.empty()]() {
0425 Exception ex(errors::InvalidReference);
0426 ex << "Requested thinned collection with ProductID " << thinnedID
0427 << " is not thinned from the parent collection with ProductID " << parentID
0428 << " or from any collection thinned from it.";
0429 if (not thinnedIsThinned) {
0430 ex << " In fact, the collection " << thinnedID
0431 << " passed in as a 'thinned' collection has not been thinned at all.";
0432 }
0433 return ex;
0434 };
0435 }
0436
0437 ThinnedAssociation const* thinnedAssociation = getThinnedAssociation(branchesToThinned->association());
0438 if (thinnedAssociation == nullptr) {
0439 Exception ex{errors::LogicError};
0440 if (thinnedAssociationParentage.empty()) {
0441 ex << "ThinnedAssociation corresponding to thinned collection with ProductID " << thinnedID
0442 << " not found.";
0443 } else {
0444 ex << "Intermediate ThinnedAssociation between the requested thinned ProductID " << thinnedID
0445 << " and parent " << parentID << " not found.";
0446 }
0447 ex << " This should not happen.\nPlease contact the core framework developers.";
0448 throw ex;
0449 }
0450
0451 thinnedAssociationParentage.push_back(thinnedAssociation);
0452 if (branchesToThinned->parent() == parent) {
0453 foundParent = true;
0454 } else {
0455
0456 thinned = branchesToThinned->parent();
0457 }
0458 }
0459
0460
0461
0462 unsigned int thinnedIndex = key;
0463 for (auto iAssociation = thinnedAssociationParentage.rbegin(), iEnd = thinnedAssociationParentage.rend();
0464 iAssociation != iEnd;
0465 ++iAssociation) {
0466 auto optIndex = (*iAssociation)->getThinnedIndex(thinnedIndex);
0467 if (optIndex) {
0468 thinnedIndex = *optIndex;
0469 } else {
0470 return std::monostate{};
0471 }
0472 }
0473 return thinnedIndex;
0474 }
0475
0476 }
0477 }
0478
0479 #endif