File indexing completed on 2023-07-04 00:49:03
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&) { 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 }
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 }
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
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
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
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
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
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
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
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
0387
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
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
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
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
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 }