diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /ARMeilleure/Common | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'ARMeilleure/Common')
| -rw-r--r-- | ARMeilleure/Common/AddressTable.cs | 252 | ||||
| -rw-r--r-- | ARMeilleure/Common/Allocator.cs | 24 | ||||
| -rw-r--r-- | ARMeilleure/Common/ArenaAllocator.cs | 187 | ||||
| -rw-r--r-- | ARMeilleure/Common/BitMap.cs | 222 | ||||
| -rw-r--r-- | ARMeilleure/Common/BitUtils.cs | 57 | ||||
| -rw-r--r-- | ARMeilleure/Common/Counter.cs | 98 | ||||
| -rw-r--r-- | ARMeilleure/Common/EntryTable.cs | 188 | ||||
| -rw-r--r-- | ARMeilleure/Common/EnumUtils.cs | 12 | ||||
| -rw-r--r-- | ARMeilleure/Common/NativeAllocator.cs | 27 |
9 files changed, 0 insertions, 1067 deletions
diff --git a/ARMeilleure/Common/AddressTable.cs b/ARMeilleure/Common/AddressTable.cs deleted file mode 100644 index 9db2d00d..00000000 --- a/ARMeilleure/Common/AddressTable.cs +++ /dev/null @@ -1,252 +0,0 @@ -using ARMeilleure.Diagnostics; -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Common -{ - /// <summary> - /// Represents a table of guest address to a value. - /// </summary> - /// <typeparam name="TEntry">Type of the value</typeparam> - unsafe class AddressTable<TEntry> : IDisposable where TEntry : unmanaged - { - /// <summary> - /// Represents a level in an <see cref="AddressTable{TEntry}"/>. - /// </summary> - public readonly struct Level - { - /// <summary> - /// Gets the index of the <see cref="Level"/> in the guest address. - /// </summary> - public int Index { get; } - - /// <summary> - /// Gets the length of the <see cref="Level"/> in the guest address. - /// </summary> - public int Length { get; } - - /// <summary> - /// Gets the mask which masks the bits used by the <see cref="Level"/>. - /// </summary> - public ulong Mask => ((1ul << Length) - 1) << Index; - - /// <summary> - /// Initializes a new instance of the <see cref="Level"/> structure with the specified - /// <paramref name="index"/> and <paramref name="length"/>. - /// </summary> - /// <param name="index">Index of the <see cref="Level"/></param> - /// <param name="length">Length of the <see cref="Level"/></param> - public Level(int index, int length) - { - (Index, Length) = (index, length); - } - - /// <summary> - /// Gets the value of the <see cref="Level"/> from the specified guest <paramref name="address"/>. - /// </summary> - /// <param name="address">Guest address</param> - /// <returns>Value of the <see cref="Level"/> from the specified guest <paramref name="address"/></returns> - public int GetValue(ulong address) - { - return (int)((address & Mask) >> Index); - } - } - - private bool _disposed; - private TEntry** _table; - private readonly List<IntPtr> _pages; - - /// <summary> - /// Gets the bits used by the <see cref="Levels"/> of the <see cref="AddressTable{TEntry}"/> instance. - /// </summary> - public ulong Mask { get; } - - /// <summary> - /// Gets the <see cref="Level"/>s used by the <see cref="AddressTable{TEntry}"/> instance. - /// </summary> - public Level[] Levels { get; } - - /// <summary> - /// Gets or sets the default fill value of newly created leaf pages. - /// </summary> - public TEntry Fill { get; set; } - - /// <summary> - /// Gets the base address of the <see cref="EntryTable{TEntry}"/>. - /// </summary> - /// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception> - public IntPtr Base - { - get - { - ObjectDisposedException.ThrowIf(_disposed, this); - - lock (_pages) - { - return (IntPtr)GetRootPage(); - } - } - } - - /// <summary> - /// Constructs a new instance of the <see cref="AddressTable{TEntry}"/> class with the specified list of - /// <see cref="Level"/>. - /// </summary> - /// <exception cref="ArgumentNullException"><paramref name="levels"/> is null</exception> - /// <exception cref="ArgumentException">Length of <paramref name="levels"/> is less than 2</exception> - public AddressTable(Level[] levels) - { - ArgumentNullException.ThrowIfNull(levels); - - if (levels.Length < 2) - { - throw new ArgumentException("Table must be at least 2 levels deep.", nameof(levels)); - } - - _pages = new List<IntPtr>(capacity: 16); - - Levels = levels; - Mask = 0; - - foreach (var level in Levels) - { - Mask |= level.Mask; - } - } - - /// <summary> - /// Determines if the specified <paramref name="address"/> is in the range of the - /// <see cref="AddressTable{TEntry}"/>. - /// </summary> - /// <param name="address">Guest address</param> - /// <returns><see langword="true"/> if is valid; otherwise <see langword="false"/></returns> - public bool IsValid(ulong address) - { - return (address & ~Mask) == 0; - } - - /// <summary> - /// Gets a reference to the value at the specified guest <paramref name="address"/>. - /// </summary> - /// <param name="address">Guest address</param> - /// <returns>Reference to the value at the specified guest <paramref name="address"/></returns> - /// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception> - /// <exception cref="ArgumentException"><paramref name="address"/> is not mapped</exception> - public ref TEntry GetValue(ulong address) - { - ObjectDisposedException.ThrowIf(_disposed, this); - - if (!IsValid(address)) - { - throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address)); - } - - lock (_pages) - { - return ref GetPage(address)[Levels[^1].GetValue(address)]; - } - } - - /// <summary> - /// Gets the leaf page for the specified guest <paramref name="address"/>. - /// </summary> - /// <param name="address">Guest address</param> - /// <returns>Leaf page for the specified guest <paramref name="address"/></returns> - private TEntry* GetPage(ulong address) - { - TEntry** page = GetRootPage(); - - for (int i = 0; i < Levels.Length - 1; i++) - { - ref Level level = ref Levels[i]; - ref TEntry* nextPage = ref page[level.GetValue(address)]; - - if (nextPage == null) - { - ref Level nextLevel = ref Levels[i + 1]; - - nextPage = i == Levels.Length - 2 ? - (TEntry*)Allocate(1 << nextLevel.Length, Fill, leaf: true) : - (TEntry*)Allocate(1 << nextLevel.Length, IntPtr.Zero, leaf: false); - } - - page = (TEntry**)nextPage; - } - - return (TEntry*)page; - } - - /// <summary> - /// Lazily initialize and get the root page of the <see cref="AddressTable{TEntry}"/>. - /// </summary> - /// <returns>Root page of the <see cref="AddressTable{TEntry}"/></returns> - private TEntry** GetRootPage() - { - if (_table == null) - { - _table = (TEntry**)Allocate(1 << Levels[0].Length, fill: IntPtr.Zero, leaf: false); - } - - return _table; - } - - /// <summary> - /// Allocates a block of memory of the specified type and length. - /// </summary> - /// <typeparam name="T">Type of elements</typeparam> - /// <param name="length">Number of elements</param> - /// <param name="fill">Fill value</param> - /// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword="false"/></param> - /// <returns>Allocated block</returns> - private IntPtr Allocate<T>(int length, T fill, bool leaf) where T : unmanaged - { - var size = sizeof(T) * length; - var page = (IntPtr)NativeAllocator.Instance.Allocate((uint)size); - var span = new Span<T>((void*)page, length); - - span.Fill(fill); - - _pages.Add(page); - - TranslatorEventSource.Log.AddressTableAllocated(size, leaf); - - return page; - } - - /// <summary> - /// Releases all resources used by the <see cref="AddressTable{TEntry}"/> instance. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases all unmanaged and optionally managed resources used by the <see cref="AddressTable{TEntry}"/> - /// instance. - /// </summary> - /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param> - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - foreach (var page in _pages) - { - Marshal.FreeHGlobal(page); - } - - _disposed = true; - } - } - - /// <summary> - /// Frees resources used by the <see cref="AddressTable{TEntry}"/> instance. - /// </summary> - ~AddressTable() - { - Dispose(false); - } - } -} diff --git a/ARMeilleure/Common/Allocator.cs b/ARMeilleure/Common/Allocator.cs deleted file mode 100644 index 247a8e8b..00000000 --- a/ARMeilleure/Common/Allocator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace ARMeilleure.Common -{ - unsafe abstract class Allocator : IDisposable - { - public T* Allocate<T>(ulong count = 1) where T : unmanaged - { - return (T*)Allocate(count * (uint)sizeof(T)); - } - - public abstract void* Allocate(ulong size); - - public abstract void Free(void* block); - - protected virtual void Dispose(bool disposing) { } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } -} diff --git a/ARMeilleure/Common/ArenaAllocator.cs b/ARMeilleure/Common/ArenaAllocator.cs deleted file mode 100644 index bce6794a..00000000 --- a/ARMeilleure/Common/ArenaAllocator.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -namespace ARMeilleure.Common -{ - unsafe sealed class ArenaAllocator : Allocator - { - private class PageInfo - { - public byte* Pointer; - public byte Unused; - public int UnusedCounter; - } - - private int _lastReset; - private ulong _index; - private int _pageIndex; - private PageInfo _page; - private List<PageInfo> _pages; - private readonly ulong _pageSize; - private readonly uint _pageCount; - private readonly List<IntPtr> _extras; - - public ArenaAllocator(uint pageSize, uint pageCount) - { - _lastReset = Environment.TickCount; - - // Set _index to pageSize so that the first allocation goes through the slow path. - _index = pageSize; - _pageIndex = -1; - - _page = null; - _pages = new List<PageInfo>(); - _pageSize = pageSize; - _pageCount = pageCount; - - _extras = new List<IntPtr>(); - } - - public Span<T> AllocateSpan<T>(ulong count) where T : unmanaged - { - return new Span<T>(Allocate<T>(count), (int)count); - } - - public override void* Allocate(ulong size) - { - if (_index + size <= _pageSize) - { - byte* result = _page.Pointer + _index; - - _index += size; - - return result; - } - - return AllocateSlow(size); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void* AllocateSlow(ulong size) - { - if (size > _pageSize) - { - void* extra = NativeAllocator.Instance.Allocate(size); - - _extras.Add((IntPtr)extra); - - return extra; - } - - if (_index + size > _pageSize) - { - _index = 0; - _pageIndex++; - } - - if (_pageIndex < _pages.Count) - { - _page = _pages[_pageIndex]; - _page.Unused = 0; - } - else - { - _page = new PageInfo(); - _page.Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize); - - _pages.Add(_page); - } - - byte* result = _page.Pointer + _index; - - _index += size; - - return result; - } - - public override void Free(void* block) { } - - public void Reset() - { - _index = _pageSize; - _pageIndex = -1; - _page = null; - - // Free excess pages that was allocated. - while (_pages.Count > _pageCount) - { - NativeAllocator.Instance.Free(_pages[_pages.Count - 1].Pointer); - - _pages.RemoveAt(_pages.Count - 1); - } - - // Free extra blocks that are not page-sized - foreach (IntPtr ptr in _extras) - { - NativeAllocator.Instance.Free((void*)ptr); - } - - _extras.Clear(); - - // Free pooled pages that has not been used in a while. Remove pages at the back first, because we try to - // keep the pages at the front alive, since they're more likely to be hot and in the d-cache. - bool removing = true; - - // If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time. - int now = Environment.TickCount; - int count = (now - _lastReset) switch { - >= 5000 => 0, - >= 2500 => 50, - >= 1000 => 100, - >= 10 => 1500, - _ => 5000 - }; - - for (int i = _pages.Count - 1; i >= 0; i--) - { - PageInfo page = _pages[i]; - - if (page.Unused == 0) - { - page.UnusedCounter = 0; - } - - page.UnusedCounter += page.Unused; - page.Unused = 1; - - // If page not used after `count` resets, remove it. - if (removing && page.UnusedCounter >= count) - { - NativeAllocator.Instance.Free(page.Pointer); - - _pages.RemoveAt(i); - } - else - { - removing = false; - } - } - - _lastReset = now; - } - - protected override void Dispose(bool disposing) - { - if (_pages != null) - { - foreach (PageInfo info in _pages) - { - NativeAllocator.Instance.Free(info.Pointer); - } - - foreach (IntPtr ptr in _extras) - { - NativeAllocator.Instance.Free((void*)ptr); - } - - _pages = null; - } - } - - ~ArenaAllocator() - { - Dispose(false); - } - } -} diff --git a/ARMeilleure/Common/BitMap.cs b/ARMeilleure/Common/BitMap.cs deleted file mode 100644 index 27ef031f..00000000 --- a/ARMeilleure/Common/BitMap.cs +++ /dev/null @@ -1,222 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace ARMeilleure.Common -{ - unsafe class BitMap : IEnumerable<int>, IDisposable - { - private const int IntSize = 64; - private const int IntMask = IntSize - 1; - - private int _count; - private long* _masks; - private readonly Allocator _allocator; - - public BitMap(Allocator allocator) - { - _allocator = allocator; - } - - public BitMap(Allocator allocator, int capacity) : this(allocator) - { - EnsureCapacity(capacity); - } - - public bool Set(int bit) - { - EnsureCapacity(bit + 1); - - int wordIndex = bit / IntSize; - int wordBit = bit & IntMask; - - long wordMask = 1L << wordBit; - - if ((_masks[wordIndex] & wordMask) != 0) - { - return false; - } - - _masks[wordIndex] |= wordMask; - - return true; - } - - public void Clear(int bit) - { - EnsureCapacity(bit + 1); - - int wordIndex = bit / IntSize; - int wordBit = bit & IntMask; - - long wordMask = 1L << wordBit; - - _masks[wordIndex] &= ~wordMask; - } - - public bool IsSet(int bit) - { - EnsureCapacity(bit + 1); - - int wordIndex = bit / IntSize; - int wordBit = bit & IntMask; - - return (_masks[wordIndex] & (1L << wordBit)) != 0; - } - - public int FindFirstUnset() - { - for (int index = 0; index < _count; index++) - { - long mask = _masks[index]; - - if (mask != -1L) - { - return BitOperations.TrailingZeroCount(~mask) + index * IntSize; - } - } - - return _count * IntSize; - } - - public bool Set(BitMap map) - { - EnsureCapacity(map._count * IntSize); - - bool modified = false; - - for (int index = 0; index < _count; index++) - { - long newValue = _masks[index] | map._masks[index]; - - if (_masks[index] != newValue) - { - _masks[index] = newValue; - - modified = true; - } - } - - return modified; - } - - public bool Clear(BitMap map) - { - EnsureCapacity(map._count * IntSize); - - bool modified = false; - - for (int index = 0; index < _count; index++) - { - long newValue = _masks[index] & ~map._masks[index]; - - if (_masks[index] != newValue) - { - _masks[index] = newValue; - - modified = true; - } - } - - return modified; - } - - private void EnsureCapacity(int size) - { - int count = (size + IntMask) / IntSize; - - if (count > _count) - { - var oldMask = _masks; - var oldSpan = new Span<long>(_masks, _count); - - _masks = _allocator.Allocate<long>((uint)count); - _count = count; - - var newSpan = new Span<long>(_masks, _count); - - oldSpan.CopyTo(newSpan); - newSpan.Slice(oldSpan.Length).Clear(); - - _allocator.Free(oldMask); - } - } - - public void Dispose() - { - if (_masks != null) - { - _allocator.Free(_masks); - - _masks = null; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator<int> IEnumerable<int>.GetEnumerator() - { - return GetEnumerator(); - } - - public Enumerator GetEnumerator() - { - return new Enumerator(this); - } - - public struct Enumerator : IEnumerator<int> - { - private long _index; - private long _mask; - private int _bit; - private readonly BitMap _map; - - public int Current => (int)_index * IntSize + _bit; - object IEnumerator.Current => Current; - - public Enumerator(BitMap map) - { - _index = -1; - _mask = 0; - _bit = 0; - _map = map; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - if (_mask != 0) - { - _mask &= ~(1L << _bit); - } - - // Manually hoist these loads, because RyuJIT does not. - long count = (uint)_map._count; - long* masks = _map._masks; - - while (_mask == 0) - { - if (++_index >= count) - { - return false; - } - - _mask = masks[_index]; - } - - _bit = BitOperations.TrailingZeroCount(_mask); - - return true; - } - - public void Reset() { } - - public void Dispose() { } - } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Common/BitUtils.cs b/ARMeilleure/Common/BitUtils.cs deleted file mode 100644 index e7697ff3..00000000 --- a/ARMeilleure/Common/BitUtils.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Numerics; - -namespace ARMeilleure.Common -{ - static class BitUtils - { - private static ReadOnlySpan<sbyte> HbsNibbleLut => new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; - - public static long FillWithOnes(int bits) - { - return bits == 64 ? -1L : (1L << bits) - 1; - } - - public static int HighestBitSet(int value) - { - return 31 - BitOperations.LeadingZeroCount((uint)value); - } - - public static int HighestBitSetNibble(int value) - { - return HbsNibbleLut[value]; - } - - public static long Replicate(long bits, int size) - { - long output = 0; - - for (int bit = 0; bit < 64; bit += size) - { - output |= bits << bit; - } - - return output; - } - - public static int RotateRight(int bits, int shift, int size) - { - return (int)RotateRight((uint)bits, shift, size); - } - - public static uint RotateRight(uint bits, int shift, int size) - { - return (bits >> shift) | (bits << (size - shift)); - } - - public static long RotateRight(long bits, int shift, int size) - { - return (long)RotateRight((ulong)bits, shift, size); - } - - public static ulong RotateRight(ulong bits, int shift, int size) - { - return (bits >> shift) | (bits << (size - shift)); - } - } -} diff --git a/ARMeilleure/Common/Counter.cs b/ARMeilleure/Common/Counter.cs deleted file mode 100644 index d7210d15..00000000 --- a/ARMeilleure/Common/Counter.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; - -namespace ARMeilleure.Common -{ - /// <summary> - /// Represents a numeric counter which can be used for instrumentation of compiled code. - /// </summary> - /// <typeparam name="T">Type of the counter</typeparam> - class Counter<T> : IDisposable where T : unmanaged - { - private bool _disposed; - /// <summary> - /// Index in the <see cref="EntryTable{T}"/> - /// </summary> - private readonly int _index; - private readonly EntryTable<T> _countTable; - - /// <summary> - /// Initializes a new instance of the <see cref="Counter{T}"/> class from the specified - /// <see cref="EntryTable{T}"/> instance and index. - /// </summary> - /// <param name="countTable"><see cref="EntryTable{T}"/> instance</param> - /// <exception cref="ArgumentNullException"><paramref name="countTable"/> is <see langword="null"/></exception> - /// <exception cref="ArgumentException"><typeparamref name="T"/> is unsupported</exception> - public Counter(EntryTable<T> countTable) - { - if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) && - typeof(T) != typeof(short) && typeof(T) != typeof(ushort) && - typeof(T) != typeof(int) && typeof(T) != typeof(uint) && - typeof(T) != typeof(long) && typeof(T) != typeof(ulong) && - typeof(T) != typeof(nint) && typeof(T) != typeof(nuint) && - typeof(T) != typeof(float) && typeof(T) != typeof(double)) - { - throw new ArgumentException("Counter does not support the specified type."); - } - - _countTable = countTable ?? throw new ArgumentNullException(nameof(countTable)); - _index = countTable.Allocate(); - } - - /// <summary> - /// Gets a reference to the value of the counter. - /// </summary> - /// <exception cref="ObjectDisposedException"><see cref="Counter{T}"/> instance was disposed</exception> - /// <remarks> - /// This can refer to freed memory if the owning <see cref="EntryTable{TEntry}"/> is disposed. - /// </remarks> - public ref T Value - { - get - { - ObjectDisposedException.ThrowIf(_disposed, this); - - return ref _countTable.GetValue(_index); - } - } - - /// <summary> - /// Releases all resources used by the <see cref="Counter{T}"/> instance. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases all unmanaged and optionally managed resources used by the <see cref="Counter{T}"/> instance. - /// </summary> - /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resources</param> - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - try - { - // The index into the EntryTable is essentially an unmanaged resource since we allocate and free the - // resource ourselves. - _countTable.Free(_index); - } - catch (ObjectDisposedException) - { - // Can happen because _countTable may be disposed before the Counter instance. - } - - _disposed = true; - } - } - - /// <summary> - /// Frees resources used by the <see cref="Counter{T}"/> instance. - /// </summary> - ~Counter() - { - Dispose(false); - } - } -} diff --git a/ARMeilleure/Common/EntryTable.cs b/ARMeilleure/Common/EntryTable.cs deleted file mode 100644 index 6f205797..00000000 --- a/ARMeilleure/Common/EntryTable.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Numerics; - -namespace ARMeilleure.Common -{ - /// <summary> - /// Represents an expandable table of the type <typeparamref name="TEntry"/>, whose entries will remain at the same - /// address through out the table's lifetime. - /// </summary> - /// <typeparam name="TEntry">Type of the entry in the table</typeparam> - class EntryTable<TEntry> : IDisposable where TEntry : unmanaged - { - private bool _disposed; - private int _freeHint; - private readonly int _pageCapacity; // Number of entries per page. - private readonly int _pageLogCapacity; - private readonly Dictionary<int, IntPtr> _pages; - private readonly BitMap _allocated; - - /// <summary> - /// Initializes a new instance of the <see cref="EntryTable{TEntry}"/> class with the desired page size in - /// bytes. - /// </summary> - /// <param name="pageSize">Desired page size in bytes</param> - /// <exception cref="ArgumentOutOfRangeException"><paramref name="pageSize"/> is less than 0</exception> - /// <exception cref="ArgumentException"><typeparamref name="TEntry"/>'s size is zero</exception> - /// <remarks> - /// The actual page size may be smaller or larger depending on the size of <typeparamref name="TEntry"/>. - /// </remarks> - public unsafe EntryTable(int pageSize = 4096) - { - if (pageSize < 0) - { - throw new ArgumentOutOfRangeException(nameof(pageSize), "Page size cannot be negative."); - } - - if (sizeof(TEntry) == 0) - { - throw new ArgumentException("Size of TEntry cannot be zero."); - } - - _allocated = new BitMap(NativeAllocator.Instance); - _pages = new Dictionary<int, IntPtr>(); - _pageLogCapacity = BitOperations.Log2((uint)(pageSize / sizeof(TEntry))); - _pageCapacity = 1 << _pageLogCapacity; - } - - /// <summary> - /// Allocates an entry in the <see cref="EntryTable{TEntry}"/>. - /// </summary> - /// <returns>Index of entry allocated in the table</returns> - /// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception> - public int Allocate() - { - ObjectDisposedException.ThrowIf(_disposed, this); - - lock (_allocated) - { - if (_allocated.IsSet(_freeHint)) - { - _freeHint = _allocated.FindFirstUnset(); - } - - int index = _freeHint++; - var page = GetPage(index); - - _allocated.Set(index); - - GetValue(page, index) = default; - - return index; - } - } - - /// <summary> - /// Frees the entry at the specified <paramref name="index"/>. - /// </summary> - /// <param name="index">Index of entry to free</param> - /// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception> - public void Free(int index) - { - ObjectDisposedException.ThrowIf(_disposed, this); - - lock (_allocated) - { - if (_allocated.IsSet(index)) - { - _allocated.Clear(index); - - _freeHint = index; - } - } - } - - /// <summary> - /// Gets a reference to the entry at the specified allocated <paramref name="index"/>. - /// </summary> - /// <param name="index">Index of the entry</param> - /// <returns>Reference to the entry at the specified <paramref name="index"/></returns> - /// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception> - /// <exception cref="ArgumentException">Entry at <paramref name="index"/> is not allocated</exception> - public ref TEntry GetValue(int index) - { - ObjectDisposedException.ThrowIf(_disposed, this); - - lock (_allocated) - { - if (!_allocated.IsSet(index)) - { - throw new ArgumentException("Entry at the specified index was not allocated", nameof(index)); - } - - var page = GetPage(index); - - return ref GetValue(page, index); - } - } - - /// <summary> - /// Gets a reference to the entry at using the specified <paramref name="index"/> from the specified - /// <paramref name="page"/>. - /// </summary> - /// <param name="page">Page to use</param> - /// <param name="index">Index to use</param> - /// <returns>Reference to the entry</returns> - private ref TEntry GetValue(Span<TEntry> page, int index) - { - return ref page[index & (_pageCapacity - 1)]; - } - - /// <summary> - /// Gets the page for the specified <see cref="index"/>. - /// </summary> - /// <param name="index">Index to use</param> - /// <returns>Page for the specified <see cref="index"/></returns> - private unsafe Span<TEntry> GetPage(int index) - { - var pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity); - - if (!_pages.TryGetValue(pageIndex, out IntPtr page)) - { - page = (IntPtr)NativeAllocator.Instance.Allocate((uint)sizeof(TEntry) * (uint)_pageCapacity); - - _pages.Add(pageIndex, page); - } - - return new Span<TEntry>((void*)page, _pageCapacity); - } - - /// <summary> - /// Releases all resources used by the <see cref="EntryTable{TEntry}"/> instance. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases all unmanaged and optionally managed resources used by the <see cref="EntryTable{TEntry}"/> - /// instance. - /// </summary> - /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param> - protected unsafe virtual void Dispose(bool disposing) - { - if (!_disposed) - { - _allocated.Dispose(); - - foreach (var page in _pages.Values) - { - NativeAllocator.Instance.Free((void*)page); - } - - _disposed = true; - } - } - - /// <summary> - /// Frees resources used by the <see cref="EntryTable{TEntry}"/> instance. - /// </summary> - ~EntryTable() - { - Dispose(false); - } - } -} diff --git a/ARMeilleure/Common/EnumUtils.cs b/ARMeilleure/Common/EnumUtils.cs deleted file mode 100644 index 2a4aa645..00000000 --- a/ARMeilleure/Common/EnumUtils.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace ARMeilleure.Common -{ - static class EnumUtils - { - public static int GetCount(Type enumType) - { - return Enum.GetNames(enumType).Length; - } - } -} diff --git a/ARMeilleure/Common/NativeAllocator.cs b/ARMeilleure/Common/NativeAllocator.cs deleted file mode 100644 index 71c04a9b..00000000 --- a/ARMeilleure/Common/NativeAllocator.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Common -{ - unsafe sealed class NativeAllocator : Allocator - { - public static NativeAllocator Instance { get; } = new(); - - public override void* Allocate(ulong size) - { - void* result = (void*)Marshal.AllocHGlobal((IntPtr)size); - - if (result == null) - { - throw new OutOfMemoryException(); - } - - return result; - } - - public override void Free(void* block) - { - Marshal.FreeHGlobal((IntPtr)block); - } - } -} |
