22 #if defined(_ACTS_ANY_ENABLE_TRACK_ALLOCATIONS)
30 #if defined(_ACTS_ANY_ENABLE_VERBOSE) || defined(_ACTS_ANY_ENABLE_DEBUG)
35 #if defined(_ACTS_ANY_ENABLE_DEBUG)
36 #define _ACTS_ANY_DEBUG(x) std::cout << x << std::endl;
38 #define _ACTS_ANY_DEBUG(x)
41 #if defined(_ACTS_ANY_ENABLE_VERBOSE)
42 #define _ACTS_ANY_VERBOSE(x) std::cout << x << std::endl;
43 #define _ACTS_ANY_VERBOSE_BUFFER(s, b) \
45 std::cout << "" << s << ": 0x"; \
47 std::cout << std::hex << (int)c; \
49 std::cout << std::endl; \
52 #define _ACTS_ANY_VERBOSE(x)
53 #define _ACTS_ANY_VERBOSE_BUFFER(s, b)
58 #if defined(_ACTS_ANY_ENABLE_TRACK_ALLOCATIONS)
59 static std::mutex _s_any_mutex;
60 static std::set<std::pair<std::type_index, void*>> _s_any_allocations;
62 #define _ACTS_ANY_TRACK_ALLOCATION(T, heap) \
64 std::lock_guard guard{_s_any_mutex}; \
65 _s_any_allocations.emplace(std::type_index(typeid(T)), heap); \
66 _ACTS_ANY_DEBUG("Allocate type: " << typeid(T).name() << " at " << heap) \
69 #define _ACTS_ANY_TRACK_DEALLOCATION(T, heap) \
71 std::lock_guard guard{_s_any_mutex}; \
73 _s_any_allocations.find(std::pair{std::type_index(typeid(T)), heap}); \
74 if (it == _s_any_allocations.end()) { \
75 throw std::runtime_error{ \
76 "Trying to deallocate heap address that we didn't allocate"}; \
78 _s_any_allocations.erase(it); \
81 struct _AnyAllocationReporter {
82 static void checkAllocations() {
83 std::lock_guard guard{_s_any_mutex};
85 if (!_s_any_allocations.empty()) {
86 std::cout <<
"Not all allocations have been released" << std::endl;
87 for (
const auto& [
idx, addr] : _s_any_allocations) {
88 std::cout <<
"- " <<
idx.name() <<
": " << addr << std::endl;
90 throw std::runtime_error{
"AnyCheckAllocations failed"};
94 ~_AnyAllocationReporter() noexcept { checkAllocations(); }
96 static _AnyAllocationReporter s_reporter;
98 #define _ACTS_ANY_TRACK_ALLOCATION(T, heap) \
101 #define _ACTS_ANY_TRACK_DEALLOCATION(T, heap) \
109 template <
size_t SIZE>
111 static_assert(
sizeof(
void*) <= SIZE,
"Size is too small for a pointer");
114 template <
typename T,
typename...
Args>
116 using U = std::decay_t<T>;
118 std::is_move_assignable_v<U> && std::is_move_constructible_v<U>,
119 "Type needs to be move assignable and move constructible");
121 std::is_copy_assignable_v<U> && std::is_copy_constructible_v<U>,
122 "Type needs to be copy assignable and copy constructible");
125 if constexpr (not heapAllocated<U>()) {
127 new (m_data.data()) U(std::forward<Args>(
args)...);
129 "Construct local (this=" <<
this <<
") at: " << (
void*)m_data.data());
132 U* heap =
new U(std::forward<Args>(
args)...);
138 #if defined(_ACTS_ANY_ENABLE_VERBOSE)
146 template <
typename T,
typename = std::enable_if_t<
147 !std::is_same_v<std::decay_t<T>, AnyBase<SIZE>>>>
149 :
AnyBase{std::in_place_type<T>, std::forward<T>(
value)} {}
151 template <
typename T>
153 static_assert(std::is_same_v<
T, std::decay_t<T>>,
154 "Please pass the raw type, no const or ref");
156 throw std::bad_any_cast{};
160 << (
m_handler->heapAllocated ?
"heap" :
"local"));
162 return *
reinterpret_cast<T*
>(dataPtr());
165 template <
typename T>
166 const T& as()
const {
167 static_assert(std::is_same_v<
T, std::decay_t<T>>,
168 "Please pass the raw type, no const or ref");
170 throw std::bad_any_cast{};
175 return *
reinterpret_cast<const T*
>(dataPtr());
189 "Copy construct (this=" <<
this <<
") at: " << (
void*)m_data.data());
197 <<
") at: " << (
void*)m_data.data());
210 throw std::bad_any_cast{};
219 "Move construct (this=" <<
this <<
") at: " << (
void*)m_data.data());
231 <<
") at: " << (
void*)m_data.data());
243 throw std::bad_any_cast{};
250 operator bool()
const {
257 return *
reinterpret_cast<void**
>(m_data.data());
259 return reinterpret_cast<void*
>(m_data.data());
263 void setDataPtr(
void* ptr) {
264 *
reinterpret_cast<void**
>(m_data.data()) = ptr;
267 const void* dataPtr()
const {
269 return *
reinterpret_cast<void* const*
>(m_data.data());
271 return reinterpret_cast<const void*
>(m_data.data());
276 void (*
destroy)(
void* ptr) =
nullptr;
278 void (*
move)(
void* from,
void* to) =
nullptr;
279 void* (*copyConstruct)(
const void* from,
void* to) =
nullptr;
280 void (*
copy)(
const void* from,
void* to) =
nullptr;
284 template <
typename T>
286 static_assert(!std::is_same_v<
T,
AnyBase<SIZE>>,
"Cannot wrap any in any");
287 static const Handler static_handler = []() {
289 h.heapAllocated = heapAllocated<T>();
290 if constexpr (!std::is_trivially_destructible_v<T> ||
291 heapAllocated<T>()) {
292 h.destroy = &destroyImpl<T>;
294 if constexpr (!std::is_trivially_move_constructible_v<T> ||
295 heapAllocated<T>()) {
296 h.moveConstruct = &moveConstructImpl<T>;
298 if constexpr (!std::is_trivially_move_assignable_v<T> ||
299 heapAllocated<T>()) {
300 h.move = &moveImpl<T>;
302 if constexpr (!std::is_trivially_copy_constructible_v<T> ||
303 heapAllocated<T>()) {
304 h.copyConstruct = ©ConstructImpl<T>;
306 if constexpr (!std::is_trivially_copy_assignable_v<T> ||
307 heapAllocated<T>()) {
308 h.copy = ©Impl<T>;
318 " -> heapAllocated: " << (h.heapAllocated ?
"yes" :
"no"));
322 return &static_handler;
325 template <
typename T>
327 return sizeof(
T) > SIZE;
343 void* to = dataPtr();
344 void* from = fromAny.dataPtr();
347 setDataPtr(fromAny.dataPtr());
349 fromAny.m_handler =
nullptr;
353 if (
m_handler->moveConstruct ==
nullptr) {
366 void* to = dataPtr();
367 void* from = fromAny.dataPtr();
372 setDataPtr(fromAny.dataPtr());
374 fromAny.m_handler =
nullptr;
391 void* to = dataPtr();
392 const void* from = fromAny.dataPtr();
394 if (
m_handler->copyConstruct ==
nullptr) {
396 m_data = fromAny.m_data;
398 void* copyAt =
m_handler->copyConstruct(from, to);
400 assert(copyAt !=
nullptr);
412 void* to = dataPtr();
413 const void* from = fromAny.dataPtr();
417 m_data = fromAny.m_data;
423 template <
typename T>
425 assert(ptr !=
nullptr &&
"Address to destroy is nullptr");
426 T* obj =
static_cast<T*
>(ptr);
427 if constexpr (!heapAllocated<T>()) {
434 <<
" heap at: " << obj);
440 template <
typename T>
443 assert(from !=
nullptr &&
"Source is null");
444 assert(to !=
nullptr &&
"Target is null");
445 T* _from =
static_cast<T*
>(from);
449 template <
typename T>
452 assert(from !=
nullptr &&
"Source is null");
453 assert(to !=
nullptr &&
"Target is null");
455 T* _from =
static_cast<T*
>(from);
456 T* _to =
static_cast<T*
>(to);
461 template <
typename T>
464 assert(from !=
nullptr &&
"Source is null");
465 const T* _from =
static_cast<const T*
>(from);
467 assert(heapAllocated<T>() &&
"Received nullptr in local buffer case");
472 assert(!heapAllocated<T>() &&
"Received non-nullptr in heap case");
478 template <
typename T>
481 assert(from !=
nullptr &&
"Source is null");
482 assert(to !=
nullptr &&
"Target is null");
484 const T* _from =
static_cast<const T*
>(from);
485 T* _to =
static_cast<T*
>(to);
491 #
if defined(__AVX512F__)
493 #elif defined(__AVX__)
495 #elif defined(__SSE__)
509 #undef _ACTS_ANY_VERBOSE
510 #undef _ACTS_ANY_VERBOSE_BUFFER
511 #undef _ACTS_ANY_ENABLE_VERBOSE