Compare commits
6 Commits
bfa948d007
...
691d97ef2c
| Author | SHA1 | Date | |
|---|---|---|---|
| 691d97ef2c | |||
| 0aeae0d1bd | |||
| 50f4d5378b | |||
| 124052be77 | |||
| fdff6b048a | |||
| 5a3f6c1cc8 |
@@ -0,0 +1 @@
|
||||
[Oo]bj/
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,6 +7,7 @@
|
||||
<li>1.3</li>
|
||||
<li>1.4</li>
|
||||
<li>1.5</li>
|
||||
<li>1.6</li>
|
||||
</supportedVersions>
|
||||
<author>bradson</author>
|
||||
<modIconPath IgnoreIfNoMatchingField="True">FisheryLib/ModIcon</modIconPath>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\1.6\Assemblies\</OutDir>
|
||||
<Copyright>Copyright (c) 2026 Bradson</Copyright>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DefineConstants>DEBUG;V1_5;V1_6</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DefineConstants>V1_5;V1_6</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.6.*" />
|
||||
<PackageReference Include="Lib.Harmony" Version="2.3.*" ExcludeAssets="runtime" />
|
||||
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2._buckets" />
|
||||
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2._entries" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Zetrith.Prepatcher" Version="1.*" />
|
||||
<PackageReference Include="PolySharp" Version="1.*" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.*" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
|
||||
<PackageReference Include="Krafs.Publicizer" Version="2.*" />
|
||||
|
||||
<Publicize Include="Assembly-CSharp;0Harmony" IncludeVirtualMembers="false" />
|
||||
@@ -90,4 +90,4 @@
|
||||
<PackagePath />
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.1.32120.378
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.5", "1.5.csproj", "{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.6", "1.6.csproj", "{87022FD2-7E2D-45E4-BFE2-8E445B46DF08}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.4", "1.4.csproj", "{BE85EB31-71CD-443C-8C93-20E2B7F3F549}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.3", "1.3.csproj", "{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}"
|
||||
@@ -21,6 +23,10 @@ Global
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{87022FD2-7E2D-45E4-BFE2-8E445B46DF08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{87022FD2-7E2D-45E4-BFE2-8E445B46DF08}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{87022FD2-7E2D-45E4-BFE2-8E445B46DF08}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{87022FD2-7E2D-45E4-BFE2-8E445B46DF08}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -7,7 +7,9 @@ using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using Verse;
|
||||
|
||||
namespace FisheryLib.FunctionPointers;
|
||||
|
||||
@@ -64,12 +66,18 @@ public abstract class MethodFactory(MethodInfo[] methods, string namePrefix, boo
|
||||
=> type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||
.Where(predicate).ToArray();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static bool UseReferenceIdentity(Type type)
|
||||
=> !type.IsValueType && typeof(Thing).IsAssignableFrom(type);
|
||||
|
||||
public new class Equals(Type type, string dynamicMethodNamePrefix, bool byRef)
|
||||
: MethodFactory(GetMethodInfoArraySafely(type), dynamicMethodNamePrefix, byRef)
|
||||
{
|
||||
protected override MethodInfo GetOrMakeMethodForType(Type type)
|
||||
=> GetSpecializedMethod(type)
|
||||
?? (type.IsAssignableTo(typeof(IEquatable<>), type)
|
||||
?? (UseReferenceIdentity(type)
|
||||
? GetGeneric(nameof(FunctionPointers.Equals.Methods.Reference), type)
|
||||
: type.IsAssignableTo(typeof(IEquatable<>), type)
|
||||
? GetGeneric(type.IsValueType
|
||||
? nameof(FunctionPointers.Equals.Methods.EquatableValueType)
|
||||
: nameof(FunctionPointers.Equals.Methods.EquatableReferenceType), type)
|
||||
@@ -235,7 +243,9 @@ public abstract class MethodFactory(MethodInfo[] methods, string namePrefix, boo
|
||||
{
|
||||
protected override MethodInfo GetOrMakeMethodForType(Type type)
|
||||
=> GetSpecializedMethod(type)
|
||||
?? (type.IsNullable(out var genericArgument)
|
||||
?? (UseReferenceIdentity(type)
|
||||
? GetGeneric(nameof(FunctionPointers.GetHashCode.Methods.Reference), type)
|
||||
: type.IsNullable(out var genericArgument)
|
||||
&& genericArgument.IsAssignableTo(typeof(IEquatable<>), genericArgument)
|
||||
? GetGeneric(nameof(FunctionPointers.GetHashCode.Methods.Nullable), genericArgument)
|
||||
: type.IsEnum
|
||||
@@ -375,4 +385,4 @@ public abstract class MethodFactory(MethodInfo[] methods, string namePrefix, boo
|
||||
private delegate int ByRefHashCodeGetter<T>(ref T arg);
|
||||
private delegate int HashCodeGetter<in T>(T arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,13 @@ public abstract class SingletonFactory<T_base> where T_base : notnull
|
||||
}
|
||||
|
||||
private static T_base GetInternal(Type type)
|
||||
=> _instances.GetOrAdd(type, static type => (T_base)Activator.CreateInstance(type, true));
|
||||
{
|
||||
if (_instances.TryGetValue(type, out var existing))
|
||||
return existing;
|
||||
|
||||
var instance = _instances.GetOrAdd(type, static type => (T_base)Activator.CreateInstance(type, true));
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, T_base> _instances = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
internal static class SpanCompatExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe ref T DangerousGetPinnableReference<T>(this Span<T> span)
|
||||
{
|
||||
if (span.Length == 0)
|
||||
return ref Unsafe.AsRef<T>((void*)1);
|
||||
|
||||
return ref span[0];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe ref T DangerousGetPinnableReference<T>(this ReadOnlySpan<T> span)
|
||||
{
|
||||
if (span.Length == 0)
|
||||
return ref Unsafe.AsRef<T>((void*)1);
|
||||
|
||||
return ref Unsafe.AsRef(in span[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user