using System;
using System.Collections.Generic;
using Unity.Collections.LowLevel.Unsafe;
namespace UnityEngine.PathTracing.Core
{
// The type parameter T is only used as a tag, preventing different kinds of handles from being mixed together.
internal readonly struct Handle<T>
{
public readonly UInt64 Value;
public Handle(UInt64 value)
{
Value = value;
}
public static readonly Handle<T> Invalid = new(0xFFFFFFFFFFFFFFFF);
public bool IsValid() => Value >= 0;
internal int ToInt()
{
Debug.Assert(UnsafeUtility.SizeOf<EntityId>() == sizeof(int),
"If this assert is firing, the size of EntityId has changed. This function should no longer be used.");
return (int)Value;
}
// Value type semantics
public override int GetHashCode() => Value.GetHashCode();
public override bool Equals(object obj) => obj is Handle<T> other && other.Value == Value;
public override string ToString() => $"Handle<{typeof(T).Name}>({Value})";
public static bool operator ==(Handle<T> a, Handle<T> b) => a.Value == b.Value;
public static bool operator !=(Handle<T> a, Handle<T> b) => a.Value != b.Value;
}
// Keeps track of allocated instance handles. Reuses freed handles.
internal class HandleSet<T>
{
private readonly Stack<Handle<T>> _freeHandles = new();
private UInt64 _nextHandleIndex;
public Handle<T> Add()
{
if (_freeHandles.Count > 0)
return _freeHandles.Pop();
return new Handle<T>(_nextHandleIndex++);
}
public void Remove(Handle<T> handle)
{
Debug.Assert(!_freeHandles.Contains(handle));
_freeHandles.Push(handle);
}
public void Clear()
{
_freeHandles.Clear();
_nextHandleIndex = 0;
}
}
}