#ifndef memory_hh_INCLUDED #define memory_hh_INCLUDED #include #include #include #include "assert.hh" #include "meta.hh" namespace Kakoune { enum class MemoryDomain { Undefined, String, SharedString, BufferContent, BufferMeta, Options, Highlight, Regions, Display, Mapping, Commands, Hooks, Aliases, EnvVars, Faces, Values, Registers, Client, WordDB, Selections, History, Remote, Events, Completion, Regex, Count }; inline const char* domain_name(MemoryDomain domain) { switch (domain) { case MemoryDomain::Undefined: return "Undefined"; case MemoryDomain::String: return "String"; case MemoryDomain::SharedString: return "SharedString"; case MemoryDomain::BufferContent: return "BufferContent"; case MemoryDomain::BufferMeta: return "BufferMeta"; case MemoryDomain::Options: return "Options"; case MemoryDomain::Highlight: return "Highlight"; case MemoryDomain::Regions: return "Regions"; case MemoryDomain::Display: return "Display"; case MemoryDomain::Mapping: return "Mapping"; case MemoryDomain::Commands: return "Commands"; case MemoryDomain::Hooks: return "Hooks"; case MemoryDomain::WordDB: return "WordDB"; case MemoryDomain::Aliases: return "Aliases"; case MemoryDomain::EnvVars: return "EnvVars"; case MemoryDomain::Faces: return "Faces"; case MemoryDomain::Values: return "Values"; case MemoryDomain::Registers: return "Registers"; case MemoryDomain::Client: return "Client"; case MemoryDomain::Selections: return "Selections"; case MemoryDomain::History: return "History"; case MemoryDomain::Remote: return "Remote"; case MemoryDomain::Events: return "Events"; case MemoryDomain::Completion: return "Completion"; case MemoryDomain::Regex: return "Regex"; case MemoryDomain::Count: break; } kak_assert(false); return ""; } struct MemoryStats { size_t allocated_bytes; size_t allocation_count; size_t total_allocation_count; }; extern MemoryStats memory_stats[(size_t)MemoryDomain::Count]; inline void on_alloc(MemoryDomain domain, size_t size) { auto& stats = memory_stats[(int)domain]; stats.allocated_bytes += size; ++stats.allocation_count; ++stats.total_allocation_count; } inline void on_dealloc(MemoryDomain domain, size_t size) { auto& stats = memory_stats[(int)domain]; kak_assert(stats.allocated_bytes >= size); stats.allocated_bytes -= size; --stats.allocation_count; } template struct Allocator { using value_type = T; Allocator() = default; template Allocator(const Allocator&) {} template struct rebind { using other = Allocator; }; T* allocate(size_t n) { size_t size = sizeof(T) * n; on_alloc(domain, size); return reinterpret_cast(::operator new(size)); } void deallocate(T* ptr, size_t n) { size_t size = sizeof(T) * n; on_dealloc(domain, size); ::operator delete(ptr); } }; template constexpr bool operator==(const Allocator&, const Allocator&) { return d1 == d2; } template constexpr bool operator!=(const Allocator&, const Allocator&) { return d1 != d2; } constexpr MemoryDomain memory_domain(Meta::AnyType) { return MemoryDomain::Undefined; } template constexpr decltype(T::Domain) memory_domain(Meta::Type) { return T::Domain; } template struct UseMemoryDomain { static constexpr MemoryDomain Domain = d; [[gnu::always_inline]] static void* operator new(size_t size) { on_alloc(Domain, size); return ::operator new(size); } [[gnu::always_inline]] static void* operator new[](size_t size) { on_alloc(Domain, size); return ::operator new[](size); } [[gnu::always_inline]] static void* operator new(size_t size, void* ptr) { return ::operator new(size, ptr); } [[gnu::always_inline]] static void operator delete(void* ptr, size_t size) { on_dealloc(Domain, size); ::operator delete(ptr); } [[gnu::always_inline]] static void operator delete[](void* ptr, size_t size) { on_dealloc(Domain, size); ::operator delete[](ptr); } }; } #endif // memory_hh_INCLUDED