Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:48:02

0001 #include <set>
0002 #include <thread>
0003 #include "FWCore/Utilities/interface/ReusableObjectHolder.h"
0004 
0005 #include <cppunit/extensions/HelperMacros.h>
0006 
0007 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
0008 #define CXX_THREAD_AVAILABLE
0009 #endif
0010 
0011 class reusableobjectholder_test : public CppUnit::TestFixture {
0012   CPPUNIT_TEST_SUITE(reusableobjectholder_test);
0013   CPPUNIT_TEST(testConstruction);
0014   CPPUNIT_TEST(testDeletion);
0015   CPPUNIT_TEST(testSimultaneousUse);
0016   CPPUNIT_TEST_SUITE_END();
0017 
0018 public:
0019   void testConstruction();
0020   void testDeletion();
0021   void testSimultaneousUse();
0022 
0023   void setUp() {}
0024   void tearDown() {}
0025 };
0026 
0027 namespace {
0028   class CustomDeleter {
0029   public:
0030     CustomDeleter() = default;
0031     explicit CustomDeleter(int val) : expectedValue_{val} {}
0032 
0033     void operator()(int* obj) {
0034       CPPUNIT_ASSERT(obj != nullptr);
0035       CPPUNIT_ASSERT(*obj == expectedValue_);
0036       delete obj;
0037     }
0038 
0039   private:
0040     int expectedValue_ = -1;
0041   };
0042 }  // namespace
0043 
0044 void reusableobjectholder_test::testConstruction() {
0045   {
0046     edm::ReusableObjectHolder<int> intHolder;
0047     auto p = intHolder.tryToGet();
0048     CPPUNIT_ASSERT(p.get() == 0);
0049 
0050     intHolder.add(std::make_unique<int>(1));
0051     p = intHolder.tryToGet();
0052     CPPUNIT_ASSERT(p.get() != 0);
0053     CPPUNIT_ASSERT(*p == 1);
0054 
0055     auto p2 = intHolder.tryToGet();
0056     CPPUNIT_ASSERT(p2.get() == 0);
0057   }
0058   {
0059     edm::ReusableObjectHolder<int> intHolder;
0060     auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0061     CPPUNIT_ASSERT(p.get() != 0);
0062     CPPUNIT_ASSERT(*p == 1);
0063 
0064     auto p2 = intHolder.tryToGet();
0065     CPPUNIT_ASSERT(p2.get() == 0);
0066   }
0067   {
0068     edm::ReusableObjectHolder<int> intHolder;
0069     auto p = intHolder.makeOrGetAndClear([]() -> int* { return new int(1); }, [](int* iV) { *iV = 0; });
0070     CPPUNIT_ASSERT(p.get() != 0);
0071     CPPUNIT_ASSERT(*p == 0);
0072 
0073     auto p2 = intHolder.tryToGet();
0074     CPPUNIT_ASSERT(p2.get() == 0);
0075   }
0076   {
0077     edm::ReusableObjectHolder<int, CustomDeleter> intHolder;
0078     auto p = intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{1}, CustomDeleter{1}}; });
0079     CPPUNIT_ASSERT(p.get() != nullptr);
0080     CPPUNIT_ASSERT(*p == 1);
0081 
0082     auto p2 = intHolder.tryToGet();
0083     CPPUNIT_ASSERT(p2.get() == nullptr);
0084   }
0085 }
0086 
0087 void reusableobjectholder_test::testDeletion() {
0088   //should also test that makeOrGetAndClear actually does a clear on returned objects
0089   {
0090     edm::ReusableObjectHolder<int> intHolder;
0091     intHolder.add(std::make_unique<int>(1));
0092     {
0093       auto p = intHolder.tryToGet();
0094       CPPUNIT_ASSERT(p.get() != 0);
0095       CPPUNIT_ASSERT(*p == 1);
0096 
0097       auto p2 = intHolder.tryToGet();
0098       CPPUNIT_ASSERT(p2.get() == 0);
0099 
0100       *p = 2;
0101     }
0102     {
0103       auto p = intHolder.tryToGet();
0104       CPPUNIT_ASSERT(p.get() != 0);
0105       CPPUNIT_ASSERT(*p == 2);
0106 
0107       auto p2 = intHolder.tryToGet();
0108       CPPUNIT_ASSERT(p2.get() == 0);
0109     }
0110   }
0111 
0112   {
0113     edm::ReusableObjectHolder<int> intHolder;
0114     {
0115       auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0116       CPPUNIT_ASSERT(p.get() != 0);
0117       CPPUNIT_ASSERT(*p == 1);
0118       *p = 2;
0119 
0120       auto p2 = intHolder.tryToGet();
0121       CPPUNIT_ASSERT(p2.get() == 0);
0122     }
0123     {
0124       auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0125       CPPUNIT_ASSERT(p.get() != 0);
0126       CPPUNIT_ASSERT(*p == 2);
0127 
0128       auto p2 = intHolder.tryToGet();
0129       CPPUNIT_ASSERT(p2.get() == 0);
0130 
0131       auto p3 = intHolder.makeOrGet([]() -> int* { return new int(1); });
0132       CPPUNIT_ASSERT(p3.get() != 0);
0133       CPPUNIT_ASSERT(*p3 == 1);
0134     }
0135   }
0136 
0137   {
0138     edm::ReusableObjectHolder<int> intHolder;
0139     int* address = 0;
0140     {
0141       auto p = intHolder.makeOrGetAndClear([]() -> int* { return new int(1); }, [](int* iV) { *iV = 0; });
0142       CPPUNIT_ASSERT(p.get() != 0);
0143       CPPUNIT_ASSERT(*p == 0);
0144       address = p.get();
0145       *p = 2;
0146 
0147       auto p2 = intHolder.tryToGet();
0148       CPPUNIT_ASSERT(p2.get() == 0);
0149     }
0150     {
0151       auto p = intHolder.makeOrGetAndClear([]() -> int* { return new int(1); }, [](int* iV) { *iV = 0; });
0152       CPPUNIT_ASSERT(p.get() != 0);
0153       CPPUNIT_ASSERT(*p == 0);
0154       CPPUNIT_ASSERT(address == p.get());
0155     }
0156   }
0157 
0158   {
0159     edm::ReusableObjectHolder<int, CustomDeleter> intHolder;
0160     {
0161       auto p = intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{1}, CustomDeleter{2}}; });
0162       CPPUNIT_ASSERT(p.get() != nullptr);
0163       CPPUNIT_ASSERT(*p == 1);
0164       *p = 2;
0165 
0166       auto p2 = intHolder.tryToGet();
0167       CPPUNIT_ASSERT(p2.get() == nullptr);
0168     }
0169     {
0170       auto p = intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{1}, CustomDeleter{2}}; });
0171       CPPUNIT_ASSERT(p.get() != nullptr);
0172       CPPUNIT_ASSERT(*p == 2);
0173 
0174       auto p2 = intHolder.tryToGet();
0175       CPPUNIT_ASSERT(p2.get() == nullptr);
0176     }
0177     {
0178       auto p = intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{1}, CustomDeleter{2}}; });
0179       CPPUNIT_ASSERT(p.get() != nullptr);
0180       CPPUNIT_ASSERT(*p == 2);
0181 
0182       {
0183         auto p3 = intHolder.makeOrGet([]() {
0184           return std::unique_ptr<int, CustomDeleter>{new int{3}, CustomDeleter{3}};
0185         });
0186         CPPUNIT_ASSERT(p.get() != nullptr);
0187         CPPUNIT_ASSERT(*p3 == 3);
0188 
0189         auto p4 = intHolder.makeOrGet([]() {
0190           return std::unique_ptr<int, CustomDeleter>{new int{4}, CustomDeleter{4}};
0191         });
0192         CPPUNIT_ASSERT(p.get() != nullptr);
0193         CPPUNIT_ASSERT(*p4 == 4);
0194       }
0195 
0196       auto p34 = intHolder.makeOrGet([]() {
0197         return std::unique_ptr<int, CustomDeleter>{new int{3}, CustomDeleter{3}};
0198       });
0199       CPPUNIT_ASSERT(p.get() != nullptr);
0200       CPPUNIT_ASSERT(*p34 == 3 or *p34 == 4);
0201 
0202       auto p43 = intHolder.makeOrGet([]() {
0203         return std::unique_ptr<int, CustomDeleter>{new int{4}, CustomDeleter{4}};
0204       });
0205       CPPUNIT_ASSERT(p.get() != nullptr);
0206       CPPUNIT_ASSERT(*p43 == 3 or *p43 == 4);
0207       CPPUNIT_ASSERT(*p34 != *p43);
0208 
0209       auto p5 = intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{5}, CustomDeleter{5}}; });
0210       CPPUNIT_ASSERT(p.get() != nullptr);
0211       CPPUNIT_ASSERT(*p5 == 5);
0212     }
0213   }
0214 }
0215 void reusableobjectholder_test::testSimultaneousUse() {
0216 #if defined(CXX_THREAD_AVAILABLE)
0217 
0218   std::set<int*> t1ItemsSeen, t2ItemsSeen;
0219   edm::ReusableObjectHolder<int> intHolder;
0220 
0221   const unsigned int kNGets = 10000000;
0222 
0223   std::thread t1([&]() {
0224     for (unsigned int i = 0; i < kNGets; ++i) {
0225       auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0226       t1ItemsSeen.insert(p.get());
0227     }
0228   });
0229 
0230   std::thread t2([&]() {
0231     for (unsigned int i = 0; i < kNGets; ++i) {
0232       auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0233       t2ItemsSeen.insert(p.get());
0234     }
0235   });
0236 
0237   t1.join();
0238   t2.join();
0239 
0240   std::cout << " # seen: " << t1ItemsSeen.size() << " " << t2ItemsSeen.size() << std::endl;
0241   CPPUNIT_ASSERT(t1ItemsSeen.size() > 0 && t1ItemsSeen.size() < 3);
0242   CPPUNIT_ASSERT(t2ItemsSeen.size() > 0 && t2ItemsSeen.size() < 3);
0243 #endif
0244 }
0245 
0246 CPPUNIT_TEST_SUITE_REGISTRATION(reusableobjectholder_test);