93 lines
3.1 KiB
C#
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);
|
|
}
|
|
}
|
|
} |