File indexing completed on 2025-10-18 08:22:51
0001
0002
0003
0004
0005
0006
0007
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
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
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
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
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
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 {
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 {
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 {
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);
0287 destroyed = false;
0288 BOOST_CHECK(!destroyed);
0289 }
0290 BOOST_CHECK(destroyed);
0291 }
0292 CHECK_ANY_ALLOCATIONS();
0293
0294 {
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);
0306 destroyed = false;
0307 BOOST_CHECK(!destroyed);
0308 }
0309 BOOST_CHECK(destroyed);
0310 }
0311 CHECK_ANY_ALLOCATIONS();
0312 }
0313
0314 BOOST_AUTO_TEST_CASE(AnyDestroyInPlace) {
0315 {
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 {
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;
0448 Any a{o};
0449 incCopyConstruct(1);
0450
0451 const auto& _a = a;
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;
0503 Any a{o};
0504 incCopyConstruct(1);
0505
0506 const auto& _a = a;
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
0536
0537 Any _a3 = a;
0538 incCopyConstruct(1);
0539 b = std::move(_a3);
0540
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 }