#pragma once #include #include #include #include #include #include #include #include #include #include // Thread pool that reads files from disk into memory so the main thread can // skip disk I/O and parse directly from RAM. Only covers the binary path // (E3D); text models fall back to synchronous load. class AsyncFilePreloader { public: using Buffer = std::shared_ptr>; AsyncFilePreloader() = default; ~AsyncFilePreloader() { stop(); } AsyncFilePreloader(const AsyncFilePreloader&) = delete; AsyncFilePreloader& operator=(const AsyncFilePreloader&) = delete; // Start N worker threads (clamped to [1, hardware_concurrency]). void start(int thread_count = 0); // Signal workers to stop and join them. Clears the queue but keeps // already-loaded buffers so late callers still get cache hits. void stop(); // Queue a file for background loading. Silently skips duplicates. void queue(std::string path); // Return the preloaded buffer for `path`, or nullptr if not ready yet. // Does NOT block — callers must fall back to synchronous I/O if nullptr. Buffer get(const std::string& path) const; // Drop all cached buffers (call after loading finishes to free memory). void clear(); bool is_running() const { return m_running.load(std::memory_order_relaxed); } private: void worker(); mutable std::mutex m_mutex; std::condition_variable m_cv; std::queue m_pending; std::unordered_set m_queued; // prevents duplicate queuing std::unordered_map m_cache; std::vector m_workers; std::atomic m_running { false }; }; extern AsyncFilePreloader GModelPreloader;