#ifndef SCAN_DATA_CACHE_H #define SCAN_DATA_CACHE_H #include #include #include #include #include #include #include #include #include #include #include "VZNL_Types.h" /** * Owns all laser lines produced by a scan. SDK callbacks only copy a line * and try to enqueue it; they never wait for the consumer or the disk. */ class ScanDataCache { public: using ScanId = std::uint64_t; using Data = std::vector>; ScanDataCache(); ~ScanDataCache(); ScanDataCache(const ScanDataCache&) = delete; ScanDataCache& operator=(const ScanDataCache&) = delete; void BeginScan(ScanId scanId); bool TryEnqueue(ScanId scanId, int cameraIndex, EVzResultDataType dataType, const SVzLaserLineData& line); void FinishCamera(ScanId scanId, int cameraIndex); // Moves a fully received camera buffer to the caller. Returns false when // the scan is not finished yet or the buffer has no data. bool TryTakeCompleted(ScanId scanId, int cameraIndex, Data& data); void Restore(ScanId scanId, int cameraIndex, Data&& data); // Used by debug-file input, which is already a complete scan. void ReplaceCompleted(ScanId scanId, int cameraIndex, Data&& data); void SetLineObserver(std::function observer); void SetReadyNotifier(std::function notifier); bool CopyData(ScanId scanId, int cameraIndex, Data& data) const; bool HasData(ScanId scanId, int cameraIndex) const; bool IsCompleted(ScanId scanId, int cameraIndex) const; bool IsIncomplete(ScanId scanId, int cameraIndex) const; std::size_t Size(ScanId scanId, int cameraIndex) const; void CancelScan(ScanId scanId); void Clear(); void Drain(); void Stop(); private: struct QueueItem { ScanId scanId = 0; int cameraIndex = 0; EVzResultDataType dataType{}; SVzLaserLineData line{}; std::size_t bytes = 0; }; struct CameraBuffer { Data data; std::size_t pending = 0; bool finishRequested = false; bool completed = false; bool incomplete = false; }; using CameraKey = std::pair; void WorkerLoop(); static bool CopyLine(EVzResultDataType dataType, const SVzLaserLineData& source, SVzLaserLineData& destination); static void FreeLine(EVzResultDataType dataType, SVzLaserLineData& line); static void FreeData(Data& data); mutable std::mutex m_stateMutex; std::map m_buffers; std::function m_lineObserver; std::function m_readyNotifier; // The SDK callback only holds these locks for the queue/state update. It // never waits for the consumer, the algorithm, or disk I/O. std::mutex m_queueMutex; std::condition_variable m_queueCondition; // The scan buffer is the source of truth and must not drop valid lines at // an arbitrary byte threshold. The queue is drained by the worker; actual // memory availability is the only general limit. std::deque m_queue; std::size_t m_queuedBytes = 0; std::size_t m_inFlight = 0; std::atomic m_running{true}; std::thread m_worker; }; #endif