Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:11:32

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2021 CERN for the benefit of the Acts project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/unit_test.hpp>
0011 
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0014 #include "Acts/Utilities/Delegate.hpp"
0015 
0016 #include <memory>
0017 #include <string>
0018 #include <type_traits>
0019 #include <utility>
0020 #include <vector>
0021 
0022 using namespace Acts;
0023 
0024 namespace bd = boost::unit_test::data;
0025 
0026 BOOST_AUTO_TEST_SUITE(DelegateTests)
0027 
0028 int sumImpl(int a, int b) {
0029   return a + b;
0030 }
0031 
0032 BOOST_AUTO_TEST_CASE(ConnectConstexprLambda) {
0033   Delegate<int(int, int)> sum;
0034   BOOST_CHECK(!sum);
0035   BOOST_CHECK(!sum.connected());
0036 
0037   sum.connect<&sumImpl>();
0038 
0039   BOOST_CHECK_EQUAL(sum(2, 5), 7);
0040   BOOST_CHECK_NE(sum(2, 3), 7);
0041 
0042   sum.connect([](const void*, int a, int b) -> int { return a + b; });
0043 
0044   BOOST_CHECK(sum);
0045   BOOST_CHECK(sum.connected());
0046 
0047   BOOST_CHECK_EQUAL(sum(2, 5), 7);
0048   BOOST_CHECK_NE(sum(2, 3), 7);
0049 }
0050 
0051 float multiply(float a, float b) {
0052   return a * b;
0053 }
0054 
0055 BOOST_AUTO_TEST_CASE(ConnectFunctionPointer) {
0056   Delegate<float(float, float)> mult;
0057 
0058   BOOST_CHECK(!mult);
0059   BOOST_CHECK(!mult.connected());
0060 
0061   mult.connect<multiply>();
0062 
0063   BOOST_CHECK(mult);
0064   BOOST_CHECK(mult.connected());
0065 
0066   CHECK_CLOSE_REL(mult(2, 5.9), 2 * 5.9, 1e-6);
0067   BOOST_CHECK_NE(mult(2, 3.2), 58.9);
0068 }
0069 
0070 struct Subtractor {
0071   int v;
0072   int execute(int a) const { return a - v; }
0073 };
0074 
0075 BOOST_AUTO_TEST_CASE(ConnectStruct) {
0076   Delegate<int(int)> sub;
0077 
0078   BOOST_CHECK(!sub);
0079   BOOST_CHECK(!sub.connected());
0080 
0081   Subtractor s{18};
0082   sub.connect<&Subtractor::execute>(&s);
0083 
0084   BOOST_CHECK(sub);
0085   BOOST_CHECK(sub.connected());
0086 
0087   BOOST_CHECK_EQUAL(sub(7), 7 - 18);
0088 }
0089 
0090 int addition(const void* /*payload*/, int a, int b) {
0091   return a + b;
0092 }
0093 
0094 BOOST_AUTO_TEST_CASE(ConnectRuntime) {
0095   {
0096     Delegate<int(int, int)> add;
0097     BOOST_CHECK(!add);
0098     BOOST_CHECK(!add.connected());
0099 
0100     add.connect(&addition);
0101     BOOST_CHECK(add);
0102     BOOST_CHECK(add.connected());
0103 
0104     BOOST_CHECK_EQUAL(add(4, 4), 8);
0105   }
0106 
0107   {
0108     Delegate<int(int, int)> add{&addition};
0109 
0110     BOOST_CHECK(add);
0111     BOOST_CHECK(add.connected());
0112 
0113     BOOST_CHECK_EQUAL(add(4, 4), 8);
0114   }
0115 
0116   {
0117     Delegate<int(int, int)> add;
0118     BOOST_CHECK(!add);
0119     BOOST_CHECK(!add.connected());
0120 
0121     add = &addition;
0122     BOOST_CHECK(add);
0123     BOOST_CHECK(add.connected());
0124 
0125     BOOST_CHECK_EQUAL(add(4, 4), 8);
0126   }
0127 }
0128 
0129 BOOST_AUTO_TEST_CASE(ConnectConstructFuncPtr) {
0130   Delegate<int(int, int)> add{DelegateFuncTag<&sumImpl>{}};
0131   BOOST_CHECK(add);
0132   BOOST_CHECK(add.connected());
0133   BOOST_CHECK_EQUAL(add(4, 4), 8);
0134 
0135   Subtractor s{18};
0136   Delegate<int(int)> sub{DelegateFuncTag<&Subtractor::execute>{}, &s};
0137 
0138   BOOST_CHECK(sub);
0139   BOOST_CHECK(sub.connected());
0140 
0141   BOOST_CHECK_EQUAL(sub(7), 7 - 18);
0142 }
0143 
0144 void modify(int& v, int a) {
0145   v = a;
0146 }
0147 
0148 void noModify(int v, int a) {
0149   (void)v;
0150   v = a;
0151 }
0152 
0153 BOOST_AUTO_TEST_CASE(DelegateReference) {
0154   Delegate<void(int&, int)> d;
0155   d.connect<&modify>();
0156 
0157   int v = 0;
0158   d(v, 42);
0159   BOOST_CHECK_EQUAL(v, 42);
0160 
0161   // This should not compile since the signature is not exactly matched
0162   // d.connect<&noModify>();
0163 }
0164 
0165 struct SignatureTest {
0166   void modify(int& v, int a) const { v = a; }
0167 
0168   void noModify(int v, int a) const {
0169     (void)v;
0170     v = a;
0171   }
0172 };
0173 
0174 BOOST_AUTO_TEST_CASE(DelegateReferenceMember) {
0175   SignatureTest s;
0176   Delegate<void(int&, int)> d;
0177   d.connect<&SignatureTest::modify>(&s);
0178 
0179   int v = 0;
0180   d(v, 42);
0181   BOOST_CHECK_EQUAL(v, 42);
0182 
0183   // This should not compile since the signature is not exactly matched
0184   // d.connect<&SignatureTest::noModify>(&s);
0185 }
0186 
0187 BOOST_AUTO_TEST_CASE(StatefullLambdas) {
0188   std::vector<int> v;
0189 
0190   auto lambda = [&](int n) -> int {
0191     v.push_back(n);
0192     return v.size();
0193   };
0194 
0195   Delegate<int(int)> d(lambda);
0196 
0197   BOOST_CHECK(d);
0198   BOOST_CHECK(d.connected());
0199   BOOST_CHECK_EQUAL(d(2), 1);
0200 
0201   d.disconnect();
0202   d = lambda;
0203 
0204   BOOST_CHECK(d);
0205   BOOST_CHECK(d.connected());
0206   BOOST_CHECK_EQUAL(d(2), 2);
0207 
0208   d.disconnect();
0209   d.connect(lambda);
0210 
0211   BOOST_CHECK(d);
0212   BOOST_CHECK(d.connected());
0213   BOOST_CHECK_EQUAL(d(2), 3);
0214 
0215   // This should not compile because of deleted && overloads
0216   // d.connect([&](int a){ v.push_back(a); return v.size(); });
0217 }
0218 
0219 struct CheckDestructor {
0220   CheckDestructor(bool* _out) : destructorCalled{_out} {}
0221 
0222   bool* destructorCalled;
0223 
0224   int func() const { return 4; }
0225 
0226   ~CheckDestructor() { (*destructorCalled) = true; }
0227 };
0228 
0229 int owningTest() {
0230   return 8;
0231 }
0232 
0233 int owningTest2(const void* /*payload*/) {
0234   return 8;
0235 }
0236 
0237 BOOST_AUTO_TEST_CASE(OwningDelegateTest) {
0238   {
0239     auto s = std::make_unique<const SignatureTest>();
0240     Delegate<void(int&, int)> d;
0241     (void)d;
0242     // This should not compile, as it would be a memory leak
0243     // d.connect<&SignatureTest::modify>(std::move(s));
0244   }
0245 
0246   {
0247     bool destructorCalled = false;
0248     auto s = std::make_unique<const CheckDestructor>(&destructorCalled);
0249     {
0250       BOOST_CHECK_EQUAL(destructorCalled, false);
0251       Delegate<int(), void, DelegateType::NonOwning> d;
0252       BOOST_CHECK_EQUAL(destructorCalled, false);
0253       d.connect<&CheckDestructor::func>(s.get());
0254       BOOST_CHECK_EQUAL(destructorCalled, false);
0255       Delegate<int(), void, DelegateType::NonOwning> dCopy{d};
0256       BOOST_CHECK_EQUAL(d(), 4);
0257       BOOST_CHECK_EQUAL(dCopy(), 4);
0258       BOOST_CHECK_EQUAL(destructorCalled, false);
0259     }
0260     // destructor not called after non-owning delegate goes out of scope
0261     BOOST_CHECK_EQUAL(destructorCalled, false);
0262 
0263     {
0264       BOOST_CHECK_EQUAL(destructorCalled, false);
0265       Delegate<int(), void, DelegateType::Owning> d;
0266       // This doesn't compile: owning delegate is not copyable
0267       // Delegate<int(), DelegateType::Owning> dCopy = d;
0268       BOOST_CHECK_EQUAL(destructorCalled, false);
0269       // This doesn't compile: owning delegate cannot accept raw pointer
0270       // instance
0271       // d.connect<&CheckDestructor::func>(s.get());
0272       d.connect<&CheckDestructor::func>(std::move(s));
0273       BOOST_CHECK_EQUAL(destructorCalled, false);
0274       BOOST_CHECK_EQUAL(d(), 4);
0275       BOOST_CHECK_EQUAL(destructorCalled, false);
0276     }
0277     // destructor called after owning delegate goes out of scope
0278     BOOST_CHECK_EQUAL(destructorCalled, true);
0279 
0280     destructorCalled = false;
0281     s = std::make_unique<const CheckDestructor>(&destructorCalled);
0282     {
0283       BOOST_CHECK_EQUAL(destructorCalled, false);
0284       OwningDelegate<int()> d;
0285       // This doesn't compile: owning delegate is not copyable
0286       // OwningDelegate<int()> dCopy = d;
0287       BOOST_CHECK_EQUAL(destructorCalled, false);
0288       d.connect<&CheckDestructor::func>(std::move(s));
0289       BOOST_CHECK_EQUAL(destructorCalled, false);
0290       BOOST_CHECK_EQUAL(d(), 4);
0291       BOOST_CHECK_EQUAL(destructorCalled, false);
0292     }
0293     // destructor called after owning delegate goes out of scope
0294     BOOST_CHECK_EQUAL(destructorCalled, true);
0295   }
0296 
0297   {
0298     bool destructorCalled = false;
0299     auto s = std::make_unique<const CheckDestructor>(&destructorCalled);
0300     {
0301       BOOST_CHECK_EQUAL(destructorCalled, false);
0302       Delegate<int(), void, DelegateType::NonOwning> d;
0303       BOOST_CHECK_EQUAL(destructorCalled, false);
0304       d.connect<&CheckDestructor::func>(s.get());
0305       Delegate<int(), void, DelegateType::NonOwning> dCopy{d};
0306       BOOST_CHECK_EQUAL(destructorCalled, false);
0307       BOOST_CHECK_EQUAL(d(), 4);
0308       BOOST_CHECK_EQUAL(dCopy(), 4);
0309       BOOST_CHECK_EQUAL(destructorCalled, false);
0310       d.disconnect();
0311       BOOST_CHECK_EQUAL(destructorCalled, false);
0312     }
0313 
0314     {
0315       BOOST_CHECK_EQUAL(destructorCalled, false);
0316       Delegate<int(), void, DelegateType::Owning> d;
0317       // This doesn't compile: owning delegate is not copyable
0318       // Delegate<int(), DelegateType::Owning> dCopy = d;
0319       BOOST_CHECK_EQUAL(destructorCalled, false);
0320       // This doesn't compile: owning delegate cannot accept raw pointer
0321       // instance
0322       // d.connect<&CheckDestructor::func>(s.get());
0323       d.connect<&CheckDestructor::func>(std::move(s));
0324       BOOST_CHECK_EQUAL(destructorCalled, false);
0325       BOOST_CHECK_EQUAL(d(), 4);
0326       BOOST_CHECK_EQUAL(destructorCalled, false);
0327       d.disconnect();
0328       BOOST_CHECK_EQUAL(destructorCalled, true);
0329     }
0330     // destructor called after owning delegate goes out of scope
0331     BOOST_CHECK_EQUAL(destructorCalled, true);
0332   }
0333 
0334   {
0335     OwningDelegate<int()> d;
0336     d.connect<&owningTest>();
0337     BOOST_CHECK_EQUAL(d(), 8);
0338 
0339     d.disconnect();
0340     d.connect<&owningTest>();
0341     BOOST_CHECK_EQUAL(d(), 8);
0342 
0343     d.disconnect();
0344     d.connect(owningTest2);
0345     BOOST_CHECK_EQUAL(d(), 8);
0346   }
0347 }
0348 
0349 struct DelegateInterface {
0350   DelegateInterface() = default;
0351   virtual ~DelegateInterface() = 0;
0352 
0353   virtual std::string func() const { return "base"; }
0354 };
0355 inline DelegateInterface::~DelegateInterface() = default;
0356 
0357 struct ConcreteDelegate : public DelegateInterface {
0358   std::string func() const final { return "derived"; }
0359 };
0360 
0361 struct SeparateDelegate {
0362   std::string func() const { return "separate"; }
0363 };
0364 
0365 BOOST_AUTO_TEST_CASE(NonVoidDelegateTest) {
0366   // check void behavior with virtuals
0367   {
0368     Delegate<std::string(), void> d;
0369     ConcreteDelegate c;
0370     d.connect<&ConcreteDelegate::func>(&c);
0371     BOOST_CHECK_EQUAL(d(), "derived");
0372 
0373     // does not compile: delegate won't hand out void pointer
0374     // d.instance();
0375   }
0376   {
0377     Delegate<std::string(), void> d;
0378     ConcreteDelegate c;
0379     d.connect<&DelegateInterface::func>(&c);
0380     BOOST_CHECK_EQUAL(
0381         d(), "derived");  // <- even if you plug in the base class member
0382                           // pointer you get the derived class call
0383   }
0384 
0385   {
0386     Delegate<std::string(), DelegateInterface> d;
0387     ConcreteDelegate c;
0388     d.connect<&ConcreteDelegate::func>(&c);
0389     BOOST_CHECK_EQUAL(d(), "derived");
0390 
0391     const auto* instance = d.instance();
0392     static_assert(
0393         std::is_same_v<
0394             std::remove_const_t<std::remove_pointer_t<decltype(instance)>>,
0395             DelegateInterface>,
0396         "Did not get correct instance pointer");
0397     BOOST_CHECK_NE(dynamic_cast<const DelegateInterface*>(instance), nullptr);
0398     BOOST_CHECK_NE(dynamic_cast<const ConcreteDelegate*>(instance), nullptr);
0399   }
0400 
0401   {
0402     Delegate<std::string(), ConcreteDelegate> d;
0403     ConcreteDelegate c;
0404     d.connect<&ConcreteDelegate::func>(&c);
0405     BOOST_CHECK_EQUAL(d(), "derived");
0406 
0407     const auto* instance = d.instance();
0408     static_assert(
0409         std::is_same_v<
0410             std::remove_const_t<std::remove_pointer_t<decltype(instance)>>,
0411             ConcreteDelegate>,
0412         "Did not get correct instance pointer");
0413     BOOST_CHECK_NE(dynamic_cast<const DelegateInterface*>(instance), nullptr);
0414     BOOST_CHECK_NE(dynamic_cast<const ConcreteDelegate*>(instance), nullptr);
0415   }
0416 
0417   {
0418     OwningDelegate<std::string(), DelegateInterface> d;
0419     d.connect<&ConcreteDelegate::func>(
0420         std::make_unique<const ConcreteDelegate>());
0421     BOOST_CHECK_EQUAL(d(), "derived");
0422 
0423     const auto* instance = d.instance();
0424     static_assert(
0425         std::is_same_v<
0426             std::remove_const_t<std::remove_pointer_t<decltype(instance)>>,
0427             DelegateInterface>,
0428         "Did not get correct instance pointer");
0429     BOOST_CHECK_NE(dynamic_cast<const DelegateInterface*>(instance), nullptr);
0430     BOOST_CHECK_NE(dynamic_cast<const ConcreteDelegate*>(instance), nullptr);
0431   }
0432 
0433   {
0434     OwningDelegate<std::string(), ConcreteDelegate> d;
0435     ConcreteDelegate c;
0436     d.connect<&ConcreteDelegate::func>(
0437         std::make_unique<const ConcreteDelegate>());
0438     BOOST_CHECK_EQUAL(d(), "derived");
0439 
0440     const auto* instance = d.instance();
0441     static_assert(
0442         std::is_same_v<
0443             std::remove_const_t<std::remove_pointer_t<decltype(instance)>>,
0444             ConcreteDelegate>,
0445         "Did not get correct instance pointer");
0446     BOOST_CHECK_NE(dynamic_cast<const DelegateInterface*>(instance), nullptr);
0447     BOOST_CHECK_NE(dynamic_cast<const ConcreteDelegate*>(instance), nullptr);
0448   }
0449 
0450   {
0451     Delegate<std::string(), DelegateInterface> d;
0452     SeparateDelegate c;
0453     // Does not compile: cannot assign unrelated type
0454     // d.connect<&SeparateDelegate::func>(&c);
0455     (void)d;
0456     (void)c;
0457   }
0458 
0459   { OwningDelegate<std::string(), DelegateInterface> d; }
0460 }
0461 
0462 BOOST_AUTO_TEST_SUITE_END()