Created
February 22, 2021 10:40
-
-
Save john-h-k/04b88de90a6b9a831b6b52f078194a76 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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