00001
00002 #include "DataFormats/Provenance/interface/ProductHolderIndexHelper.h"
00003 #include "FWCore/Utilities/interface/DictionaryTools.h"
00004 #include "FWCore/Utilities/interface/EDMException.h"
00005 #include "FWCore/Utilities/interface/TypeWithDict.h"
00006
00007 #include <iostream>
00008 #include <limits>
00009
00010 namespace edm {
00011
00012 ProductHolderIndexHelper::ProductHolderIndexHelper() :
00013 nextIndexValue_(0),
00014 beginElements_(0),
00015 items_(new std::set<ProductHolderIndexHelper::Item>),
00016 processItems_(new std::set<std::string>) {
00017 }
00018
00019 ProductHolderIndex
00020 ProductHolderIndexHelper::index(KindOfType kindOfType,
00021 TypeID const& typeID,
00022 char const* moduleLabel,
00023 char const* instance,
00024 char const* process) const {
00025
00026 unsigned int iToIndexAndNames = indexToIndexAndNames(kindOfType,
00027 typeID,
00028 moduleLabel,
00029 instance,
00030 process);
00031
00032 if (iToIndexAndNames == std::numeric_limits<unsigned int>::max()) {
00033 return ProductHolderIndexInvalid;
00034 }
00035 return indexAndNames_[iToIndexAndNames].index();
00036 }
00037
00038 ProductHolderIndexHelper::Matches::Matches(ProductHolderIndexHelper const* productHolderIndexHelper,
00039 unsigned int startInIndexAndNames,
00040 unsigned int numberOfMatches) :
00041 productHolderIndexHelper_(productHolderIndexHelper),
00042 startInIndexAndNames_(startInIndexAndNames),
00043 numberOfMatches_(numberOfMatches) {
00044 if (numberOfMatches != 0 && startInIndexAndNames_ + numberOfMatches_ > productHolderIndexHelper_->indexAndNames_.size()) {
00045 throw Exception(errors::LogicError)
00046 << "ProductHolderIndexHelper::Matches::Matches - Arguments exceed vector bounds.\n";
00047 }
00048 }
00049
00050 ProductHolderIndex
00051 ProductHolderIndexHelper::Matches::index(unsigned int i) const {
00052 if (i >= numberOfMatches_) {
00053 throw Exception(errors::LogicError)
00054 << "ProductHolderIndexHelper::Matches::index - Argument is out of range.\n";
00055 }
00056 return productHolderIndexHelper_->indexAndNames_[startInIndexAndNames_ + i].index();
00057 }
00058
00059 bool
00060 ProductHolderIndexHelper::Matches::isFullyResolved(unsigned int i) const {
00061 if (i >= numberOfMatches_) {
00062 throw Exception(errors::LogicError)
00063 << "ProductHolderIndexHelper::Matches::isFullyResolved - Argument is out of range.\n";
00064 }
00065 return (productHolderIndexHelper_->indexAndNames_[startInIndexAndNames_ + i].startInProcessNames() != 0U);
00066 }
00067
00068 ProductHolderIndexHelper::Matches
00069 ProductHolderIndexHelper::relatedIndexes(KindOfType kindOfType,
00070 TypeID const& typeID,
00071 char const* moduleLabel,
00072 char const* instance) const {
00073
00074 unsigned int startInIndexAndNames = indexToIndexAndNames(kindOfType,
00075 typeID,
00076 moduleLabel,
00077 instance,
00078 0);
00079 unsigned int numberOfMatches = 1;
00080
00081 if (startInIndexAndNames == std::numeric_limits<unsigned int>::max()) {
00082 numberOfMatches = 0;
00083 } else {
00084 auto vSize = indexAndNames_.size();
00085 for (unsigned int j = startInIndexAndNames + 1U;
00086 j < vSize && (indexAndNames_[j].startInProcessNames() != 0U);
00087 ++j) {
00088 ++numberOfMatches;
00089 }
00090 }
00091 return Matches(this, startInIndexAndNames, numberOfMatches);
00092 }
00093
00094 ProductHolderIndexHelper::Matches
00095 ProductHolderIndexHelper::relatedIndexes(KindOfType kindOfType,
00096 TypeID const& typeID) const {
00097
00098 unsigned int startInIndexAndNames = std::numeric_limits<unsigned int>::max();
00099 unsigned int numberOfMatches = 0;
00100
00101
00102 unsigned iType = indexToType(kindOfType, typeID);
00103 if (iType != std::numeric_limits<unsigned int>::max()) {
00104
00105
00106 Range const& range = ranges_[iType];
00107
00108 startInIndexAndNames = range.begin();
00109 numberOfMatches = range.end() - range.begin();
00110 }
00111 return Matches(this, startInIndexAndNames, numberOfMatches);
00112 }
00113
00114 ProductHolderIndex
00115 ProductHolderIndexHelper::insert(TypeWithDict const& typeWithDict,
00116 char const* moduleLabel,
00117 char const* instance,
00118 char const* process) {
00119 if (!items_) {
00120 throw Exception(errors::LogicError)
00121 << "ProductHolderIndexHelper::insert - Attempt to insert more elements after frozen.\n";
00122 }
00123
00124 if (process == 0 || *process == '\0') {
00125 throw Exception(errors::LogicError)
00126 << "ProductHolderIndexHelper::insert - Empty process.\n";
00127 }
00128
00129 TypeID typeID(typeWithDict.typeInfo());
00130
00131
00132 Item item(PRODUCT_TYPE, typeID, moduleLabel, instance, process, 0);
00133 std::set<Item>::iterator iter = items_->find(item);
00134 if (iter != items_->end()) {
00135 throw Exception(errors::LogicError)
00136 << "ProductHolderIndexHelper::insert - Attempt to insert duplicate entry.\n";
00137 }
00138
00139
00140 item.setIndex(nextIndexValue_);
00141 unsigned int savedProductIndex = nextIndexValue_;
00142 ++nextIndexValue_;
00143 items_->insert(item);
00144
00145
00146
00147 item.clearProcess();
00148 iter = items_->find(item);
00149 if (iter == items_->end()) {
00150 item.setIndex(nextIndexValue_);
00151 ++nextIndexValue_;
00152 items_->insert(item);
00153 }
00154
00155
00156
00157 TypeWithDict containedType;
00158 if((is_RefVector(typeWithDict, containedType) ||
00159 is_PtrVector(typeWithDict, containedType) ||
00160 is_RefToBaseVector(typeWithDict, containedType) ||
00161 value_type_of(typeWithDict, containedType))
00162 && bool(containedType)) {
00163
00164 TypeID containedTypeID(containedType.typeInfo());
00165 Item containedItem(ELEMENT_TYPE, containedTypeID, moduleLabel, instance, process, savedProductIndex);
00166 iter = items_->find(containedItem);
00167 if (iter != items_->end()) {
00168 containedItem.setIndex(ProductHolderIndexAmbiguous);
00169 items_->erase(iter);
00170 }
00171 items_->insert(containedItem);
00172
00173 containedItem.clearProcess();
00174 iter = items_->find(containedItem);
00175 if (iter == items_->end()) {
00176 containedItem.setIndex(nextIndexValue_);
00177 ++nextIndexValue_;
00178 items_->insert(containedItem);
00179 }
00180
00181
00182 std::vector<TypeWithDict> baseTypes;
00183 public_base_classes(containedType, baseTypes);
00184
00185 for(TypeWithDict const& baseType : baseTypes) {
00186
00187 TypeID baseTypeID(baseType.typeInfo());
00188 Item baseItem(ELEMENT_TYPE, baseTypeID, moduleLabel, instance, process, savedProductIndex);
00189 iter = items_->find(baseItem);
00190 if (iter != items_->end()) {
00191 baseItem.setIndex(ProductHolderIndexAmbiguous);
00192 items_->erase(iter);
00193 }
00194 items_->insert(baseItem);
00195
00196 baseItem.clearProcess();
00197 iter = items_->find(baseItem);
00198 if (iter == items_->end()) {
00199 baseItem.setIndex(nextIndexValue_);
00200 ++nextIndexValue_;
00201 items_->insert(baseItem);
00202 }
00203 }
00204 }
00205 return savedProductIndex;
00206 }
00207
00208 void ProductHolderIndexHelper::setFrozen() {
00209
00210 if (!items_) return;
00211
00212
00213
00214
00215 bool iFirstThisType = true;
00216 bool beginElementsWasSet = false;
00217 TypeID previousTypeID;
00218 KindOfType previousKindOfType = PRODUCT_TYPE;
00219 std::string previousModuleLabel;
00220 std::string previousInstance;
00221 unsigned int iCountTypes = 0;
00222 unsigned int iCountCharacters = 0;
00223 for (auto const& item : *items_) {
00224
00225 if (iFirstThisType || item.typeID() != previousTypeID || item.kindOfType() != previousKindOfType) {
00226 ++iCountTypes;
00227 iFirstThisType = true;
00228
00229 if (!beginElementsWasSet) {
00230 if (item.kindOfType() == ELEMENT_TYPE) {
00231 beginElementsWasSet = true;
00232 } else {
00233 beginElements_ = iCountTypes;
00234 }
00235 }
00236 }
00237
00238 processItems_->insert(item.process());
00239
00240 if (iFirstThisType ||
00241 item.moduleLabel() != previousModuleLabel ||
00242 item.instance() != previousInstance) {
00243 iCountCharacters += item.moduleLabel().size();
00244 iCountCharacters += item.instance().size();
00245 iCountCharacters += 2;
00246 }
00247
00248 iFirstThisType = false;
00249 previousTypeID = item.typeID();
00250 previousKindOfType = item.kindOfType();
00251 previousModuleLabel = item.moduleLabel();
00252 previousInstance = item.instance();
00253 }
00254
00255
00256 unsigned int processNamesSize = 0;
00257 for (auto const& processItem : *processItems_) {
00258 processNamesSize += processItem.size();
00259 ++processNamesSize;
00260 }
00261 processNames_.reserve(processNamesSize);
00262 for (auto const& processItem : *processItems_) {
00263 for (auto const& c : processItem) {
00264 processNames_.push_back(c);
00265 }
00266 processNames_.push_back('\0');
00267 lookupProcessNames_.push_back(processItem);
00268 }
00269
00270
00271 sortedTypeIDs_.reserve(iCountTypes);
00272 ranges_.reserve(iCountTypes);
00273 indexAndNames_.reserve(items_->size());
00274 bigNamesContainer_.reserve(iCountCharacters);
00275
00276
00277 bool iFirstType = true;
00278 iFirstThisType = true;
00279 previousTypeID = TypeID();
00280 unsigned int iCount = 0;
00281 unsigned int iBeginning = 0;
00282 iCountCharacters = 0;
00283 unsigned int previousCharacterCount = 0;
00284 if (!items_->empty()) {
00285 for (auto const& item : *items_) {
00286
00287 if (iFirstThisType || item.typeID() != previousTypeID || item.kindOfType() != previousKindOfType) {
00288 iFirstThisType = true;
00289 sortedTypeIDs_.push_back(item.typeID());
00290 if (iFirstType) {
00291 iFirstType = false;
00292 } else {
00293 ranges_.push_back(Range(iBeginning, iCount));
00294 }
00295 iBeginning = iCount;
00296 }
00297 ++iCount;
00298
00299 if (iFirstThisType ||
00300 item.moduleLabel() != previousModuleLabel ||
00301 item.instance() != previousInstance) {
00302
00303 unsigned int labelSize = item.moduleLabel().size();
00304 for (unsigned int j = 0; j < labelSize; ++j) {
00305 bigNamesContainer_.push_back(item.moduleLabel()[j]);
00306 }
00307 bigNamesContainer_.push_back('\0');
00308
00309 unsigned int instanceSize = item.instance().size();
00310 for (unsigned int j = 0; j < instanceSize; ++j) {
00311 bigNamesContainer_.push_back(item.instance()[j]);
00312 }
00313 bigNamesContainer_.push_back('\0');
00314
00315 previousCharacterCount = iCountCharacters;
00316
00317 iCountCharacters += labelSize;
00318 iCountCharacters += instanceSize;
00319 iCountCharacters += 2;
00320 }
00321
00322 unsigned int processStart = processIndex(item.process().c_str());
00323 if (processStart == std::numeric_limits<unsigned int>::max()) {
00324 throw Exception(errors::LogicError)
00325 << "ProductHolderIndexHelper::setFrozen - Process not found in processNames_.\n";
00326 }
00327 indexAndNames_.emplace_back(item.index(), previousCharacterCount, processStart);
00328
00329 iFirstThisType = false;
00330 previousTypeID = item.typeID();
00331 previousKindOfType = item.kindOfType();
00332 previousModuleLabel = item.moduleLabel();
00333 previousInstance = item.instance();
00334 }
00335 ranges_.push_back(Range(iBeginning, iCount));
00336 }
00337
00338
00339
00340
00341 sanityCheck();
00342
00343
00344 items_.reset();
00345 processItems_.reset();
00346 }
00347
00348 std::vector<std::string> const& ProductHolderIndexHelper::lookupProcessNames() const {
00349 if (items_) {
00350 throw Exception(errors::LogicError)
00351 << "ProductHolderIndexHelper::lookupProcessNames - Attempt to access names before frozen.\n";
00352 }
00353 return lookupProcessNames_;
00354 }
00355
00356 unsigned int
00357 ProductHolderIndexHelper::indexToIndexAndNames(KindOfType kindOfType,
00358 TypeID const& typeID,
00359 char const* moduleLabel,
00360 char const* instance,
00361 char const* process) const {
00362
00363
00364 unsigned iType = indexToType(kindOfType, typeID);
00365 if (iType != std::numeric_limits<unsigned int>::max()) {
00366
00367 unsigned startProcess = 0;
00368 if (process) {
00369 startProcess = processIndex(process);
00370 if (startProcess == std::numeric_limits<unsigned int>::max()) {
00371 return std::numeric_limits<unsigned int>::max();
00372 }
00373 }
00374
00375 ProductHolderIndexHelper::Range const& range = ranges_[iType];
00376 unsigned int begin = range.begin();
00377 unsigned int end = range.end();
00378
00379 while (begin < end) {
00380
00381 unsigned int midpoint = begin + ((end - begin) / 2);
00382 char const* namePtr = &bigNamesContainer_[indexAndNames_[midpoint].startInBigNamesContainer()];
00383
00384
00385 char const* label = moduleLabel;
00386 while (*namePtr && (*namePtr == *label)) {
00387 ++namePtr; ++label;
00388 }
00389 if (*namePtr == *label) {
00390 ++namePtr;
00391
00392
00393 char const* instanceName = instance;
00394 while (*namePtr && (*namePtr == *instanceName)) {
00395 ++namePtr; ++instanceName;
00396 }
00397 if (*namePtr == *instanceName) {
00398
00399
00400 if (startProcess == indexAndNames_[midpoint].startInProcessNames()) {
00401 return midpoint;
00402 } else {
00403 if (indexAndNames_[midpoint].startInProcessNames() > startProcess) {
00404 while (true) {
00405 --midpoint;
00406 if (indexAndNames_[midpoint].startInProcessNames() == startProcess) {
00407 return midpoint;
00408 }
00409 if (indexAndNames_[midpoint].startInProcessNames() == 0) break;
00410 }
00411 } else {
00412 while (true) {
00413 ++midpoint;
00414 if (midpoint == indexAndNames_.size()) break;
00415 if (indexAndNames_[midpoint].startInProcessNames() == 0) break;
00416 if (indexAndNames_[midpoint].startInProcessNames() == startProcess) {
00417 return midpoint;
00418 }
00419 }
00420 }
00421 break;
00422 }
00423 } else if (*namePtr < *instanceName) {
00424 if (begin == midpoint) break;
00425 begin = midpoint;
00426 } else {
00427 end = midpoint;
00428 }
00429 } else if (*namePtr < *label) {
00430 if (begin == midpoint) break;
00431 begin = midpoint;
00432 } else {
00433 end = midpoint;
00434 }
00435 }
00436 }
00437 return std::numeric_limits<unsigned int>::max();
00438 }
00439
00440 unsigned int
00441 ProductHolderIndexHelper::indexToType(KindOfType kindOfType,
00442 TypeID const& typeID) const {
00443
00444 unsigned int beginType = 0;
00445 unsigned int endType = beginElements_;
00446 if (kindOfType == ELEMENT_TYPE) {
00447 beginType = beginElements_;
00448 endType = sortedTypeIDs_.size();
00449 }
00450
00451 while (beginType < endType) {
00452 unsigned int midpointType = beginType + ((endType - beginType) / 2);
00453 if (sortedTypeIDs_[midpointType] == typeID) {
00454 return midpointType;
00455 } else if (sortedTypeIDs_[midpointType] < typeID) {
00456 if (beginType == midpointType) break;
00457 beginType = midpointType;
00458 } else {
00459 endType = midpointType;
00460 }
00461 }
00462 return std::numeric_limits<unsigned int>::max();
00463 }
00464
00465 unsigned int ProductHolderIndexHelper::processIndex(char const* process) const {
00466
00467 char const* ptr = &processNames_[0];
00468 char const* begin = ptr;
00469 while (true) {
00470 char const* p = process;
00471 char const* beginName = ptr;
00472 while (*ptr && (*ptr == *p)) {
00473 ++ptr; ++p;
00474 }
00475 if (*ptr == *p) {
00476 return beginName - begin;
00477 }
00478 while (*ptr) {
00479 ++ptr;
00480 }
00481 ++ptr;
00482 if (static_cast<unsigned>(ptr - begin) >= processNames_.size()) {
00483 return std::numeric_limits<unsigned int>::max();
00484 }
00485 }
00486 return 0;
00487 }
00488
00489 void ProductHolderIndexHelper::sanityCheck() const {
00490 bool sanityChecksPass = true;
00491 if (sortedTypeIDs_.size() != ranges_.size()) sanityChecksPass = false;
00492
00493 unsigned int previousEnd = 0;
00494 for ( auto const& range : ranges_) {
00495 if (range.begin() != previousEnd) sanityChecksPass = false;
00496 if (range.begin() >= range.end()) sanityChecksPass = false;
00497 previousEnd = range.end();
00498 }
00499 if (previousEnd != indexAndNames_.size()) sanityChecksPass = false;
00500
00501
00502 unsigned maxStart = 0;
00503 unsigned maxStartProcess = 0;
00504 for (auto const& indexAndName : indexAndNames_) {
00505 if (indexAndName.index() >= nextIndexValue_ && indexAndName.index() != ProductHolderIndexAmbiguous) sanityChecksPass = false;
00506
00507 if (indexAndName.startInBigNamesContainer() >= bigNamesContainer_.size()) sanityChecksPass = false;
00508 if (indexAndName.startInProcessNames() >= processNames_.size()) sanityChecksPass = false;
00509
00510 if (indexAndName.startInBigNamesContainer() > maxStart) maxStart = indexAndName.startInBigNamesContainer();
00511 if (indexAndName.startInProcessNames() > maxStartProcess) maxStartProcess = indexAndName.startInProcessNames();
00512 }
00513
00514 if (!indexAndNames_.empty()) {
00515 if (bigNamesContainer_.back() != '\0') sanityChecksPass = false;
00516 if (processNames_.back() != '\0') sanityChecksPass = false;
00517 if (maxStart >= bigNamesContainer_.size()) sanityChecksPass = false;
00518 unsigned int countZeroes = 0;
00519 for (unsigned j = maxStart; j < bigNamesContainer_.size(); ++j) {
00520 if (bigNamesContainer_[j] == '\0') {
00521 ++countZeroes;
00522 }
00523 }
00524 if (countZeroes != 2) sanityChecksPass = false;
00525 if (maxStartProcess >= processNames_.size()) sanityChecksPass = false;
00526 countZeroes = 0;
00527 for (unsigned j = maxStartProcess; j < processNames_.size(); ++j) {
00528 if (processNames_[j] == '\0') {
00529 ++countZeroes;
00530 }
00531 }
00532 if (countZeroes != 1) sanityChecksPass = false;
00533 }
00534
00535 if (!sanityChecksPass) {
00536 throw Exception(errors::LogicError)
00537 << "ProductHolderIndexHelper::setFrozen - Detected illegal state.\n";
00538 }
00539 }
00540
00541 ProductHolderIndexHelper::Item::Item(KindOfType kindOfType,
00542 TypeID const& typeID,
00543 std::string const& moduleLabel,
00544 std::string const& instance,
00545 std::string const& process,
00546 ProductHolderIndex index) :
00547 kindOfType_(kindOfType),
00548 typeID_(typeID),
00549 moduleLabel_(moduleLabel),
00550 instance_(instance),
00551 process_(process),
00552 index_(index) {
00553 }
00554
00555 bool
00556 ProductHolderIndexHelper::Item::operator<(Item const& right) const {
00557 if (kindOfType_ < right.kindOfType_) return true;
00558 if (kindOfType_ > right.kindOfType_) return false;
00559 if (typeID_ < right.typeID_) return true;
00560 if (typeID_ > right.typeID_) return false;
00561 if (moduleLabel_ < right.moduleLabel_) return true;
00562 if (moduleLabel_ > right.moduleLabel_) return false;
00563 if (instance_ < right.instance_) return true;
00564 if (instance_ > right.instance_) return false;
00565 return process_ < right.process_;
00566 }
00567
00568 void ProductHolderIndexHelper::print(std::ostream& os) const {
00569
00570 os << "\n******* Dump ProductHolderIndexHelper *************************\n";
00571
00572 os << "\nnextIndexValue_ = " << nextIndexValue_ << "\n";
00573 os << "beginElements_ = " << beginElements_ << "\n";
00574
00575 os << "\n******* sortedTypeIDs_ \n";
00576 for (auto const& i : sortedTypeIDs_) {
00577 os << i << "\n";
00578 }
00579 os << "******* ranges_ \n";
00580 for (auto const& i : ranges_) {
00581 os << i.begin() << " " << i.end() << "\n";
00582 }
00583 os << "******* indexAndNames_ \n";
00584 for (auto const& i : indexAndNames_) {
00585 os << i.index() << " " << i.startInBigNamesContainer() << " ";
00586 char const* ptr = &bigNamesContainer_[i.startInBigNamesContainer()];
00587 while (*ptr) {
00588 os << *ptr;
00589 ++ptr;
00590 }
00591 ++ptr;
00592 os << " ";
00593 while (*ptr) {
00594 os << *ptr;
00595 ++ptr;
00596 }
00597 os << " " << i.startInProcessNames() << " ";
00598 ptr = &processNames_[i.startInProcessNames()];
00599 while (*ptr) {
00600 os << *ptr;
00601 ++ptr;
00602 }
00603 os << "\n";
00604 }
00605 os << "******* bigNamesContainer_ \n";
00606 for (auto i : bigNamesContainer_) {
00607 if (i == '\0') os << '\\' << '0';
00608 else os << i;
00609 }
00610 if (!bigNamesContainer_.empty()) os << "\n";
00611 os << "******* processNames_ \n";
00612 for (auto i : processNames_) {
00613 if (i == '\0') os << '\\' << '0';
00614 else os << i;
00615 }
00616 if (!processNames_.empty()) os << "\n";
00617 if (items_) {
00618 os << "******* items_ \n";
00619 for (auto const& item : *items_) {
00620 std:: cout << item.kindOfType() << " " << item.moduleLabel() << " " << item.instance() << " " << item.process() << " " << item.index() << " " << item.typeID() << "\n";
00621 }
00622 }
00623 if (processItems_) {
00624 os << "******* processItems_ \n";
00625 for (auto const& item : *processItems_) {
00626 os << item << "\n";
00627 }
00628 }
00629 os << "sortedTypeIDs_.size() = " << sortedTypeIDs_.size() << "\n";
00630 os << "indexAndNames_.size() = " << indexAndNames_.size() << "\n";
00631 os << "bigNamesContainer_.size() = " << bigNamesContainer_.size() << "\n";
00632 os << "processNames_.size() = " << processNames_.size() << "\n";
00633 os << "\n";
00634 }
00635 }