/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR. */ using System; using System.Collections.Generic; namespace OmiLAXR.Utils { /// /// Delegate for providing default values when creating new file buffers. /// Used to initialize buffer data when no existing data is available. /// /// Default value object for the new buffer public delegate object DefaultValueHandler(); /// /// Thread-safe manager for multiple file buffers with associated data storage. /// Provides centralized management of file writing operations and buffer lifecycle. /// Each buffer combines a file writer with arbitrary data storage for complex scenarios. /// public class FileBufferManager : IDisposable { /// /// Dictionary mapping buffer IDs to their corresponding FileBuffer instances. /// Thread-safe access is ensured through locking mechanisms. /// public readonly Dictionary FileBuffers = new Dictionary(10); /// /// Represents a single file buffer with associated data and writer. /// Combines file I/O capabilities with flexible data storage. /// public class FileBuffer { /// /// Arbitrary data object associated with this buffer. /// Can store any type of data needed alongside file operations. /// public object Data; /// /// BufferedUtf8Writer instance for efficient file writing operations. /// Handles the actual file I/O with buffering for performance. /// public BufferedUtf8Writer Writer; /// /// Gets the stored data as a specific type with type safety. /// /// Type to cast the data to /// Data cast to the specified type public T GetValue() => (T)Data; /// /// Sets the stored data with type safety. /// /// Type of the value being stored /// Value to store in this buffer public void SetValue(T value) => Data = value; } /// /// Flushes all managed file buffers to ensure data is written to disk. /// Thread-safe operation that processes all buffers atomically. /// public void FlushAll() { lock (FileBuffers) { // Iterate through all buffers and flush their writers foreach (var bufferId in FileBuffers.Keys) { FileBuffers[bufferId].Writer.Flush(); } } } /// /// Flushes a specific file buffer identified by its buffer ID. /// Ensures the specified buffer's data is written to disk immediately. /// /// ID of the buffer to flush public void Flush(int bufferId) { lock (FileBuffers) { FileBuffers[bufferId].Writer.Flush(); } } private readonly Dictionary WritersByPath = new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// Ensures a file buffer exists for the given ID, creating it if necessary. /// Thread-safe creation and retrieval of buffers with optional default data initialization. /// /// Unique identifier for the buffer /// File path for the buffer's writer (used only if creating new buffer) /// Optional delegate to provide default data value for new buffers /// The FileBuffer instance (existing or newly created) public FileBuffer EnsureBuffer(int bufferId, string filePath, DefaultValueHandler fallbackValue = null) { lock (FileBuffers) { // Falls bereits ein Buffer mit dieser ID existiert, zurückgeben if (FileBuffers.TryGetValue(bufferId, out var existingBuffer)) return existingBuffer; // Gibt es bereits einen Writer für diesen Pfad? if (!WritersByPath.TryGetValue(filePath, out var writer)) { writer = new BufferedUtf8Writer(filePath); WritersByPath[filePath] = writer; } var buffer = new FileBuffer { Data = fallbackValue?.Invoke(), Writer = writer }; FileBuffers.Add(bufferId, buffer); return buffer; } } public void DisposeAll() { lock (FileBuffers) { foreach (var writer in WritersByPath.Values) { writer?.Dispose(); } WritersByPath.Clear(); FileBuffers.Clear(); } } /// /// Disposes all managed resources including file writers and buffers. /// Ensures all data is flushed before disposing writers to prevent data loss. /// Thread-safe cleanup operation. /// public void Dispose() { DisposeAll(); lock (FileBuffers) { // Clean up each buffer individually foreach (var buffer in FileBuffers.Values) { // Skip if writer is already disposed if (buffer.Writer == null) continue; // Flush remaining data and dispose writer buffer.Writer.Flush(); buffer.Writer.Dispose(); buffer.Writer = null; } // Clear the dictionary after disposing all buffers FileBuffers.Clear(); } } } }