Files
AdamuSw/src/Persistence/IdGenerator.cs
2026-07-14 19:00:35 +03:00

93 lines
3.1 KiB
C#

// <copyright file="IdGenerator.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Persistence;
using System.Collections.Concurrent;
using System.Threading;
/// <summary>
/// A generator which generates id which should be unique within an instance of a generator.
/// Ids which are no longer used can be given back to the generator, e.g. when an object joins a game map,
/// it gets an id, later when it leaves the map, it gives the id back, so another player can use it.
/// </summary>
/// <remarks>
/// The namespace for this class is probably not the right one - we're missing something like a "Utility" namespace for things like that.
/// </remarks>
public class IdGenerator
{
private readonly int _maxValue;
private readonly ConcurrentQueue<int> _givenBack = new();
private int _currentValue;
/// <summary>
/// Initializes a new instance of the <see cref="IdGenerator"/> class.
/// </summary>
/// <param name="firstValue">The first value.</param>
/// <param name="maxValue">The maximum value.</param>
public IdGenerator(int firstValue, int maxValue)
{
this._maxValue = maxValue;
this._currentValue = firstValue - 1; // will be increased by 1 by GenerateId
}
/// <summary>
/// Defines how ids are reused, which were given back with <see cref="IdGenerator.GiveBack"/>.
/// </summary>
public enum ReUsePolicy
{
/// <summary>
/// The given back id is reused on the next call of <see cref="IdGenerator.GenerateId"/>.
/// </summary>
ReUseOnNextRetrieve,
/// <summary>
/// The given back id is reused when all of the available ids were exceeded.
/// </summary>
ReUseWhenExceeded,
}
/// <summary>
/// Gets or sets the <see cref="ReUsePolicy"/> which defines how ids are reused, which were given back with <see cref="IdGenerator.GiveBack"/>.
/// </summary>
public ReUsePolicy ReUseSetting { get; set; }
/// <summary>
/// Gets an identifier which is unique within this generator instance.
/// </summary>
/// <returns>An identifier which is unique within this generator instance.</returns>
/// <exception cref="InvalidOperationException">Maximum object id exceeded.</exception>
public int GenerateId()
{
if (this.ReUseSetting == ReUsePolicy.ReUseOnNextRetrieve
&& this._givenBack.TryDequeue(out int next))
{
return next;
}
if (this._currentValue == this._maxValue)
{
if (this._givenBack.TryDequeue(out next))
{
return next;
}
throw new InvalidOperationException("Maximum object id exceeded");
}
return Interlocked.Increment(ref this._currentValue);
}
/// <summary>
/// Gives the id back for further usage by the next object.
/// </summary>
/// <param name="id">The identifier.</param>
public void GiveBack(int id)
{
if (id <= this._maxValue)
{
this._givenBack.Enqueue(id);
}
}
}