CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/DataFormats/Common/src/MultiAssociation.cc

Go to the documentation of this file.
00001 #include <algorithm>
00002 #include "DataFormats/Common/interface/MultiAssociation.h"
00003 #include "FWCore/Utilities/interface/Exception.h"
00004 
00005 #include <iostream>
00006 
00007 using edm::helper::IndexRangeAssociation;
00008 using edm::ProductID;
00009 
00010 IndexRangeAssociation::range
00011 IndexRangeAssociation::get(const ProductID &id, unsigned int key) const {
00012     typedef IndexRangeAssociation::id_offset_vector::const_iterator iter;
00013     iter pos = std::lower_bound(id_offsets_.begin(), id_offsets_.end(), id, IDComparator()); 
00014     if ((pos == id_offsets_.end()) || (pos->first != id)) {
00015         throw cms::Exception("Bad Key") << "Product ID " << id << " not found in this IndexRangeAssociation\n";
00016     }
00017     // === Do we want this check ? I would say yes, even if it costs some extra CPU cycles
00018     if ((pos + 1 != id_offsets_.end()) && (pos->second + key >= (pos+1)->second)) {
00019         throw cms::Exception("Bad Offset") << "Key " << key << " goes beyond bounds " 
00020                     << ((pos+1)->second - pos->second) 
00021                     << " of this key collection within IndexRangeAssociation\n";
00022     }
00023     // === End check
00024     offset_vector::const_iterator offs = ref_offsets_.begin() + pos->second + key;
00025     if (offs >= ref_offsets_.end()-1) {
00026         throw cms::Exception("Bad Offset") << "Key " << key << " goes beyond bounds " << ref_offsets_.size()-1 << " of this IndexRangeAssociation\n";
00027     }
00028     return range(*offs,*(offs+1));
00029 }
00030 
00031 bool
00032 IndexRangeAssociation::contains(ProductID id) const {
00033     typedef IndexRangeAssociation::id_offset_vector::const_iterator iter;
00034     iter pos = std::lower_bound(id_offsets_.begin(), id_offsets_.end(), id, IDComparator());
00035     return (pos != id_offsets_.end()) && (pos->first == id);
00036 }
00037 
00038 void
00039 IndexRangeAssociation::swap(IndexRangeAssociation &other) {
00040     if (isFilling_ || other.isFilling_) throw cms::Exception("Busy") << "Can't swap an IndexRangeAssociation while it's being filled!\n";
00041     id_offsets_.swap(other.id_offsets_);
00042     ref_offsets_.swap(other.ref_offsets_);
00043 }
00044 
00045 IndexRangeAssociation::FastFiller::FastFiller(IndexRangeAssociation &assoc, ProductID id, unsigned int size) :
00046     assoc_(assoc), id_(id), 
00047     start_(assoc.ref_offsets_.empty() ? 0 : assoc.ref_offsets_.size() - 1), // must skip the end marker element
00048     end_(start_ + size),
00049     lastKey_(-1)
00050 {
00051     if (assoc_.isFilling_) throw cms::Exception("Unsupported Operation") << 
00052         "IndexRangeAssociation::FastFiller: you already have one active filler for this map.\n";
00053 
00054     // Look if the key is there, or find the right place to insert it
00055     typedef IndexRangeAssociation::id_offset_vector::iterator iter;
00056     iter pos = std::lower_bound(assoc_.id_offsets_.begin(), assoc_.id_offsets_.end(), id, IndexRangeAssociation::IDComparator());
00057 
00058     // Check for duplicate ProductID
00059     if ((pos != assoc_.id_offsets_.end()) && (pos->first == id)) throw cms::Exception("Duplicated Key") << 
00060         "IndexRangeAssociation::FastFiller: there is already an entry for ProductID " << id << " in this map.\n";
00061 
00062     // Lock the map    
00063     assoc_.isFilling_ = true;
00064 
00065     // Insert the key, keeping id_offsets_ sorted
00066     assoc_.id_offsets_.insert(pos, IndexRangeAssociation::id_off_pair(id, start_));
00067 
00068     int lastEnd = (assoc_.ref_offsets_.empty() ? 0 : assoc_.ref_offsets_.back());
00069     assoc_.ref_offsets_.resize(end_ + 1, -1);
00070     assoc_.ref_offsets_.back() = lastEnd;
00071 }
00072 
00073 IndexRangeAssociation::FastFiller::~FastFiller() {
00074     // I have to consolidate, replacing "-1" with the correct end offset.
00075     // I can start from the end, as I know that the last item is never -1
00076     typedef IndexRangeAssociation::offset_vector::iterator IT;
00077     //std::cout << "Fixupping [" << start_ << ", " << end_ << "]" << std::endl;
00078     //for(IT i = assoc_.ref_offsets_.begin() + start_; i <= assoc_.ref_offsets_.begin() + end_; ++i) { std::cout << "  - " << *i << std::endl; }
00079     IT top = assoc_.ref_offsets_.begin() + start_;
00080     IT it  = assoc_.ref_offsets_.begin() + end_;
00081     int offset = *it;
00082     for (--it; it >= top; --it) {
00083         if (*it == -1) {
00084             //std::cout << " > replace *it " << *it << " with offset " << offset << " at " << (it - top) << std::endl;
00085             *it = offset; // replace -1 with real end offset
00086         } else {
00087             //std::cout << " > replace offset " << offset << " with *it " << *it << " at " << (it - top) << std::endl;
00088             offset = *it;           // take as new end offset for the preceding "-1"s
00089         }
00090     }
00091     assoc_.isFilling_ = false; // unlock
00092     //std::cout << "Fixupped [" << start_ << ", " << end_ << "]" << std::endl;
00093     //for(IT i = assoc_.ref_offsets_.begin() + start_; i <= assoc_.ref_offsets_.begin() + end_; ++i) { std::cout << "  - " << *i << std::endl; }
00094 }
00095 
00096 void
00097 IndexRangeAssociation::FastFiller::insert(edm::ProductID id, unsigned int key, unsigned int startingOffset, unsigned int size) {
00098     if (id != id_) IndexRangeAssociation::throwUnexpectedProductID(id,id_,"FastFiller::insert");
00099     if (int(key) <= lastKey_) throw cms::Exception("Bad Key") << 
00100             "IndexRangeAssociation::FastFiller: you must fill this in strict key order\n" << 
00101             "\tLast key = " << lastKey_ << ", this key = " << key << "\n";
00102     if (key >= end_)  throw cms::Exception("Bad Key") <<
00103             "IndexRangeAssociation::FastFiller: key index out of bounds for this collection\n" << 
00104             "\tKey = " << key << ", bound = " << end_ << "\n";
00105     if ((assoc_.ref_offsets_.back() != 0) && (int(startingOffset) != assoc_.ref_offsets_.back())) 
00106         throw cms::Exception("Bad Offset") <<
00107             "IndexRangeAssociation::FastFiller: The start for this key is not the end of the preceding key.\n" << 
00108             "\tThis offset = " << startingOffset << ", last key = " << lastKey_ << 
00109             ", last end offset = " << assoc_.ref_offsets_.back() << "\n";
00110     assoc_.ref_offsets_[start_ + key] = startingOffset; 
00111     lastKey_ = key;
00112     assoc_.ref_offsets_.back() += size;
00113 }
00114 
00115 void
00116 IndexRangeAssociation::throwUnexpectedProductID(ProductID found, ProductID expected, const char *where) {
00117     throw cms::Exception("Unexpected ProductID") << where <<
00118           ": found product id " << found << ", while expecting " << expected << ".\n" << 
00119           "Make sure you're not mismatching references from different collections.\n";
00120 }