Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-13 07:34:46

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 #pragma once
0010 
0011 #include "Acts/Utilities/HashedString.hpp"
0012 
0013 #include <algorithm>
0014 #include <any>
0015 #include <array>
0016 #include <cassert>
0017 #include <cstddef>
0018 #include <type_traits>
0019 #include <typeinfo>
0020 #include <utility>
0021 
0022 // #define _ACTS_ANY_ENABLE_VERBOSE
0023 // #define _ACTS_ANY_ENABLE_DEBUG
0024 // #define _ACTS_ANY_ENABLE_TRACK_ALLOCATIONS
0025 
0026 #if defined(_ACTS_ANY_ENABLE_TRACK_ALLOCATIONS)
0027 #include <iostream>
0028 #include <mutex>
0029 #include <set>
0030 #include <typeindex>
0031 #endif
0032 
0033 #if defined(_ACTS_ANY_ENABLE_VERBOSE) || defined(_ACTS_ANY_ENABLE_DEBUG)
0034 #include <iomanip>
0035 #include <iostream>
0036 #endif
0037 
0038 #if defined(_ACTS_ANY_ENABLE_DEBUG)
0039 #define _ACTS_ANY_DEBUG(x) std::cout << x << std::endl;
0040 #else
0041 #define _ACTS_ANY_DEBUG(x)
0042 #endif
0043 
0044 #if defined(_ACTS_ANY_ENABLE_VERBOSE)
0045 #define _ACTS_ANY_VERBOSE(x) std::cout << x << std::endl;
0046 #define _ACTS_ANY_VERBOSE_BUFFER(s, b)              \
0047   do {                                              \
0048     std::cout << "" << s << ": 0x";                 \
0049     for (char c : b) {                              \
0050       std::cout << std::hex << static_cast<int>(c); \
0051     }                                               \
0052     std::cout << std::endl;                         \
0053   } while (0)
0054 #else
0055 #define _ACTS_ANY_VERBOSE(x)
0056 #define _ACTS_ANY_VERBOSE_BUFFER(s, b)
0057 #endif
0058 
0059 namespace Acts {
0060 
0061 namespace detail {
0062 #if defined(_ACTS_ANY_ENABLE_TRACK_ALLOCATIONS)
0063 static std::mutex _s_any_mutex;
0064 static std::set<std::pair<std::type_index, void*>> _s_any_allocations;
0065 
0066 #define _ACTS_ANY_TRACK_ALLOCATION(T, heap)                                  \
0067   do {                                                                       \
0068     std::lock_guard guard{detail::_s_any_mutex};                             \
0069     detail::_s_any_allocations.emplace(std::type_index(typeid(T)), heap);    \
0070     _ACTS_ANY_DEBUG("Allocate type: " << typeid(T).name() << " at " << heap) \
0071   } while (0)
0072 
0073 #define _ACTS_ANY_TRACK_DEALLOCATION(T, heap)                           \
0074   do {                                                                  \
0075     std::lock_guard guard{detail::_s_any_mutex};                        \
0076     auto it = detail::_s_any_allocations.find(                          \
0077         std::pair{std::type_index(typeid(T)), heap});                   \
0078     if (it == detail::_s_any_allocations.end()) {                       \
0079       throw std::runtime_error{                                         \
0080           "Trying to deallocate heap address that we didn't allocate"}; \
0081     }                                                                   \
0082     detail::_s_any_allocations.erase(it);                               \
0083   } while (0)
0084 
0085 // Do not make member functions noexcept in the debug case
0086 static constexpr bool kAnyNoexcept = false;
0087 
0088 struct _AnyAllocationReporter {
0089   static void checkAllocations() {
0090     std::lock_guard guard{detail::_s_any_mutex};
0091 
0092     if (!detail::_s_any_allocations.empty()) {
0093       std::cout << "Not all allocations have been released" << std::endl;
0094       for (const auto& [idx, addr] : detail::_s_any_allocations) {
0095         std::cout << "- " << idx.name() << ": " << addr << std::endl;
0096       }
0097       throw std::runtime_error{"AnyCheckAllocations failed"};
0098     }
0099   }
0100 
0101   ~_AnyAllocationReporter() noexcept { checkAllocations(); }
0102 };
0103 static _AnyAllocationReporter s_reporter;
0104 #else
0105 #define _ACTS_ANY_TRACK_ALLOCATION(T, heap) \
0106   do {                                      \
0107   } while (0)
0108 #define _ACTS_ANY_TRACK_DEALLOCATION(T, heap) \
0109   do {                                        \
0110   } while (0)
0111 static constexpr bool kAnyNoexcept = true;
0112 #endif
0113 }  // namespace detail
0114 
0115 /// @addtogroup utilities
0116 /// @{
0117 
0118 /// Base class for all instances of @ref AnyBase regarfless of SBO size
0119 class AnyBaseAll {};
0120 
0121 /// Small opaque type-erased type with configurable small buffer optimization
0122 ///
0123 /// @tparam sb_size Size of the internal buffer for small buffer optimization
0124 /// @tparam copyable If true, stored types must be copyable and AnyBase is
0125 ///         copyable. If false, move-only types are allowed and AnyBase is
0126 ///         move-only (copy constructor and copy assignment are deleted).
0127 ///
0128 /// @note
0129 /// Type requirements when copyable is true:
0130 /// - All stored types must be copy constructible and copy assignable.
0131 /// - Types stored locally (`sizeof(T) <= sb_size`) must also be move
0132 /// constructible
0133 ///   and move assignable because local moves use move operations when not
0134 ///   trivially movable (trivial moves fall back to buffer copies).
0135 /// - Types stored on the heap (`sizeof(T) > sb_size`) are moved by stealing the
0136 ///   pointer, so no move operations are required in that case.
0137 ///
0138 /// @note
0139 /// Type requirements when copyable is false:
0140 /// - All stored types must be move constructible.
0141 /// - Types stored locally must also be move assignable.
0142 /// - Heap-allocated types only need move constructible (pointer steal).
0143 ///
0144 /// @note
0145 /// In summary:
0146 /// - Local storage: values live inside the internal buffer; moves may invoke
0147 ///   move operations or buffer copies; copies use copy operations or buffer
0148 ///   copies when trivial.
0149 /// - Heap storage: values are allocated on the heap; moves transfer ownership
0150 ///   of the pointer; copies allocate and copy-construct the pointee.
0151 template <std::size_t sb_size, bool copyable = true>
0152 class AnyBase : public AnyBaseAll {
0153   static_assert(sizeof(void*) <= sb_size, "Size is too small for a pointer");
0154 
0155   /// Type trait: T is storable when copyable requires copy+move, else
0156   /// move-only.
0157   /// @tparam U Type to check
0158   /// @return True if the type is storable, false otherwise
0159   template <typename U>
0160   static constexpr bool isStorable() {
0161     if constexpr (std::is_base_of_v<AnyBaseAll, U>) {
0162       return false;
0163     } else if constexpr (copyable) {
0164       return std::is_copy_assignable_v<U> && std::is_copy_constructible_v<U> &&
0165              (sizeof(U) > sb_size || (std::is_move_assignable_v<U> &&
0166                                       std::is_move_constructible_v<U>));
0167     } else {
0168       return std::is_move_constructible_v<U> &&
0169              (sizeof(U) > sb_size || std::is_move_assignable_v<U>);
0170     }
0171   }
0172 
0173  public:
0174   /// Construct with in-place type construction
0175   /// @tparam T Type to construct
0176   /// @tparam Args Constructor argument types
0177   /// @param args Arguments to forward to T's constructor
0178   template <typename T, typename... Args>
0179     requires(isStorable<std::decay_t<T>>())
0180   explicit AnyBase(std::in_place_type_t<T> /*unused*/, Args&&... args) {
0181     using U = std::decay_t<T>;
0182     m_handler = makeHandler<U>();
0183     constructValue<U>(std::forward<Args>(args)...);
0184   }
0185 
0186 #if defined(_ACTS_ANY_ENABLE_VERBOSE)
0187   AnyBase() { _ACTS_ANY_VERBOSE("Default construct this=" << this); };
0188 #else
0189   AnyBase() = default;
0190 #endif
0191 
0192   /// Construct from any value type
0193   /// @tparam T Type of the value to store
0194   /// @param value Value to store in the Any
0195   template <typename T>
0196   explicit AnyBase(T&& value) noexcept(detail::kAnyNoexcept)
0197     requires(isStorable<std::decay_t<T>>())
0198       : AnyBase{std::in_place_type<T>, std::forward<T>(value)} {}
0199 
0200   /// Construct a new value in place, destroying any existing value
0201   /// @tparam T Type to construct
0202   /// @tparam Args Constructor argument types
0203   /// @param args Arguments to forward to T's constructor
0204   /// @return Reference to the newly constructed value
0205   template <typename T, typename... Args>
0206     requires(isStorable<std::decay_t<T>>())
0207   T& emplace(Args&&... args) {
0208     using U = std::decay_t<T>;
0209     destroy();
0210     m_handler = makeHandler<U>();
0211     return *constructValue<U>(std::forward<Args>(args)...);
0212   }
0213 
0214   /// Get reference to stored value of specified type
0215   /// @tparam T Type to retrieve (must be exact type, no const/ref)
0216   /// @return Reference to the stored value
0217   /// @throws std::bad_any_cast if stored type doesn't match T
0218   template <typename T>
0219   T& as() {
0220     static_assert(std::is_same_v<T, std::decay_t<T>>,
0221                   "Please pass the raw type, no const or ref");
0222     if (m_handler == nullptr || m_handler->typeHash != typeHash<T>()) {
0223       throw std::bad_any_cast{};
0224     }
0225 
0226     _ACTS_ANY_VERBOSE("Get as "
0227                       << (m_handler->heapAllocated ? "heap" : "local"));
0228 
0229     return *std::bit_cast<T*>(dataPtr());
0230   }
0231 
0232   /// Get const reference to stored value of specified type
0233   /// @tparam T Type to retrieve (must be exact type, no const/ref)
0234   /// @return Const reference to the stored value
0235   /// @throws std::bad_any_cast if stored type doesn't match T
0236   template <typename T>
0237   const T& as() const {
0238     static_assert(std::is_same_v<T, std::decay_t<T>>,
0239                   "Please pass the raw type, no const or ref");
0240     if (m_handler == nullptr || m_handler->typeHash != typeHash<T>()) {
0241       throw std::bad_any_cast{};
0242     }
0243 
0244     _ACTS_ANY_VERBOSE("Get as "
0245                       << (m_handler->heapAllocated ? "heap" : "local"));
0246 
0247     return *std::bit_cast<const T*>(dataPtr());
0248   }
0249 
0250   /// Get pointer to stored value of specified type
0251   /// @tparam T Type to retrieve (must be exact type, no const/ref)
0252   /// @return Pointer to the stored value, or nullptr if the type doesn't match
0253   ///         or the Any is empty
0254   template <typename T>
0255   T* asPtr() {
0256     static_assert(std::is_same_v<T, std::decay_t<T>>,
0257                   "Please pass the raw type, no const or ref");
0258     if (m_handler == nullptr || m_handler->typeHash != typeHash<T>()) {
0259       return nullptr;
0260     }
0261     return std::bit_cast<T*>(dataPtr());
0262   }
0263 
0264   /// Get const pointer to stored value of specified type
0265   /// @tparam T Type to retrieve (must be exact type, no const/ref)
0266   /// @return Const pointer to the stored value, or nullptr if the type doesn't
0267   ///         match or the Any is empty
0268   template <typename T>
0269   const T* asPtr() const {
0270     static_assert(std::is_same_v<T, std::decay_t<T>>,
0271                   "Please pass the raw type, no const or ref");
0272     if (m_handler == nullptr || m_handler->typeHash != typeHash<T>()) {
0273       return nullptr;
0274     }
0275     return std::bit_cast<const T*>(dataPtr());
0276   }
0277 
0278   /// Move the stored value out. Leaves this Any empty.
0279   /// @tparam T Type to retrieve (must be exact type, no const/ref)
0280   /// @return The moved-out value
0281   /// @throws std::bad_any_cast if stored type doesn't match T or Any is empty
0282   template <typename T>
0283   T take() {
0284     static_assert(std::is_same_v<T, std::decay_t<T>>,
0285                   "Please pass the raw type, no const or ref");
0286     if (m_handler == nullptr || m_handler->typeHash != typeHash<T>()) {
0287       throw std::bad_any_cast{};
0288     }
0289     T* ptr = std::bit_cast<T*>(dataPtr());
0290     T value = std::move(*ptr);
0291     destroy();
0292     return value;
0293   }
0294 
0295   ~AnyBase() { destroy(); }
0296 
0297   /// Copy constructor (only when copyable is true)
0298   /// @param other The AnyBase to copy from
0299   AnyBase(const AnyBase& other) noexcept(detail::kAnyNoexcept)
0300     requires copyable
0301   {
0302     if (m_handler == nullptr && other.m_handler == nullptr) {
0303       // both are empty, noop
0304       return;
0305     }
0306 
0307     _ACTS_ANY_VERBOSE("Copy construct (this="
0308                       << this << ") at: " << static_cast<void*>(m_data.data()));
0309 
0310     m_handler = other.m_handler;
0311     copyConstruct(other);
0312   }
0313 
0314   /// Copy constructor deleted when copyable is false (move-only variant)
0315   AnyBase(const AnyBase&)
0316     requires(!copyable)
0317   = delete;
0318 
0319   /// Copy assignment operator (only when copyable is true)
0320   /// @param other The AnyBase to copy from
0321   /// @return Reference to this object
0322   AnyBase& operator=(const AnyBase& other) noexcept(detail::kAnyNoexcept)
0323     requires copyable
0324   {
0325     _ACTS_ANY_VERBOSE("Copy assign (this="
0326                       << this << ") at: " << static_cast<void*>(m_data.data()));
0327 
0328     if (m_handler == nullptr && other.m_handler == nullptr) {
0329       // both are empty, noop
0330       return *this;
0331     }
0332 
0333     if (m_handler == other.m_handler) {
0334       // same type, but checked before they're not both nullptr
0335       copy(other);
0336     } else {
0337       if (m_handler != nullptr) {
0338         // this object is not empty, but have different types => destroy
0339         destroy();
0340       }
0341       assert(m_handler == nullptr);
0342       m_handler = other.m_handler;
0343       copyConstruct(other);
0344     }
0345     return *this;
0346   }
0347 
0348   /// Copy assignment deleted when copyable is false (move-only variant)
0349   AnyBase& operator=(const AnyBase&)
0350     requires(!copyable)
0351   = delete;
0352 
0353   /// Move constructor
0354   /// @param other The AnyBase to move from
0355   AnyBase(AnyBase&& other) noexcept(detail::kAnyNoexcept) {
0356     _ACTS_ANY_VERBOSE("Move construct (this="
0357                       << this << ") at: " << static_cast<void*>(m_data.data()));
0358     if (m_handler == nullptr && other.m_handler == nullptr) {
0359       // both are empty, noop
0360       return;
0361     }
0362 
0363     m_handler = other.m_handler;
0364     moveConstruct(std::move(other));
0365   }
0366 
0367   /// Move assignment operator
0368   /// @param other The AnyBase to move from
0369   /// @return Reference to this object
0370   AnyBase& operator=(AnyBase&& other) noexcept(detail::kAnyNoexcept) {
0371     _ACTS_ANY_VERBOSE("Move assign (this="
0372                       << this << ") at: " << static_cast<void*>(m_data.data()));
0373     if (m_handler == nullptr && other.m_handler == nullptr) {
0374       // both are empty, noop
0375       return *this;
0376     }
0377 
0378     // At this point they can't be equal and nullptr, so it's safe to
0379     // dereference
0380     if (m_handler == other.m_handler &&
0381         m_handler->typeHash == other.m_handler->typeHash) {
0382       // same type, but checked before they're not both nullptr
0383       move(std::move(other));
0384     } else {
0385       if (m_handler != nullptr) {
0386         // this object is not empty, but have different types => destroy
0387         destroy();
0388       }
0389       assert(m_handler == nullptr);
0390       m_handler = other.m_handler;
0391       moveConstruct(std::move(other));
0392     }
0393 
0394     return *this;
0395   }
0396 
0397   /// Check if the AnyBase contains a value
0398   /// @return True if a value is stored, false if empty
0399   explicit operator bool() const { return m_handler != nullptr; }
0400 
0401   /// Type info of the stored value. Returns nullptr if empty.
0402   /// @return Pointer to the type info of the stored value, or nullptr if empty
0403   const std::type_info* typeInfo() const {
0404     return m_handler != nullptr ? m_handler->typeInfo : nullptr;
0405   }
0406 
0407  private:
0408   void* dataPtr() {
0409     if (m_handler->heapAllocated) {
0410       return *std::bit_cast<void**>(m_data.data());
0411     } else {
0412       return std::bit_cast<void*>(m_data.data());
0413     }
0414   }
0415 
0416   void setDataPtr(void* ptr) { *std::bit_cast<void**>(m_data.data()) = ptr; }
0417 
0418   const void* dataPtr() const {
0419     if (m_handler->heapAllocated) {
0420       return *std::bit_cast<void* const*>(m_data.data());
0421     } else {
0422       return std::bit_cast<const void*>(m_data.data());
0423     }
0424   }
0425 
0426   struct Handler {
0427     void (*destroy)(void* ptr) = nullptr;
0428     void (*moveConstruct)(void* from, void* to) = nullptr;
0429     void (*move)(void* from, void* to) = nullptr;
0430     void* (*copyConstruct)(const void* from, void* to) = nullptr;
0431     void (*copy)(const void* from, void* to) = nullptr;
0432     bool heapAllocated{false};
0433     std::uint64_t typeHash{0};
0434     const std::type_info* typeInfo{nullptr};
0435   };
0436 
0437   template <typename T>
0438   static const Handler* makeHandler() {
0439     static_assert(!std::is_base_of_v<AnyBaseAll, std::decay_t<T>>,
0440                   "Cannot wrap Any in Any");
0441     static const Handler static_handler = []() {
0442       Handler h;
0443       h.heapAllocated = heapAllocated<T>();
0444       if constexpr (!std::is_trivially_destructible_v<T> ||
0445                     heapAllocated<T>()) {
0446         h.destroy = &destroyImpl<T>;
0447       }
0448       if constexpr (!heapAllocated<T>() &&
0449                     !std::is_trivially_move_constructible_v<T>) {
0450         h.moveConstruct = &moveConstructImpl<T>;
0451       }
0452       if constexpr (!heapAllocated<T>() &&
0453                     !std::is_trivially_move_assignable_v<T>) {
0454         h.move = &moveImpl<T>;
0455       }
0456       if constexpr (std::is_copy_constructible_v<T> &&
0457                     (!std::is_trivially_copy_constructible_v<T> ||
0458                      heapAllocated<T>())) {
0459         h.copyConstruct = &copyConstructImpl<T>;
0460       }
0461 
0462       if constexpr (std::is_copy_assignable_v<T> &&
0463                     (!std::is_trivially_copy_assignable_v<T> ||
0464                      heapAllocated<T>())) {
0465         h.copy = &copyImpl<T>;
0466       }
0467 
0468       h.typeHash = typeHash<T>();
0469       h.typeInfo = &typeid(T);
0470 
0471       _ACTS_ANY_DEBUG("Type: " << typeid(T).name());
0472       _ACTS_ANY_DEBUG(" -> destroy: " << h.destroy);
0473       _ACTS_ANY_DEBUG(" -> moveConstruct: " << h.moveConstruct);
0474       _ACTS_ANY_DEBUG(" -> move: " << h.move);
0475       _ACTS_ANY_DEBUG(" -> copyConstruct: " << h.copyConstruct);
0476       _ACTS_ANY_DEBUG(" -> copy: " << h.copy);
0477       _ACTS_ANY_DEBUG(
0478           " -> heapAllocated: " << (h.heapAllocated ? "yes" : "no"));
0479 
0480       return h;
0481     }();
0482     return &static_handler;
0483   }
0484 
0485   template <typename T>
0486   static constexpr bool heapAllocated() {
0487     return sizeof(T) > sb_size;
0488   }
0489 
0490   template <typename T, typename... Args>
0491   T* constructValue(Args&&... args) {
0492     if constexpr (!heapAllocated<T>()) {
0493       // construct into local buffer
0494       auto* ptr = new (m_data.data()) T(std::forward<Args>(args)...);
0495       _ACTS_ANY_VERBOSE("Construct local (this="
0496                         << this
0497                         << ") at: " << static_cast<void*>(m_data.data()));
0498       return ptr;
0499     } else {
0500       // too large, heap allocate
0501       auto* heap = new T(std::forward<Args>(args)...);
0502       _ACTS_ANY_DEBUG("Allocate type: " << typeid(T).name() << " at " << heap);
0503       _ACTS_ANY_TRACK_ALLOCATION(T, heap);
0504       setDataPtr(heap);
0505       return heap;
0506     }
0507   }
0508 
0509   void destroy() {
0510     _ACTS_ANY_VERBOSE("Destructor this=" << this << " handler: " << m_handler);
0511     if (m_handler != nullptr && m_handler->destroy != nullptr) {
0512       _ACTS_ANY_VERBOSE("Non-trivial destruction");
0513       m_handler->destroy(dataPtr());
0514     }
0515     m_handler = nullptr;
0516   }
0517 
0518   void moveConstruct(AnyBase&& fromAny) {
0519     if (m_handler == nullptr) {
0520       return;
0521     }
0522 
0523     void* to = dataPtr();
0524     void* from = fromAny.dataPtr();
0525     if (m_handler->heapAllocated) {
0526       // stored on heap: just copy the pointer
0527       setDataPtr(fromAny.dataPtr());
0528       // do not delete in moved-from any
0529       fromAny.m_handler = nullptr;
0530       return;
0531     }
0532 
0533     if (m_handler->moveConstruct == nullptr) {
0534       _ACTS_ANY_VERBOSE("Trivially move construct");
0535       // trivially move constructible
0536       m_data = std::move(fromAny.m_data);
0537     } else {
0538       m_handler->moveConstruct(from, to);
0539     }
0540   }
0541 
0542   void move(AnyBase&& fromAny) {
0543     if (m_handler == nullptr) {
0544       return;
0545     }
0546 
0547     void* to = dataPtr();
0548     void* from = fromAny.dataPtr();
0549     if (m_handler->heapAllocated) {
0550       // stored on heap: just copy the pointer
0551       // need to delete existing pointer
0552       m_handler->destroy(dataPtr());
0553       setDataPtr(fromAny.dataPtr());
0554       // do not delete in moved-from any
0555       fromAny.m_handler = nullptr;
0556       return;
0557     }
0558 
0559     if (m_handler->move == nullptr) {
0560       _ACTS_ANY_VERBOSE("Trivially move");
0561       // trivially movable
0562       m_data = std::move(fromAny.m_data);
0563     } else {
0564       m_handler->move(from, to);
0565     }
0566   }
0567 
0568   void copyConstruct(const AnyBase& fromAny) {
0569     if (m_handler == nullptr) {
0570       return;
0571     }
0572 
0573     void* to = dataPtr();
0574     const void* from = fromAny.dataPtr();
0575 
0576     if (m_handler->copyConstruct == nullptr) {
0577       _ACTS_ANY_VERBOSE("Trivially copy construct");
0578       // trivially copy constructible
0579       m_data = fromAny.m_data;
0580     } else {
0581       void* copyAt = m_handler->copyConstruct(from, to);
0582       if (to == nullptr) {
0583         assert(copyAt != nullptr);
0584         // copy allocated, store pointer
0585         setDataPtr(copyAt);
0586       }
0587     }
0588   }
0589 
0590   void copy(const AnyBase& fromAny) {
0591     if (m_handler == nullptr) {
0592       return;
0593     }
0594 
0595     void* to = dataPtr();
0596     const void* from = fromAny.dataPtr();
0597 
0598     if (m_handler->copy == nullptr) {
0599       _ACTS_ANY_VERBOSE("Trivially copy");
0600       // trivially copyable
0601       m_data = fromAny.m_data;
0602     } else {
0603       m_handler->copy(from, to);
0604     }
0605   }
0606 
0607   template <typename T>
0608   static void destroyImpl(void* ptr) {
0609     assert(ptr != nullptr && "Address to destroy is nullptr");
0610     auto* obj = static_cast<T*>(ptr);
0611     if constexpr (!heapAllocated<T>()) {
0612       // stored in place: just call the destructor
0613       _ACTS_ANY_VERBOSE("Destroy local at: " << ptr);
0614       obj->~T();
0615     } else {
0616       // stored on heap: delete
0617       _ACTS_ANY_DEBUG("Delete type: " << typeid(T).name()
0618                                       << " heap at: " << obj);
0619       _ACTS_ANY_TRACK_DEALLOCATION(T, obj);
0620       delete obj;
0621     }
0622   }
0623 
0624   template <typename T>
0625   static void moveConstructImpl(void* from, void* to) {
0626     _ACTS_ANY_VERBOSE("move const: " << from << " -> " << to);
0627     assert(from != nullptr && "Source is null");
0628     assert(to != nullptr && "Target is null");
0629     auto* _from = static_cast<T*>(from);
0630     /*T* ptr =*/new (to) T(std::move(*_from));
0631   }
0632 
0633   template <typename T>
0634   static void moveImpl(void* from, void* to) {
0635     _ACTS_ANY_VERBOSE("move: " << from << " -> " << to);
0636     assert(from != nullptr && "Source is null");
0637     assert(to != nullptr && "Target is null");
0638 
0639     auto* _from = static_cast<T*>(from);
0640     auto* _to = static_cast<T*>(to);
0641 
0642     (*_to) = std::move(*_from);
0643   }
0644 
0645   template <typename T>
0646   static void* copyConstructImpl(const void* from, void* to) {
0647     _ACTS_ANY_VERBOSE("copy const: " << from << " -> " << to);
0648     assert(from != nullptr && "Source is null");
0649     const auto* _from = static_cast<const T*>(from);
0650     if (to == nullptr) {
0651       assert(heapAllocated<T>() && "Received nullptr in local buffer case");
0652       to = new T(*_from);
0653       _ACTS_ANY_TRACK_ALLOCATION(T, to);
0654 
0655     } else {
0656       assert(!heapAllocated<T>() && "Received non-nullptr in heap case");
0657       /*T* ptr =*/new (to) T(*_from);
0658     }
0659     return to;
0660   }
0661 
0662   template <typename T>
0663   static void copyImpl(const void* from, void* to) {
0664     _ACTS_ANY_VERBOSE("copy: " << from << " -> " << to);
0665     assert(from != nullptr && "Source is null");
0666     assert(to != nullptr && "Target is null");
0667 
0668     const auto* _from = static_cast<const T*>(from);
0669     auto* _to = static_cast<T*>(to);
0670 
0671     (*_to) = *_from;
0672   }
0673 
0674   static constexpr std::size_t kMaxAlignment =
0675       std::max(alignof(std::max_align_t),
0676 #if defined(__AVX512F__)
0677                std::size_t{64}
0678 #elif defined(__AVX__)
0679                std::size_t{32}
0680 #elif defined(__SSE__)
0681                std::size_t{16}
0682 #else
0683                std::size_t{0}
0684   // Neutral element
0685   // for maximum
0686 #endif
0687       );
0688 
0689   alignas(kMaxAlignment) std::array<std::byte, sb_size> m_data{};
0690   const Handler* m_handler{nullptr};
0691 };
0692 
0693 /// @brief A type-safe container for single values of any type
0694 /// @details This is a custom implementation similar to `std::any` but optimized for small types
0695 ///          that can fit into a pointer-sized buffer. Values larger than a
0696 ///          pointer are stored on the heap.
0697 using Any = AnyBase<sizeof(void*), true>;
0698 
0699 /// @brief Move-only variant that can store move-only types (e.g. std::unique_ptr)
0700 /// @details Same as Any but copy constructor and copy assignment are deleted.
0701 ///          Use when storing types that are not copyable.
0702 using AnyMoveOnly = AnyBase<sizeof(void*), false>;
0703 
0704 /// @}
0705 
0706 #undef _ACTS_ANY_VERBOSE
0707 #undef _ACTS_ANY_VERBOSE_BUFFER
0708 #undef _ACTS_ANY_ENABLE_VERBOSE
0709 
0710 }  // namespace Acts