#pragma once #include #include #include #include namespace grove { // ============================================================================ // Frame Allocator - Lock-free linear allocator, reset each frame // ============================================================================ class FrameAllocator { public: static constexpr size_t DEFAULT_SIZE = 16 * 1024 * 1024; // 16 MB explicit FrameAllocator(size_t size = DEFAULT_SIZE); ~FrameAllocator(); // Non-copyable FrameAllocator(const FrameAllocator&) = delete; FrameAllocator& operator=(const FrameAllocator&) = delete; // Thread-safe, lock-free allocation void* allocate(size_t size, size_t alignment = 16); // Typed allocation with constructor template T* allocate(Args&&... args) { void* ptr = allocate(sizeof(T), alignof(T)); if (!ptr) return nullptr; return new (ptr) T(std::forward(args)...); } // Array allocation template T* allocateArray(size_t count) { void* ptr = allocate(sizeof(T) * count, alignof(T)); if (!ptr) return nullptr; for (size_t i = 0; i < count; ++i) { new (static_cast(ptr) + i) T(); } return static_cast(ptr); } // Reset (called once per frame, single-thread) void reset(); // Stats size_t getUsed() const; size_t getCapacity() const { return m_capacity; } private: uint8_t* m_buffer; size_t m_capacity; std::atomic m_offset; }; } // namespace grove