File indexing completed on 2025-01-18 09:12:55
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 BOOST_AUTO_TEST_SUITE(AnyTests)
0033
0034 BOOST_AUTO_TEST_CASE(AnyConstructPrimitive) {
0035 {
0036
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
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
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
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
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 {
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 {
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 {
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);
0285 destroyed = false;
0286 BOOST_CHECK(!destroyed);
0287 }
0288 BOOST_CHECK(destroyed);
0289 }
0290 CHECK_ANY_ALLOCATIONS();
0291
0292 {
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);
0304 destroyed = false;
0305 BOOST_CHECK(!destroyed);
0306 }
0307 BOOST_CHECK(destroyed);
0308 }
0309 CHECK_ANY_ALLOCATIONS();
0310 }
0311
0312 BOOST_AUTO_TEST_CASE(AnyDestroyInPlace) {
0313 {
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 {
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;
0446 Any a{o};
0447 incCopyConstruct(1);
0448
0449 const auto& _a = a;
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;
0501 Any a{o};
0502 incCopyConstruct(1);
0503
0504 const auto& _a = a;
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
0534
0535 Any _a3 = a;
0536 incCopyConstruct(1);
0537 b = std::move(_a3);
0538
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()