Added pools, IndexedFishMap, IndexedFishSet, fixed bugs related to FishTable.Remove, added Preview.png, various smaller additions, some refactoring too

This commit is contained in:
bbradson
2024-01-27 10:02:57 +01:00
parent cdf209eb02
commit af759661bd
38 changed files with 1879 additions and 642 deletions
+105 -14
View File
@@ -145,7 +145,8 @@ public static class CollectionExtensions
{
if (dictionary.buckets != null)
{
var keyCode = HashCode.Get(key) & 0x7FFFFFFF; // HashCode.Get can handle null, & 0x7FFFFFFF removes any sign
var keyCode = HashCode.Get(key) & int.MaxValue;
// HashCode.Get can handle null, & int.MaxValue removes any sign
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
while (bucket >= 0)
@@ -165,7 +166,7 @@ public static class CollectionExtensions
{
if (dictionary.buckets != null)
{
var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(ref key) & int.MaxValue;
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
while (bucket >= 0)
@@ -192,7 +193,7 @@ public static class CollectionExtensions
{
if (dictionary.buckets != null)
{
var keyCode = HashCode.Get(key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(key) & int.MaxValue;
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
while (bucket >= 0)
@@ -212,7 +213,7 @@ public static class CollectionExtensions
{
if (dictionary.buckets != null)
{
var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(ref key) & int.MaxValue;
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
while (bucket >= 0)
@@ -232,7 +233,7 @@ public static class CollectionExtensions
{
if (dictionary.buckets != null)
{
var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(ref key) & int.MaxValue;
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
while (bucket >= 0)
@@ -253,7 +254,7 @@ public static class CollectionExtensions
{
if (dictionary.buckets != null)
{
var keyCode = HashCode.Get(key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(key) & int.MaxValue;
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
while (bucket >= 0)
@@ -273,7 +274,7 @@ public static class CollectionExtensions
public static ref TValue GetOrAddReference<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
where TValue : new()
{
var keyCode = HashCode.Get(key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(key) & int.MaxValue;
StartOfLookup:
if (dictionary.buckets != null)
@@ -297,7 +298,7 @@ public static class CollectionExtensions
public static ref TValue GetOrAddReference<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, ref TKey key)
where TValue : new()
{
var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(ref key) & int.MaxValue;
StartOfLookup:
if (dictionary.buckets != null)
@@ -320,7 +321,7 @@ public static class CollectionExtensions
// public static bool TryGetOrAddReference<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key,
// ref TValue reference)
// {
// var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
// var keyCode = HashCode.Get(ref key) & int.MaxValue;
// var result = true;
//
// StartOfLookup:
@@ -349,7 +350,7 @@ public static class CollectionExtensions
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
where TValue : new()
{
var keyCode = HashCode.Get(key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(key) & int.MaxValue;
StartOfLookup:
if (dictionary.buckets != null)
@@ -373,7 +374,7 @@ public static class CollectionExtensions
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, ref TKey key)
where TValue : new()
{
var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(ref key) & int.MaxValue;
StartOfLookup:
if (dictionary.buckets != null)
@@ -396,7 +397,7 @@ public static class CollectionExtensions
public static bool TryGetOrAddValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key,
out TValue value)
{
var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF;
var keyCode = HashCode.Get(ref key) & int.MaxValue;
var result = true;
StartOfLookup:
@@ -421,6 +422,38 @@ public static class CollectionExtensions
goto StartOfLookup;
}
public static int RemoveWhere<TKey, TValue>(this Dictionary<TKey, TValue> dictionary,
Predicate<KeyValuePair<TKey, TValue>> predicate)
{
Guard.IsNotNull(dictionary);
Guard.IsNotNull(predicate);
var entries = dictionary.entries;
if (entries is null)
return 0;
var removedCount = 0;
var entriesCount = entries.Length;
for (var i = 0; i < entriesCount; i++)
{
ref var entry = ref entries[i];
if (entry.hashCode < 0) // valid entries are stored with & int.MaxValue on hashCode
continue;
// predicate might modify collection, turning a ref invalid
var keyValuePair = new KeyValuePair<TKey,TValue>(entry.key, entry.value);
if (!predicate(keyValuePair))
continue;
if (dictionary.Remove(keyValuePair.Key))
removedCount++;
}
return removedCount;
}
[DoesNotReturn]
private static ref V ThrowKeyNotFoundException<T, V>(T key)
{
@@ -640,7 +673,28 @@ public static class CollectionExtensions
public static StringBuilder Append(this StringBuilder builder, List<char> value)
=> builder.Append(value._items, 0, value._size);
public static ref T GetReferenceUnverifiable<T>(this List<T> list, int index) => ref list._items[index];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static StringBuilder Append<T>(this StringBuilder builder, T? value)
// ReSharper disable once RedundantToStringCallForValueType
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable once HeapView.PossibleBoxingAllocation
=> value == null ? builder : builder.Append(value.ToString());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetReference<T>(this List<T> list, int index)
{
Guard.IsInRange(index, 0, list.Count);
list._version++;
return ref list._items[index];
}
[Obsolete("Renamed to GetReferenceUnsafe")]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetReferenceUnverifiable<T>(this List<T> list, int index) => ref list.GetReferenceUnsafe(index);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetReferenceUnsafe<T>(this List<T> list, int index) => ref list._items[index];
public static IList TryNew(IEnumerable enumerable, Type type) => GetListExtensionMethods(type).New(enumerable);
@@ -649,6 +703,40 @@ public static class CollectionExtensions
public static Array TryToArray(this IList list, Type type) => GetListExtensionMethods(type).ToArray(list);
public static void RemoveAtFastUnordered<T>(this List<T> list, int index)
{
ref var lastBucket = ref list._items[list._size - 1];
list[index] = lastBucket;
lastBucket = default!;
list._size--;
}
public static bool RemoveFastUnordered<T>(this List<T> list, T item)
{
var index = list.IndexOf(item);
if (index < 0)
return false;
list.RemoveAtFastUnordered(index);
return true;
}
public static void InsertFastUnordered<T>(this List<T> list, int index, T item)
{
if ((uint) index > (uint) list._size)
ThrowHelper.ThrowArgumentOutOfRangeException();
if (list._size == list._items.Length)
list.EnsureCapacity(list._size + 1);
ref var targetBucket = ref list._items[index];
list._items[list._size] = targetBucket;
targetBucket = item;
list._size++;
list._version++;
}
public static unsafe uint GetSizeEstimate<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
=> dictionary.GetType().ComputeManagedObjectSizeEstimate()
+ ((uint)sizeof(Dictionary<TKey, TValue>.Entry) * (uint)(dictionary.entries?.Length ?? 0))
@@ -657,7 +745,8 @@ public static class CollectionExtensions
internal static unsafe uint ComputeManagedObjectSizeEstimate(this Type type)
{
var objectHeader = (uint)sizeof(void*) * 2u;
ref var cachedSize = ref CachedManagedObjectSizes.GetOrAddReference(type.TypeHandle.Value);
var cachedSize = CachedManagedObjectSizes.GetOrAdd(type.TypeHandle.Value);
// can't use GetOrAddReference here due to recursion
if (cachedSize.Size == uint.MaxValue)
UpdateCachedManagedObjectSize(type, ref cachedSize);
@@ -689,6 +778,8 @@ public static class CollectionExtensions
var remainder = cachedSize.Size % (uint)IntPtr.Size;
if (remainder != 0u)
cachedSize.Size += (uint)IntPtr.Size - remainder;
CachedManagedObjectSizes[type.TypeHandle.Value] = cachedSize;
}
private static FishTable<IntPtr, ManagedObjectSize> CachedManagedObjectSizes => _cachedManagedObjectSizes ??= new();