Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #include "DataFormats/Common/interface/OwnVector.h"
0002 #include "DataFormats/Common/interface/PtrVector.h"
0003 #include "DataFormats/Common/interface/RefVector.h"
0004 #include "DataFormats/Common/interface/TestHandle.h"
0005 #include "FWCore/Utilities/interface/Exception.h"
0006 
0007 #include "cppunit/extensions/HelperMacros.h"
0008 
0009 #include "boost/lambda/bind.hpp"
0010 #include "boost/lambda/lambda.hpp"
0011 
0012 #include <algorithm>
0013 #include <cmath>
0014 #include <iomanip>
0015 #include <iostream>
0016 #include <iterator>
0017 #include <memory>
0018 
0019 #include "DataFormats/Common/interface/MultiAssociation.h"
0020 
0021 namespace {
0022   struct DummyBase {
0023     virtual ~DummyBase() {}
0024     virtual int id() const { return 0; }
0025     virtual DummyBase* clone() const { return new DummyBase(*this); }
0026     void const* addr() const { return this; }
0027   };
0028   struct DummyDer1 : public DummyBase {
0029     virtual int id() const { return 1; }
0030     virtual DummyDer1* clone() const { return new DummyDer1(*this); }
0031   };
0032   struct DummyDer2 : public DummyBase {
0033     virtual int id() const { return 2; }
0034     virtual DummyDer2* clone() const { return new DummyDer2(*this); }
0035   };
0036 }  // namespace
0037 
0038 using namespace edm;
0039 
0040 class testMultiAssociation : public CppUnit::TestFixture {
0041   CPPUNIT_TEST_SUITE(testMultiAssociation);
0042   CPPUNIT_TEST(checkAll);
0043   CPPUNIT_TEST(checkVals);
0044   CPPUNIT_TEST(checkTwoFillers);
0045   CPPUNIT_TEST(checkUnsortedKeys);
0046   CPPUNIT_TEST(checkBadFill);
0047   CPPUNIT_TEST(checkBadRead);
0048   CPPUNIT_TEST(checkWithPtr);
0049   CPPUNIT_TEST(checkWithOwn);
0050   CPPUNIT_TEST(checkWritableMap);
0051   CPPUNIT_TEST_SUITE_END();
0052   typedef std::vector<double> CVal;  // Values
0053   typedef std::vector<int> CKey1;    // Keys 1
0054   typedef std::vector<float> CKey2;  // Keys 2
0055   typedef std::vector<DummyDer1> CObj;
0056   typedef Ptr<DummyBase> PObj;
0057   typedef PtrVector<DummyBase> PObjs;
0058   typedef OwnVector<DummyBase> OObj;
0059   typedef MultiAssociation<RefVector<CVal> > MultiRef;
0060   typedef MultiAssociation<CVal> MultiVal;
0061   typedef MultiAssociation<PObjs> MultiPtr;
0062   typedef MultiAssociation<OObj> MultiOwn;
0063   /**
0064    * Map to each key, all values that are greater than key
0065    * Try both with MultiAssociation<RefVector<double>> and  MultiAssociation<vector<double> >
0066    */
0067 public:
0068   testMultiAssociation();
0069   void setUp() {}
0070   void tearDown() {}
0071   void checkAll();
0072   void checkVals();
0073   void checkTwoFillers();
0074   void checkUnsortedKeys();
0075   void checkBadFill();
0076   void checkBadRead();
0077   template <typename Map>
0078   bool tryTwoFillers(bool lazy);
0079   template <typename Map>
0080   bool tryUnsortedKeys(bool lazy);
0081   bool tryBadFill(int i);
0082   bool tryBadRead(int i);
0083   void checkWithPtr();
0084   void checkWithOwn();
0085   void checkWritableMap();
0086   void test(MultiRef const&);
0087   void test(MultiVal const&);
0088   void test2(MultiRef const&);
0089 #ifdef private
0090   void dump(MultiRef::Indices const&);
0091   template <typename T>
0092   void dump(RefVector<T> const&);
0093   template <typename T>
0094   void dump(std::vector<T> const&);
0095   void dump(MultiRef const&, char const* when);
0096   void dump(MultiVal const&, char const* when);
0097 #else
0098   template <typename T>
0099   void dump(RefVector<T> const&) {}
0100   template <typename T>
0101   void dump(std::vector<T> const&) {}
0102   void dump(MultiRef const&, char const* /*when*/) {}
0103   void dump(MultiVal const&, char const* /*when*/) {}
0104 #endif
0105   CVal k;
0106   CKey1 v1;
0107   CKey2 v2;
0108   CObj der1s;
0109   PObjs ptrs;
0110   OObj bases;
0111   edm::TestHandle<CVal> handleV;
0112   edm::TestHandle<CKey1> handleK1;
0113   edm::TestHandle<CKey2> handleK2;
0114   std::vector<int> w1, w2;
0115 
0116   template <typename Key, typename UnaryFunc, typename BinaryFunc>
0117   void fastFillRefs(edm::TestHandle<Key> const& handle, MultiRef& map, UnaryFunc const& u, BinaryFunc const& f) {
0118     MultiRef::FastFiller filler = map.fastFiller(handle);
0119     for (typename Key::const_iterator it = handle->begin(), ed = handle->end(); it != ed; ++it) {
0120       if (!u(*it))
0121         continue;
0122       RefVector<CVal> vals;
0123       for (std::vector<double>::const_iterator it2 = k.begin(), ed2 = k.end(); it2 != ed2; ++it2) {
0124         if (f(*it, *it2)) {
0125           vals.push_back(Ref<CVal>(handleV, it2 - k.begin()));
0126         }
0127       }
0128       filler.setValues(Ref<Key>(handle, it - handle->begin()), vals);
0129     }
0130   }
0131 
0132   template <typename Key, typename UnaryFunc, typename BinaryFunc>
0133   void lazyFillRefs(
0134       edm::TestHandle<Key> const& handle, MultiRef& map, UnaryFunc const& u, BinaryFunc const& f, bool swap) {
0135     MultiRef::LazyFiller filler = map.lazyFiller(handle, true);
0136     for (typename Key::const_iterator it = handle->begin(), ed = handle->end(); it != ed; ++it) {
0137       if (!u(*it))
0138         continue;
0139       RefVector<CVal> vals;
0140       for (std::vector<double>::const_iterator it2 = k.begin(), ed2 = k.end(); it2 != ed2; ++it2) {
0141         if (f(*it, *it2)) {
0142           vals.push_back(Ref<CVal>(handleV, it2 - k.begin()));
0143         }
0144       }
0145       if (swap) {
0146         filler.swapValues(Ref<Key>(handle, it - handle->begin()), vals);
0147       } else {
0148         filler.setValues(Ref<Key>(handle, it - handle->begin()), vals);
0149       }
0150     }
0151   }
0152 
0153   template <typename Key, typename UnaryFunc, typename BinaryFunc>
0154   void fastFillVals(edm::TestHandle<Key> const& handle, MultiVal& map, UnaryFunc const& u, BinaryFunc const& f) {
0155     MultiVal::FastFiller filler = map.fastFiller(handle);
0156     for (typename Key::const_iterator it = handle->begin(), ed = handle->end(); it != ed; ++it) {
0157       if (!u(*it))
0158         continue;
0159       CVal vals;
0160       for (std::vector<double>::const_iterator it2 = k.begin(), ed2 = k.end(); it2 != ed2; ++it2) {
0161         if (f(*it, *it2)) {
0162           vals.push_back(*it2);
0163         }
0164       }
0165       filler.setValues(Ref<Key>(handle, it - handle->begin()), vals);
0166     }
0167   }
0168 
0169   template <typename Key, typename UnaryFunc, typename BinaryFunc>
0170   void lazyFillVals(
0171       edm::TestHandle<Key> const& handle, MultiVal& map, UnaryFunc const& u, BinaryFunc const& f, bool swap) {
0172     MultiVal::LazyFiller filler = map.lazyFiller(handle, true);
0173     for (typename Key::const_iterator it = handle->begin(), ed = handle->end(); it != ed; ++it) {
0174       if (!u(*it))
0175         continue;
0176       CVal vals;
0177       for (std::vector<double>::const_iterator it2 = k.begin(), ed2 = k.end(); it2 != ed2; ++it2) {
0178         if (f(*it, *it2)) {
0179           vals.push_back(*it2);
0180         }
0181       }
0182       if (swap) {
0183         filler.swapValues(Ref<Key>(handle, it - handle->begin()), vals);
0184       } else {
0185         filler.setValues(Ref<Key>(handle, it - handle->begin()), vals);
0186       }
0187     }
0188   }
0189 
0190   //template<typename Map, typename Filler> tryUnsortedKeys() ;
0191 };
0192 
0193 CPPUNIT_TEST_SUITE_REGISTRATION(testMultiAssociation);
0194 
0195 testMultiAssociation::testMultiAssociation() {
0196   k.push_back(1.1);
0197   k.push_back(2.2);
0198   k.push_back(3.3);
0199   k.push_back(4.4);
0200   ProductID const pidV(1);
0201   handleV = edm::TestHandle<CVal>(&k, pidV);
0202 
0203   v1.push_back(1);
0204   v1.push_back(2);
0205   v1.push_back(3);
0206   v1.push_back(4);
0207   ProductID const pidK1(2);
0208   handleK1 = edm::TestHandle<CKey1>(&v1, pidK1);
0209 
0210   v2.push_back(1.);
0211   v2.push_back(2.);
0212   v2.push_back(3.);
0213   v2.push_back(4.);
0214   v2.push_back(5.);
0215   ProductID const pidK2(3);
0216   handleK2 = edm::TestHandle<CKey2>(&v2, pidK2);
0217 
0218   for (size_t j = 0; j < 10; ++j)
0219     der1s.push_back(DummyDer1());
0220   for (size_t j = 0; j < 10; ++j) {
0221     if (j % 3 == 0)
0222       bases.push_back(std::make_unique<DummyBase>());
0223     if (j % 3 == 1)
0224       bases.push_back(std::make_unique<DummyDer1>());
0225     if (j % 3 == 2)
0226       bases.push_back(std::make_unique<DummyDer2>());
0227     CPPUNIT_ASSERT(bases[j].id() == int(j % 3));
0228   }
0229   edm::TestHandle<CObj> handleObj(&der1s, ProductID(10));
0230   for (size_t j = 0; j < 7; ++j) {
0231     size_t k = (j * 37) % 10;
0232     ptrs.push_back(PObj(handleObj, k));
0233     CPPUNIT_ASSERT(ptrs[j]->id() == 1);
0234     CPPUNIT_ASSERT(ptrs[j]->addr() == &der1s[k]);
0235   }
0236 }
0237 
0238 void testMultiAssociation::checkAll() {
0239   using boost::lambda::_1;
0240   using boost::lambda::_2;
0241   {
0242     MultiRef try1;
0243     dump(try1, "empty");
0244     fastFillRefs(handleK1, try1, _1 > 0, _1 > _2);
0245     dump(try1, "fill 1");
0246     fastFillRefs(handleK2, try1, _1 > 0, _1 > _2);
0247     dump(try1, "fill 2");
0248     test(try1);
0249   }
0250   {
0251     MultiRef try2;
0252     fastFillRefs(
0253         handleK1, try2, _1 > 0, (_1 < _2) && (2 * bind(floor, _1 / 2) != _1));  // fill all, but leave empty the odds
0254     fastFillRefs(
0255         handleK2, try2, _1 > 0, (_1 < _2) && (2 * bind(floor, _1 / 2) != _1));  // fill all, but leave empty the odds
0256     dump(try2, "fill 2");
0257     test2(try2);
0258   }
0259   {
0260     MultiRef try2;
0261     fastFillRefs(handleK1,
0262                  try2,
0263                  (2 * bind(floor, _1 / 2) != _1),
0264                  (_1 < _2) && (2 * bind(floor, _1 / 2) != _1));  // don't fill the odds
0265     fastFillRefs(handleK2,
0266                  try2,
0267                  (2 * bind(floor, _1 / 2) != _1),
0268                  (_1 < _2) && (2 * bind(floor, _1 / 2) != _1));  // don't fill the odds
0269     dump(try2, "fill 2");
0270     test2(try2);
0271   }
0272   {
0273     MultiRef try3;
0274     fastFillRefs(handleK1, try3, _1 < 0, (_1 > _2));  // don't fill any of the first
0275     fastFillRefs(handleK2, try3, _1 > 0, (_1 > _2));  //
0276     dump(try3, "no first");
0277   }
0278   {
0279     MultiRef try3;
0280     fastFillRefs(handleK1, try3, _1 > 0, (_1 > _2));  //
0281     fastFillRefs(handleK2, try3, _1 < 0, (_1 > _2));  // don't fill the second
0282     dump(try3, "no second");
0283   }
0284   {
0285     MultiRef try3;
0286     fastFillRefs(handleK1, try3, _1 < 0, (_1 > _2));  // don't fill any of the first
0287     fastFillRefs(handleK2, try3, _1 < 0, (_1 > _2));  // nor the second
0288     dump(try3, "neither");
0289   }
0290   {
0291     MultiRef try1;
0292     lazyFillRefs(handleK1, try1, _1 > 0, _1 > _2, false);
0293     lazyFillRefs(handleK2, try1, _1 > 0, _1 > _2, false);
0294     dump(try1, "fill 2");
0295     test(try1);
0296   }
0297   {
0298     MultiRef try2;
0299     lazyFillRefs(handleK1,
0300                  try2,
0301                  (2 * bind(floor, _1 / 2) != _1),
0302                  (_1 < _2) && (2 * bind(floor, _1 / 2) != _1),
0303                  false);  // don't fill the odds
0304     lazyFillRefs(handleK2,
0305                  try2,
0306                  (2 * bind(floor, _1 / 2) != _1),
0307                  (_1 < _2) && (2 * bind(floor, _1 / 2) != _1),
0308                  false);  // don't fill the odds
0309     dump(try2, "fill 2");
0310     test2(try2);
0311   }
0312   {
0313     MultiRef try1;
0314     lazyFillRefs(handleK1, try1, _1 > 0, _1 > _2, true);
0315     lazyFillRefs(handleK2, try1, _1 > 0, _1 > _2, true);
0316     dump(try1, "fill 2");
0317     test(try1);
0318   }
0319   {
0320     MultiRef try2;
0321     lazyFillRefs(handleK1,
0322                  try2,
0323                  (2 * bind(floor, _1 / 2) != _1),
0324                  (_1 < _2) && (2 * bind(floor, _1 / 2) != _1),
0325                  true);  // don't fill the odds
0326     lazyFillRefs(handleK2,
0327                  try2,
0328                  (2 * bind(floor, _1 / 2) != _1),
0329                  (_1 < _2) && (2 * bind(floor, _1 / 2) != _1),
0330                  true);  // don't fill the odds
0331     dump(try2, "fill 2");
0332     test2(try2);
0333   }
0334 }
0335 
0336 void testMultiAssociation::checkVals() {
0337   using boost::lambda::_1;
0338   using boost::lambda::_2;
0339   {
0340     MultiVal try1;
0341     dump(try1, "empty");
0342     fastFillVals(handleK1, try1, _1 > 0, _1 > _2);
0343     dump(try1, "fill 1");
0344     fastFillVals(handleK2, try1, _1 > 0, _1 > _2);
0345     dump(try1, "fill 2");
0346     test(try1);
0347   }
0348   {
0349     MultiVal try1;
0350     lazyFillVals(handleK1, try1, _1 > 0, _1 > _2, false);
0351     lazyFillVals(handleK2, try1, _1 > 0, _1 > _2, false);
0352     dump(try1, "fill 2");
0353     test(try1);
0354   }
0355   {
0356     MultiVal try1;
0357     lazyFillVals(handleK1, try1, _1 > 0, _1 > _2, true);
0358     lazyFillVals(handleK2, try1, _1 > 0, _1 > _2, true);
0359     dump(try1, "fill 2");
0360     test(try1);
0361   }
0362 }
0363 
0364 #ifdef private
0365 void testMultiAssociation::dump(MultiRef::Indices const& indices) {
0366   using namespace std;
0367   cerr << "    Dumping Index map at " << &indices << endl;
0368   cerr << "    id_offsets_ (size = " << indices.id_offsets_.size() << ")" << endl;
0369   for (size_t i = 0; i < indices.id_offsets_.size(); ++i) {
0370     cerr << "      [" << setw(3) << i << "]: (" << setw(3) << indices.id_offsets_[i].first << ", " << setw(3)
0371          << indices.id_offsets_[i].second << ")" << endl;
0372   }
0373   cerr << "    ref_offsets_ (size = " << indices.ref_offsets_.size() << ")" << endl;
0374   for (size_t i = 0; i < indices.ref_offsets_.size(); ++i) {
0375     cerr << "      [" << setw(3) << i << "]: " << setw(4) << indices.ref_offsets_[i] << ")" << endl;
0376   }
0377   cerr << "    isFilling_: " << indices.isFilling_ << endl;
0378 }
0379 template <typename T>
0380 void testMultiAssociation::dump(edm::RefVector<T> const& data) {
0381   using namespace std;
0382   cerr << "  Dumping " << typeid(data).name() << " at " << &data << endl;
0383   cerr << "    ID: " << data.id() << endl;
0384   cerr << "    Values (size = " << data.size() << ")" << endl;
0385   for (size_t i = 0; i < data.size(); ++i) {
0386     cerr << "      [" << setw(3) << i << "]: key = " << setw(4) << data[i].key();
0387     if (data[i].isNull())
0388       cerr << ", NULL" << endl;
0389     else
0390       cerr << ", value = " << *data[i] << endl;
0391   }
0392 }
0393 template <typename T>
0394 void testMultiAssociation::dump(std::vector<T> const& data) {
0395   using namespace std;
0396   cerr << "  Dumping " << typeid(data).name() << " at " << &data << endl;
0397   cerr << "    Values (size = " << data.size() << ")" << endl;
0398   for (size_t i = 0; i < data.size(); ++i) {
0399     cerr << "      [" << setw(3) << i << "]: key = " << setw(4) << data[i] << endl;
0400   }
0401 }
0402 
0403 void testMultiAssociation::dump(MultiRef const& assoc, char const* what) {
0404   using namespace std;
0405   cerr << "\nDumping MultiRef at " << &assoc << " for " << what << endl;
0406   dump(assoc.indices_);
0407   dump(assoc.data_);
0408   cerr << endl;
0409 }
0410 void testMultiAssociation::dump(MultiVal const& assoc, char const* what) {
0411   using namespace std;
0412   cerr << "\nDumping MultiVal at " << &assoc << " for " << what << endl;
0413   dump(assoc.indices_);
0414   dump(assoc.data_);
0415   cerr << endl;
0416 }
0417 
0418 #endif
0419 
0420 void testMultiAssociation::test(MultiRef const& assoc) {
0421   // TEST contains
0422   CPPUNIT_ASSERT(!assoc.contains(ProductID(1)));
0423   CPPUNIT_ASSERT(assoc.contains(ProductID(2)));
0424   CPPUNIT_ASSERT(assoc.contains(ProductID(3)));
0425   CPPUNIT_ASSERT(!assoc.contains(ProductID(4)));
0426 
0427   // TEST const_range access
0428   MultiRef::const_range br1, br2, br3, br4;
0429   br1 = assoc[edm::Ref<CKey1>(handleK1, 0)];
0430   br2 = assoc[edm::Ref<CKey1>(handleK1, 1)];
0431   br3 = assoc[edm::Ref<CKey1>(handleK1, 2)];
0432   br4 = assoc[edm::Ref<CKey1>(handleK1, 3)];
0433   CPPUNIT_ASSERT(br1.size() == 0);
0434   CPPUNIT_ASSERT(br2.size() == 1);
0435   CPPUNIT_ASSERT(br3.size() == 2);
0436   CPPUNIT_ASSERT(br4.size() == 3);
0437   CPPUNIT_ASSERT(br2.begin()->id() == ProductID(1));
0438   CPPUNIT_ASSERT(br2.begin()->key() == 0);
0439   CPPUNIT_ASSERT(**br2.begin() == k.front());
0440   CPPUNIT_ASSERT(*br2.front() == k.front());
0441   CPPUNIT_ASSERT(*br2[0] == k[0]);
0442   CPPUNIT_ASSERT(br4.back().id() == ProductID(1));
0443   CPPUNIT_ASSERT(br4.back().key() == 2);
0444   CPPUNIT_ASSERT(br4[2].key() == 2);
0445 
0446   // TEST const_ranges
0447   // Check that ranges are consecutive
0448   br1 = assoc[edm::Ref<CKey1>(handleK1, 0)];
0449   CPPUNIT_ASSERT(br1.end() == br1.begin());
0450   br2 = assoc[edm::Ref<CKey1>(handleK1, 1)];
0451   CPPUNIT_ASSERT(br2.end() == br2.begin() + 1);
0452   CPPUNIT_ASSERT(br2.begin() == br1.end());
0453   br3 = assoc[edm::Ref<CKey1>(handleK1, 2)];
0454   CPPUNIT_ASSERT(br3.end() == br3.begin() + 2);
0455   CPPUNIT_ASSERT(br3.begin() == br2.end());
0456   // Check that ranges are consecutive across collections
0457   br1 = assoc[edm::Ref<CKey1>(handleK1, 3)];
0458   br2 = assoc[edm::Ref<CKey2>(handleK2, 0)];
0459   br3 = assoc[edm::Ref<CKey2>(handleK2, 1)];
0460   CPPUNIT_ASSERT(br1.end() == br1.begin() + 3);
0461   CPPUNIT_ASSERT(br1.end() == br2.begin() + 0);
0462   CPPUNIT_ASSERT(br2.end() == br2.begin() + 0);
0463   CPPUNIT_ASSERT(br2.end() == br3.begin() + 0);
0464   CPPUNIT_ASSERT(br3.end() == br3.begin() + 1);
0465 
0466   // TEST RefVector access
0467   edm::RefVector<CVal> r1, r2, r3, r4, r5;
0468   r1 = assoc.getValues(edm::Ref<CKey1>(handleK1, 0));
0469   r2 = assoc.getValues(edm::Ref<CKey1>(handleK1, 1));
0470   r3 = assoc.getValues(edm::Ref<CKey1>(handleK1, 2));
0471   r4 = assoc.getValues(edm::Ref<CKey1>(handleK1, 3));
0472   CPPUNIT_ASSERT(r1.size() == 0);
0473   CPPUNIT_ASSERT(r2.size() == 1);
0474   CPPUNIT_ASSERT(r3.size() == 2);
0475   CPPUNIT_ASSERT(r4.size() == 3);
0476   CPPUNIT_ASSERT(r2.begin()->id() == ProductID(1));
0477   CPPUNIT_ASSERT(r2.begin()->key() == 0);
0478   CPPUNIT_ASSERT(**r2.begin() == k.front());
0479   CPPUNIT_ASSERT(**r2.begin() == k.front());
0480   CPPUNIT_ASSERT((r4.end() - 1)->id() == ProductID(1));
0481   CPPUNIT_ASSERT((r4.end() - 1)->key() == 2);
0482 }
0483 
0484 void testMultiAssociation::test2(MultiRef const& assoc) {
0485   // TEST contains
0486   CPPUNIT_ASSERT(!assoc.contains(ProductID(1)));
0487   CPPUNIT_ASSERT(assoc.contains(ProductID(2)));
0488   CPPUNIT_ASSERT(assoc.contains(ProductID(3)));
0489   CPPUNIT_ASSERT(!assoc.contains(ProductID(4)));
0490 
0491   // TEST const_range access
0492   MultiRef::const_range br1, br2, br3, br4;
0493   br1 = assoc[edm::Ref<CKey1>(handleK1, 0)];
0494   CPPUNIT_ASSERT(br1.end() == br1.begin() + 4);
0495   br2 = assoc[edm::Ref<CKey1>(handleK1, 1)];
0496   CPPUNIT_ASSERT(br2.end() == br2.begin() + 0);
0497   CPPUNIT_ASSERT(br2.begin() == br1.end());
0498   br3 = assoc[edm::Ref<CKey1>(handleK1, 2)];
0499   CPPUNIT_ASSERT(br3.end() == br3.begin() + 2);
0500   CPPUNIT_ASSERT(br3.begin() == br2.end());
0501   // Check that ranges are consecutive across collections
0502   br1 = assoc[edm::Ref<CKey1>(handleK1, 3)];
0503   br2 = assoc[edm::Ref<CKey2>(handleK2, 0)];
0504   br3 = assoc[edm::Ref<CKey2>(handleK2, 1)];
0505   CPPUNIT_ASSERT(br1.end() == br1.begin() + 0);
0506   CPPUNIT_ASSERT(br1.end() == br2.begin() + 0);
0507   CPPUNIT_ASSERT(br2.end() == br2.begin() + 4);
0508   CPPUNIT_ASSERT(br2.end() == br3.begin() + 0);
0509   CPPUNIT_ASSERT(br3.end() == br3.begin() + 0);
0510 }
0511 
0512 void testMultiAssociation::test(MultiVal const& assoc) {
0513 #if 1
0514   // TEST Vector access
0515   MultiVal::const_range r1, r2, r3, r4, r5;
0516   r1 = assoc[edm::Ref<CKey1>(handleK1, 0)];
0517   r2 = assoc[edm::Ref<CKey1>(handleK1, 1)];
0518   r3 = assoc[edm::Ref<CKey1>(handleK1, 2)];
0519   r4 = assoc[edm::Ref<CKey1>(handleK1, 3)];
0520 #else
0521   // TEST Vector access
0522   CVal r1, r2, r3, r4, r5;
0523   r1 = assoc.getValues(edm::Ref<CKey1>(handleK1, 0));
0524   r2 = assoc.getValues(edm::Ref<CKey1>(handleK1, 1));
0525   r3 = assoc.getValues(edm::Ref<CKey1>(handleK1, 2));
0526   r4 = assoc.getValues(edm::Ref<CKey1>(handleK1, 3));
0527 #endif
0528   CPPUNIT_ASSERT(r1.size() == 0);
0529   CPPUNIT_ASSERT(r2.size() == 1);
0530   CPPUNIT_ASSERT(r3.size() == 2);
0531   CPPUNIT_ASSERT(r4.size() == 3);
0532   CPPUNIT_ASSERT(r2[0] == k[0]);
0533   CPPUNIT_ASSERT(r3[0] == k[0]);
0534   CPPUNIT_ASSERT(r3[1] == k[1]);
0535   CPPUNIT_ASSERT(r4[0] == k[0]);
0536   CPPUNIT_ASSERT(r4[1] == k[1]);
0537   CPPUNIT_ASSERT(r4[2] == k[2]);
0538 }
0539 
0540 template <typename Map>
0541 bool testMultiAssociation::tryTwoFillers(bool lazyfiller) {
0542   Map map;
0543   if (lazyfiller) {
0544     typename Map::LazyFiller filler1(map, handleK1, true);
0545     typename Map::LazyFiller filler2(map, handleK2, true);
0546   } else {
0547     typename Map::FastFiller filler1(map, handleK1);
0548     typename Map::FastFiller filler2(map, handleK2);
0549   }
0550   return true;
0551 }
0552 void testMultiAssociation::checkTwoFillers() {
0553   CPPUNIT_ASSERT(tryTwoFillers<MultiRef>(true));
0554   CPPUNIT_ASSERT_THROW(tryTwoFillers<MultiRef>(false), cms::Exception);
0555   CPPUNIT_ASSERT(tryTwoFillers<MultiVal>(true));
0556   CPPUNIT_ASSERT_THROW(tryTwoFillers<MultiVal>(false), cms::Exception);
0557 }
0558 template <typename Map>
0559 bool testMultiAssociation::tryUnsortedKeys(bool lazy) {
0560   Map map;
0561   typename Map::Collection coll1, coll2;
0562   if (lazy) {
0563     typename Map::LazyFiller filler(map, handleK1, true);
0564     filler.setValues(Ref<CKey1>(handleK1, 1), coll1);
0565     filler.setValues(Ref<CKey1>(handleK1, 0), coll2);
0566   } else {
0567     typename Map::FastFiller filler(map, handleK1);
0568     filler.setValues(Ref<CKey1>(handleK1, 1), coll1);
0569     filler.setValues(Ref<CKey1>(handleK1, 0), coll2);
0570   }
0571   return true;
0572 }
0573 void testMultiAssociation::checkUnsortedKeys() {
0574   CPPUNIT_ASSERT(tryUnsortedKeys<MultiRef>(true));
0575   CPPUNIT_ASSERT_THROW(tryUnsortedKeys<MultiRef>(false), cms::Exception);
0576   CPPUNIT_ASSERT(tryUnsortedKeys<MultiVal>(true));
0577   CPPUNIT_ASSERT_THROW(tryUnsortedKeys<MultiVal>(false), cms::Exception);
0578 }
0579 
0580 // i = even: succeed; i = odd: fail
0581 bool testMultiAssociation::tryBadFill(int i) {
0582   MultiRef m;
0583   MultiRef::Collection coll1;
0584   coll1.push_back(Ref<CVal>(handleV, 1));
0585   switch (i) {
0586     case 0: {  // fill with right prod. id
0587       MultiRef::FastFiller filler = m.fastFiller(handleK1);
0588       filler.setValues(Ref<CKey1>(handleK1, 0), coll1);
0589     }; break;
0590     case 1: {  // fill with wrong prod. id
0591       MultiRef::FastFiller filler = m.fastFiller(handleK1);
0592       filler.setValues(Ref<CKey2>(handleK2, 0), coll1);
0593     }; break;
0594     case 2: {  // fill again with different id
0595       {
0596         MultiRef::FastFiller filler = m.fastFiller(handleK1);
0597       }
0598       { MultiRef::FastFiller filler = m.fastFiller(handleK2); }
0599     }; break;
0600     case 3: {  // fill again with the same id
0601       {
0602         MultiRef::FastFiller filler = m.fastFiller(handleK1);
0603       }
0604       { MultiRef::FastFiller filler = m.fastFiller(handleK1); }
0605     }; break;
0606     case 4: {  // Check lazyFiller doesn't fill if not requested
0607       {
0608         MultiRef::LazyFiller filler = m.lazyFiller(handleK1);
0609       }
0610       { MultiRef::LazyFiller filler = m.lazyFiller(handleK1); }
0611     }; break;
0612     case 5: {  // Check lazyFiller can't fill twice the same key if requested
0613       {
0614         MultiRef::LazyFiller filler = m.lazyFiller(handleK1, true);
0615       }
0616       { MultiRef::LazyFiller filler = m.lazyFiller(handleK1, true); }
0617     }; break;
0618     case 6: {  // Check lazyFiller doesn't fill twice by mistake
0619       MultiRef::LazyFiller filler = m.lazyFiller(handleK1, true);
0620       CPPUNIT_ASSERT(m.empty());
0621       filler.fill();
0622       CPPUNIT_ASSERT(!m.empty());
0623       filler.fill();
0624     }; break;
0625     case 8: {  // Check lazyFiller doesn't fill if not requested
0626       {
0627         MultiRef::LazyFiller filler = m.lazyFiller(handleK1, false);
0628       }
0629       CPPUNIT_ASSERT(m.empty());
0630     } break;
0631     case 9: {  // Check index out of bounds
0632       MultiRef::FastFiller filler = m.fastFiller(handleK1);
0633       filler.setValues(Ref<CKey1>(handleK1, handleK1->size() + 5, false), coll1);
0634     } break;
0635     case 10: {  // Can copy a LazyFiller, if I don't fill twice
0636       MultiRef::LazyFiller filler = m.lazyFiller(handleK1, false);
0637       MultiRef::LazyFiller filler2 = filler;
0638       filler2.setValues(Ref<CKey1>(handleK1, 0), coll1);
0639       filler2.fill();
0640     } break;
0641     case 11: {  // Can copy a LazyFiller, but crash if I fill twice
0642       MultiRef::LazyFiller filler = m.lazyFiller(handleK1, true);
0643       MultiRef::LazyFiller filler2 = filler;
0644     } break;
0645     case 12: {  // Can copy a FastFiller
0646       MultiRef::FastFiller filler = m.fastFiller(handleK1);
0647       MultiRef::FastFiller filler2 = filler;
0648     } break;
0649     default:
0650       if (i % 2 == 1)
0651         throw cms::Exception("Programmed failure");
0652       break;
0653   }
0654   return true;
0655 }
0656 void testMultiAssociation::checkBadFill() {
0657   for (int i = 0; i < 100; ++i) {
0658     if (i % 2 == 0)
0659       CPPUNIT_ASSERT(tryBadFill(i));
0660     else
0661       CPPUNIT_ASSERT_THROW(tryBadFill(i), cms::Exception);
0662   }
0663 }
0664 
0665 bool testMultiAssociation::tryBadRead(int i) {
0666   using boost::lambda::_1;
0667   using boost::lambda::_2;
0668   MultiRef m;
0669   fastFillRefs(handleK1, m, _1 > 0, _1 > _2);
0670   fastFillRefs(handleK2, m, _1 > 0, _1 > _2);
0671   switch (i) {
0672     case 0:  // good id and key
0673       m[Ref<CKey1>(handleK1, 0, false)];
0674       break;
0675     case 1:  // wrong id
0676       m[Ref<CVal>(handleV, 0, false)];
0677       break;
0678     case 3:  // wrong id & key, and outside bounds
0679              // this does crash
0680       m[Ref<CKey2>(handleK2, 5, false)];
0681       break;
0682     case 5:  // wrong id & key, but still within bounds
0683              // we check explicitly for this in Indexconst_rangeAssociation::get, even if it costs
0684              // extra time
0685       m[Ref<CKey1>(handleK1, 5, false)];
0686       break;
0687     default:
0688       if (i % 2 == 1)
0689         throw cms::Exception("Programmed failure");
0690       break;
0691   }
0692   return true;
0693 }
0694 void testMultiAssociation::checkWritableMap() {
0695   using boost::lambda::_1;
0696   using boost::lambda::_2;
0697   MultiVal tryRW;
0698   fastFillVals(handleK1, tryRW, _1 > 0, _1 > _2);
0699   fastFillVals(handleK2, tryRW, _1 > 0, _1 > _2);
0700   test(tryRW);
0701 
0702   MultiVal::range r1, r1bis;
0703   r1 = tryRW[edm::Ref<CKey1>(handleK1, 1)];
0704   CPPUNIT_ASSERT(r1[0] == k[0]);
0705   r1[0] = k[1];
0706   // check that we modified the range
0707   CPPUNIT_ASSERT(r1[0] == k[1]);
0708   // check that even the real thing got modified
0709   r1bis = tryRW[edm::Ref<CKey1>(handleK1, 1)];
0710   CPPUNIT_ASSERT(r1bis[0] == k[1]);
0711 }
0712 
0713 void testMultiAssociation::checkBadRead() {
0714   for (int i = 0; i < 100; ++i) {
0715     if (i % 2 == 0)
0716       CPPUNIT_ASSERT(tryBadRead(i));
0717     else
0718       CPPUNIT_ASSERT_THROW(tryBadRead(i), cms::Exception);
0719   }
0720 }
0721 
0722 void testMultiAssociation::checkWithPtr() {
0723   MultiPtr map;
0724   {  // Fill the map
0725     MultiPtr::FastFiller filler = map.fastFiller(handleK1);
0726     edm::TestHandle<CObj> handleObj(&der1s, ProductID(10));
0727     for (size_t i = 0; i < handleK1->size(); ++i) {
0728       PObjs vals;
0729       for (size_t j = 0; j < ((i + 2) % 3); ++j) {
0730         vals.push_back(PObj(handleObj, (3 * i + 4 * j) % 10));
0731       }
0732       if (!vals.empty())
0733         filler.setValues(Ref<CKey1>(handleK1, i), vals);
0734     }
0735   }
0736   {  // Read the map
0737     for (size_t i = 0; i < handleK1->size(); ++i) {
0738       MultiPtr::const_range r = map[Ref<CKey1>(handleK1, i)];
0739       CPPUNIT_ASSERT(static_cast<size_t>(r.size()) == ((i + 2) % 3));
0740       for (size_t j = 0; j < ((i + 2) % 3); ++j) {
0741         CPPUNIT_ASSERT(r[j].key() == (3 * i + 4 * j) % 10);
0742         CPPUNIT_ASSERT(r[j]->addr() == &der1s[(3 * i + 4 * j) % 10]);
0743         //CPPUNIT_ASSERT(  (r.begin()+j)->key()   ==        (3*i+4*j)%10 );
0744         //CPPUNIT_ASSERT(  (*(r.begin()+j))->addr() == &der1s[(3*i+4*j)%10]);
0745       }
0746     }
0747   }
0748 }
0749 void testMultiAssociation::checkWithOwn() {
0750   MultiOwn map;
0751   {  // Fill the map
0752     MultiOwn::FastFiller filler = map.fastFiller(handleK1);
0753     for (size_t i = 0; i < handleK1->size(); ++i) {
0754       OObj vals;
0755       for (size_t j = 0; j < ((i + 2) % 3); ++j) {
0756         vals.push_back(bases[(i + j) % 3].clone());
0757       }
0758       if (!vals.empty())
0759         filler.setValues(Ref<CKey1>(handleK1, i), vals);
0760     }
0761   }
0762   {  // Read the map
0763     for (size_t i = 0; i < handleK1->size(); ++i) {
0764       MultiOwn::const_range r = map[Ref<CKey1>(handleK1, i)];
0765       CPPUNIT_ASSERT(static_cast<size_t>(r.size()) == ((i + 2) % 3));
0766       for (size_t j = 0; j < ((i + 2) % 3); ++j) {
0767         CPPUNIT_ASSERT((r.begin() + j)->id() == bases[(i + j) % 3].id());
0768       }
0769     }
0770   }
0771 }