File indexing completed on 2024-04-06 12:12:22
0001
0002
0003
0004
0005
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::ESResolverIndex>> updateFromMayConsumes(A const&, B const&) const {
0057 return {};
0058 }
0059 static constexpr edm::ESResolverIndex 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&) {
0074 ++value_;
0075 if (produce_)
0076 return std::make_unique<Data>(value_);
0077 else
0078 return nullptr;
0079 }
0080
0081 int value_;
0082 bool produce_ = true;
0083 };
0084
0085 struct SharedPtrProd : public Base {
0086 SharedPtrProd() : ptr_(new Data()) {}
0087 std::shared_ptr<Data> method(const Record&) {
0088 ++ptr_->value_;
0089 if (produce_)
0090 return ptr_;
0091 else
0092 return nullptr;
0093 }
0094 std::shared_ptr<Data> ptr_;
0095 bool produce_ = true;
0096 };
0097
0098 struct OptionalProd : public Base {
0099 constexpr OptionalProd() : value_(0) {}
0100 std::optional<Data> method(const Record&) {
0101 ++value_;
0102 if (produce_)
0103 return Data(value_);
0104 else
0105 return {};
0106 }
0107
0108 int value_;
0109 bool produce_ = true;
0110 };
0111
0112 struct PtrProductsProd : public Base {
0113 PtrProductsProd() : data_(), double_() {}
0114 edm::ESProducts<std::shared_ptr<Data>, std::shared_ptr<Double>> method(const Record&) {
0115 using namespace edm::es;
0116 auto dataT = std::shared_ptr<Data>(&data_, edm::do_nothing_deleter());
0117 auto doubleT = std::shared_ptr<Double>(&double_, edm::do_nothing_deleter());
0118 ++data_.value_;
0119 ++double_.value_;
0120 return products(dataT, doubleT);
0121 }
0122
0123 Data data_;
0124 Double double_;
0125 };
0126 }
0127
0128 EVENTSETUP_RECORD_REG(callbacktest::Record);
0129
0130 namespace {
0131 template <typename CALLBACK>
0132 void call(CALLBACK& iCallback) {
0133 edm::ActivityRegistry ar;
0134 edm::eventsetup::EventSetupRecordImpl rec(edm::eventsetup::EventSetupRecordKey::makeKey<callbacktest::Record>(),
0135 &ar);
0136 oneapi::tbb::task_group group;
0137 edm::FinalWaitingTask task{group};
0138 edm::ServiceToken token;
0139 iCallback.prefetchAsync(edm::WaitingTaskHolder(group, &task), &rec, nullptr, token, edm::ESParentContext{});
0140 task.wait();
0141 }
0142 }
0143
0144 using namespace callbacktest;
0145 using namespace edm::eventsetup;
0146
0147 class testCallback : public CppUnit::TestFixture {
0148 CPPUNIT_TEST_SUITE(testCallback);
0149
0150 CPPUNIT_TEST(uniquePtrTest);
0151 CPPUNIT_TEST(sharedPtrTest);
0152 CPPUNIT_TEST(optionalTest);
0153 CPPUNIT_TEST(ptrProductsTest);
0154
0155 CPPUNIT_TEST(uniquePtrLambdaTest);
0156 CPPUNIT_TEST(uniquePtrLambdaCaptureTest);
0157 CPPUNIT_TEST(sharedPtrLambdaTest);
0158 CPPUNIT_TEST(optionalLambdaTest);
0159 CPPUNIT_TEST(ptrProductsLambdaTest);
0160
0161 CPPUNIT_TEST_SUITE_END();
0162
0163 public:
0164 void setUp() { m_scheduler = std::make_unique<edm::ThreadsController>(1); }
0165 void tearDown() {}
0166
0167 void uniquePtrTest();
0168 void sharedPtrTest();
0169 void optionalTest();
0170 void ptrProductsTest();
0171
0172 void uniquePtrLambdaTest();
0173 void uniquePtrLambdaCaptureTest();
0174 void sharedPtrLambdaTest();
0175 void optionalLambdaTest();
0176 void ptrProductsLambdaTest();
0177
0178 private:
0179 edm::propagate_const<std::unique_ptr<edm::ThreadsController>> m_scheduler;
0180 };
0181
0182
0183 CPPUNIT_TEST_SUITE_REGISTRATION(testCallback);
0184
0185 template <typename P, typename F>
0186 using UniquePtrCallbackT = Callback<P, F, std::unique_ptr<Data>, Record>;
0187
0188 void testCallback::uniquePtrTest() {
0189 UniquePtrProd prod;
0190
0191 auto func = [&prod](Record const& rec) { return prod.method(rec); };
0192 using UniquePtrCallback = UniquePtrCallbackT<UniquePtrProd, decltype(func)>;
0193 UniquePtrCallback callback(&prod, func, 0);
0194 std::unique_ptr<Data> handle;
0195 callback.holdOntoPointer(&handle);
0196
0197 auto callback2 = std::unique_ptr<UniquePtrCallback>(callback.clone());
0198 std::unique_ptr<Data> handle2;
0199 callback2->holdOntoPointer(&handle2);
0200
0201 callback.newRecordComing();
0202 call(callback);
0203 CPPUNIT_ASSERT(0 != handle.get());
0204 CPPUNIT_ASSERT(prod.value_ == 1);
0205 assert(0 != handle.get());
0206 CPPUNIT_ASSERT(prod.value_ == handle->value_);
0207
0208
0209 call(callback);
0210 CPPUNIT_ASSERT(prod.value_ == 1);
0211 CPPUNIT_ASSERT(prod.value_ == handle->value_);
0212
0213 handle.release();
0214
0215 callback.newRecordComing();
0216
0217 call(callback);
0218 CPPUNIT_ASSERT(0 != handle.get());
0219 CPPUNIT_ASSERT(prod.value_ == 2);
0220 assert(0 != handle.get());
0221 CPPUNIT_ASSERT(prod.value_ == handle->value_);
0222
0223 call(*callback2);
0224 CPPUNIT_ASSERT(handle2->value_ == 3);
0225 CPPUNIT_ASSERT(handle->value_ == 2);
0226
0227 call(callback);
0228 call(*callback2);
0229 CPPUNIT_ASSERT(handle2->value_ == 3);
0230 CPPUNIT_ASSERT(handle->value_ == 2);
0231
0232 callback2->newRecordComing();
0233 call(callback);
0234 call(*callback2);
0235 CPPUNIT_ASSERT(handle2->value_ == 4);
0236 CPPUNIT_ASSERT(handle->value_ == 2);
0237
0238 callback.newRecordComing();
0239 call(callback);
0240 call(*callback2);
0241 CPPUNIT_ASSERT(handle2->value_ == 4);
0242 CPPUNIT_ASSERT(handle->value_ == 5);
0243
0244
0245 prod.produce_ = false;
0246 callback.newRecordComing();
0247 call(callback);
0248 call(*callback2);
0249 CPPUNIT_ASSERT(handle2->value_ == 4);
0250 CPPUNIT_ASSERT(handle.get() == nullptr);
0251
0252 callback2->newRecordComing();
0253 call(callback);
0254 call(*callback2);
0255 CPPUNIT_ASSERT(handle2.get() == nullptr);
0256 CPPUNIT_ASSERT(handle.get() == nullptr);
0257
0258 prod.produce_ = true;
0259 callback.newRecordComing();
0260 call(callback);
0261 call(*callback2);
0262 CPPUNIT_ASSERT(handle2.get() == nullptr);
0263 CPPUNIT_ASSERT(handle->value_ == 8);
0264
0265 callback2->newRecordComing();
0266 call(callback);
0267 call(*callback2);
0268 CPPUNIT_ASSERT(handle2->value_ == 9);
0269 CPPUNIT_ASSERT(handle->value_ == 8);
0270 }
0271
0272 template <typename P, typename F>
0273 using SharedPtrCallbackT = Callback<P, F, std::shared_ptr<Data>, Record>;
0274
0275 void testCallback::sharedPtrTest() {
0276 SharedPtrProd prod;
0277
0278 auto func = [&prod](Record const& rec) { return prod.method(rec); };
0279
0280 using SharedPtrCallback = SharedPtrCallbackT<SharedPtrProd, decltype(func)>;
0281 SharedPtrCallback callback(&prod, func, 0);
0282 std::shared_ptr<Data> handle;
0283
0284 callback.holdOntoPointer(&handle);
0285
0286 callback.newRecordComing();
0287 call(callback);
0288 CPPUNIT_ASSERT(handle.get() == prod.ptr_.get());
0289 CPPUNIT_ASSERT(prod.ptr_->value_ == 1);
0290
0291
0292 call(callback);
0293 CPPUNIT_ASSERT(handle.get() == prod.ptr_.get());
0294 CPPUNIT_ASSERT(prod.ptr_->value_ == 1);
0295
0296 handle.reset();
0297 callback.newRecordComing();
0298
0299 call(callback);
0300 CPPUNIT_ASSERT(handle.get() == prod.ptr_.get());
0301 CPPUNIT_ASSERT(prod.ptr_->value_ == 2);
0302
0303
0304 prod.produce_ = false;
0305 callback.newRecordComing();
0306 call(callback);
0307 CPPUNIT_ASSERT(handle.get() == nullptr);
0308
0309 call(callback);
0310 CPPUNIT_ASSERT(handle.get() == nullptr);
0311
0312 prod.produce_ = true;
0313 callback.newRecordComing();
0314 call(callback);
0315 CPPUNIT_ASSERT(handle->value_ == 4);
0316 }
0317
0318 template <typename P, typename F>
0319 using OptionalCallbackT = Callback<P, F, std::optional<Data>, Record>;
0320
0321 void testCallback::optionalTest() {
0322 OptionalProd prod;
0323
0324 auto func = [&prod](Record const& rec) { return prod.method(rec); };
0325
0326 using OptionalCallback = OptionalCallbackT<OptionalProd, decltype(func)>;
0327 OptionalCallback callback(&prod, func, 0);
0328 std::optional<Data> handle;
0329
0330 callback.holdOntoPointer(&handle);
0331
0332 callback.newRecordComing();
0333 call(callback);
0334 CPPUNIT_ASSERT(handle.has_value());
0335 CPPUNIT_ASSERT(prod.value_ == 1);
0336 CPPUNIT_ASSERT(prod.value_ == handle->value_);
0337
0338
0339 call(callback);
0340 CPPUNIT_ASSERT(handle.has_value());
0341 CPPUNIT_ASSERT(prod.value_ == 1);
0342 CPPUNIT_ASSERT(prod.value_ == handle->value_);
0343
0344 handle.reset();
0345 callback.newRecordComing();
0346
0347 call(callback);
0348 CPPUNIT_ASSERT(handle.has_value());
0349 CPPUNIT_ASSERT(prod.value_ == 2);
0350 CPPUNIT_ASSERT(prod.value_ == handle->value_);
0351
0352
0353 prod.produce_ = false;
0354 callback.newRecordComing();
0355 call(callback);
0356 CPPUNIT_ASSERT(not handle.has_value());
0357
0358 call(callback);
0359 CPPUNIT_ASSERT(not handle.has_value());
0360
0361 prod.produce_ = true;
0362 callback.newRecordComing();
0363 call(callback);
0364 CPPUNIT_ASSERT(handle->value_ == 4);
0365 }
0366
0367 template <typename P, typename F>
0368 using PtrProductsCallbackT = Callback<P, F, edm::ESProducts<std::shared_ptr<Data>, std::shared_ptr<Double>>, Record>;
0369
0370 void testCallback::ptrProductsTest() {
0371 PtrProductsProd prod;
0372
0373 auto func = [&prod](Record const& rec) { return prod.method(rec); };
0374
0375 using PtrProductsCallback = PtrProductsCallbackT<PtrProductsProd, decltype(func)>;
0376 PtrProductsCallback callback(&prod, func, 0);
0377 std::shared_ptr<Data> handle;
0378 std::shared_ptr<Double> doubleHandle;
0379
0380 callback.holdOntoPointer(&handle);
0381 callback.holdOntoPointer(&doubleHandle);
0382
0383 callback.newRecordComing();
0384 call(callback);
0385 CPPUNIT_ASSERT(handle.get() == &(prod.data_));
0386 CPPUNIT_ASSERT(prod.data_.value_ == 1);
0387
0388
0389 call(callback);
0390 CPPUNIT_ASSERT(handle.get() == &(prod.data_));
0391 CPPUNIT_ASSERT(prod.data_.value_ == 1);
0392
0393 callback.newRecordComing();
0394
0395 call(callback);
0396 CPPUNIT_ASSERT(handle.get() == &(prod.data_));
0397 CPPUNIT_ASSERT(prod.data_.value_ == 2);
0398 }
0399
0400
0401
0402 void testCallback::uniquePtrLambdaTest() {
0403 Base prod;
0404
0405 int value = 0;
0406 auto func = [&value](Record const& rec) mutable { return std::make_unique<Data>(++value); };
0407 using UniquePtrCallback = UniquePtrCallbackT<Base, decltype(func)>;
0408 UniquePtrCallback callback(&prod, func, 0);
0409 std::unique_ptr<Data> handle;
0410 callback.holdOntoPointer(&handle);
0411
0412 auto callback2 = std::unique_ptr<UniquePtrCallback>(callback.clone());
0413 std::unique_ptr<Data> handle2;
0414 callback2->holdOntoPointer(&handle2);
0415
0416 callback.newRecordComing();
0417 call(callback);
0418 CPPUNIT_ASSERT(0 != handle.get());
0419 CPPUNIT_ASSERT(value == 1);
0420 CPPUNIT_ASSERT(value == handle->value_);
0421
0422
0423 call(callback);
0424 CPPUNIT_ASSERT(value == 1);
0425 CPPUNIT_ASSERT(value == handle->value_);
0426
0427 handle.release();
0428
0429 callback.newRecordComing();
0430
0431 call(callback);
0432 CPPUNIT_ASSERT(0 != handle.get());
0433 CPPUNIT_ASSERT(value == 2);
0434 CPPUNIT_ASSERT(value == handle->value_);
0435
0436 call(*callback2);
0437 CPPUNIT_ASSERT(handle2->value_ == 3);
0438 CPPUNIT_ASSERT(handle->value_ == 2);
0439
0440 call(callback);
0441 call(*callback2);
0442 CPPUNIT_ASSERT(handle2->value_ == 3);
0443 CPPUNIT_ASSERT(handle->value_ == 2);
0444
0445 callback2->newRecordComing();
0446 call(callback);
0447 call(*callback2);
0448 CPPUNIT_ASSERT(handle2->value_ == 4);
0449 CPPUNIT_ASSERT(handle->value_ == 2);
0450
0451 callback.newRecordComing();
0452 call(callback);
0453 call(*callback2);
0454 CPPUNIT_ASSERT(handle2->value_ == 4);
0455 CPPUNIT_ASSERT(handle->value_ == 5);
0456 }
0457
0458 void testCallback::uniquePtrLambdaCaptureTest() {
0459
0460
0461 Base prod;
0462
0463 auto func = [value = int(0)](Record const& rec) mutable { return std::make_unique<Data>(++value); };
0464 using UniquePtrCallback = UniquePtrCallbackT<Base, decltype(func)>;
0465 UniquePtrCallback callback(&prod, func, 0);
0466 std::unique_ptr<Data> handle;
0467 callback.holdOntoPointer(&handle);
0468
0469 auto callback2 = std::unique_ptr<UniquePtrCallback>(callback.clone());
0470 std::unique_ptr<Data> handle2;
0471 callback2->holdOntoPointer(&handle2);
0472
0473 callback.newRecordComing();
0474 call(callback);
0475 CPPUNIT_ASSERT(0 != handle.get());
0476 CPPUNIT_ASSERT(handle->value_ == 1);
0477
0478
0479 call(callback);
0480 CPPUNIT_ASSERT(handle->value_ == 1);
0481
0482 handle.release();
0483
0484 callback.newRecordComing();
0485
0486 call(callback);
0487 CPPUNIT_ASSERT(handle->value_ == 2);
0488
0489 call(*callback2);
0490 CPPUNIT_ASSERT(handle2->value_ == 3);
0491 CPPUNIT_ASSERT(handle->value_ == 2);
0492
0493 call(callback);
0494 call(*callback2);
0495 CPPUNIT_ASSERT(handle2->value_ == 3);
0496 CPPUNIT_ASSERT(handle->value_ == 2);
0497
0498 callback2->newRecordComing();
0499 call(callback);
0500 call(*callback2);
0501 CPPUNIT_ASSERT(handle2->value_ == 4);
0502 CPPUNIT_ASSERT(handle->value_ == 2);
0503
0504 callback.newRecordComing();
0505 call(callback);
0506 call(*callback2);
0507 CPPUNIT_ASSERT(handle2->value_ == 4);
0508 CPPUNIT_ASSERT(handle->value_ == 5);
0509 }
0510
0511 void testCallback::sharedPtrLambdaTest() {
0512 Base prod;
0513
0514 auto ptr = std::make_shared<Data>();
0515 auto func = [ptr](Record const& rec) mutable {
0516 ++ptr->value_;
0517 return ptr;
0518 };
0519
0520 using SharedPtrCallback = SharedPtrCallbackT<Base, decltype(func)>;
0521 SharedPtrCallback callback(&prod, func, 0);
0522 std::shared_ptr<Data> handle;
0523
0524 callback.holdOntoPointer(&handle);
0525
0526 callback.newRecordComing();
0527 call(callback);
0528 CPPUNIT_ASSERT(handle.get() == ptr.get());
0529 CPPUNIT_ASSERT(ptr->value_ == 1);
0530
0531
0532 call(callback);
0533 CPPUNIT_ASSERT(handle.get() == ptr.get());
0534 CPPUNIT_ASSERT(ptr->value_ == 1);
0535
0536 handle.reset();
0537 callback.newRecordComing();
0538
0539 call(callback);
0540 CPPUNIT_ASSERT(handle.get() == ptr.get());
0541 CPPUNIT_ASSERT(ptr->value_ == 2);
0542 }
0543
0544 void testCallback::optionalLambdaTest() {
0545 Base prod;
0546
0547 int value = 0;
0548 auto func = [&value](Record const& rec) { return std::optional<Data>(++value); };
0549
0550 using OptionalCallback = OptionalCallbackT<Base, decltype(func)>;
0551 OptionalCallback callback(&prod, func, 0);
0552 std::optional<Data> handle;
0553
0554 callback.holdOntoPointer(&handle);
0555
0556 callback.newRecordComing();
0557 call(callback);
0558 CPPUNIT_ASSERT(handle.has_value());
0559 CPPUNIT_ASSERT(value == 1);
0560 CPPUNIT_ASSERT(value == handle->value_);
0561
0562
0563 call(callback);
0564 CPPUNIT_ASSERT(handle.has_value());
0565 CPPUNIT_ASSERT(value == 1);
0566 CPPUNIT_ASSERT(value == handle->value_);
0567
0568 handle.reset();
0569 callback.newRecordComing();
0570
0571 call(callback);
0572 CPPUNIT_ASSERT(handle.has_value());
0573 CPPUNIT_ASSERT(value == 2);
0574 CPPUNIT_ASSERT(value == handle->value_);
0575 }
0576
0577 void testCallback::ptrProductsLambdaTest() {
0578 PtrProductsProd prod;
0579
0580 Data dataValue;
0581 auto func = [&dataValue, doubleValue = Double()](Record const& rec) mutable {
0582 auto dataT = std::shared_ptr<Data>(&dataValue, edm::do_nothing_deleter());
0583 auto doubleT = std::shared_ptr<Double>(&doubleValue, edm::do_nothing_deleter());
0584 ++dataValue.value_;
0585 ++doubleValue.value_;
0586 return edm::es::products(dataT, doubleT);
0587 };
0588
0589 using PtrProductsCallback = PtrProductsCallbackT<Base, decltype(func)>;
0590 PtrProductsCallback callback(&prod, func, 0);
0591 std::shared_ptr<Data> handle;
0592 std::shared_ptr<Double> doubleHandle;
0593
0594 callback.holdOntoPointer(&handle);
0595 callback.holdOntoPointer(&doubleHandle);
0596
0597 callback.newRecordComing();
0598 call(callback);
0599 CPPUNIT_ASSERT(handle.get() == &dataValue);
0600 CPPUNIT_ASSERT(dataValue.value_ == 1);
0601
0602
0603 call(callback);
0604 CPPUNIT_ASSERT(handle.get() == &dataValue);
0605 CPPUNIT_ASSERT(dataValue.value_ == 1);
0606
0607 callback.newRecordComing();
0608
0609 call(callback);
0610 CPPUNIT_ASSERT(handle.get() == &dataValue);
0611 CPPUNIT_ASSERT(dataValue.value_ == 2);
0612 }