add 1.6 support and restore 1.5 compatibility
This commit is contained in:
@@ -140,21 +140,54 @@ public static class CollectionExtensions
|
||||
array.FillUsingEnumerable(enumerable, startIndex, count);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int[]? GetBuckets<TKey, TValue>(Dictionary<TKey, TValue> dictionary)
|
||||
#if V1_6
|
||||
=> dictionary._buckets;
|
||||
#else
|
||||
=> dictionary.buckets;
|
||||
#endif
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Dictionary<TKey, TValue>.Entry[]? GetEntries<TKey, TValue>(Dictionary<TKey, TValue> dictionary)
|
||||
#if V1_6
|
||||
=> dictionary._entries;
|
||||
#else
|
||||
=> dictionary.entries;
|
||||
#endif
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int GetBucketEntryIndex(int[] buckets, int hashCode)
|
||||
#if V1_6
|
||||
=> buckets[hashCode % buckets.Length] - 1;
|
||||
#else
|
||||
=> buckets[hashCode % buckets.Length];
|
||||
#endif
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool IsValidEntryIndex<T>(int index, T[] entries)
|
||||
=> (uint)index < (uint)entries.Length;
|
||||
|
||||
public static ref TValue GetReference<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
|
||||
{
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var entries = GetEntries(dictionary)!;
|
||||
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)
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||
return ref entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,18 +196,23 @@ public static class CollectionExtensions
|
||||
|
||||
public static ref TValue GetReference<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, ref TKey key)
|
||||
{
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||
return ref entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,18 +228,23 @@ public static class CollectionExtensions
|
||||
/// <returns>ref TValue or Unsafe.NullRef{TValue}</returns>
|
||||
public static ref TValue TryGetReferenceUnsafe<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
|
||||
{
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||
return ref entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,18 +253,23 @@ public static class CollectionExtensions
|
||||
|
||||
public static ref TValue TryGetReferenceUnsafe<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, ref TKey key)
|
||||
{
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||
return ref entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,18 +278,23 @@ public static class CollectionExtensions
|
||||
|
||||
public static TValue? TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, ref TKey key)
|
||||
{
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||
return entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,18 +304,23 @@ public static class CollectionExtensions
|
||||
[return: MaybeNull]
|
||||
public static TValue TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
|
||||
{
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||
return entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,16 +334,21 @@ public static class CollectionExtensions
|
||||
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||
|
||||
StartOfLookup:
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||
return ref entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,16 +363,21 @@ public static class CollectionExtensions
|
||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||
|
||||
StartOfLookup:
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||
return ref entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,16 +420,21 @@ public static class CollectionExtensions
|
||||
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||
|
||||
StartOfLookup:
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||
return entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,16 +449,21 @@ public static class CollectionExtensions
|
||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||
|
||||
StartOfLookup:
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||
return entry.value;
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,12 +478,15 @@ public static class CollectionExtensions
|
||||
var result = true;
|
||||
|
||||
StartOfLookup:
|
||||
if (dictionary.buckets != null)
|
||||
var buckets = GetBuckets(dictionary);
|
||||
if (buckets != null)
|
||||
{
|
||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
||||
while (bucket >= 0)
|
||||
var entries = GetEntries(dictionary)!;
|
||||
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||
var collisionCount = 0;
|
||||
while (IsValidEntryIndex(bucket, entries))
|
||||
{
|
||||
ref var entry = ref dictionary.entries[bucket];
|
||||
ref var entry = ref entries[bucket];
|
||||
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||
{
|
||||
value = entry.value;
|
||||
@@ -413,6 +494,8 @@ public static class CollectionExtensions
|
||||
}
|
||||
|
||||
bucket = entry.next;
|
||||
if (collisionCount++ >= entries.Length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +510,7 @@ public static class CollectionExtensions
|
||||
Guard.IsNotNull(dictionary);
|
||||
Guard.IsNotNull(predicate);
|
||||
|
||||
var entries = dictionary.entries;
|
||||
var entries = GetEntries(dictionary);
|
||||
if (entries is null)
|
||||
return 0;
|
||||
|
||||
@@ -653,13 +736,13 @@ public static class CollectionExtensions
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T UnsafeLoad<T>(this T[] array, int index) => Array.UnsafeLoad(array, index);
|
||||
public static T UnsafeLoad<T>(this T[] array, int index) => array[index];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void UnsafeStore<T>(this T[] array, int index, T value) => Array.UnsafeStore(array, index, value);
|
||||
public static void UnsafeStore<T>(this T[] array, int index, T value) => array[index] = value;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TTo UnsafeCast<TFrom, TTo>(this TFrom obj) => Array.UnsafeMov<TFrom, TTo>(obj);
|
||||
public static TTo UnsafeCast<TFrom, TTo>(this TFrom obj) => Unsafe.As<TFrom, TTo>(ref obj);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AddRangeFast<T>(this List<T> list, T[] range)
|
||||
@@ -687,8 +770,7 @@ public static class CollectionExtensions
|
||||
return;
|
||||
|
||||
list.EnsureCapacity(list._size + value.Length);
|
||||
UnsafeBlockCopy(ref value.m_firstChar,
|
||||
ref list._items[list._size], value.Length);
|
||||
value.CopyTo(0, list._items, list._size, value.Length);
|
||||
|
||||
list._size += value.Length;
|
||||
list._version++;
|
||||
@@ -764,8 +846,8 @@ public static class CollectionExtensions
|
||||
|
||||
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))
|
||||
+ (sizeof(int) * (uint)(dictionary.buckets?.Length ?? 0));
|
||||
+ ((uint)sizeof(Dictionary<TKey, TValue>.Entry) * (uint)(GetEntries(dictionary)?.Length ?? 0))
|
||||
+ (sizeof(int) * (uint)(GetBuckets(dictionary)?.Length ?? 0));
|
||||
|
||||
internal static unsafe uint ComputeManagedObjectSizeEstimate(this Type type)
|
||||
{
|
||||
@@ -857,4 +939,4 @@ public static class CollectionExtensions
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override IList New(IEnumerable enumerable) => new List<T>((IEnumerable<T>)enumerable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user