using System;
using System.Buffers;
using System.Collections.Generic;
using System.Threading;
namespace RGB.NET.Core;
///
/// Represents a generic update queue.
///
/// The type of the key used to identify some data.
/// The type of the data.
public abstract class UpdateQueue : AbstractReferenceCounting, IUpdateQueue
where TIdentifier : notnull
{
#region Properties & Fields
private readonly Lock _dataLock = new();
private readonly IDeviceUpdateTrigger _updateTrigger;
private readonly Dictionary _currentDataSet = [];
///
public bool RequiresFlush { get; private set; }
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The causing this queue to update.
protected UpdateQueue(IDeviceUpdateTrigger updateTrigger)
{
this._updateTrigger = updateTrigger;
_updateTrigger.Starting += OnStartup;
_updateTrigger.Update += OnUpdate;
}
#endregion
#region Methods
///
/// Event handler for the -event.
///
/// The causing this update.
/// provided by the trigger.
protected virtual void OnUpdate(object? sender, CustomUpdateData customData)
{
(TIdentifier, TData)[] dataSet;
Span<(TIdentifier, TData)> data;
lock (_dataLock)
{
if (_currentDataSet.Count == 0) return;
dataSet = ArrayPool<(TIdentifier, TData)>.Shared.Rent(_currentDataSet.Count);
data = new Span<(TIdentifier, TData)>(dataSet)[.._currentDataSet.Count];
int i = 0;
foreach ((TIdentifier key, TData value) in _currentDataSet)
data[i++] = (key, value);
_currentDataSet.Clear();
}
RequiresFlush = !Update(data);
ArrayPool<(TIdentifier, TData)>.Shared.Return(dataSet);
}
///
/// Event handler for the -event.
///
/// The starting .
/// provided by the trigger.
protected virtual void OnStartup(object? sender, CustomUpdateData customData) { }
///
/// Performs the update this queue is responsible for.
///
/// The set of data that needs to be updated.
protected abstract bool Update(ReadOnlySpan<(TIdentifier key, TData color)> dataSet);
///
/// Sets or merges the provided data set in the current dataset and notifies the trigger that there is new data available.
///
/// The set of data.
// ReSharper disable once MemberCanBeProtected.Global
public virtual void SetData(ReadOnlySpan<(TIdentifier, TData)> data)
{
if (data.Length == 0) return;
lock (_dataLock)
{
foreach ((TIdentifier key, TData value) in data)
_currentDataSet[key] = value;
}
_updateTrigger.TriggerHasData();
}
///
/// Resets the current data set.
///
public virtual void Reset()
{
lock (_dataLock)
_currentDataSet.Clear();
}
///
public virtual void Dispose()
{
_updateTrigger.Starting -= OnStartup;
_updateTrigger.Update -= OnUpdate;
Reset();
GC.SuppressFinalize(this);
}
#endregion
}
///
/// Represents a generic using an object as the key and a color as the value.
///
public abstract class UpdateQueue : UpdateQueue