CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_1/src/DataFormats/Provenance/src/TransientProductLookupMap.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Provenance
00004 // Class  :     TransientProductLookupMap
00005 //
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Chris Jones
00010 //         Created:  Fri May  1 12:17:12 CDT 2009
00011 //
00012 
00013 // system include files
00014 #include <algorithm>
00015 
00016 // user include files
00017 #include "DataFormats/Provenance/interface/TransientProductLookupMap.h"
00018 #include "DataFormats/Provenance/interface/ProcessHistory.h"
00019 #include "DataFormats/Provenance/interface/ConstBranchDescription.h"
00020 
00021 //
00022 // constants, enums and typedefs
00023 //
00024 
00025 //
00026 // static data member definitions
00027 //
00028 
00029 namespace edm {
00030   bool CompareTypeInBranchTypeConstBranchDescription::operator()(std::pair<TypeInBranchType, ConstBranchDescription const*> const& iLHS,
00031                      std::pair<TypeInBranchType, ConstBranchDescription const*> const& iRHS) const {
00032      if(iLHS.first < iRHS.first) {
00033         return true;
00034      }
00035      if(iRHS.first < iLHS.first) {
00036         return false;
00037      }
00038 
00039      int c = iLHS.second->moduleLabel().compare(iRHS.second->moduleLabel());
00040      if(c < 0) {
00041         return true;
00042      }
00043      if(c > 0) {
00044         return false;
00045      }
00046      c = iLHS.second->productInstanceName().compare(iRHS.second->productInstanceName());
00047      if(c < 0) {
00048         return true;
00049      }
00050      if(c > 0) {
00051         return false;
00052      }
00053 
00054      return iLHS.second->processName() < iRHS.second->processName();
00055   }
00056 
00057   //
00058   // constructors and destructor
00059   //
00060   TransientProductLookupMap::TransientProductLookupMap() :
00061       branchLookup_(),
00062       productLookupIndexList_(),
00063       historyIDsForBranchType_(static_cast<unsigned int>(NumBranchTypes), ProcessHistoryID()),
00064       processNameOrderingForBranchType_(static_cast<unsigned int>(NumBranchTypes), std::vector<std::string>()),
00065       fillCount_(0) {
00066   }
00067 
00068   // TransientProductLookupMap::TransientProductLookupMap(TransientProductLookupMap const& rhs) {
00069   //    // do actual copying here;
00070   // }
00071 
00072   //TransientProductLookupMap::~TransientProductLookupMap() {
00073   //}
00074 
00075   void
00076   TransientProductLookupMap::reset() {
00077       branchLookup_.clear();
00078       productLookupIndexList_.clear();
00079       for (unsigned int i = 0; i < static_cast<unsigned int>(NumBranchTypes); ++i) {
00080         historyIDsForBranchType_[i].reset();
00081         processNameOrderingForBranchType_[i].clear();
00082       }
00083       fillCount_ = 0;
00084   }
00085 
00086   //
00087   // assignment operators
00088   //
00089   // TransientProductLookupMap const& TransientProductLookupMap::operator=(TransientProductLookupMap const& rhs) {
00090   //   //An exception safe implementation is
00091   //   TransientProductLookupMap temp(rhs);
00092   //   swap(rhs);
00093   //
00094   //   return *this;
00095   // }
00096 
00097   //
00098   // member functions
00099   //
00100   namespace  {
00101 
00102      struct CompareModuleLabelAndProductInstanceName {
00103         typedef std::pair<std::string const*, std::string const*> StringPtrPair;
00104         bool operator()(StringPtrPair const& iLHS, StringPtrPair const& iRHS) const {
00105            int c = iLHS.first->compare(*iRHS.first);
00106            if (c < 0) return true;
00107            if (c > 0) return false;
00108            return(*iLHS.second < *iRHS.second);
00109         }
00110         bool operator()(ProductLookupIndex const& iLHS, StringPtrPair const& iRHS) const {
00111            int c = iLHS.branchDescription()->moduleLabel().compare(*iRHS.first);
00112            if (c < 0) return true;
00113            if (c > 0) return false;
00114            return(iLHS.branchDescription()->productInstanceName() < *iRHS.second);
00115         }
00116         bool operator()(StringPtrPair const& iLHS, ProductLookupIndex const& iRHS) const {
00117            int c = iLHS.first->compare(iRHS.branchDescription()->moduleLabel());
00118            if (c < 0) return true;
00119            if (c > 0) return false;
00120            return(*iLHS.second < iRHS.branchDescription()->productInstanceName());
00121         }
00122         bool operator()(ProductLookupIndex const& iLHS, ProductLookupIndex const& iRHS) const {
00123            int c = iLHS.branchDescription()->moduleLabel().compare(iRHS.branchDescription()->moduleLabel());
00124            if (c < 0) return true;
00125            if (c > 0) return false;
00126            return(iLHS.branchDescription()->productInstanceName() < iRHS.branchDescription()->productInstanceName());
00127         }
00128      };
00129 
00130      struct BranchTypeOnlyCompare {
00131         bool operator()(std::pair<TypeInBranchType, BranchDescriptionIndex> const& iLHS, std::pair<TypeInBranchType, BranchDescriptionIndex> const& iRHS) const {
00132            return iLHS.first.branchType() < iRHS.first.branchType();
00133         }
00134      };
00135 
00136      struct CompareProcessList {
00137         std::vector<std::string> const* list_;
00138 
00139         CompareProcessList(std::vector<std::string> const* iList) : list_(iList) {}
00140 
00141         bool operator()(ProductLookupIndex const& iLHS, ProductLookupIndex const& iRHS) const {
00142            std::string const& lhs = iLHS.branchDescription()->processName();
00143            std::string const& rhs = iRHS.branchDescription()->processName();
00144            if(lhs == rhs) {return false;}
00145            //NOTE: names in the vector are oldest to newest and we want to order by newest
00146            for(std::vector<std::string>::const_reverse_iterator it = list_->rbegin(), itEnd = list_->rend();
00147                it != itEnd;
00148                ++it){
00149               if(*it == lhs) {return true;}
00150               if(*it == rhs) { return false;}
00151            }
00152            return false;
00153         }
00154      };
00155   }
00156 
00157   static
00158   void
00159   fillInProcessIndexes(TransientProductLookupMap::ProductLookupIndexList::iterator iIt,
00160                         TransientProductLookupMap::ProductLookupIndexList::iterator iEnd,
00161                         std::vector<std::string> const& iNameOrder) {
00162      //NOTE the iterators are already in the same order as iNameOrder
00163      std::vector<std::string>::const_reverse_iterator itNO = iNameOrder.rbegin();
00164      unsigned int index = 0;
00165      for(; iIt != iEnd; ++iIt) {
00166         if(iIt->isFirst()) {
00167            itNO = iNameOrder.rbegin();
00168            index = 0;
00169         }
00170         while(*itNO != iIt->branchDescription()->processName()) {
00171            ++itNO;
00172            assert(itNO != iNameOrder.rend());
00173            ++index;
00174         }
00175         iIt->setProcessIndex(index);
00176      }
00177   }
00178 
00179   void
00180   TransientProductLookupMap::reorderIfNecessary(BranchType iBranch, ProcessHistory const& iHistory, std::string const& iNewProcessName) {
00181 
00182      ProcessHistoryID& historyID = historyIDsForBranchType_[iBranch];
00183      if(iHistory.id() == historyID) {
00184         //std::cout <<"no reordering since history unchanged"<<std::endl;
00185         return;
00186      }
00187 
00188      if(iHistory.empty()) {
00189         //std::cout <<"no reordering since history empty"<<std::endl;
00190         historyID = iHistory.id();
00191         return;
00192      }
00193      std::vector<std::string>& processNameOrdering = processNameOrderingForBranchType_[iBranch];
00194 
00195      //iHistory may be missing entries in processNameOrdering if two files were merged together and one file
00196      // had fewer processing steps than the other one.
00197      //iHistory may have more entries than processNameOrdering if all data products for those extra entries
00198      // were dropped
00199 
00200      //if iHistory already in same order as processNameOrdering than we don't have to do anything
00201      std::vector<std::string>::iterator it = processNameOrdering.begin();
00202      std::vector<std::string>::iterator itEnd = processNameOrdering.end();
00203      ProcessHistory::const_iterator itH = iHistory.begin();
00204      ProcessHistory::const_iterator itHEnd = iHistory.end();
00205 
00206      {
00207         std::vector<std::string>::iterator itStart = it;
00208         bool mustReorder = false;
00209         while(it != itEnd && itH != itHEnd) {
00210            if(*it == itH->processName()) {
00211               ++it;
00212            } else {
00213               //see if we already passed it
00214               for(std::vector<std::string>::iterator itOld = itStart; itOld != it; ++itOld) {
00215                  if(*itOld == itH->processName()) {
00216                     mustReorder = true;
00217                     break;
00218                  }
00219               }
00220               if(mustReorder) {
00221                  break;
00222               }
00223            }
00224            ++itH;
00225         }
00226         if(!mustReorder && it != itEnd && *it == iNewProcessName) {
00227            ++it;
00228         }
00229         //can only reach the end if we found all the items in the correct order
00230         if(it == itEnd) {
00231            return;
00232         }
00233      }
00234 
00235      //must re-sort
00236      //Increment the fill count so users can check if the map has been modified.
00237      ++fillCount_;
00238      historyID = iHistory.id();
00239      std::vector<std::string> temp(processNameOrdering.size(), std::string());
00240 
00241      //we want to add the items at the back
00242      std::vector<std::string>::reverse_iterator itR = temp.rbegin();
00243      std::vector<std::string>::reverse_iterator itREnd = temp.rend();
00244      ProcessHistory::const_reverse_iterator itRH = iHistory.rbegin();
00245      ProcessHistory::const_reverse_iterator itRHEnd = iHistory.rend();
00246 
00247      if(processNameOrdering.end() != std::find(processNameOrdering.begin(), processNameOrdering.end(), iNewProcessName)) {
00248         *itR = iNewProcessName;
00249         ++itR;
00250         if (iNewProcessName == itRH->processName()) {
00251           ++itRH;
00252         }
00253      }
00254      for(; itRH != itRHEnd; ++itRH) {
00255         if(processNameOrdering.end() != std::find(processNameOrdering.begin(), processNameOrdering.end(), itRH->processName())) {
00256 
00257            *itR = itRH->processName();
00258            ++itR;
00259         }
00260      }
00261 
00262      //have to fill in the missing processes from processNameOrdering_
00263      // we do this at the beginning because we lookup data in the reverse order
00264      // so we want the ones we know are there to be searched first
00265      std::vector<std::string>::iterator itOld = processNameOrdering.begin();
00266      it = temp.begin();
00267      std::vector<std::string>::iterator itStart = temp.begin()+(itREnd - itR);
00268      while(it != itStart) {
00269         assert(itOld != processNameOrdering.end());
00270         if(temp.end() == std::find(itStart, temp.end(), *itOld)) {
00271            //didn't find it so need to add this to our list
00272            *it = *itOld;
00273            ++it;
00274         }
00275         ++itOld;
00276      }
00277 
00278      processNameOrdering.swap(temp);
00279 
00280      //now we need to go through our data structure and change the processing orders
00281      //first find the range for this BranchType
00282      std::pair<TypeInBranchTypeLookup::iterator, TypeInBranchTypeLookup::iterator> branchRange =
00283      std::equal_range(branchLookup_.begin(), branchLookup_.end(), std::make_pair(TypeInBranchType(TypeID(), iBranch), BranchDescriptionIndex(0)), BranchTypeOnlyCompare());
00284 
00285      if(branchRange.first == branchRange.second) {
00286         return;
00287      }
00288      //convert this into Index iterators since that is the structure we must reorder
00289      ProductLookupIndexList::iterator itIndex = productLookupIndexList_.begin() + branchRange.first->second;
00290      ProductLookupIndexList::iterator itIndexEnd = productLookupIndexList_.end();
00291      if(branchRange.second != branchLookup_.end()) {
00292         itIndexEnd = productLookupIndexList_.begin() + branchRange.second->second;
00293      }
00294 
00295      while(itIndex != itIndexEnd) {
00296         itIndex->setIsFirst(false);
00297         ProductLookupIndexList::iterator itNext = itIndex;
00298         while(itNext != itIndexEnd && !itNext->isFirst()) {
00299            ++itNext;
00300         }
00301         std::sort(itIndex, itNext, CompareProcessList(&processNameOrdering));
00302         itIndex->setIsFirst(true);
00303         itIndex = itNext;
00304      }
00305 
00306      //Now that we know all the IDs time to set the values
00307      fillInProcessIndexes(productLookupIndexList_.begin() + branchRange.first->second, itIndexEnd, processNameOrdering);
00308 
00309   }
00310 
00311   void
00312   TransientProductLookupMap::fillFrom(FillFromMap const& iMap) {
00313 
00314      assert(processNameOrderingForBranchType_.size() == historyIDsForBranchType_.size());
00315 
00316      //Increment the fill count so users can check if the map has been modified.
00317      ++fillCount_;
00318 
00319      productLookupIndexList_.clear();
00320      productLookupIndexList_.reserve(iMap.size());
00321      branchLookup_.clear();
00322      branchLookup_.reserve(iMap.size()); //this is an upperbound
00323 
00324      std::set<std::string, std::greater<std::string> > processNames;
00325      TypeInBranchType lastSeen(TypeID(), NumBranchTypes);
00326 
00327      //since the actual strings are stored elsewhere, there is no reason to make a copy
00328      static std::string const kEmpty;
00329      std::string const* lastSeenModule = &kEmpty;
00330      std::string const* lastSeenProductInstance = &kEmpty;
00331      for(FillFromMap::const_iterator it = iMap.begin(), itEnd = iMap.end();
00332          it != itEnd;
00333          ++it) {
00334         bool isFirst =  ((lastSeen < it->first.first) || (it->first.first < lastSeen));
00335         if(isFirst) {
00336            lastSeen = it->first.first;
00337            branchLookup_.push_back(std::make_pair(lastSeen, BranchDescriptionIndex(productLookupIndexList_.size())));
00338         } else {
00339            //see if this is the first of a group that only differ by ProcessName
00340            isFirst = (*lastSeenModule != it->first.second->moduleLabel() ||
00341                       *lastSeenProductInstance != it->first.second->productInstanceName());
00342         }
00343         productLookupIndexList_.push_back(ProductLookupIndex(it->first.second,
00344                                                 it->second,
00345                                                 0,
00346                                                 isFirst)
00347                             );
00348         if(isFirst) {
00349            lastSeenModule = &(it->first.second->moduleLabel());
00350            lastSeenProductInstance = &(it->first.second->productInstanceName());
00351         }
00352         processNames.insert(it->first.second->processName());
00353      }
00354 
00355      std::vector<ProcessHistoryID>::iterator itPH = historyIDsForBranchType_.begin();
00356      std::vector<ProcessHistoryID>::iterator itPHEnd = historyIDsForBranchType_.end();
00357 
00358      std::vector<std::vector<std::string> >::iterator itPN = processNameOrderingForBranchType_.begin();
00359      //std::vector<std::vector<std::string> >::iterator itPNEnd = processNameOrderingForBranchType_.end();
00360 
00361      for(;itPH != itPHEnd; ++itPH, ++itPN) {
00362         *itPH = ProcessHistoryID();
00363         itPN->assign(processNames.begin(), processNames.end());
00364      }
00365 
00366      //Now that we know all the IDs time to set the values
00367      fillInProcessIndexes(productLookupIndexList_.begin(), productLookupIndexList_.end(), processNameOrderingForBranchType_.front());
00368   }
00369 
00370   //
00371   // const member functions
00372   //
00373   namespace {
00374      struct CompareFirst {
00375         bool operator()(TransientProductLookupMap::TypeInBranchTypeLookup::value_type const& iLHS,
00376                         TransientProductLookupMap::TypeInBranchTypeLookup::value_type const& iRHS) const {
00377            return iLHS.first < iRHS.first;
00378         }
00379      };
00380   }
00381 
00382   std::pair<TransientProductLookupMap::const_iterator, TransientProductLookupMap::const_iterator>
00383   TransientProductLookupMap::equal_range(TypeInBranchType const& iKey) const {
00384      TypeInBranchTypeLookup::const_iterator itFind = std::lower_bound(branchLookup_.begin(),
00385                                                                       branchLookup_.end(),
00386                                                                       std::make_pair(iKey, BranchDescriptionIndex(0)),
00387                                                                       CompareFirst());
00388      if(itFind == branchLookup_.end() || iKey < itFind->first) {
00389         return std::make_pair(productLookupIndexList_.end(), productLookupIndexList_.end());
00390      }
00391      const_iterator itStart = productLookupIndexList_.begin() + itFind->second;
00392      const_iterator itEnd = productLookupIndexList_.end();
00393      if(++itFind != branchLookup_.end()) {
00394         itEnd = productLookupIndexList_.begin() + itFind->second;
00395      }
00396      return std::make_pair(itStart, itEnd);
00397   }
00398 
00399   std::pair<TransientProductLookupMap::const_iterator, TransientProductLookupMap::const_iterator>
00400   TransientProductLookupMap::equal_range(TypeInBranchType const& iKey,
00401          std::string const& moduleLabel,
00402          std::string const& productInstanceName) const {
00403      std::pair<const_iterator, const_iterator> itPair = this->equal_range(iKey);
00404 
00405      if (itPair.first == itPair.second) {
00406         return itPair;
00407      }
00408 
00409      // Advance lower bound only
00410      itPair.first = std::lower_bound(itPair.first, itPair.second, std::make_pair(&moduleLabel, &productInstanceName), CompareModuleLabelAndProductInstanceName());
00411      // Protect against no match
00412      if (!(itPair.first < itPair.second) ||
00413          itPair.first->branchDescription()->moduleLabel() != moduleLabel ||
00414          itPair.first->branchDescription()->productInstanceName() != productInstanceName) {
00415        itPair.second = itPair.first;
00416      }
00417      return itPair;
00418   }
00419 
00420   //
00421   // static member functions
00422   //
00423 }