Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-08-30 04:05:53

0001 /*
0002  *  callback_t.cc
0003  *  EDMProto
0004  *  Created by Chris Jones on 4/17/05.
0005  *  Changed by Viji Sundararajan on 03-Jul-05.
0006  *
0007  */
0008 
0009 #include "cppunit/extensions/HelperMacros.h"
0010 #include "FWCore/Utilities/interface/do_nothing_deleter.h"
0011 #include "FWCore/Framework/interface/Callback.h"
0012 #include "FWCore/Framework/interface/ESProducts.h"
0013 #include "FWCore/Framework/interface/ComponentDescription.h"
0014 #include "FWCore/Concurrency/interface/ThreadsController.h"
0015 #include "FWCore/Concurrency/interface/WaitingTaskHolder.h"
0016 #include "FWCore/Concurrency/interface/FinalWaitingTask.h"
0017 
0018 #include "FWCore/Framework/interface/eventsetuprecord_registration_macro.h"
0019 
0020 #include <memory>
0021 #include <cassert>
0022 
0023 namespace callbacktest {
0024   struct Data {
0025     Data() : value_(0) {}
0026     Data(int iValue) : value_(iValue) {}
0027     virtual ~Data() {}
0028     int value_;
0029   };
0030 
0031   struct Double {
0032     Double() : value_(0) {}
0033     Double(double iValue) : value_(iValue) {}
0034     virtual ~Double() {}
0035     double value_;
0036   };
0037 
0038   struct Record {
0039     void setImpl(void const* iImpl,
0040                  unsigned int transitionID,
0041                  void const* getTokenIndices,
0042                  void const* iEventSetupImpl,
0043                  void const* ESParentContext) {}
0044     constexpr static bool allowConcurrentIOVs_ = false;
0045   };
0046 
0047   struct Queue {
0048     template <typename T>
0049     void push(oneapi::tbb::task_group&, T&& iT) {
0050       iT();
0051     }
0052   };
0053 
0054   struct Base {
0055     template <typename A, typename B>
0056     std::optional<std::vector<edm::ESProxyIndex>> updateFromMayConsumes(A const&, B const&) const {
0057       return {};
0058     }
0059     static constexpr edm::ESProxyIndex const* getTokenIndices(unsigned int) { return nullptr; }
0060     static constexpr edm::ESRecordIndex const* getTokenRecordIndices(unsigned int) { return nullptr; }
0061     static constexpr size_t numberOfTokenIndices(unsigned int) { return 0; }
0062     static constexpr bool hasMayConsumes() { return false; }
0063     static edm::eventsetup::ComponentDescription const& description() {
0064       static const edm::eventsetup::ComponentDescription s_description;
0065       return s_description;
0066     }
0067 
0068     Queue queue() { return Queue(); }
0069   };
0070 
0071   struct UniquePtrProd : public Base {
0072     constexpr UniquePtrProd() : value_(0) {}
0073     std::unique_ptr<Data> method(const Record&) { return std::make_unique<Data>(++value_); }
0074 
0075     int value_;
0076   };
0077 
0078   struct SharedPtrProd : public Base {
0079     SharedPtrProd() : ptr_(new Data()) {}
0080     std::shared_ptr<Data> method(const Record&) {
0081       ++ptr_->value_;
0082       return ptr_;
0083     }
0084     std::shared_ptr<Data> ptr_;
0085   };
0086 
0087   struct OptionalProd : public Base {
0088     constexpr OptionalProd() : value_(0) {}
0089     std::optional<Data> method(const Record&) { return Data(++value_); }
0090 
0091     int value_;
0092   };
0093 
0094   struct PtrProductsProd : public Base {
0095     PtrProductsProd() : data_(), double_() {}
0096     edm::ESProducts<std::shared_ptr<Data>, std::shared_ptr<Double>> method(const Record&) {
0097       using namespace edm::es;
0098       auto dataT = std::shared_ptr<Data>(&data_, edm::do_nothing_deleter());
0099       auto doubleT = std::shared_ptr<Double>(&double_, edm::do_nothing_deleter());
0100       ++data_.value_;
0101       ++double_.value_;
0102       return products(dataT, doubleT);
0103     }
0104 
0105     Data data_;
0106     Double double_;
0107   };
0108 }  // namespace callbacktest
0109 
0110 EVENTSETUP_RECORD_REG(callbacktest::Record);
0111 
0112 namespace {
0113   template <typename CALLBACK>
0114   void call(CALLBACK& iCallback) {
0115     edm::ActivityRegistry ar;
0116     edm::eventsetup::EventSetupRecordImpl rec(edm::eventsetup::EventSetupRecordKey::makeKey<callbacktest::Record>(),
0117                                               &ar);
0118     oneapi::tbb::task_group group;
0119     edm::FinalWaitingTask task{group};
0120     edm::ServiceToken token;
0121     iCallback.prefetchAsync(edm::WaitingTaskHolder(group, &task), &rec, nullptr, token, edm::ESParentContext{});
0122     task.waitNoThrow();
0123   }
0124 }  // namespace
0125 
0126 using namespace callbacktest;
0127 using namespace edm::eventsetup;
0128 
0129 class testCallback : public CppUnit::TestFixture {
0130   CPPUNIT_TEST_SUITE(testCallback);
0131 
0132   CPPUNIT_TEST(uniquePtrTest);
0133   CPPUNIT_TEST(sharedPtrTest);
0134   CPPUNIT_TEST(optionalTest);
0135   CPPUNIT_TEST(ptrProductsTest);
0136 
0137   CPPUNIT_TEST(uniquePtrLambdaTest);
0138   CPPUNIT_TEST(uniquePtrLambdaCaptureTest);
0139   CPPUNIT_TEST(sharedPtrLambdaTest);
0140   CPPUNIT_TEST(optionalLambdaTest);
0141   CPPUNIT_TEST(ptrProductsLambdaTest);
0142 
0143   CPPUNIT_TEST_SUITE_END();
0144 
0145 public:
0146   void setUp() { m_scheduler = std::make_unique<edm::ThreadsController>(1); }
0147   void tearDown() {}
0148 
0149   void uniquePtrTest();
0150   void sharedPtrTest();
0151   void optionalTest();
0152   void ptrProductsTest();
0153 
0154   void uniquePtrLambdaTest();
0155   void uniquePtrLambdaCaptureTest();
0156   void sharedPtrLambdaTest();
0157   void optionalLambdaTest();
0158   void ptrProductsLambdaTest();
0159 
0160 private:
0161   edm::propagate_const<std::unique_ptr<edm::ThreadsController>> m_scheduler;
0162 };
0163 
0164 ///registration of the test so that the runner can find it
0165 CPPUNIT_TEST_SUITE_REGISTRATION(testCallback);
0166 
0167 template <typename P, typename F>
0168 using UniquePtrCallbackT = Callback<P, F, std::unique_ptr<Data>, Record>;
0169 
0170 void testCallback::uniquePtrTest() {
0171   UniquePtrProd prod;
0172 
0173   auto func = [&prod](Record const& rec) { return prod.method(rec); };
0174   using UniquePtrCallback = UniquePtrCallbackT<UniquePtrProd, decltype(func)>;
0175   UniquePtrCallback callback(&prod, func, 0);
0176   std::unique_ptr<Data> handle;
0177   callback.holdOntoPointer(&handle);
0178 
0179   auto callback2 = std::unique_ptr<UniquePtrCallback>(callback.clone());
0180   std::unique_ptr<Data> handle2;
0181   callback2->holdOntoPointer(&handle2);
0182 
0183   callback.newRecordComing();
0184   call(callback);
0185   CPPUNIT_ASSERT(0 != handle.get());
0186   CPPUNIT_ASSERT(prod.value_ == 1);
0187   assert(0 != handle.get());
0188   CPPUNIT_ASSERT(prod.value_ == handle->value_);
0189 
0190   //since haven't cleared, should not have changed
0191   call(callback);
0192   CPPUNIT_ASSERT(prod.value_ == 1);
0193   CPPUNIT_ASSERT(prod.value_ == handle->value_);
0194 
0195   handle.release();
0196 
0197   callback.newRecordComing();
0198 
0199   call(callback);
0200   CPPUNIT_ASSERT(0 != handle.get());
0201   CPPUNIT_ASSERT(prod.value_ == 2);
0202   assert(0 != handle.get());
0203   CPPUNIT_ASSERT(prod.value_ == handle->value_);
0204 
0205   call(*callback2);
0206   CPPUNIT_ASSERT(handle2->value_ == 3);
0207   CPPUNIT_ASSERT(handle->value_ == 2);
0208 
0209   call(callback);
0210   call(*callback2);
0211   CPPUNIT_ASSERT(handle2->value_ == 3);
0212   CPPUNIT_ASSERT(handle->value_ == 2);
0213 
0214   callback2->newRecordComing();
0215   call(callback);
0216   call(*callback2);
0217   CPPUNIT_ASSERT(handle2->value_ == 4);
0218   CPPUNIT_ASSERT(handle->value_ == 2);
0219 
0220   callback.newRecordComing();
0221   call(callback);
0222   call(*callback2);
0223   CPPUNIT_ASSERT(handle2->value_ == 4);
0224   CPPUNIT_ASSERT(handle->value_ == 5);
0225 }
0226 
0227 template <typename P, typename F>
0228 using SharedPtrCallbackT = Callback<P, F, std::shared_ptr<Data>, Record>;
0229 
0230 void testCallback::sharedPtrTest() {
0231   SharedPtrProd prod;
0232 
0233   auto func = [&prod](Record const& rec) { return prod.method(rec); };
0234 
0235   using SharedPtrCallback = SharedPtrCallbackT<SharedPtrProd, decltype(func)>;
0236   SharedPtrCallback callback(&prod, func, 0);
0237   std::shared_ptr<Data> handle;
0238 
0239   callback.holdOntoPointer(&handle);
0240 
0241   callback.newRecordComing();
0242   call(callback);
0243   CPPUNIT_ASSERT(handle.get() == prod.ptr_.get());
0244   CPPUNIT_ASSERT(prod.ptr_->value_ == 1);
0245 
0246   //since haven't cleared, should not have changed
0247   call(callback);
0248   CPPUNIT_ASSERT(handle.get() == prod.ptr_.get());
0249   CPPUNIT_ASSERT(prod.ptr_->value_ == 1);
0250 
0251   handle.reset();
0252   callback.newRecordComing();
0253 
0254   call(callback);
0255   CPPUNIT_ASSERT(handle.get() == prod.ptr_.get());
0256   CPPUNIT_ASSERT(prod.ptr_->value_ == 2);
0257 }
0258 
0259 template <typename P, typename F>
0260 using OptionalCallbackT = Callback<P, F, std::optional<Data>, Record>;
0261 
0262 void testCallback::optionalTest() {
0263   OptionalProd prod;
0264 
0265   auto func = [&prod](Record const& rec) { return prod.method(rec); };
0266 
0267   using OptionalCallback = OptionalCallbackT<OptionalProd, decltype(func)>;
0268   OptionalCallback callback(&prod, func, 0);
0269   std::optional<Data> handle;
0270 
0271   callback.holdOntoPointer(&handle);
0272 
0273   callback.newRecordComing();
0274   call(callback);
0275   CPPUNIT_ASSERT(handle.has_value());
0276   CPPUNIT_ASSERT(prod.value_ == 1);
0277   CPPUNIT_ASSERT(prod.value_ == handle->value_);
0278 
0279   //since haven't cleared, should not have changed
0280   call(callback);
0281   CPPUNIT_ASSERT(handle.has_value());
0282   CPPUNIT_ASSERT(prod.value_ == 1);
0283   CPPUNIT_ASSERT(prod.value_ == handle->value_);
0284 
0285   handle.reset();
0286   callback.newRecordComing();
0287 
0288   call(callback);
0289   CPPUNIT_ASSERT(handle.has_value());
0290   CPPUNIT_ASSERT(prod.value_ == 2);
0291   CPPUNIT_ASSERT(prod.value_ == handle->value_);
0292 }
0293 
0294 template <typename P, typename F>
0295 using PtrProductsCallbackT = Callback<P, F, edm::ESProducts<std::shared_ptr<Data>, std::shared_ptr<Double>>, Record>;
0296 
0297 void testCallback::ptrProductsTest() {
0298   PtrProductsProd prod;
0299 
0300   auto func = [&prod](Record const& rec) { return prod.method(rec); };
0301 
0302   using PtrProductsCallback = PtrProductsCallbackT<PtrProductsProd, decltype(func)>;
0303   PtrProductsCallback callback(&prod, func, 0);
0304   std::shared_ptr<Data> handle;
0305   std::shared_ptr<Double> doubleHandle;
0306 
0307   callback.holdOntoPointer(&handle);
0308   callback.holdOntoPointer(&doubleHandle);
0309 
0310   callback.newRecordComing();
0311   call(callback);
0312   CPPUNIT_ASSERT(handle.get() == &(prod.data_));
0313   CPPUNIT_ASSERT(prod.data_.value_ == 1);
0314 
0315   //since haven't cleared, should not have changed
0316   call(callback);
0317   CPPUNIT_ASSERT(handle.get() == &(prod.data_));
0318   CPPUNIT_ASSERT(prod.data_.value_ == 1);
0319 
0320   callback.newRecordComing();
0321 
0322   call(callback);
0323   CPPUNIT_ASSERT(handle.get() == &(prod.data_));
0324   CPPUNIT_ASSERT(prod.data_.value_ == 2);
0325 }
0326 
0327 // Lambda tests
0328 
0329 void testCallback::uniquePtrLambdaTest() {
0330   Base prod;
0331 
0332   int value = 0;
0333   auto func = [&value](Record const& rec) mutable { return std::make_unique<Data>(++value); };
0334   using UniquePtrCallback = UniquePtrCallbackT<Base, decltype(func)>;
0335   UniquePtrCallback callback(&prod, func, 0);
0336   std::unique_ptr<Data> handle;
0337   callback.holdOntoPointer(&handle);
0338 
0339   auto callback2 = std::unique_ptr<UniquePtrCallback>(callback.clone());
0340   std::unique_ptr<Data> handle2;
0341   callback2->holdOntoPointer(&handle2);
0342 
0343   callback.newRecordComing();
0344   call(callback);
0345   CPPUNIT_ASSERT(0 != handle.get());
0346   CPPUNIT_ASSERT(value == 1);
0347   CPPUNIT_ASSERT(value == handle->value_);
0348 
0349   //since haven't cleared, should not have changed
0350   call(callback);
0351   CPPUNIT_ASSERT(value == 1);
0352   CPPUNIT_ASSERT(value == handle->value_);
0353 
0354   handle.release();
0355 
0356   callback.newRecordComing();
0357 
0358   call(callback);
0359   CPPUNIT_ASSERT(0 != handle.get());
0360   CPPUNIT_ASSERT(value == 2);
0361   CPPUNIT_ASSERT(value == handle->value_);
0362 
0363   call(*callback2);
0364   CPPUNIT_ASSERT(handle2->value_ == 3);
0365   CPPUNIT_ASSERT(handle->value_ == 2);
0366 
0367   call(callback);
0368   call(*callback2);
0369   CPPUNIT_ASSERT(handle2->value_ == 3);
0370   CPPUNIT_ASSERT(handle->value_ == 2);
0371 
0372   callback2->newRecordComing();
0373   call(callback);
0374   call(*callback2);
0375   CPPUNIT_ASSERT(handle2->value_ == 4);
0376   CPPUNIT_ASSERT(handle->value_ == 2);
0377 
0378   callback.newRecordComing();
0379   call(callback);
0380   call(*callback2);
0381   CPPUNIT_ASSERT(handle2->value_ == 4);
0382   CPPUNIT_ASSERT(handle->value_ == 5);
0383 }
0384 
0385 void testCallback::uniquePtrLambdaCaptureTest() {
0386   // The difference wrt uniquePtrLambdaTest is that the 'value' is
0387   // stored only in the lambda capture
0388   Base prod;
0389 
0390   auto func = [value = int(0)](Record const& rec) mutable { return std::make_unique<Data>(++value); };
0391   using UniquePtrCallback = UniquePtrCallbackT<Base, decltype(func)>;
0392   UniquePtrCallback callback(&prod, func, 0);
0393   std::unique_ptr<Data> handle;
0394   callback.holdOntoPointer(&handle);
0395 
0396   auto callback2 = std::unique_ptr<UniquePtrCallback>(callback.clone());
0397   std::unique_ptr<Data> handle2;
0398   callback2->holdOntoPointer(&handle2);
0399 
0400   callback.newRecordComing();
0401   call(callback);
0402   CPPUNIT_ASSERT(0 != handle.get());
0403   CPPUNIT_ASSERT(handle->value_ == 1);
0404 
0405   //since haven't cleared, should not have changed
0406   call(callback);
0407   CPPUNIT_ASSERT(handle->value_ == 1);
0408 
0409   handle.release();
0410 
0411   callback.newRecordComing();
0412 
0413   call(callback);
0414   CPPUNIT_ASSERT(handle->value_ == 2);
0415 
0416   call(*callback2);
0417   CPPUNIT_ASSERT(handle2->value_ == 3);
0418   CPPUNIT_ASSERT(handle->value_ == 2);
0419 
0420   call(callback);
0421   call(*callback2);
0422   CPPUNIT_ASSERT(handle2->value_ == 3);
0423   CPPUNIT_ASSERT(handle->value_ == 2);
0424 
0425   callback2->newRecordComing();
0426   call(callback);
0427   call(*callback2);
0428   CPPUNIT_ASSERT(handle2->value_ == 4);
0429   CPPUNIT_ASSERT(handle->value_ == 2);
0430 
0431   callback.newRecordComing();
0432   call(callback);
0433   call(*callback2);
0434   CPPUNIT_ASSERT(handle2->value_ == 4);
0435   CPPUNIT_ASSERT(handle->value_ == 5);
0436 }
0437 
0438 void testCallback::sharedPtrLambdaTest() {
0439   Base prod;
0440 
0441   auto ptr = std::make_shared<Data>();
0442   auto func = [ptr](Record const& rec) mutable {
0443     ++ptr->value_;
0444     return ptr;
0445   };
0446 
0447   using SharedPtrCallback = SharedPtrCallbackT<Base, decltype(func)>;
0448   SharedPtrCallback callback(&prod, func, 0);
0449   std::shared_ptr<Data> handle;
0450 
0451   callback.holdOntoPointer(&handle);
0452 
0453   callback.newRecordComing();
0454   call(callback);
0455   CPPUNIT_ASSERT(handle.get() == ptr.get());
0456   CPPUNIT_ASSERT(ptr->value_ == 1);
0457 
0458   //since haven't cleared, should not have changed
0459   call(callback);
0460   CPPUNIT_ASSERT(handle.get() == ptr.get());
0461   CPPUNIT_ASSERT(ptr->value_ == 1);
0462 
0463   handle.reset();
0464   callback.newRecordComing();
0465 
0466   call(callback);
0467   CPPUNIT_ASSERT(handle.get() == ptr.get());
0468   CPPUNIT_ASSERT(ptr->value_ == 2);
0469 }
0470 
0471 void testCallback::optionalLambdaTest() {
0472   Base prod;
0473 
0474   int value = 0;
0475   auto func = [&value](Record const& rec) { return std::optional<Data>(++value); };
0476 
0477   using OptionalCallback = OptionalCallbackT<Base, decltype(func)>;
0478   OptionalCallback callback(&prod, func, 0);
0479   std::optional<Data> handle;
0480 
0481   callback.holdOntoPointer(&handle);
0482 
0483   callback.newRecordComing();
0484   call(callback);
0485   CPPUNIT_ASSERT(handle.has_value());
0486   CPPUNIT_ASSERT(value == 1);
0487   CPPUNIT_ASSERT(value == handle->value_);
0488 
0489   //since haven't cleared, should not have changed
0490   call(callback);
0491   CPPUNIT_ASSERT(handle.has_value());
0492   CPPUNIT_ASSERT(value == 1);
0493   CPPUNIT_ASSERT(value == handle->value_);
0494 
0495   handle.reset();
0496   callback.newRecordComing();
0497 
0498   call(callback);
0499   CPPUNIT_ASSERT(handle.has_value());
0500   CPPUNIT_ASSERT(value == 2);
0501   CPPUNIT_ASSERT(value == handle->value_);
0502 }
0503 
0504 void testCallback::ptrProductsLambdaTest() {
0505   PtrProductsProd prod;
0506 
0507   Data dataValue;
0508   auto func = [&dataValue, doubleValue = Double()](Record const& rec) mutable {
0509     auto dataT = std::shared_ptr<Data>(&dataValue, edm::do_nothing_deleter());
0510     auto doubleT = std::shared_ptr<Double>(&doubleValue, edm::do_nothing_deleter());
0511     ++dataValue.value_;
0512     ++doubleValue.value_;
0513     return edm::es::products(dataT, doubleT);
0514   };
0515 
0516   using PtrProductsCallback = PtrProductsCallbackT<Base, decltype(func)>;
0517   PtrProductsCallback callback(&prod, func, 0);
0518   std::shared_ptr<Data> handle;
0519   std::shared_ptr<Double> doubleHandle;
0520 
0521   callback.holdOntoPointer(&handle);
0522   callback.holdOntoPointer(&doubleHandle);
0523 
0524   callback.newRecordComing();
0525   call(callback);
0526   CPPUNIT_ASSERT(handle.get() == &dataValue);
0527   CPPUNIT_ASSERT(dataValue.value_ == 1);
0528 
0529   //since haven't cleared, should not have changed
0530   call(callback);
0531   CPPUNIT_ASSERT(handle.get() == &dataValue);
0532   CPPUNIT_ASSERT(dataValue.value_ == 1);
0533 
0534   callback.newRecordComing();
0535 
0536   call(callback);
0537   CPPUNIT_ASSERT(handle.get() == &dataValue);
0538   CPPUNIT_ASSERT(dataValue.value_ == 2);
0539 }