Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-18 08:22:51

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Utilities/Any.hpp"
0012 
0013 #include <any>
0014 #include <array>
0015 #include <cstddef>
0016 #include <type_traits>
0017 #include <utility>
0018 
0019 using namespace Acts;
0020 
0021 #if defined(_ACTS_ANY_ENABLE_TRACK_ALLOCATIONS)
0022 #define CHECK_ANY_ALLOCATIONS()                 \
0023   do {                                          \
0024     _AnyAllocationReporter::checkAllocations(); \
0025   } while (0)
0026 #else
0027 #define CHECK_ANY_ALLOCATIONS() \
0028   do {                          \
0029   } while (0)
0030 #endif
0031 
0032 namespace ActsTests {
0033 
0034 BOOST_AUTO_TEST_SUITE(UtilitiesSuite)
0035 
0036 BOOST_AUTO_TEST_CASE(AnyConstructPrimitive) {
0037   {
0038     // small type
0039     Any a;
0040     BOOST_CHECK(!a);
0041 
0042     int v = 5;
0043     a = Any{v};
0044     BOOST_CHECK(!!a);
0045 
0046     BOOST_CHECK_EQUAL(a.as<int>(), v);
0047     BOOST_CHECK_NE(a.as<int>(), v + 1);
0048 
0049     BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
0050   }
0051   CHECK_ANY_ALLOCATIONS();
0052 
0053   {
0054     // type that is large
0055     Any a;
0056     BOOST_CHECK(!a);
0057 
0058     std::array<int, 2> v{1, 2};
0059     a = Any{v};
0060     BOOST_CHECK(!!a);
0061 
0062     BOOST_CHECK_EQUAL_COLLECTIONS(a.as<decltype(v)>().begin(),
0063                                   a.as<decltype(v)>().end(), v.begin(),
0064                                   v.end());
0065     BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
0066   }
0067   CHECK_ANY_ALLOCATIONS();
0068 
0069   {
0070     // type that is large
0071     Any a;
0072     BOOST_CHECK(!a);
0073 
0074     std::array<unsigned long, 5> v{1, 2, 3, 4, 5};
0075     a = Any{v};
0076     BOOST_CHECK(!!a);
0077 
0078     BOOST_CHECK_EQUAL_COLLECTIONS(a.as<decltype(v)>().begin(),
0079                                   a.as<decltype(v)>().end(), v.begin(),
0080                                   v.end());
0081     BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
0082   }
0083   CHECK_ANY_ALLOCATIONS();
0084 }
0085 
0086 BOOST_AUTO_TEST_CASE(AnyAssignConstructEmpty) {
0087   Any a;
0088   Any b;
0089   a = b;
0090   Any c{a};
0091   a = std::move(b);
0092   Any d{std::move(a)};
0093 
0094   BOOST_CHECK(!a);
0095   BOOST_CHECK(!b);
0096   BOOST_CHECK(!c);
0097   BOOST_CHECK(!d);
0098 
0099   CHECK_ANY_ALLOCATIONS();
0100 }
0101 
0102 BOOST_AUTO_TEST_CASE(AnyConstructCustom) {
0103   struct A {
0104     int value;
0105     A() { value = 76; }
0106   };
0107 
0108   Any a;
0109   BOOST_CHECK(!a);
0110   a = Any{A{}};
0111 
0112   BOOST_CHECK(!!a);
0113 
0114   BOOST_CHECK_EQUAL(a.as<A>().value, 76);
0115 
0116   CHECK_ANY_ALLOCATIONS();
0117 }
0118 
0119 BOOST_AUTO_TEST_CASE(AnyConstructCustomInPlace) {
0120   struct A {
0121     int value;
0122     explicit A(int v) { value = v; }
0123   };
0124 
0125   Any a{std::in_place_type<A>, 42};
0126   BOOST_CHECK(!!a);
0127   BOOST_CHECK_EQUAL(a.as<A>().value, 42);
0128 
0129   CHECK_ANY_ALLOCATIONS();
0130 }
0131 
0132 BOOST_AUTO_TEST_CASE(AnyMove) {
0133   {
0134     // small type
0135     Any a;
0136     BOOST_CHECK(!a);
0137 
0138     int v = 5;
0139     a = Any{v};
0140     BOOST_CHECK(!!a);
0141 
0142     Any b = std::move(a);
0143     BOOST_CHECK(!!b);
0144     BOOST_CHECK_EQUAL(b.as<int>(), 5);
0145 
0146     Any c;
0147     c = std::move(b);
0148     BOOST_CHECK(!!c);
0149     BOOST_CHECK_EQUAL(c.as<int>(), 5);
0150   }
0151 
0152   CHECK_ANY_ALLOCATIONS();
0153 }
0154 
0155 BOOST_AUTO_TEST_CASE(AnyCopy) {
0156   {
0157     // small type
0158     Any a;
0159     BOOST_CHECK(!a);
0160 
0161     int v = 5;
0162     a = Any{v};
0163     BOOST_CHECK(!!a);
0164 
0165     Any b = a;
0166     BOOST_CHECK(!!b);
0167     BOOST_CHECK_EQUAL(b.as<int>(), 5);
0168 
0169     Any c;
0170     c = a;
0171     BOOST_CHECK(!!c);
0172     BOOST_CHECK_EQUAL(c.as<int>(), 5);
0173   }
0174   CHECK_ANY_ALLOCATIONS();
0175 }
0176 
0177 struct D {
0178   bool* destroyed;
0179   explicit D(bool* d) : destroyed{d} {}
0180   ~D() { *destroyed = true; }
0181 };
0182 
0183 struct D2 {
0184   bool* destroyed{nullptr};
0185   std::array<char, 512> blob{};
0186 
0187   explicit D2(bool* d) : destroyed{d} {}
0188 
0189   ~D2() { *destroyed = true; }
0190 };
0191 
0192 BOOST_AUTO_TEST_CASE(AnyMoveTypeChange) {
0193   BOOST_TEST_CONTEXT("Small type") {
0194     bool destroyed = false;
0195     D d{&destroyed};
0196     Any a{std::move(d)};
0197     BOOST_CHECK(!destroyed);
0198 
0199     int value = 5;
0200     Any b{value};
0201     a = std::move(b);
0202     BOOST_CHECK(destroyed);
0203     BOOST_CHECK_EQUAL(a.as<int>(), value);
0204   }
0205 
0206   bool destroyed = false;
0207   BOOST_TEST_CONTEXT("Large type") {
0208     D2 d{&destroyed};
0209     Any a{std::move(d)};
0210     BOOST_CHECK(!destroyed);
0211 
0212     int value = 5;
0213     Any b{value};
0214     a = std::move(b);
0215     BOOST_CHECK(destroyed);
0216     BOOST_CHECK_EQUAL(a.as<int>(), value);
0217   }
0218 }
0219 
0220 BOOST_AUTO_TEST_CASE(AnyCopyTypeChange) {
0221   BOOST_TEST_CONTEXT("Small type") {
0222     bool destroyed = false;
0223     D d{&destroyed};
0224     Any a{std::move(d)};
0225     BOOST_CHECK(!destroyed);
0226 
0227     int value = 5;
0228     Any b{value};
0229     a = b;
0230     BOOST_CHECK(destroyed);
0231     BOOST_CHECK_EQUAL(a.as<int>(), value);
0232   }
0233 
0234   bool destroyed = false;
0235   BOOST_TEST_CONTEXT("Large type") {
0236     D2 d{&destroyed};
0237     Any a{std::move(d)};
0238     BOOST_CHECK(!destroyed);
0239 
0240     int value = 5;
0241     Any b{value};
0242     a = b;
0243     BOOST_CHECK(destroyed);
0244     BOOST_CHECK_EQUAL(a.as<int>(), value);
0245   }
0246 }
0247 
0248 BOOST_AUTO_TEST_CASE(AnyDestroy) {
0249   {  // small type
0250     bool destroyed = false;
0251     D d{&destroyed};
0252     BOOST_CHECK(!destroyed);
0253     {
0254       Any a{std::move(d)};
0255       BOOST_CHECK(!destroyed);
0256     }
0257     BOOST_CHECK(destroyed);
0258   }
0259   CHECK_ANY_ALLOCATIONS();
0260 
0261   {  // large type
0262     bool destroyed = false;
0263     D2 d{&destroyed};
0264     BOOST_CHECK(!destroyed);
0265     {
0266       Any a{std::move(d)};
0267       BOOST_CHECK(!destroyed);
0268     }
0269     BOOST_CHECK(destroyed);
0270   }
0271   CHECK_ANY_ALLOCATIONS();
0272 }
0273 
0274 BOOST_AUTO_TEST_CASE(AnyDestroyCopy) {
0275   {  // small type
0276     bool destroyed = false;
0277 
0278     {
0279       Any b;
0280       {
0281         Any a{std::in_place_type<D>, &destroyed};
0282         BOOST_CHECK(!destroyed);
0283         b = a;
0284         BOOST_CHECK(!destroyed);
0285       }
0286       BOOST_CHECK(destroyed);  // a destroyed, should be true
0287       destroyed = false;
0288       BOOST_CHECK(!destroyed);
0289     }
0290     BOOST_CHECK(destroyed);  // b destroyed, should be true again
0291   }
0292   CHECK_ANY_ALLOCATIONS();
0293 
0294   {  // large type
0295     bool destroyed = false;
0296 
0297     {
0298       Any b;
0299       {
0300         Any a{std::in_place_type<D2>, &destroyed};
0301         BOOST_CHECK(!destroyed);
0302         b = a;
0303         BOOST_CHECK(!destroyed);
0304       }
0305       BOOST_CHECK(destroyed);  // a destroyed, should be true
0306       destroyed = false;
0307       BOOST_CHECK(!destroyed);
0308     }
0309     BOOST_CHECK(destroyed);  // b destroyed, should be true again
0310   }
0311   CHECK_ANY_ALLOCATIONS();
0312 }
0313 
0314 BOOST_AUTO_TEST_CASE(AnyDestroyInPlace) {
0315   {  // small type
0316     bool destroyed = false;
0317     BOOST_CHECK(!destroyed);
0318     {
0319       Any a{std::in_place_type<D>, &destroyed};
0320       BOOST_CHECK(!destroyed);
0321     }
0322     BOOST_CHECK(destroyed);
0323   }
0324   CHECK_ANY_ALLOCATIONS();
0325 
0326   {  // large type
0327     bool destroyed = false;
0328     BOOST_CHECK(!destroyed);
0329     {
0330       Any a{std::in_place_type<D2>, &destroyed};
0331       BOOST_CHECK(!destroyed);
0332     }
0333     BOOST_CHECK(destroyed);
0334   }
0335   CHECK_ANY_ALLOCATIONS();
0336 }
0337 
0338 struct D3 {
0339   std::size_t* destroyed{nullptr};
0340   std::array<char, 512> blob{};
0341 
0342   explicit D3(std::size_t* d) : destroyed{d} {}
0343 
0344   ~D3() { (*destroyed)++; }
0345 };
0346 
0347 BOOST_AUTO_TEST_CASE(LeakCheck) {
0348   std::size_t destroyed = 0;
0349   for (std::size_t i = 0; i < 10000; i++) {
0350     {
0351       BOOST_CHECK_EQUAL(destroyed, i);
0352       Any a;
0353       BOOST_CHECK_EQUAL(destroyed, i);
0354       a = Any{std::in_place_type<D3>, &destroyed};
0355       BOOST_CHECK_EQUAL(destroyed, i);
0356     }
0357     BOOST_CHECK_EQUAL(destroyed, i + 1);
0358   }
0359   CHECK_ANY_ALLOCATIONS();
0360 }
0361 
0362 struct LifecycleCounters {
0363   std::size_t nDestroy = 0;
0364   std::size_t nCopyConstruct = 0;
0365   std::size_t nCopy = 0;
0366   std::size_t nMoveConstruct = 0;
0367   std::size_t nMove = 0;
0368 };
0369 
0370 template <std::size_t PADDING>
0371 struct Lifecycle;
0372 
0373 template <>
0374 struct Lifecycle<0> {
0375   LifecycleCounters* counters;
0376 
0377   explicit Lifecycle(LifecycleCounters* _counters) : counters{_counters} {}
0378 
0379   Lifecycle(Lifecycle&& o) {
0380     counters = o.counters;
0381     counters->nMoveConstruct++;
0382   }
0383 
0384   Lifecycle& operator=(Lifecycle&& o) {
0385     counters = o.counters;
0386     counters->nMove++;
0387     return *this;
0388   }
0389 
0390   Lifecycle(const Lifecycle& o) {
0391     counters = o.counters;
0392     counters->nCopyConstruct++;
0393   }
0394 
0395   Lifecycle& operator=(const Lifecycle& o) {
0396     counters = o.counters;
0397     counters->nCopy++;
0398     return *this;
0399   }
0400 
0401   ~Lifecycle() { counters->nDestroy++; }
0402 };
0403 
0404 template <std::size_t PADDING>
0405 struct Lifecycle : public Lifecycle<0> {
0406   std::array<char, PADDING> m_padding{};
0407 
0408   explicit Lifecycle(LifecycleCounters* _counters) : Lifecycle<0>(_counters) {}
0409 };
0410 
0411 template <std::size_t PADDING>
0412 struct LifecycleHandle {
0413   LifecycleCounters counters;
0414   Lifecycle<PADDING> inner;
0415 
0416   LifecycleHandle() : counters{}, inner{&counters} {}
0417 };
0418 
0419 #define checkCounters()                                                      \
0420   do {                                                                       \
0421     BOOST_REQUIRE_EQUAL(l.counters.nCopy, counters.nCopy);                   \
0422     BOOST_REQUIRE_EQUAL(l.counters.nCopyConstruct, counters.nCopyConstruct); \
0423     BOOST_REQUIRE_EQUAL(l.counters.nMove, counters.nMove);                   \
0424     BOOST_REQUIRE_EQUAL(l.counters.nMoveConstruct, counters.nMoveConstruct); \
0425     BOOST_REQUIRE_EQUAL(l.counters.nDestroy, counters.nDestroy);             \
0426   } while (0)
0427 
0428 #define makeCounter(counter, n) \
0429   do {                          \
0430     counter += n;               \
0431     checkCounters();            \
0432   } while (0)
0433 
0434 #define incCopyConstruct(n) makeCounter(counters.nCopyConstruct, n)
0435 #define incCopy(n) makeCounter(counters.nCopy, n)
0436 #define incMoveConstruct(n) makeCounter(counters.nMoveConstruct, n)
0437 #define incMove(n) makeCounter(counters.nMove, n)
0438 #define incDestroy(n) makeCounter(counters.nDestroy, n)
0439 
0440 BOOST_AUTO_TEST_CASE(LifeCycleSmall) {
0441   LifecycleCounters counters;
0442   LifecycleHandle<0> l;
0443 
0444   checkCounters();
0445 
0446   {
0447     const auto& o = l.inner;  // force copy
0448     Any a{o};
0449     incCopyConstruct(1);
0450 
0451     const auto& _a = a;  // force copy later
0452     {
0453       Any b{_a};
0454       incCopyConstruct(1);
0455     }
0456     incDestroy(1);
0457 
0458     {
0459       Any b;
0460       b = _a;
0461       incCopyConstruct(1);
0462       b = _a;
0463       incCopy(1);
0464     }
0465     incDestroy(1);
0466 
0467     {
0468       Any b{a};
0469       incCopyConstruct(1);
0470       b = a;
0471       incCopy(1);
0472     }
0473     incDestroy(1);
0474 
0475     {
0476       auto _a2 = a;
0477       incCopyConstruct(1);
0478       Any b;
0479       b = std::move(_a2);
0480       incMoveConstruct(1);
0481       auto _a3 = a;
0482       incCopyConstruct(1);
0483       b = std::move(_a3);
0484       incMove(1);
0485     }
0486     incDestroy(3);
0487   }
0488   incDestroy(1);
0489 
0490   checkCounters();
0491 
0492   CHECK_ANY_ALLOCATIONS();
0493 }
0494 
0495 BOOST_AUTO_TEST_CASE(LifeCycleHeap) {
0496   LifecycleCounters counters;
0497   LifecycleHandle<512> l;
0498 
0499   checkCounters();
0500 
0501   {
0502     const auto& o = l.inner;  // force copy
0503     Any a{o};
0504     incCopyConstruct(1);
0505 
0506     const auto& _a = a;  // force copy later
0507     {
0508       Any b{_a};
0509       incCopyConstruct(1);
0510     }
0511     incDestroy(1);
0512 
0513     {
0514       Any b;
0515       b = _a;
0516       incCopyConstruct(1);
0517       b = _a;
0518       incCopy(1);
0519     }
0520     incDestroy(1);
0521 
0522     {
0523       Any b{a};
0524       incCopyConstruct(1);
0525       b = a;
0526       incCopy(1);
0527     }
0528     incDestroy(1);
0529 
0530     {
0531       Any _a2 = a;
0532       incCopyConstruct(1);
0533       Any b;
0534       b = std::move(_a2);
0535       // no actual move
0536 
0537       Any _a3 = a;
0538       incCopyConstruct(1);
0539       b = std::move(_a3);
0540       // no actual move
0541       incDestroy(1);
0542     }
0543     incDestroy(1);
0544   }
0545   incDestroy(1);
0546 
0547   checkCounters();
0548 
0549   CHECK_ANY_ALLOCATIONS();
0550 }
0551 
0552 BOOST_AUTO_TEST_SUITE_END()
0553 
0554 }  // namespace ActsTests