Compare commits
8 Commits
bfa948d007
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
e3e306879a
|
|||
|
5bc4202100
|
|||
| 691d97ef2c | |||
| 0aeae0d1bd | |||
| 50f4d5378b | |||
| 124052be77 | |||
| fdff6b048a | |||
| 5a3f6c1cc8 |
@@ -0,0 +1,2 @@
|
|||||||
|
[Oo]bj/
|
||||||
|
[Bb]in/
|
||||||
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.
+3
-2
@@ -7,10 +7,11 @@
|
|||||||
<li>1.3</li>
|
<li>1.3</li>
|
||||||
<li>1.4</li>
|
<li>1.4</li>
|
||||||
<li>1.5</li>
|
<li>1.5</li>
|
||||||
|
<li>1.6</li>
|
||||||
</supportedVersions>
|
</supportedVersions>
|
||||||
<author>bradson</author>
|
<author>bradson, localavaster, Lionel Colaso, Riggs0</author>
|
||||||
<modIconPath IgnoreIfNoMatchingField="True">FisheryLib/ModIcon</modIconPath>
|
<modIconPath IgnoreIfNoMatchingField="True">FisheryLib/ModIcon</modIconPath>
|
||||||
<url>https://github.com/bbradson/fishery</url>
|
<url>https://git.hudsonriggs.systems/HRiggs/Fishery</url>
|
||||||
<loadBefore>
|
<loadBefore>
|
||||||
<li>Ludeon.RimWorld</li>
|
<li>Ludeon.RimWorld</li>
|
||||||
<li>me.samboycoding.betterloading</li>
|
<li>me.samboycoding.betterloading</li>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutDir>..\..\1.6\Assemblies\</OutDir>
|
||||||
|
<Copyright>Copyright (c) 2026 Bradson</Copyright>
|
||||||
|
<PolySharpUseEmbeddedAttributeForGeneratedTypes>false</PolySharpUseEmbeddedAttributeForGeneratedTypes>
|
||||||
|
</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="Microsoft.NETFramework.ReferenceAssemblies.net48" Version="1.0.3" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.6.4871" />
|
||||||
|
<PackageReference Include="Lib.Harmony" Version="2.3.6" ExcludeAssets="runtime" />
|
||||||
|
<PackageReference Update="Zetrith.Prepatcher" Version="1.2.0" />
|
||||||
|
<PackageReference Update="PolySharp" Version="1.16.0" />
|
||||||
|
<PackageReference Update="Krafs.Publicizer" Version="2.3.2" />
|
||||||
|
<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);
|
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)
|
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;
|
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||||
// HashCode.Get can handle null, & int.MaxValue removes any sign
|
// HashCode.Get can handle null, & int.MaxValue removes any sign
|
||||||
|
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||||
while (bucket >= 0)
|
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))
|
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||||
return ref entry.value;
|
return ref entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
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)
|
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 keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||||
|
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||||
while (bucket >= 0)
|
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))
|
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||||
return ref entry.value;
|
return ref entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,18 +228,23 @@ public static class CollectionExtensions
|
|||||||
/// <returns>ref TValue or Unsafe.NullRef{TValue}</returns>
|
/// <returns>ref TValue or Unsafe.NullRef{TValue}</returns>
|
||||||
public static ref TValue TryGetReferenceUnsafe<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
|
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 keyCode = HashCode.Get(key) & int.MaxValue;
|
||||||
|
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||||
while (bucket >= 0)
|
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))
|
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||||
return ref entry.value;
|
return ref entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
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)
|
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 keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||||
|
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||||
while (bucket >= 0)
|
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))
|
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||||
return ref entry.value;
|
return ref entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
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)
|
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 keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||||
|
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||||
while (bucket >= 0)
|
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))
|
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||||
return entry.value;
|
return entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,18 +304,23 @@ public static class CollectionExtensions
|
|||||||
[return: MaybeNull]
|
[return: MaybeNull]
|
||||||
public static TValue TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
|
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 keyCode = HashCode.Get(key) & int.MaxValue;
|
||||||
|
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var bucket = GetBucketEntryIndex(buckets, keyCode);
|
||||||
while (bucket >= 0)
|
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))
|
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||||
return entry.value;
|
return entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,16 +334,21 @@ public static class CollectionExtensions
|
|||||||
var keyCode = HashCode.Get(key) & int.MaxValue;
|
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||||
|
|
||||||
StartOfLookup:
|
StartOfLookup:
|
||||||
if (dictionary.buckets != null)
|
var buckets = GetBuckets(dictionary);
|
||||||
|
if (buckets != null)
|
||||||
{
|
{
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var entries = GetEntries(dictionary)!;
|
||||||
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))
|
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||||
return ref entry.value;
|
return ref entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,16 +363,21 @@ public static class CollectionExtensions
|
|||||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||||
|
|
||||||
StartOfLookup:
|
StartOfLookup:
|
||||||
if (dictionary.buckets != null)
|
var buckets = GetBuckets(dictionary);
|
||||||
|
if (buckets != null)
|
||||||
{
|
{
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var entries = GetEntries(dictionary)!;
|
||||||
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))
|
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||||
return ref entry.value;
|
return ref entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,16 +420,21 @@ public static class CollectionExtensions
|
|||||||
var keyCode = HashCode.Get(key) & int.MaxValue;
|
var keyCode = HashCode.Get(key) & int.MaxValue;
|
||||||
|
|
||||||
StartOfLookup:
|
StartOfLookup:
|
||||||
if (dictionary.buckets != null)
|
var buckets = GetBuckets(dictionary);
|
||||||
|
if (buckets != null)
|
||||||
{
|
{
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var entries = GetEntries(dictionary)!;
|
||||||
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))
|
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||||
return entry.value;
|
return entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,16 +449,21 @@ public static class CollectionExtensions
|
|||||||
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
var keyCode = HashCode.Get(ref key) & int.MaxValue;
|
||||||
|
|
||||||
StartOfLookup:
|
StartOfLookup:
|
||||||
if (dictionary.buckets != null)
|
var buckets = GetBuckets(dictionary);
|
||||||
|
if (buckets != null)
|
||||||
{
|
{
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var entries = GetEntries(dictionary)!;
|
||||||
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))
|
if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key))
|
||||||
return entry.value;
|
return entry.value;
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,12 +478,15 @@ public static class CollectionExtensions
|
|||||||
var result = true;
|
var result = true;
|
||||||
|
|
||||||
StartOfLookup:
|
StartOfLookup:
|
||||||
if (dictionary.buckets != null)
|
var buckets = GetBuckets(dictionary);
|
||||||
|
if (buckets != null)
|
||||||
{
|
{
|
||||||
var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length];
|
var entries = GetEntries(dictionary)!;
|
||||||
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))
|
if (entry.hashCode == keyCode && entry.key.Equals<TKey>(key))
|
||||||
{
|
{
|
||||||
value = entry.value;
|
value = entry.value;
|
||||||
@@ -413,6 +494,8 @@ public static class CollectionExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
bucket = entry.next;
|
bucket = entry.next;
|
||||||
|
if (collisionCount++ >= entries.Length)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,7 +510,7 @@ public static class CollectionExtensions
|
|||||||
Guard.IsNotNull(dictionary);
|
Guard.IsNotNull(dictionary);
|
||||||
Guard.IsNotNull(predicate);
|
Guard.IsNotNull(predicate);
|
||||||
|
|
||||||
var entries = dictionary.entries;
|
var entries = GetEntries(dictionary);
|
||||||
if (entries is null)
|
if (entries is null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -653,13 +736,13 @@ public static class CollectionExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)]
|
[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)]
|
[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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void AddRangeFast<T>(this List<T> list, T[] range)
|
public static void AddRangeFast<T>(this List<T> list, T[] range)
|
||||||
@@ -687,8 +770,7 @@ public static class CollectionExtensions
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
list.EnsureCapacity(list._size + value.Length);
|
list.EnsureCapacity(list._size + value.Length);
|
||||||
UnsafeBlockCopy(ref value.m_firstChar,
|
value.CopyTo(0, list._items, list._size, value.Length);
|
||||||
ref list._items[list._size], value.Length);
|
|
||||||
|
|
||||||
list._size += value.Length;
|
list._size += value.Length;
|
||||||
list._version++;
|
list._version++;
|
||||||
@@ -764,8 +846,8 @@ public static class CollectionExtensions
|
|||||||
|
|
||||||
public static unsafe uint GetSizeEstimate<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
|
public static unsafe uint GetSizeEstimate<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
|
||||||
=> dictionary.GetType().ComputeManagedObjectSizeEstimate()
|
=> dictionary.GetType().ComputeManagedObjectSizeEstimate()
|
||||||
+ ((uint)sizeof(Dictionary<TKey, TValue>.Entry) * (uint)(dictionary.entries?.Length ?? 0))
|
+ ((uint)sizeof(Dictionary<TKey, TValue>.Entry) * (uint)(GetEntries(dictionary)?.Length ?? 0))
|
||||||
+ (sizeof(int) * (uint)(dictionary.buckets?.Length ?? 0));
|
+ (sizeof(int) * (uint)(GetBuckets(dictionary)?.Length ?? 0));
|
||||||
|
|
||||||
internal static unsafe uint ComputeManagedObjectSizeEstimate(this Type type)
|
internal static unsafe uint ComputeManagedObjectSizeEstimate(this Type type)
|
||||||
{
|
{
|
||||||
@@ -857,4 +939,4 @@ public static class CollectionExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override IList New(IEnumerable enumerable) => new List<T>((IEnumerable<T>)enumerable);
|
public override IList New(IEnumerable enumerable) => new List<T>((IEnumerable<T>)enumerable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ public class IndexedFishMap<TX, TY> : IList<(TX X, TY Y)>, IList, IReadOnlyList<
|
|||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_xIndices.Clear();
|
_xIndices.Clear();
|
||||||
|
_yIndices.Clear();
|
||||||
_items.Clear();
|
_items.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,4 +257,4 @@ public class IndexedFishMap<TX, TY> : IList<(TX X, TY Y)>, IList, IReadOnlyList<
|
|||||||
|
|
||||||
private static (TX X, TY Y) EnsureCorrectType([NotNullWhen(true)] object? item)
|
private static (TX X, TY Y) EnsureCorrectType([NotNullWhen(true)] object? item)
|
||||||
=> item is ValueTuple<TX, TY> t ? t : ThrowHelper.ThrowArgumentException<(TX X, TY Y)>();
|
=> item is ValueTuple<TX, TY> t ? t : ThrowHelper.ThrowArgumentException<(TX X, TY Y)>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Zetrith.Prepatcher" Version="1.*" />
|
<PackageReference Include="Zetrith.Prepatcher" Version="1.*" />
|
||||||
<PackageReference Include="PolySharp" 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.*" />
|
<PackageReference Include="Krafs.Publicizer" Version="2.*" />
|
||||||
|
|
||||||
<Publicize Include="Assembly-CSharp;0Harmony" IncludeVirtualMembers="false" />
|
<Publicize Include="Assembly-CSharp;0Harmony" IncludeVirtualMembers="false" />
|
||||||
@@ -90,4 +90,4 @@
|
|||||||
<PackagePath />
|
<PackagePath />
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.1.32120.378
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.5", "1.5.csproj", "{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.5", "1.5.csproj", "{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}"
|
||||||
EndProject
|
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}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.4", "1.4.csproj", "{BE85EB31-71CD-443C-8C93-20E2B7F3F549}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.3", "1.3.csproj", "{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}"
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Debug|Any CPU.Build.0 = 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
|
{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.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
namespace FisheryLib.FunctionPointers;
|
namespace FisheryLib.FunctionPointers;
|
||||||
|
|
||||||
@@ -64,12 +66,18 @@ public abstract class MethodFactory(MethodInfo[] methods, string namePrefix, boo
|
|||||||
=> type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
=> type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||||
.Where(predicate).ToArray();
|
.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)
|
public new class Equals(Type type, string dynamicMethodNamePrefix, bool byRef)
|
||||||
: MethodFactory(GetMethodInfoArraySafely(type), dynamicMethodNamePrefix, byRef)
|
: MethodFactory(GetMethodInfoArraySafely(type), dynamicMethodNamePrefix, byRef)
|
||||||
{
|
{
|
||||||
protected override MethodInfo GetOrMakeMethodForType(Type type)
|
protected override MethodInfo GetOrMakeMethodForType(Type type)
|
||||||
=> GetSpecializedMethod(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
|
? GetGeneric(type.IsValueType
|
||||||
? nameof(FunctionPointers.Equals.Methods.EquatableValueType)
|
? nameof(FunctionPointers.Equals.Methods.EquatableValueType)
|
||||||
: nameof(FunctionPointers.Equals.Methods.EquatableReferenceType), type)
|
: 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)
|
protected override MethodInfo GetOrMakeMethodForType(Type type)
|
||||||
=> GetSpecializedMethod(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)
|
&& genericArgument.IsAssignableTo(typeof(IEquatable<>), genericArgument)
|
||||||
? GetGeneric(nameof(FunctionPointers.GetHashCode.Methods.Nullable), genericArgument)
|
? GetGeneric(nameof(FunctionPointers.GetHashCode.Methods.Nullable), genericArgument)
|
||||||
: type.IsEnum
|
: 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 ByRefHashCodeGetter<T>(ref T arg);
|
||||||
private delegate int HashCodeGetter<in T>(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)
|
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();
|
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