#pragma once #include #include #include #include /// Implementation of std::allocator interface that tracks memory with MemoryTracker. /// NOTE We already plug MemoryTracker into new/delete operators. So, everything works even with default allocator. /// But it is enabled only if jemalloc is used (to obtain the size of the allocation on call to delete). /// And jemalloc is disabled for builds with sanitizers. In these cases memory was not always tracked. template struct AllocatorWithMemoryTracking { using value_type = T; AllocatorWithMemoryTracking() = default; template constexpr explicit AllocatorWithMemoryTracking(const AllocatorWithMemoryTracking &) noexcept { } [[nodiscard]] T * allocate(size_t n) { if (n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); size_t bytes = n * sizeof(T); CurrentMemoryTracker::alloc(bytes); T * p = static_cast(malloc(bytes)); if (!p) throw std::bad_alloc(); return p; } void deallocate(T * p, size_t n) noexcept { free(p); size_t bytes = n * sizeof(T); CurrentMemoryTracker::free(bytes); } }; template bool operator==(const AllocatorWithMemoryTracking &, const AllocatorWithMemoryTracking &) { return true; } template bool operator!=(const AllocatorWithMemoryTracking &, const AllocatorWithMemoryTracking &) { return false; }