Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:55

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