File indexing completed on 2025-08-06 08:11:31
0001
0002
0003
0004
0005
0006
0007
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
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
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
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
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
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 {
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 {
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 {
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);
0233 destroyed = false;
0234 BOOST_CHECK(!destroyed);
0235 }
0236 BOOST_CHECK(destroyed);
0237 }
0238 CHECK_ANY_ALLOCATIONS();
0239
0240 {
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);
0252 destroyed = false;
0253 BOOST_CHECK(!destroyed);
0254 }
0255 BOOST_CHECK(destroyed);
0256 }
0257 CHECK_ANY_ALLOCATIONS();
0258 }
0259
0260 BOOST_AUTO_TEST_CASE(AnyDestroyInPlace) {
0261 {
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 {
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;
0394 Any a{o};
0395 incCopyConstruct(1);
0396
0397 const auto& _a = a;
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;
0449 Any a{o};
0450 incCopyConstruct(1);
0451
0452 const auto& _a = a;
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
0482
0483 Any _a3 = a;
0484 incCopyConstruct(1);
0485 b = std::move(_a3);
0486
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()