Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-17 07:36:28

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 <memory>
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     detail::_AnyAllocationReporter::checkAllocations(); \
0026   } while (0)
0027 #else
0028 #define CHECK_ANY_ALLOCATIONS() \
0029   do {                          \
0030   } while (0)
0031 #endif
0032 
0033 namespace ActsTests {
0034 
0035 BOOST_AUTO_TEST_SUITE(UtilitiesSuite)
0036 
0037 BOOST_AUTO_TEST_CASE(AnyConstructPrimitive) {
0038   {
0039     // small type
0040     Any a;
0041     BOOST_CHECK(!a);
0042 
0043     int v = 5;
0044     a = Any{v};
0045     BOOST_CHECK(!!a);
0046 
0047     BOOST_CHECK_EQUAL(a.as<int>(), v);
0048     BOOST_CHECK_NE(a.as<int>(), v + 1);
0049 
0050     BOOST_CHECK_THROW(a.as<float>(), std::bad_any_cast);
0051   }
0052   CHECK_ANY_ALLOCATIONS();
0053 
0054   {
0055     // type that is large
0056     Any a;
0057     BOOST_CHECK(!a);
0058 
0059     std::array<int, 2> v{1, 2};
0060     a = Any{v};
0061     BOOST_CHECK(!!a);
0062 
0063     BOOST_CHECK_EQUAL_COLLECTIONS(a.as<decltype(v)>().begin(),
0064                                   a.as<decltype(v)>().end(), v.begin(),
0065                                   v.end());
0066     BOOST_CHECK_THROW(a.as<float>(), 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   }
0084   CHECK_ANY_ALLOCATIONS();
0085 }
0086 
0087 BOOST_AUTO_TEST_CASE(AnyAsPtr) {
0088   {
0089     // small type: correct type returns non-null pointer
0090     Any a{42};
0091     int* p = a.asPtr<int>();
0092     BOOST_REQUIRE_NE(p, static_cast<int*>(nullptr));
0093     BOOST_CHECK_EQUAL(*p, 42);
0094 
0095     // wrong type returns nullptr
0096     BOOST_CHECK_EQUAL(a.asPtr<float>(), static_cast<float*>(nullptr));
0097     BOOST_CHECK_EQUAL(a.asPtr<double>(), static_cast<double*>(nullptr));
0098 
0099     // mutation through pointer
0100     *p = 99;
0101     BOOST_CHECK_EQUAL(a.as<int>(), 99);
0102   }
0103   CHECK_ANY_ALLOCATIONS();
0104 
0105   {
0106     // large (heap-allocated) type: correct type returns non-null pointer
0107     std::array<unsigned long, 5> v{10, 20, 30, 40, 50};
0108     Any a{v};
0109     auto* p = a.asPtr<std::array<unsigned long, 5>>();
0110     BOOST_REQUIRE_NE(p, static_cast<decltype(p)>(nullptr));
0111     BOOST_CHECK_EQUAL_COLLECTIONS(p->begin(), p->end(), v.begin(), v.end());
0112 
0113     // wrong type returns nullptr
0114     BOOST_CHECK_EQUAL(a.asPtr<int>(), static_cast<int*>(nullptr));
0115   }
0116   CHECK_ANY_ALLOCATIONS();
0117 
0118   {
0119     // empty Any returns nullptr
0120     Any a;
0121     BOOST_CHECK_EQUAL(a.asPtr<int>(), static_cast<int*>(nullptr));
0122     BOOST_CHECK_EQUAL(a.asPtr<float>(), static_cast<float*>(nullptr));
0123   }
0124   CHECK_ANY_ALLOCATIONS();
0125 
0126   {
0127     // const overload
0128     const Any a{3.14f};
0129     const float* p = a.asPtr<float>();
0130     BOOST_REQUIRE_NE(p, static_cast<const float*>(nullptr));
0131     BOOST_CHECK_EQUAL(*p, 3.14f);
0132 
0133     // wrong type on const Any
0134     BOOST_CHECK_EQUAL(a.asPtr<int>(), static_cast<const int*>(nullptr));
0135   }
0136   CHECK_ANY_ALLOCATIONS();
0137 
0138   {
0139     // const overload with empty Any
0140     const Any a;
0141     BOOST_CHECK_EQUAL(a.asPtr<int>(), static_cast<const int*>(nullptr));
0142   }
0143   CHECK_ANY_ALLOCATIONS();
0144 
0145   {
0146     // const overload with heap-allocated type
0147     std::array<int, 64> v{};
0148     v.fill(7);
0149     const Any a{v};
0150     const auto* p = a.asPtr<std::array<int, 64>>();
0151     BOOST_REQUIRE_NE(p, static_cast<decltype(p)>(nullptr));
0152     for (const auto& elem : *p) {
0153       BOOST_CHECK_EQUAL(elem, 7);
0154     }
0155     BOOST_CHECK_EQUAL(a.asPtr<float>(), static_cast<const float*>(nullptr));
0156   }
0157   CHECK_ANY_ALLOCATIONS();
0158 }
0159 
0160 BOOST_AUTO_TEST_CASE(AnyAssignConstructEmpty) {
0161   Any a;
0162   Any b;
0163   a = b;
0164   Any c{a};
0165   a = std::move(b);
0166   Any d{std::move(a)};
0167 
0168   BOOST_CHECK(!a);
0169   BOOST_CHECK(!b);
0170   BOOST_CHECK(!c);
0171   BOOST_CHECK(!d);
0172 
0173   CHECK_ANY_ALLOCATIONS();
0174 }
0175 
0176 BOOST_AUTO_TEST_CASE(AnyConstructCustom) {
0177   struct A {
0178     int value;
0179     A() { value = 76; }
0180   };
0181 
0182   Any a;
0183   BOOST_CHECK(!a);
0184   a = Any{A{}};
0185 
0186   BOOST_CHECK(!!a);
0187 
0188   BOOST_CHECK_EQUAL(a.as<A>().value, 76);
0189 
0190   CHECK_ANY_ALLOCATIONS();
0191 }
0192 
0193 BOOST_AUTO_TEST_CASE(AnyConstructCustomInPlace) {
0194   struct A {
0195     int value;
0196     explicit A(int v) { value = v; }
0197   };
0198 
0199   Any a{std::in_place_type<A>, 42};
0200   BOOST_CHECK(!!a);
0201   BOOST_CHECK_EQUAL(a.as<A>().value, 42);
0202 
0203   CHECK_ANY_ALLOCATIONS();
0204 }
0205 
0206 BOOST_AUTO_TEST_CASE(AnyMove) {
0207   {
0208     // small type
0209     Any a;
0210     BOOST_CHECK(!a);
0211 
0212     int v = 5;
0213     a = Any{v};
0214     BOOST_CHECK(!!a);
0215 
0216     Any b = std::move(a);
0217     BOOST_CHECK(!!b);
0218     BOOST_CHECK_EQUAL(b.as<int>(), 5);
0219 
0220     Any c;
0221     c = std::move(b);
0222     BOOST_CHECK(!!c);
0223     BOOST_CHECK_EQUAL(c.as<int>(), 5);
0224   }
0225 
0226   CHECK_ANY_ALLOCATIONS();
0227 }
0228 
0229 BOOST_AUTO_TEST_CASE(AnyCopy) {
0230   {
0231     // small type
0232     Any a;
0233     BOOST_CHECK(!a);
0234 
0235     int v = 5;
0236     a = Any{v};
0237     BOOST_CHECK(!!a);
0238 
0239     Any b = a;
0240     BOOST_CHECK(!!b);
0241     BOOST_CHECK_EQUAL(b.as<int>(), 5);
0242 
0243     Any c;
0244     c = a;
0245     BOOST_CHECK(!!c);
0246     BOOST_CHECK_EQUAL(c.as<int>(), 5);
0247   }
0248   CHECK_ANY_ALLOCATIONS();
0249 }
0250 
0251 struct D {
0252   bool* destroyed;
0253   explicit D(bool* d) : destroyed{d} {}
0254   ~D() { *destroyed = true; }
0255 };
0256 
0257 struct D2 {
0258   bool* destroyed{nullptr};
0259   std::array<char, 512> blob{};
0260 
0261   explicit D2(bool* d) : destroyed{d} {}
0262 
0263   ~D2() { *destroyed = true; }
0264 };
0265 
0266 BOOST_AUTO_TEST_CASE(AnyEmplace) {
0267   {
0268     Any a;
0269     auto& value = a.emplace<int>(42);
0270     BOOST_CHECK_EQUAL(value, 42);
0271     BOOST_CHECK_EQUAL(a.as<int>(), 42);
0272     value = 84;
0273     BOOST_CHECK_EQUAL(a.as<int>(), 84);
0274   }
0275   CHECK_ANY_ALLOCATIONS();
0276 
0277   {
0278     bool destroyed = false;
0279     Any a{std::in_place_type<D>, &destroyed};
0280     BOOST_CHECK(!destroyed);
0281     a.emplace<int>(7);
0282     BOOST_CHECK(destroyed);
0283     BOOST_CHECK_EQUAL(a.as<int>(), 7);
0284   }
0285   CHECK_ANY_ALLOCATIONS();
0286 
0287   {
0288     bool destroyed = false;
0289     Any a{std::in_place_type<D2>, &destroyed};
0290     BOOST_CHECK(!destroyed);
0291     bool destroyed2 = false;
0292     auto& ref = a.emplace<D2>(&destroyed2);
0293     BOOST_CHECK(destroyed);
0294     BOOST_CHECK(!destroyed2);
0295     BOOST_CHECK_EQUAL(ref.destroyed, &destroyed2);
0296     BOOST_CHECK_EQUAL(a.as<D2>().destroyed, &destroyed2);
0297   }
0298   CHECK_ANY_ALLOCATIONS();
0299 }
0300 
0301 BOOST_AUTO_TEST_CASE(AnyMoveTypeChange) {
0302   BOOST_TEST_CONTEXT("Small type") {
0303     bool destroyed = false;
0304     D d{&destroyed};
0305     Any a{std::move(d)};
0306     BOOST_CHECK(!destroyed);
0307 
0308     int value = 5;
0309     Any b{value};
0310     a = std::move(b);
0311     BOOST_CHECK(destroyed);
0312     BOOST_CHECK_EQUAL(a.as<int>(), value);
0313   }
0314 
0315   bool destroyed = false;
0316   BOOST_TEST_CONTEXT("Large type") {
0317     D2 d{&destroyed};
0318     Any a{std::move(d)};
0319     BOOST_CHECK(!destroyed);
0320 
0321     int value = 5;
0322     Any b{value};
0323     a = std::move(b);
0324     BOOST_CHECK(destroyed);
0325     BOOST_CHECK_EQUAL(a.as<int>(), value);
0326   }
0327 }
0328 
0329 BOOST_AUTO_TEST_CASE(AnyCopyTypeChange) {
0330   BOOST_TEST_CONTEXT("Small type") {
0331     bool destroyed = false;
0332     D d{&destroyed};
0333     Any a{std::move(d)};
0334     BOOST_CHECK(!destroyed);
0335 
0336     int value = 5;
0337     Any b{value};
0338     a = b;
0339     BOOST_CHECK(destroyed);
0340     BOOST_CHECK_EQUAL(a.as<int>(), value);
0341   }
0342 
0343   bool destroyed = false;
0344   BOOST_TEST_CONTEXT("Large type") {
0345     D2 d{&destroyed};
0346     Any a{std::move(d)};
0347     BOOST_CHECK(!destroyed);
0348 
0349     int value = 5;
0350     Any b{value};
0351     a = b;
0352     BOOST_CHECK(destroyed);
0353     BOOST_CHECK_EQUAL(a.as<int>(), value);
0354   }
0355 }
0356 
0357 BOOST_AUTO_TEST_CASE(AnyDestroy) {
0358   {  // small type
0359     bool destroyed = false;
0360     D d{&destroyed};
0361     BOOST_CHECK(!destroyed);
0362     {
0363       Any a{std::move(d)};
0364       BOOST_CHECK(!destroyed);
0365     }
0366     BOOST_CHECK(destroyed);
0367   }
0368   CHECK_ANY_ALLOCATIONS();
0369 
0370   {  // large type
0371     bool destroyed = false;
0372     D2 d{&destroyed};
0373     BOOST_CHECK(!destroyed);
0374     {
0375       Any a{std::move(d)};
0376       BOOST_CHECK(!destroyed);
0377     }
0378     BOOST_CHECK(destroyed);
0379   }
0380   CHECK_ANY_ALLOCATIONS();
0381 }
0382 
0383 BOOST_AUTO_TEST_CASE(AnyDestroyCopy) {
0384   {  // small type
0385     bool destroyed = false;
0386 
0387     {
0388       Any b;
0389       {
0390         Any a{std::in_place_type<D>, &destroyed};
0391         BOOST_CHECK(!destroyed);
0392         b = a;
0393         BOOST_CHECK(!destroyed);
0394       }
0395       BOOST_CHECK(destroyed);  // a destroyed, should be true
0396       destroyed = false;
0397       BOOST_CHECK(!destroyed);
0398     }
0399     BOOST_CHECK(destroyed);  // b destroyed, should be true again
0400   }
0401   CHECK_ANY_ALLOCATIONS();
0402 
0403   {  // large type
0404     bool destroyed = false;
0405 
0406     {
0407       Any b;
0408       {
0409         Any a{std::in_place_type<D2>, &destroyed};
0410         BOOST_CHECK(!destroyed);
0411         b = a;
0412         BOOST_CHECK(!destroyed);
0413       }
0414       BOOST_CHECK(destroyed);  // a destroyed, should be true
0415       destroyed = false;
0416       BOOST_CHECK(!destroyed);
0417     }
0418     BOOST_CHECK(destroyed);  // b destroyed, should be true again
0419   }
0420   CHECK_ANY_ALLOCATIONS();
0421 }
0422 
0423 BOOST_AUTO_TEST_CASE(AnyDestroyInPlace) {
0424   {  // small type
0425     bool destroyed = false;
0426     BOOST_CHECK(!destroyed);
0427     {
0428       Any a{std::in_place_type<D>, &destroyed};
0429       BOOST_CHECK(!destroyed);
0430     }
0431     BOOST_CHECK(destroyed);
0432   }
0433   CHECK_ANY_ALLOCATIONS();
0434 
0435   {  // large type
0436     bool destroyed = false;
0437     BOOST_CHECK(!destroyed);
0438     {
0439       Any a{std::in_place_type<D2>, &destroyed};
0440       BOOST_CHECK(!destroyed);
0441     }
0442     BOOST_CHECK(destroyed);
0443   }
0444   CHECK_ANY_ALLOCATIONS();
0445 }
0446 
0447 struct D3 {
0448   std::size_t* destroyed{nullptr};
0449   std::array<char, 512> blob{};
0450 
0451   explicit D3(std::size_t* d) : destroyed{d} {}
0452 
0453   ~D3() { (*destroyed)++; }
0454 };
0455 
0456 BOOST_AUTO_TEST_CASE(LeakCheck) {
0457   std::size_t destroyed = 0;
0458   for (std::size_t i = 0; i < 10000; i++) {
0459     {
0460       BOOST_CHECK_EQUAL(destroyed, i);
0461       Any a;
0462       BOOST_CHECK_EQUAL(destroyed, i);
0463       a = Any{std::in_place_type<D3>, &destroyed};
0464       BOOST_CHECK_EQUAL(destroyed, i);
0465     }
0466     BOOST_CHECK_EQUAL(destroyed, i + 1);
0467   }
0468   CHECK_ANY_ALLOCATIONS();
0469 }
0470 
0471 struct LifecycleCounters {
0472   std::size_t nDestroy = 0;
0473   std::size_t nCopyConstruct = 0;
0474   std::size_t nCopy = 0;
0475   std::size_t nMoveConstruct = 0;
0476   std::size_t nMove = 0;
0477 };
0478 
0479 template <std::size_t PADDING>
0480 struct Lifecycle;
0481 
0482 template <>
0483 struct Lifecycle<0> {
0484   LifecycleCounters* counters;
0485 
0486   explicit Lifecycle(LifecycleCounters* _counters) : counters{_counters} {}
0487 
0488   Lifecycle(Lifecycle&& o) {
0489     counters = o.counters;
0490     counters->nMoveConstruct++;
0491   }
0492 
0493   Lifecycle& operator=(Lifecycle&& o) {
0494     counters = o.counters;
0495     counters->nMove++;
0496     return *this;
0497   }
0498 
0499   Lifecycle(const Lifecycle& o) {
0500     counters = o.counters;
0501     counters->nCopyConstruct++;
0502   }
0503 
0504   Lifecycle& operator=(const Lifecycle& o) {
0505     counters = o.counters;
0506     counters->nCopy++;
0507     return *this;
0508   }
0509 
0510   ~Lifecycle() { counters->nDestroy++; }
0511 };
0512 
0513 template <std::size_t PADDING>
0514 struct Lifecycle : public Lifecycle<0> {
0515   std::array<char, PADDING> m_padding{};
0516 
0517   explicit Lifecycle(LifecycleCounters* _counters) : Lifecycle<0>(_counters) {}
0518 };
0519 
0520 template <std::size_t PADDING>
0521 struct LifecycleHandle {
0522   LifecycleCounters counters;
0523   Lifecycle<PADDING> inner;
0524 
0525   LifecycleHandle() : counters{}, inner{&counters} {}
0526 };
0527 
0528 #define checkCounters()                                                      \
0529   do {                                                                       \
0530     BOOST_REQUIRE_EQUAL(l.counters.nCopy, counters.nCopy);                   \
0531     BOOST_REQUIRE_EQUAL(l.counters.nCopyConstruct, counters.nCopyConstruct); \
0532     BOOST_REQUIRE_EQUAL(l.counters.nMove, counters.nMove);                   \
0533     BOOST_REQUIRE_EQUAL(l.counters.nMoveConstruct, counters.nMoveConstruct); \
0534     BOOST_REQUIRE_EQUAL(l.counters.nDestroy, counters.nDestroy);             \
0535   } while (0)
0536 
0537 #define makeCounter(counter, n) \
0538   do {                          \
0539     counter += n;               \
0540     checkCounters();            \
0541   } while (0)
0542 
0543 #define incCopyConstruct(n) makeCounter(counters.nCopyConstruct, n)
0544 #define incCopy(n) makeCounter(counters.nCopy, n)
0545 #define incMoveConstruct(n) makeCounter(counters.nMoveConstruct, n)
0546 #define incMove(n) makeCounter(counters.nMove, n)
0547 #define incDestroy(n) makeCounter(counters.nDestroy, n)
0548 
0549 BOOST_AUTO_TEST_CASE(LifeCycleSmall) {
0550   LifecycleCounters counters;
0551   LifecycleHandle<0> l;
0552 
0553   checkCounters();
0554 
0555   {
0556     const auto& o = l.inner;  // force copy
0557     Any a{o};
0558     incCopyConstruct(1);
0559 
0560     const auto& _a = a;  // force copy later
0561     {
0562       Any b{_a};
0563       incCopyConstruct(1);
0564     }
0565     incDestroy(1);
0566 
0567     {
0568       Any b;
0569       b = _a;
0570       incCopyConstruct(1);
0571       b = _a;
0572       incCopy(1);
0573     }
0574     incDestroy(1);
0575 
0576     {
0577       Any b{a};
0578       incCopyConstruct(1);
0579       b = a;
0580       incCopy(1);
0581     }
0582     incDestroy(1);
0583 
0584     {
0585       auto _a2 = a;
0586       incCopyConstruct(1);
0587       Any b;
0588       b = std::move(_a2);
0589       incMoveConstruct(1);
0590       auto _a3 = a;
0591       incCopyConstruct(1);
0592       b = std::move(_a3);
0593       incMove(1);
0594     }
0595     incDestroy(3);
0596   }
0597   incDestroy(1);
0598 
0599   checkCounters();
0600 
0601   CHECK_ANY_ALLOCATIONS();
0602 }
0603 
0604 BOOST_AUTO_TEST_CASE(LifeCycleHeap) {
0605   LifecycleCounters counters;
0606   LifecycleHandle<512> l;
0607 
0608   checkCounters();
0609 
0610   {
0611     const auto& o = l.inner;  // force copy
0612     Any a{o};
0613     incCopyConstruct(1);
0614 
0615     const auto& _a = a;  // force copy later
0616     {
0617       Any b{_a};
0618       incCopyConstruct(1);
0619     }
0620     incDestroy(1);
0621 
0622     {
0623       Any b;
0624       b = _a;
0625       incCopyConstruct(1);
0626       b = _a;
0627       incCopy(1);
0628     }
0629     incDestroy(1);
0630 
0631     {
0632       Any b{a};
0633       incCopyConstruct(1);
0634       b = a;
0635       incCopy(1);
0636     }
0637     incDestroy(1);
0638 
0639     {
0640       Any _a2 = a;
0641       incCopyConstruct(1);
0642       Any b;
0643       b = std::move(_a2);
0644       // no actual move
0645 
0646       Any _a3 = a;
0647       incCopyConstruct(1);
0648       b = std::move(_a3);
0649       // no actual move
0650       incDestroy(1);
0651     }
0652     incDestroy(1);
0653   }
0654   incDestroy(1);
0655 
0656   checkCounters();
0657 
0658   CHECK_ANY_ALLOCATIONS();
0659 }
0660 
0661 BOOST_AUTO_TEST_CASE(AnyMoveOnlyMoveOnlyTypes) {
0662   using MoveOnlyAny = Acts::AnyMoveOnly;
0663 
0664   using Ptr = std::unique_ptr<int>;
0665 
0666   // AnyMoveOnly can store move-only types
0667   {
0668     auto ptr = std::make_unique<int>(42);
0669     MoveOnlyAny a{std::move(ptr)};
0670     BOOST_CHECK(!!a);
0671     Ptr const* storedPtr = a.asPtr<Ptr>();
0672     BOOST_REQUIRE_NE(storedPtr, nullptr);
0673     BOOST_CHECK_NE(storedPtr->get(), nullptr);
0674     BOOST_CHECK_EQUAL(**storedPtr, 42);
0675   }
0676 
0677   // AnyMoveOnly is moveable
0678   {
0679     auto ptr = std::make_unique<int>(7);
0680     MoveOnlyAny a{std::move(ptr)};
0681     MoveOnlyAny b = std::move(a);
0682     // Note: moved-from Any may still report non-empty for local storage
0683     BOOST_CHECK(!!b);
0684     Ptr const* bPtr = b.asPtr<Ptr>();
0685     BOOST_REQUIRE_NE(bPtr, nullptr);
0686     int val = **bPtr;
0687     BOOST_CHECK_EQUAL(val, 7);
0688   }
0689 
0690   // AnyMoveOnly is not copyable
0691   static_assert(!std::is_copy_constructible_v<MoveOnlyAny>);
0692   static_assert(!std::is_copy_assignable_v<MoveOnlyAny>);
0693 }
0694 
0695 BOOST_AUTO_TEST_CASE(AnyTake) {
0696   // take() moves value out and leaves Any empty
0697   {
0698     Any a{42};
0699     BOOST_CHECK(!!a);
0700     int val = a.take<int>();
0701     BOOST_CHECK_EQUAL(val, 42);
0702     BOOST_CHECK(!a);
0703   }
0704 
0705   // take() with move-only type
0706   {
0707     auto ptr = std::make_unique<int>(99);
0708     Acts::AnyMoveOnly a{std::move(ptr)};
0709     BOOST_CHECK(!!a);
0710     auto taken = a.take<std::unique_ptr<int>>();
0711     BOOST_REQUIRE_NE(taken.get(), nullptr);
0712     BOOST_CHECK_EQUAL(*taken, 99);
0713     BOOST_CHECK(!a);
0714   }
0715 
0716   // take() throws on wrong type
0717   {
0718     Any a{42};
0719     BOOST_CHECK_THROW(a.take<float>(), std::bad_any_cast);
0720     BOOST_CHECK(!!a);
0721     BOOST_CHECK_EQUAL(a.as<int>(), 42);
0722   }
0723 
0724   // take() throws on empty
0725   {
0726     Any a;
0727     BOOST_CHECK_THROW(a.take<int>(), std::bad_any_cast);
0728   }
0729 }
0730 
0731 BOOST_AUTO_TEST_SUITE_END()
0732 
0733 }  // namespace ActsTests