Back to home page

sPhenix code displayed by LXR

 
 

    


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

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