#include #include #include #include #include #include #include #include #include "../Renderive/base/Memory.h" namespace { struct Callback_State { std::atomic allocation_count{}; std::atomic deallocation_count{}; std::atomic_bool alignment_error{}; std::atomic_bool deallocated_off_main_thread{}; std::thread::id main_thread; }; Callback_State callback_state; void* callback_allocate(void* context, std::size_t size, std::size_t alignment) { auto* state = static_cast(context); void* result{}; try { result = std::pmr::new_delete_resource()->allocate(size, alignment); } catch (...) { return nullptr; } state->allocation_count.fetch_add(1, std::memory_order_relaxed); if (reinterpret_cast(result) % alignment) state->alignment_error.store(true, std::memory_order_relaxed); return result; } void callback_deallocate(void* context, void* address, std::size_t size, std::size_t alignment) { auto* state = static_cast(context); state->deallocation_count.fetch_add(1, std::memory_order_relaxed); if (std::this_thread::get_id() != state->main_thread) state->deallocated_off_main_thread.store(true, std::memory_order_relaxed); std::pmr::new_delete_resource()->deallocate(address, size, alignment); } struct Payload { std::uint64_t value{}; }; struct Large_Payload { std::array data{}; }; } int main() { callback_state.main_thread = std::this_thread::get_id(); renderive::Memory_Callbacks invalid_callbacks; invalid_callbacks.context = &callback_state; invalid_callbacks.allocate = callback_allocate; try { renderive::set_memory_callbacks(invalid_callbacks); return 1; } catch (const std::invalid_argument&) {} invalid_callbacks.allocate = nullptr; invalid_callbacks.deallocate = callback_deallocate; try { renderive::set_memory_callbacks(invalid_callbacks); return 2; } catch (const std::invalid_argument&) {} renderive::Memory_Callbacks callbacks; callbacks.context = &callback_state; callbacks.allocate = callback_allocate; callbacks.deallocate = callback_deallocate; renderive::set_memory_callbacks(callbacks); try { renderive::set_memory_callbacks(callbacks); return 3; } catch (const std::logic_error&) {} { std::pmr::vector values(renderive::memory_resource()); values.resize(8192, 11); auto owner = renderive::make_shared(); auto large_owner = renderive::make_shared(); owner->value = values.front(); std::thread release_thread([owner = std::move(owner), large_owner = std::move(large_owner)]() mutable { owner.reset(); large_owner.reset(); }); release_thread.join(); } renderive::release_unused_memory(); renderive::Memory_Stats stats = renderive::memory_stats(); if (callback_state.alignment_error.load(std::memory_order_relaxed)) return 4; if (!callback_state.allocation_count.load(std::memory_order_relaxed)) return 5; if (stats.upstream_allocation_count != callback_state.allocation_count.load(std::memory_order_relaxed)) return 6; if (!callback_state.deallocation_count.load(std::memory_order_relaxed) || !callback_state.deallocated_off_main_thread.load(std::memory_order_relaxed)) return 7; renderive::shutdown_memory(); if (renderive::memory_stats().upstream_current_bytes) return 8; return 0; }