File indexing completed on 2024-09-07 04:36:26
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 }
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
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 =
0184 intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{3}, CustomDeleter{3}}; });
0185 CPPUNIT_ASSERT(p.get() != nullptr);
0186 CPPUNIT_ASSERT(*p3 == 3);
0187
0188 auto p4 =
0189 intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{4}, CustomDeleter{4}}; });
0190 CPPUNIT_ASSERT(p.get() != nullptr);
0191 CPPUNIT_ASSERT(*p4 == 4);
0192 }
0193
0194 auto p34 =
0195 intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{3}, CustomDeleter{3}}; });
0196 CPPUNIT_ASSERT(p.get() != nullptr);
0197 CPPUNIT_ASSERT(*p34 == 3 or *p34 == 4);
0198
0199 auto p43 =
0200 intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{4}, CustomDeleter{4}}; });
0201 CPPUNIT_ASSERT(p.get() != nullptr);
0202 CPPUNIT_ASSERT(*p43 == 3 or *p43 == 4);
0203 CPPUNIT_ASSERT(*p34 != *p43);
0204
0205 auto p5 = intHolder.makeOrGet([]() { return std::unique_ptr<int, CustomDeleter>{new int{5}, CustomDeleter{5}}; });
0206 CPPUNIT_ASSERT(p.get() != nullptr);
0207 CPPUNIT_ASSERT(*p5 == 5);
0208 }
0209 }
0210 }
0211 void reusableobjectholder_test::testSimultaneousUse() {
0212 #if defined(CXX_THREAD_AVAILABLE)
0213
0214 std::set<int*> t1ItemsSeen, t2ItemsSeen;
0215 edm::ReusableObjectHolder<int> intHolder;
0216
0217 const unsigned int kNGets = 10000000;
0218
0219 std::thread t1([&]() {
0220 for (unsigned int i = 0; i < kNGets; ++i) {
0221 auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0222 t1ItemsSeen.insert(p.get());
0223 }
0224 });
0225
0226 std::thread t2([&]() {
0227 for (unsigned int i = 0; i < kNGets; ++i) {
0228 auto p = intHolder.makeOrGet([]() -> int* { return new int(1); });
0229 t2ItemsSeen.insert(p.get());
0230 }
0231 });
0232
0233 t1.join();
0234 t2.join();
0235
0236 std::cout << " # seen: " << t1ItemsSeen.size() << " " << t2ItemsSeen.size() << std::endl;
0237 CPPUNIT_ASSERT(t1ItemsSeen.size() > 0 && t1ItemsSeen.size() < 3);
0238 CPPUNIT_ASSERT(t2ItemsSeen.size() > 0 && t2ItemsSeen.size() < 3);
0239 #endif
0240 }
0241
0242 CPPUNIT_TEST_SUITE_REGISTRATION(reusableobjectholder_test);