Skip to content

Instantly share code, notes, and snippets.

@john-h-k
Created February 22, 2021 10:40
Show Gist options
  • Save john-h-k/04b88de90a6b9a831b6b52f078194a76 to your computer and use it in GitHub Desktop.
Save john-h-k/04b88de90a6b9a831b6b52f078194a76 to your computer and use it in GitHub Desktop.
public readonly struct GenerationalHandle
{
public readonly uint Generation;
public readonly uint Handle;
public GenerationalHandle(uint generation, uint handle)
{
Generation = generation;
Handle = handle;
}
}
public interface IHandle<THandle> where THandle : struct, IHandle<THandle>
{
public GenerationalHandle Generational { get; }
public THandle FromGenerationHandle(GenerationalHandle handle);
}
public sealed class GenerationHandleAllocator<THandle, THandleData> where THandle : struct, IHandle<THandle>
{
private const uint InvalidGeneration = uint.MaxValue;
private struct HandleDataPair
{
public bool IsAllocated;
public GenerationalHandle Handle;
public THandleData HandleData;
}
private HandleDataPair[] _array;
public GenerationHandleAllocator(int capacity)
{
_array = new HandleDataPair[capacity];
}
public THandle AllocateHandle()
{
for (int i = 0; i < _array.Length; i++)
{
ref var pair = ref _array[i];
if (!pair.IsAllocated)
{
// Next generation
pair.Handle = new GenerationalHandle(pair.Handle.Generation + 1, pair.Handle.Handle);
pair.IsAllocated = true;
pair.HandleData = default!; // zero for safety
return default(THandle).FromGenerationHandle(pair.Handle);
}
}
// resize
throw new NotImplementedException();
}
public bool IsHandleValid(THandle handle)
{
return IsValid(handle, GetPairRef(handle));
}
private bool IsValid(THandle handle, in HandleDataPair pair) => pair.IsAllocated && pair.Handle.Generation == handle.Generational.Generation;
private ref HandleDataPair GetValidPairRef(THandle handle)
{
ref var pair = ref GetPairRef(handle);
if (!IsValid(handle, pair))
{
ThrowHelper.ThrowArgumentException("Handle is invalid");
}
return ref pair;
}
private ref HandleDataPair GetPairRef(THandle handle)
{
var genHandle = handle.Generational;
return ref _array[genHandle.Handle];
}
public bool TryGetHandleData(THandle handle, out THandleData data)
{
ref var pair = ref GetPairRef(handle);
if (IsValid(handle, pair))
{
data = pair.HandleData;
return true;
}
data = default!;
return false;
}
public THandleData GetHandleData(THandle handle) => GetValidPairRef(handle).HandleData;
public void SetHandleData(THandle handle, in THandleData data)
{
GetValidPairRef(handle).HandleData = data;
}
public unsafe void ModifyHandleData(THandle handle, delegate* <in THandleData, void> modifier)
{
modifier(in GetValidPairRef(handle).HandleData);
}
public void FreeHandle(THandle handle)
{
GetValidPairRef(handle).IsAllocated = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment